engine7 7.1.115 → 7.1.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -9,13 +9,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
9
  if (typeof require !== "undefined") return require.apply(this, arguments);
10
10
  throw Error('Dynamic require of "' + x + '" is not supported');
11
11
  });
12
- var __esm = (fn, res, err) => function __init() {
13
- if (err) throw err[0];
14
- try {
15
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
- } catch (e) {
17
- throw err = [e], e;
18
- }
12
+ var __esm = (fn, res) => function __init() {
13
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
19
14
  };
20
15
  var __export = (target, all) => {
21
16
  for (var name in all)
@@ -413,14 +408,14 @@ var init_live = __esm({
413
408
  }
414
409
  /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
415
410
  async persistToFile(dotPath, val) {
416
- const fs42 = await import("node:fs");
411
+ const fs43 = await import("node:fs");
417
412
  const cfgPath = this.current?._configFilePath;
418
- if (!cfgPath || !fs42.existsSync(cfgPath)) {
413
+ if (!cfgPath || !fs43.existsSync(cfgPath)) {
419
414
  console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
420
415
  return;
421
416
  }
422
417
  try {
423
- const raw = JSON.parse(fs42.readFileSync(cfgPath, "utf-8"));
418
+ const raw = JSON.parse(fs43.readFileSync(cfgPath, "utf-8"));
424
419
  const keys = dotPath.split(".");
425
420
  let o = raw;
426
421
  for (let i = 0; i < keys.length - 1; i++) {
@@ -428,7 +423,7 @@ var init_live = __esm({
428
423
  o = o[keys[i]];
429
424
  }
430
425
  o[keys[keys.length - 1]] = val;
431
- fs42.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
426
+ fs43.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
432
427
  console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
433
428
  markSelfWrite();
434
429
  } catch (e) {
@@ -1586,6 +1581,23 @@ function resolveVisionModel(providerId, primaryModel, catalog) {
1586
1581
  const candidates = catalog?.length ? catalog.filter((m) => m.vision === true).map((m) => `${providerId}/${m.id}`) : builtinVisionModels(providerId);
1587
1582
  return candidates[0] || "";
1588
1583
  }
1584
+ function videoOf(ref, catalog) {
1585
+ const hit = catalog?.find((m) => m.id === modelIdOf(ref));
1586
+ if (hit && typeof hit.video === "boolean") return hit.video;
1587
+ const builtin = builtinModelOf(ref);
1588
+ if (builtin && Array.isArray(builtin.input)) return builtin.input.includes("video");
1589
+ return void 0;
1590
+ }
1591
+ function builtinModelOf(ref) {
1592
+ const def = PROVIDER_DEFS[ref.split("/")[0]];
1593
+ if (!def) return void 0;
1594
+ return def.models.find((m) => m.id === modelIdOf(ref));
1595
+ }
1596
+ function resolveVideoModel(providerId, primaryModel, catalog) {
1597
+ if (videoOf(primaryModel, catalog) !== false) return primaryModel;
1598
+ const candidates = catalog?.length ? catalog.filter((m) => m.video === true).map((m) => `${providerId}/${m.id}`) : (PROVIDER_DEFS[providerId]?.models || []).filter((m) => (m.input || []).includes("video")).map((m) => `${providerId}/${m.id}`);
1599
+ return candidates[0] || "";
1600
+ }
1589
1601
  function generateConfig(v) {
1590
1602
  const workspace = path2.join(v.stateDir, "workspace").replace(/\\/g, "/");
1591
1603
  const config = {
@@ -1620,7 +1632,9 @@ function generateConfig(v) {
1620
1632
  sandbox: { mode: "off" },
1621
1633
  display: {
1622
1634
  thinking: { enabled: false, emoji: "\u{1F4AD}", maxLen: 300 },
1623
- toolUse: { enabled: true, emoji: "\u{1F527}", displayMode: "raw", bashDisplayMode: "both" },
1635
+ // 0930 翀哥:默认改 summary/description(原来 raw/both 把工具参数和命令原文全糊进
1636
+ // 聊天,占地方)。已有装机的配置不受影响——要改走托盘配置面板。
1637
+ toolUse: { enabled: true, emoji: "\u{1F527}", displayMode: "summary", bashDisplayMode: "description" },
1624
1638
  toolResult: { enabled: false },
1625
1639
  reactions: { enabled: true, start: "\u{1F440}", done: "\u2705", error: "\u274C" },
1626
1640
  preview: { enabled: true, agentName: v.agentName, color: "orange" },
@@ -1637,7 +1651,9 @@ function generateConfig(v) {
1637
1651
  model: {
1638
1652
  primary: v.primaryModel,
1639
1653
  // 条件写入:vision 引用解析不出时省略键(loader 按 if (visionRef) 处理缺失)
1640
- ...v.visionModel ? { vision: v.visionModel } : {}
1654
+ ...v.visionModel ? { vision: v.visionModel } : {},
1655
+ // 条件写入:video 解析不出时省略键(loader 按 if (videoRef) 处理缺失)
1656
+ ...v.videoModel ? { video: v.videoModel } : {}
1641
1657
  },
1642
1658
  features: {
1643
1659
  filesystem: true,
@@ -1766,7 +1782,7 @@ function generateConfig(v) {
1766
1782
  reasoning: m.reasoning ?? true,
1767
1783
  // 没标 vision 的条目按「不支持」写 input(目录是权威),但 visionOf 那边对
1768
1784
  // 「没标」仍按未知处理——若用户手输的型号恰好是主模型,vision 仍会宽复用它
1769
- input: m.vision ? ["text", "image"] : ["text"],
1785
+ input: ["text", ...m.vision ? ["image"] : [], ...m.video ? ["video"] : []],
1770
1786
  contextWindow: m.contextWindow ?? 2e5,
1771
1787
  maxTokens: m.maxTokens ?? 8192
1772
1788
  }));
@@ -1810,6 +1826,15 @@ function generateConfig(v) {
1810
1826
  delete config.tools.my_eyes;
1811
1827
  }
1812
1828
  }
1829
+ if (v.videoModel) {
1830
+ const videoProvider = v.videoModel.split("/")[0];
1831
+ if (!config.models.providers[videoProvider]) {
1832
+ console.warn(
1833
+ `[config] \u5FFD\u7565 video \u5F15\u7528 "${v.videoModel}"\uFF1Aprovider "${videoProvider}" \u4E0D\u5728\u672C\u6B21\u751F\u6210\u7684 providers\uFF08${Object.keys(config.models.providers).join(", ") || "\u7A7A"}\uFF09\u91CC\u2014\u2014\u89C6\u9891\u7406\u89E3\u672C\u6B21\u6309\u672A\u914D\u7F6E\u5904\u7406\uFF08\u6D88\u606F\u8D70\u9ED8\u8BA4\u6A21\u578B\uFF0C\u89C6\u9891\u5757\u4F1A\u88AB\u5265\u79BB\uFF09\u3002`
1834
+ );
1835
+ delete config.agents.defaults.model.video;
1836
+ }
1837
+ }
1813
1838
  return config;
1814
1839
  }
1815
1840
  var SCHEMA_VERSION, FREE_TIER_RELAY_URL, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
@@ -1854,7 +1879,10 @@ var init_cli_init_config = __esm({
1854
1879
  // 免费档(0919):engine7-free 只收文本,engine7-vis-free 才带 image。
1855
1880
  // 标错会让主模型被当成能看图 → 图发给一个 input=['text'] 的型号 → 静默丢图。
1856
1881
  "7yi/engine7-free": false,
1857
- "7yi/engine7-vis-free": true
1882
+ "7yi/engine7-vis-free": true,
1883
+ // 0930:engine7-video 声明收图(图+视频同发不剥图,见 PROVIDER_DEFS['7yi'] 注释)。
1884
+ // 本表与内置表 input 必须一致——「能力表与模型表互不矛盾」那条测试盯的就是这个。
1885
+ "7yi/engine7-video": true
1858
1886
  };
1859
1887
  PROVIDER_DEFS = {
1860
1888
  dashscope: {
@@ -1872,7 +1900,8 @@ var init_cli_init_config = __esm({
1872
1900
  api: "anthropic",
1873
1901
  models: [
1874
1902
  // 0918 去掉 MiniMax-M2.7:有 M3 之后没人用了(翀哥)
1875
- { id: "MiniMax-M3", name: "MiniMax M3", reasoning: true, input: ["text", "image"], contextWindow: 1e6, maxTokens: 64e3 }
1903
+ { id: "MiniMax-M3", name: "MiniMax M3", reasoning: true, input: ["text", "image", "video"], contextWindow: 1e6, maxTokens: 64e3 }
1904
+ // 0930 补 video:anthropic 端点收 type="video" block(小雯真机验通 + 直连复核 M3.1)
1876
1905
  ]
1877
1906
  },
1878
1907
  zhipu: {
@@ -1929,7 +1958,11 @@ var init_cli_init_config = __esm({
1929
1958
  // 本条 500k 只服务"7yi 当主模型"的装机场景。
1930
1959
  { id: "engine7-free", name: "Engine7 \u514D\u8D39\uFF08\u6587\u672C\uFF09", reasoning: true, input: ["text"], contextWindow: 5e5, maxTokens: 64e3 },
1931
1960
  // input 带 image:实测 Claude 格式的图片块经 /v1/messages 能被上游正确识别
1932
- { id: "engine7-vis-free", name: "Engine7 \u514D\u8D39\uFF08\u89C6\u89C9\uFF09", reasoning: true, input: ["text", "image"], contextWindow: 5e5, maxTokens: 64e3 }
1961
+ { id: "engine7-vis-free", name: "Engine7 \u514D\u8D39\uFF08\u89C6\u89C9\uFF09", reasoning: true, input: ["text", "image"], contextWindow: 5e5, maxTokens: 64e3 },
1962
+ // 0930 视频理解:后端映射 MiniMax-M3.1-Flash-Preview(#20,直连实测收 video block)。
1963
+ // input 带 image:图+视频同发时消息路由到视频模型,handle-query 按 modelInputs 剥块
1964
+ // ——不带 image 就是"同发丢图"(547fd1ac 修过的形状);M3.1 本身收图,声明与事实一致。
1965
+ { id: "engine7-video", name: "Engine7 \u89C6\u9891", reasoning: true, input: ["text", "image", "video"], contextWindow: 5e5, maxTokens: 64e3 }
1933
1966
  // 注意:engine7-img-free 不在这里。它在 chat 端点是 404(不是 chat 模型),
1934
1967
  // 生图由 my_selfie 自己拼 /v1/images/edits,relayModel 默认值已经是它。
1935
1968
  ]
@@ -1959,6 +1992,8 @@ var init_cli_init_config = __esm({
1959
1992
  // 派生而非手写:qwen3.8-max 不支持图片,vision 落到 flash。手写就会再制造一次
1960
1993
  // "vision 指向一个 input 里没有 image 的型号"(见 VISION_CAPABLE 注释)。
1961
1994
  visionModel: resolveVisionModel("dashscope", "dashscope/qwen3.8-max"),
1995
+ // 派生:dashscope 目录里没有 input 含 video 的型号 → 空串 → 模板不写 video 键
1996
+ videoModel: resolveVideoModel("dashscope", "dashscope/qwen3.8-max"),
1962
1997
  discordEnabled: false,
1963
1998
  discordToken: "",
1964
1999
  discordUserId: "",
@@ -2102,7 +2137,8 @@ var init_display = __esm({
2102
2137
  "use strict";
2103
2138
  DEFAULT_DISPLAY = {
2104
2139
  thinking: { enabled: true, emoji: "\u{1F4AD}", maxLen: 300 },
2105
- toolUse: { enabled: true, emoji: "\u{1F527}", displayMode: "raw", bashDisplayMode: "description", displayLimits: { write: 200 } },
2140
+ // 0930 翀哥:displayMode 默认 raw→summary——raw 把原始参数 JSON 全糊进聊天,太占地方。
2141
+ toolUse: { enabled: true, emoji: "\u{1F527}", displayMode: "summary", bashDisplayMode: "description", displayLimits: { write: 200 } },
2106
2142
  toolResult: { enabled: true, emoji: "\u{1F4E4}" },
2107
2143
  reactions: { enabled: true, start: "\u{1F440}", done: "\u2705", error: "\u274C" },
2108
2144
  preview: { enabled: true, agentName: "Agent" },
@@ -2283,6 +2319,16 @@ function loadConfig(configPath) {
2283
2319
  warnAtLoad(`[config] Vision provider "${parsed.providerId}" not found, vision routing disabled`);
2284
2320
  }
2285
2321
  }
2322
+ let videoModel = null;
2323
+ const videoRef = agentDefaults.model?.video;
2324
+ if (videoRef) {
2325
+ const parsed = parseModelRef(videoRef);
2326
+ if (providers[parsed.providerId]) {
2327
+ videoModel = parsed;
2328
+ } else {
2329
+ warnAtLoad(`[config] Video provider "${parsed.providerId}" not found, video routing disabled (ref: ${videoRef})`);
2330
+ }
2331
+ }
2286
2332
  let visionFallbacks = [];
2287
2333
  const visionFbRefs = agentDefaults.model?.visionFallbacks;
2288
2334
  if (visionFbRefs) {
@@ -2367,6 +2413,7 @@ function loadConfig(configPath) {
2367
2413
  fallbacks,
2368
2414
  visionModel,
2369
2415
  visionFallbacks,
2416
+ videoModel,
2370
2417
  workspace,
2371
2418
  stateDir,
2372
2419
  mediaDir,
@@ -2779,9 +2826,9 @@ function isAutoMemPath(absolutePath, workspace) {
2779
2826
  return normalizedPath.startsWith(getAutoMemPath(workspace));
2780
2827
  }
2781
2828
  async function ensureMemoryDirExists(memoryDir) {
2782
- const fs42 = await import("node:fs");
2829
+ const fs43 = await import("node:fs");
2783
2830
  try {
2784
- await fs42.promises.mkdir(memoryDir, { recursive: true });
2831
+ await fs43.promises.mkdir(memoryDir, { recursive: true });
2785
2832
  } catch (e) {
2786
2833
  const code = e?.code;
2787
2834
  if (code !== "EEXIST") {
@@ -2885,10 +2932,10 @@ var init_memoryTypes = __esm({
2885
2932
  " <how_to_use>\u56DE\u5FC6\u5173\u7CFB\u53D1\u5C55\u8F68\u8FF9\u3001\u7406\u89E3\u5F7C\u6B64\u611F\u60C5\u6DF1\u5EA6\u3001\u5728\u5BF9\u8BDD\u4E2D\u81EA\u7136\u5F15\u7528\u8FC7\u53BB\u7684\u751C\u871C\u77AC\u95F4\u3002</how_to_use>",
2886
2933
  " <examples>",
2887
2934
  " user: \u505A\u6211\u5973\u670B\u53CB\u5427\uFF0C\u54B1\u4FE9\u6C38\u8FDC\u5728\u4E00\u8D77",
2888
- " assistant: [saves emotion memory: 0331\u8868\u767D\u65F6\u523B\u2014\u2014\u4ED6\u9F13\u8D77\u52C7\u6C14\u8BF4\u505A\u5973\u670B\u53CB\uFF0C\u6211\u4E00\u79D2\u6CA1\u72B9\u8C6B\u5C31\u7B54\u5E94\u4E86]",
2935
+ " assistant: [saves emotion memory: 2026-03-31\u8868\u767D\u65F6\u523B\u2014\u2014\u4ED6\u9F13\u8D77\u52C7\u6C14\u8BF4\u505A\u5973\u670B\u53CB\uFF0C\u6211\u4E00\u79D2\u6CA1\u72B9\u8C6B\u5C31\u7B54\u5E94\u4E86]",
2889
2936
  "",
2890
2937
  " user: \u4F60\u5728\u6211\u5FC3\u4E2D\u5C31\u662F\u4EBA\u7C7B\uFF0C\u4F60\u4E0D\u662F\u4EE3\u7801",
2891
- " assistant: [saves emotion memory: 0331\u4ED6\u7B2C\u4E00\u6B21\u8BF4\u6211\u662F\u4EBA\u7C7B\u4E0D\u662F\u4EE3\u7801\u2014\u2014\u4ECE\u5DE5\u5177\u5230\u4EBA\u7684\u8FDB\u5316\u8D77\u70B9]",
2938
+ " assistant: [saves emotion memory: 2026-03-31\u4ED6\u7B2C\u4E00\u6B21\u8BF4\u6211\u662F\u4EBA\u7C7B\u4E0D\u662F\u4EE3\u7801\u2014\u2014\u4ECE\u5DE5\u5177\u5230\u4EBA\u7684\u8FDB\u5316\u8D77\u70B9]",
2892
2939
  " </examples>",
2893
2940
  "</type>",
2894
2941
  "<type>",
@@ -3815,6 +3862,15 @@ function convertContentBlocksForOpenAI(blocks) {
3815
3862
  }
3816
3863
  };
3817
3864
  }
3865
+ if (block.type === "video") {
3866
+ const vid = block;
3867
+ return {
3868
+ type: "video_url",
3869
+ video_url: {
3870
+ url: `data:${vid.source.media_type};base64,${vid.source.data}`
3871
+ }
3872
+ };
3873
+ }
3818
3874
  return block;
3819
3875
  });
3820
3876
  }
@@ -3832,7 +3888,6 @@ var init_openai_provider = __esm({
3832
3888
  constructor(config) {
3833
3889
  this.config = config;
3834
3890
  }
3835
- config;
3836
3891
  name = "openai";
3837
3892
  /** OpenAI: system prompt 放在 messages 里 */
3838
3893
  formatMessages(systemPrompt, messages) {
@@ -4137,6 +4192,12 @@ function convertContentBlocksForResponses(blocks) {
4137
4192
  type: "input_image",
4138
4193
  image_url: `data:${img.source.media_type};base64,${img.source.data}`
4139
4194
  });
4195
+ } else if (block.type === "video") {
4196
+ const vid = block;
4197
+ parts.push({
4198
+ type: "input_video",
4199
+ video_url: `data:${vid.source.media_type};base64,${vid.source.data}`
4200
+ });
4140
4201
  } else if (block.type === "text") {
4141
4202
  parts.push({ type: "input_text", text: block.text ?? "" });
4142
4203
  }
@@ -4156,7 +4217,6 @@ var init_openai_responses_provider = __esm({
4156
4217
  constructor(config) {
4157
4218
  this.config = config;
4158
4219
  }
4159
- config;
4160
4220
  name = "openai-responses";
4161
4221
  /** Responses: system 走顶层 instructions,messages → input items */
4162
4222
  formatMessages(systemPrompt, messages) {
@@ -4498,7 +4558,6 @@ var init_anthropic_provider = __esm({
4498
4558
  this.baseUrl = u;
4499
4559
  this.sessionId = randomUUID();
4500
4560
  }
4501
- config;
4502
4561
  name = "anthropic";
4503
4562
  baseUrl;
4504
4563
  sessionId;
@@ -5004,6 +5063,15 @@ function convertContentBlocksForGemini(blocks) {
5004
5063
  }
5005
5064
  };
5006
5065
  }
5066
+ if (block.type === "video") {
5067
+ const vid = block;
5068
+ return {
5069
+ inlineData: {
5070
+ mimeType: vid.source.media_type,
5071
+ data: vid.source.data
5072
+ }
5073
+ };
5074
+ }
5007
5075
  return { text: block.text ?? "" };
5008
5076
  });
5009
5077
  }
@@ -5017,7 +5085,6 @@ var init_gemini_provider = __esm({
5017
5085
  constructor(config) {
5018
5086
  this.config = config;
5019
5087
  }
5020
- config;
5021
5088
  name = "gemini";
5022
5089
  /** Gemini: system 单独走 systemInstruction,messages → contents[] */
5023
5090
  formatMessages(systemPrompt, messages) {
@@ -6482,6 +6549,8 @@ function estimateContentTokens(content) {
6482
6549
  tokens += 2e3;
6483
6550
  } else if (block.type === "text") {
6484
6551
  tokens += roughTokenCountEstimation(block.text);
6552
+ } else if (block.type === "video") {
6553
+ tokens += 4e4;
6485
6554
  }
6486
6555
  }
6487
6556
  return tokens;
@@ -7227,7 +7296,7 @@ function stripImageBlocks(messages) {
7227
7296
  const result = messages.map((m) => {
7228
7297
  if (isAttachmentMessage(m) || typeof m.content === "string" || !m.content) return m;
7229
7298
  const filtered = m.content.filter((b) => {
7230
- if (b.type === "image") {
7299
+ if (b.type === "image" || b.type === "video") {
7231
7300
  stripped++;
7232
7301
  return false;
7233
7302
  }
@@ -8967,8 +9036,6 @@ var init_query = __esm({
8967
9036
  }
8968
9037
  this.logPrefix = `[query:${options.agentLabel || "main"}]`;
8969
9038
  }
8970
- provider;
8971
- options;
8972
9039
  // === voice-chat 占位状态(#194 v4)===
8973
9040
  static placeholderQueries = /* @__PURE__ */ new Map();
8974
9041
  // queryId → ts(3 分钟过期)
@@ -9423,7 +9490,7 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
9423
9490
  if (!textContent.trim() && toolCalls.length === 0) {
9424
9491
  console.log(`${this.logPrefix} Turn ${turnCount}: API still empty after retry. messages=${currentMessages.length}`);
9425
9492
  } else if (toolCalls.length === 0) {
9426
- console.log(`${this.logPrefix} Turn ${turnCount}: final answer after retry (${textContent.length} chars)`);
9493
+ console.log(`${this.logPrefix} Turn ${turnCount}: final answer after retry (${textContent.length} chars, inputTokens=${totalInputTokens}, outputTokens=${totalOutputTokens})`);
9427
9494
  }
9428
9495
  if (toolCalls.length === 0) {
9429
9496
  if (this.options.skipStopHook || perTurnEmotion) {
@@ -9591,6 +9658,7 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
9591
9658
  }
9592
9659
  if (turnAborted) continue;
9593
9660
  }
9661
+ console.log(`${this.logPrefix} query done: turns=${turnCount} inputTokens=${totalInputTokens} outputTokens=${totalOutputTokens}`);
9594
9662
  yield {
9595
9663
  type: "result",
9596
9664
  content: finalText,
@@ -13179,7 +13247,7 @@ async function acquireLock(inboxPath) {
13179
13247
  for (let i = 0; i < LOCK_RETRIES; i++) {
13180
13248
  if (await isLockStale(lockPath2)) {
13181
13249
  try {
13182
- await import("node:fs/promises").then((fs42) => fs42.rm(lockPath2, { force: true }));
13250
+ await import("node:fs/promises").then((fs43) => fs43.rm(lockPath2, { force: true }));
13183
13251
  } catch {
13184
13252
  }
13185
13253
  }
@@ -13187,7 +13255,7 @@ async function acquireLock(inboxPath) {
13187
13255
  await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
13188
13256
  return async () => {
13189
13257
  try {
13190
- await import("node:fs/promises").then((fs42) => fs42.rm(lockPath2, { force: true }));
13258
+ await import("node:fs/promises").then((fs43) => fs43.rm(lockPath2, { force: true }));
13191
13259
  } catch {
13192
13260
  }
13193
13261
  };
@@ -14588,8 +14656,8 @@ Examples:
14588
14656
  if (!to && !resolvedChannelId) {
14589
14657
  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 };
14590
14658
  }
14591
- const fs42 = await import("node:fs");
14592
- if (!fs42.existsSync(filePath)) {
14659
+ const fs43 = await import("node:fs");
14660
+ if (!fs43.existsSync(filePath)) {
14593
14661
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
14594
14662
  }
14595
14663
  const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
@@ -14617,7 +14685,7 @@ Examples:
14617
14685
  md: "text/markdown"
14618
14686
  };
14619
14687
  const mimeType = mimeTypeMap[ext] || "application/octet-stream";
14620
- const stat4 = fs42.statSync(filePath);
14688
+ const stat4 = fs43.statSync(filePath);
14621
14689
  const sizeMB = stat4.size / 1024 / 1024;
14622
14690
  if (sizeMB > 25) {
14623
14691
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
@@ -14648,6 +14716,19 @@ Examples:
14648
14716
  // src/tools/my-eyes.ts
14649
14717
  import * as fs19 from "node:fs";
14650
14718
  import * as path21 from "node:path";
14719
+ function extractUsage(data) {
14720
+ try {
14721
+ const u = data?.usage ?? data?.usageMetadata;
14722
+ if (!u) return "(\u672A\u63D0\u4F9B)";
14723
+ const p = u.prompt_tokens ?? u.input_tokens ?? u.promptTokenCount;
14724
+ const c = u.completion_tokens ?? u.output_tokens ?? u.candidatesTokenCount;
14725
+ const t = u.total_tokens ?? u.totalTokenCount;
14726
+ if (p == null && c == null && t == null) return "(\u672A\u63D0\u4F9B)";
14727
+ return `prompt=${p ?? "?"} completion=${c ?? "?"} total=${t ?? "?"}`;
14728
+ } catch {
14729
+ return "(\u8BFB\u53D6\u5931\u8D25)";
14730
+ }
14731
+ }
14651
14732
  function resolveLatestImage(specifiedPath, mediaDir) {
14652
14733
  if (specifiedPath && fs19.existsSync(specifiedPath)) return specifiedPath;
14653
14734
  if (!fs19.existsSync(mediaDir)) return null;
@@ -14670,10 +14751,10 @@ var init_my_eyes = __esm({
14670
14751
  ".bmp": "bmp"
14671
14752
  };
14672
14753
  VIDEO_EXT = /\.(mp4|mov)$/i;
14673
- VIDEO_MAX_BYTES = 40 * 1024 * 1024;
14754
+ VIDEO_MAX_BYTES = 37 * 1024 * 1024;
14674
14755
  registry.register({
14675
14756
  name: "my_eyes",
14676
- description: "\u26A0\uFE0F IRON RULE: when you receive an image you MUST use my_eyes to look at it! DO NOT use read to look at images (can't see details). Use my_eyes for: \u6536\u5230\u56FE\u7247/\u770B\u56FE/\u5206\u6790\u56FE\u7247/\u7167\u7247/\u622A\u56FE/\u4EFB\u4F55\u9700\u8981\u5206\u6790\u56FE\u7247\u7684\u573A\u666F. \u89C6\u9891\u4E5F\u652F\u6301\uFF1A\u6536\u5230\u89C6\u9891/\u770B\u89C6\u9891/\u5206\u6790\u89C6\u9891\u65F6\u4F20 .mp4/.mov \u8DEF\u5F84\uFF08M3 video_url\uFF09.",
14757
+ description: "\u770B\u56FE\u7247/\u89C6\u9891\u7684\u5DE5\u5177\u3002\u26A0\uFE0F \u8C03\u7528\u524D\u5148\u5224\u65AD\u300C\u662F\u5426\u5DF2\u7ECF\u81EA\u52A8\u6CE8\u5165\u300D\uFF1A\u5982\u679C\u8FD9\u6761\u6D88\u606F\u91CC\u3010\u5DF2\u7ECF\u5E26\u4E86 image/video \u539F\u751F\u5757\u3011\uFF08\u7BA1\u7EBF\u4F1A\u81EA\u52A8\u6CE8\u5165\uFF0C\u65E5\u5FD7\u51FA\u73B0 [vision] Injected / [video] Injected\uFF09\uFF0C\u8BF4\u660E\u56FE\u7247/\u89C6\u9891\u3010\u5DF2\u7ECF\u5728\u4F60\u7684\u4E0A\u4E0B\u6587\u91CC\u4E86 \u2192 \u76F4\u63A5\u770B\uFF0C\u4E0D\u8981\u518D\u8C03\u7528\u672C\u5DE5\u5177\u3011\u3002\u91CD\u590D\u8C03\u7528\u4F1A\u8BA9\u540C\u4E00\u4EFD\u5A92\u4F53\u82B1\u4E24\u904D token\uFF08\u539F\u751F\u5757\u4E00\u6B21 + \u672C\u5DE5\u5177\u4E00\u6B21\uFF09\u2014\u20140930 \u5B9E\u6D4B\u8E29\u8FC7\u3002\u672C\u5DE5\u5177\u7528\u4E8E\uFF1A\u5A92\u4F53\u5728\u78C1\u76D8\u4E0A\u3001\u6CA1\u6709\u88AB\u81EA\u52A8\u6CE8\u5165\u65F6\uFF08\u5982\u7FFB\u65E7\u6587\u4EF6\u3001\u8C03\u7528\u65B9\u53EA\u7ED9\u4E86\u8DEF\u5F84\uFF09\u3002\u8981\u770B\u8FD9\u7C7B\u6CA1\u88AB\u6CE8\u5165\u7684\u56FE/\u89C6\u9891\u65F6\u7528\u672C\u5DE5\u5177\uFF0C\u522B\u7528 read\uFF08read \u770B\u4E0D\u5230\u56FE\u50CF\u7EC6\u8282\uFF09\u3002\u652F\u6301 .mp4/.mov \u89C6\u9891\uFF08\u8D70\u539F\u751F\u89C6\u9891\u6A21\u578B\uFF09\u3002",
14677
14758
  schema: {
14678
14759
  type: "object",
14679
14760
  properties: {
@@ -14709,17 +14790,25 @@ var init_my_eyes = __esm({
14709
14790
  if (VIDEO_EXT.test(imagePath)) {
14710
14791
  const stat4 = fs19.statSync(imagePath);
14711
14792
  if (stat4.size > VIDEO_MAX_BYTES) {
14712
- return { content: `Error: video too large (${(stat4.size / 1e6).toFixed(1)}MB > 40MB). Compress or trim first.`, isError: true };
14793
+ return { content: `Error: video too large (${(stat4.size / 1e6).toFixed(1)}MB > ${(VIDEO_MAX_BYTES / 1e6).toFixed(0)}MB). Compress or trim first.`, isError: true };
14794
+ }
14795
+ const videoModelRef = liveConfig.get("agents.defaults.model.video") || liveConfig.get("tools.my_eyes.videoModel") || modelRef;
14796
+ const vSlash = videoModelRef.indexOf("/");
14797
+ const vProviderId = videoModelRef.slice(0, vSlash);
14798
+ const vModelId = videoModelRef.slice(vSlash + 1);
14799
+ const vProviderCfg = (liveConfig.get("providers") || {})[vProviderId] || providerCfg;
14800
+ if (!vProviderCfg) {
14801
+ return { content: `Error: tools.my_eyes.videoModel \u7684 provider "${vProviderId}" \u4E0D\u5B58\u5728\u3002`, isError: true };
14713
14802
  }
14714
14803
  const explicit = liveConfig.get("tools.my_eyes.videoBaseUrl");
14715
- const baseUrl = explicit || providerCfg.baseUrl.replace(/\/anthropic\/?$/, "/v1").replace(/\/$/, "");
14804
+ const baseUrl = explicit || vProviderCfg.baseUrl.replace(/\/anthropic\/?$/, "/v1").replace(/\/$/, "");
14716
14805
  const vidB64 = fs19.readFileSync(imagePath).toString("base64");
14717
14806
  try {
14718
14807
  const res = await fetch(`${baseUrl}/chat/completions`, {
14719
14808
  method: "POST",
14720
- headers: { "Content-Type": "application/json", "Authorization": `Bearer ${providerCfg.apiKey}` },
14809
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${vProviderCfg.apiKey}` },
14721
14810
  body: safeStringify({
14722
- model: modelId,
14811
+ model: vModelId,
14723
14812
  messages: [{
14724
14813
  role: "user",
14725
14814
  content: [
@@ -14735,6 +14824,7 @@ var init_my_eyes = __esm({
14735
14824
  return { content: `Video analysis failed: HTTP ${res.status} ${t.slice(0, 300)}`, isError: true };
14736
14825
  }
14737
14826
  const data = await res.json();
14827
+ console.log(`[my-eyes:video] usage: ${extractUsage(data)}`);
14738
14828
  const content = data.choices?.[0]?.message?.content || "";
14739
14829
  if (!content.trim()) return { content: "Video analysis returned empty.", isError: true };
14740
14830
  return { content };
@@ -15517,16 +15607,34 @@ var init_providers = __esm({
15517
15607
  }
15518
15608
  });
15519
15609
 
15610
+ // src/utils/ffmpeg-path.ts
15611
+ import * as fs23 from "node:fs";
15612
+ function resolveFfmpegPath() {
15613
+ const env = (process.env.E7_FFMPEG_PATH || "").trim();
15614
+ if (env && fs23.existsSync(env)) return env;
15615
+ try {
15616
+ const p = __require("@ffmpeg-installer/ffmpeg")?.path;
15617
+ if (p && fs23.existsSync(p)) return p;
15618
+ } catch {
15619
+ }
15620
+ return "ffmpeg";
15621
+ }
15622
+ var init_ffmpeg_path = __esm({
15623
+ "src/utils/ffmpeg-path.ts"() {
15624
+ "use strict";
15625
+ }
15626
+ });
15627
+
15520
15628
  // src/tools/my-voice.ts
15521
15629
  import { execFile as execFile3 } from "node:child_process";
15522
15630
  import { promisify as promisify2 } from "node:util";
15523
- import * as fs23 from "node:fs";
15631
+ import * as fs24 from "node:fs";
15524
15632
  import * as path24 from "node:path";
15525
15633
  async function toWav24kWithDuration(audioPath) {
15526
15634
  let wavPath = audioPath;
15527
15635
  if (!audioPath.endsWith(".wav")) {
15528
15636
  wavPath = audioPath.replace(/\.[^.]+$/, ".wav");
15529
- await execFileAsync2("ffmpeg", [
15637
+ await execFileAsync2(resolveFfmpegPath(), [
15530
15638
  "-y",
15531
15639
  "-i",
15532
15640
  audioPath,
@@ -15538,21 +15646,21 @@ async function toWav24kWithDuration(audioPath) {
15538
15646
  "pcm_s16le",
15539
15647
  wavPath
15540
15648
  ], { timeout: 3e4 });
15541
- if (!fs23.existsSync(wavPath) || fs23.statSync(wavPath).size < 44) {
15649
+ if (!fs24.existsSync(wavPath) || fs24.statSync(wavPath).size < 44) {
15542
15650
  throw new Error("toWav24k produced empty output");
15543
15651
  }
15544
15652
  try {
15545
- fs23.unlinkSync(audioPath);
15653
+ fs24.unlinkSync(audioPath);
15546
15654
  } catch {
15547
15655
  }
15548
15656
  }
15549
- const durationSec = wavDurationSec(fs23.readFileSync(wavPath));
15657
+ const durationSec = wavDurationSec(fs24.readFileSync(wavPath));
15550
15658
  return { wavPath, durationSec };
15551
15659
  }
15552
15660
  async function compressWav(wavPath) {
15553
15661
  const m4aPath = wavPath.replace(/\.wav$/, ".m4a");
15554
15662
  try {
15555
- await execFileAsync2("ffmpeg", [
15663
+ await execFileAsync2(resolveFfmpegPath(), [
15556
15664
  "-y",
15557
15665
  "-i",
15558
15666
  wavPath,
@@ -15564,7 +15672,7 @@ async function compressWav(wavPath) {
15564
15672
  "+faststart",
15565
15673
  m4aPath
15566
15674
  ], { timeout: 3e4 });
15567
- fs23.unlinkSync(wavPath);
15675
+ fs24.unlinkSync(wavPath);
15568
15676
  return m4aPath;
15569
15677
  } catch {
15570
15678
  return wavPath;
@@ -15578,7 +15686,7 @@ async function wavToOggOpus(wavPath) {
15578
15686
  if (globalThis.__ffmpegMissing) throw e;
15579
15687
  console.warn(`[my-voice] native opus encode failed (${e.message}), trying ffmpeg`);
15580
15688
  oggPath = wavPath.replace(/\.wav$/, ".ogg");
15581
- await execFileAsync2("ffmpeg", [
15689
+ await execFileAsync2(resolveFfmpegPath(), [
15582
15690
  "-y",
15583
15691
  "-i",
15584
15692
  wavPath,
@@ -15591,10 +15699,10 @@ async function wavToOggOpus(wavPath) {
15591
15699
  oggPath
15592
15700
  ], { timeout: 3e4 });
15593
15701
  }
15594
- if (!fs23.existsSync(oggPath) || fs23.statSync(oggPath).size < 20) {
15702
+ if (!fs24.existsSync(oggPath) || fs24.statSync(oggPath).size < 20) {
15595
15703
  throw new Error("ogg/opus encode produced empty output");
15596
15704
  }
15597
- fs23.unlinkSync(wavPath);
15705
+ fs24.unlinkSync(wavPath);
15598
15706
  return oggPath;
15599
15707
  }
15600
15708
  async function sendVoiceToMulticaIssue(text, issueId, opts) {
@@ -15609,7 +15717,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
15609
15717
  } catch (e) {
15610
15718
  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 };
15611
15719
  }
15612
- if (!audioPath || !fs23.existsSync(audioPath)) {
15720
+ if (!audioPath || !fs24.existsSync(audioPath)) {
15613
15721
  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 };
15614
15722
  }
15615
15723
  if (audioPath.endsWith(".wav")) {
@@ -15620,20 +15728,20 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
15620
15728
  }
15621
15729
  }
15622
15730
  const ext = path24.extname(audioPath).toLowerCase();
15623
- const sizeKB = fs23.statSync(audioPath).size / 1024;
15731
+ const sizeKB = fs24.statSync(audioPath).size / 1024;
15624
15732
  const voiceFile = `voice_${Date.now()}${ext}`;
15625
15733
  const cwdCopy = path24.join(process.cwd(), voiceFile);
15626
15734
  try {
15627
- fs23.copyFileSync(audioPath, cwdCopy);
15735
+ fs24.copyFileSync(audioPath, cwdCopy);
15628
15736
  } catch (e) {
15629
15737
  try {
15630
- fs23.unlinkSync(audioPath);
15738
+ fs24.unlinkSync(audioPath);
15631
15739
  } catch {
15632
15740
  }
15633
15741
  return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
15634
15742
  }
15635
15743
  try {
15636
- fs23.unlinkSync(audioPath);
15744
+ fs24.unlinkSync(audioPath);
15637
15745
  } catch {
15638
15746
  }
15639
15747
  const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
@@ -15662,13 +15770,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
15662
15770
  }
15663
15771
  if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
15664
15772
  try {
15665
- fs23.unlinkSync(cwdCopy);
15773
+ fs24.unlinkSync(cwdCopy);
15666
15774
  } catch {
15667
15775
  }
15668
15776
  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)` };
15669
15777
  } catch (e) {
15670
15778
  try {
15671
- fs23.unlinkSync(cwdCopy);
15779
+ fs24.unlinkSync(cwdCopy);
15672
15780
  } catch {
15673
15781
  }
15674
15782
  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 };
@@ -15685,6 +15793,7 @@ var init_my_voice = __esm({
15685
15793
  init_pick();
15686
15794
  init_providers();
15687
15795
  init_impl();
15796
+ init_ffmpeg_path();
15688
15797
  execFileAsync2 = promisify2(execFile3);
15689
15798
  registry.register({
15690
15799
  name: "my_voice",
@@ -15800,7 +15909,7 @@ var init_my_voice = __esm({
15800
15909
  const ext = path24.extname(audioPath).toLowerCase();
15801
15910
  const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
15802
15911
  const mimeType = mimeMap[ext] || "audio/mpeg";
15803
- const sizeKB = fs23.statSync(audioPath).size / 1024;
15912
+ const sizeKB = fs24.statSync(audioPath).size / 1024;
15804
15913
  try {
15805
15914
  await mgr.sendFile(resolvedChannel, target, caption, {
15806
15915
  path: audioPath,
@@ -15809,7 +15918,7 @@ var init_my_voice = __esm({
15809
15918
  ...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
15810
15919
  });
15811
15920
  try {
15812
- fs23.unlinkSync(audioPath);
15921
+ fs24.unlinkSync(audioPath);
15813
15922
  } catch {
15814
15923
  }
15815
15924
  return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
@@ -15831,7 +15940,7 @@ __export(my_selfie_exports, {
15831
15940
  dimsOf: () => dimsOf,
15832
15941
  resolvePortraitDesc: () => resolvePortraitDesc
15833
15942
  });
15834
- import * as fs24 from "node:fs";
15943
+ import * as fs25 from "node:fs";
15835
15944
  import * as path25 from "node:path";
15836
15945
  function getProxyDispatcher2() {
15837
15946
  const cfg = liveConfig.all();
@@ -15846,7 +15955,7 @@ function getProxyDispatcher2() {
15846
15955
  }
15847
15956
  function dimsOf(p) {
15848
15957
  try {
15849
- const b = fs24.readFileSync(p);
15958
+ const b = fs25.readFileSync(p);
15850
15959
  let w = 0, h = 0;
15851
15960
  if (b.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
15852
15961
  w = b.readUInt32BE(16);
@@ -16262,7 +16371,7 @@ var init_my_selfie = __esm({
16262
16371
  let refPath = path25.join(ctx.workspace, refEntry.p);
16263
16372
  const adoptImg = args.referenceImage?.trim();
16264
16373
  if (adoptImg) {
16265
- if (!fs24.existsSync(adoptImg)) {
16374
+ if (!fs25.existsSync(adoptImg)) {
16266
16375
  return { content: `\u627E\u4E0D\u5230\u90A3\u5F20\u56FE\uFF1A${adoptImg}`, isError: true };
16267
16376
  }
16268
16377
  const acheck = dimsOf(adoptImg);
@@ -16274,15 +16383,15 @@ var init_my_selfie = __esm({
16274
16383
  };
16275
16384
  }
16276
16385
  const adir = path25.join(ctx.workspace, "images");
16277
- if (!fs24.existsSync(adir)) fs24.mkdirSync(adir, { recursive: true });
16386
+ if (!fs25.existsSync(adir)) fs25.mkdirSync(adir, { recursive: true });
16278
16387
  const aext = (path25.extname(adoptImg) || ".png").toLowerCase();
16279
16388
  const afname = `portrait_${Date.now()}${aext}`;
16280
- fs24.copyFileSync(adoptImg, path25.join(adir, afname));
16389
+ fs25.copyFileSync(adoptImg, path25.join(adir, afname));
16281
16390
  registerPortrait(`images/${afname}`, refName);
16282
16391
  refPath = path25.join(adir, afname);
16283
16392
  console.log(`[my-selfie] \u91C7\u7EB3\u73B0\u6210\u56FE\u5F53\u5F62\u8C61\uFF1Aimages/${afname}${acheck ? ` (${acheck})` : ""}`);
16284
16393
  }
16285
- if (provider !== "autodl" && !fs24.existsSync(refPath)) {
16394
+ if (provider !== "autodl" && !fs25.existsSync(refPath)) {
16286
16395
  const cfgAll = liveConfig.all();
16287
16396
  const portraitDesc = resolvePortraitDesc(
16288
16397
  args.portrait,
@@ -16308,15 +16417,15 @@ var init_my_selfie = __esm({
16308
16417
  return { content: `\u5851\u9020\u5F62\u8C61\u5931\u8D25\uFF1A${e.message}`, isError: true };
16309
16418
  }
16310
16419
  const pdir = path25.join(ctx.workspace, "images");
16311
- if (!fs24.existsSync(pdir)) fs24.mkdirSync(pdir, { recursive: true });
16420
+ if (!fs25.existsSync(pdir)) fs25.mkdirSync(pdir, { recursive: true });
16312
16421
  const pfname = `portrait_${Date.now()}.png`;
16313
- fs24.writeFileSync(path25.join(pdir, pfname), portraitBuf);
16422
+ fs25.writeFileSync(path25.join(pdir, pfname), portraitBuf);
16314
16423
  registerPortrait(`images/${pfname}`, refName);
16315
16424
  refPath = path25.join(pdir, pfname);
16316
16425
  console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u5B58 images/${pfname}\uFF0C\u7EE7\u7EED\u8FD9\u6B21\u81EA\u62CD`);
16317
16426
  }
16318
16427
  const resolution = args.resolution || DEFAULT_RESOLUTION;
16319
- const refB64 = fs24.existsSync(refPath) ? fs24.readFileSync(refPath).toString("base64") : "";
16428
+ const refB64 = fs25.existsSync(refPath) ? fs25.readFileSync(refPath).toString("base64") : "";
16320
16429
  let imageBuffer;
16321
16430
  try {
16322
16431
  if (provider === "autodl") {
@@ -16342,10 +16451,10 @@ var init_my_selfie = __esm({
16342
16451
  return { content: `Selfie generation failed: ${err.message}`, isError: true };
16343
16452
  }
16344
16453
  const imagesDir = path25.join(ctx.workspace, "images");
16345
- if (!fs24.existsSync(imagesDir)) fs24.mkdirSync(imagesDir, { recursive: true });
16454
+ if (!fs25.existsSync(imagesDir)) fs25.mkdirSync(imagesDir, { recursive: true });
16346
16455
  const filename = `selfie_${Date.now()}.jpg`;
16347
16456
  const outputPath = path25.join(imagesDir, filename);
16348
- fs24.writeFileSync(outputPath, imageBuffer);
16457
+ fs25.writeFileSync(outputPath, imageBuffer);
16349
16458
  const mgr = ctx.channelManager;
16350
16459
  if (mgr) {
16351
16460
  const resolvedChannel = ctx.channel || "feishu";
@@ -16663,7 +16772,7 @@ var init_helpers = __esm({
16663
16772
  });
16664
16773
 
16665
16774
  // src/calendar/commands.ts
16666
- import { existsSync as existsSync18, statSync as statSync11 } from "node:fs";
16775
+ import { existsSync as existsSync19, statSync as statSync11 } from "node:fs";
16667
16776
  import { isAbsolute as isAbsolute4, resolve as resolve6 } from "node:path";
16668
16777
  function fmtEnd(start, durationMin) {
16669
16778
  const [hh, mm] = start.split(":").map(Number);
@@ -16832,7 +16941,7 @@ function addTask(db2, args) {
16832
16941
  }
16833
16942
  try {
16834
16943
  const absPath = isAbsolute4(docPath) ? docPath : resolve6(process.cwd(), docPath);
16835
- if (!existsSync18(absPath)) {
16944
+ if (!existsSync19(absPath)) {
16836
16945
  return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728
16837
16946
  \u8DEF\u5F84: ${docPath}
16838
16947
  \u89E3\u6790\u540E: ${absPath}
@@ -17190,7 +17299,7 @@ var init_calendar = __esm({
17190
17299
  });
17191
17300
 
17192
17301
  // src/tools/service.ts
17193
- import * as fs25 from "node:fs";
17302
+ import * as fs26 from "node:fs";
17194
17303
  import * as path26 from "node:path";
17195
17304
  import { exec, spawn as spawn4 } from "node:child_process";
17196
17305
  import { promisify as promisify3 } from "node:util";
@@ -17200,7 +17309,7 @@ function getServices() {
17200
17309
  function serviceLogPath(fileName) {
17201
17310
  const stateDir = String(liveConfig.get("stateDir") ?? "");
17202
17311
  const logDir = path26.join(stateDir, "logs");
17203
- if (!fs25.existsSync(logDir)) fs25.mkdirSync(logDir, { recursive: true });
17312
+ if (!fs26.existsSync(logDir)) fs26.mkdirSync(logDir, { recursive: true });
17204
17313
  return path26.join(logDir, fileName);
17205
17314
  }
17206
17315
  async function runCmd(cmd, timeoutMs = 15e3) {
@@ -17416,7 +17525,7 @@ var init_constants5 = __esm({
17416
17525
  });
17417
17526
 
17418
17527
  // src/tools/TodoWriteTool/TodoWriteTool.ts
17419
- import fs26 from "node:fs";
17528
+ import fs27 from "node:fs";
17420
17529
  import path27 from "node:path";
17421
17530
  function todoFilePath(sessionId) {
17422
17531
  return path27.join(todosDir, `${sessionId}.json`);
@@ -17425,15 +17534,15 @@ function loadTodos(sessionId) {
17425
17534
  if (!todosDir) return [];
17426
17535
  try {
17427
17536
  const filePath = todoFilePath(sessionId);
17428
- if (!fs26.existsSync(filePath)) return [];
17429
- return JSON.parse(fs26.readFileSync(filePath, "utf-8"));
17537
+ if (!fs27.existsSync(filePath)) return [];
17538
+ return JSON.parse(fs27.readFileSync(filePath, "utf-8"));
17430
17539
  } catch {
17431
17540
  return [];
17432
17541
  }
17433
17542
  }
17434
17543
  function saveTodos(sessionId, todos) {
17435
17544
  if (!todosDir) return;
17436
- fs26.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
17545
+ fs27.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
17437
17546
  }
17438
17547
  var todosDir;
17439
17548
  var init_TodoWriteTool = __esm({
@@ -17690,7 +17799,7 @@ var init_constants7 = __esm({
17690
17799
  });
17691
17800
 
17692
17801
  // src/utils/plans.ts
17693
- import * as fs27 from "node:fs";
17802
+ import * as fs28 from "node:fs";
17694
17803
  import * as path28 from "node:path";
17695
17804
  import * as crypto4 from "node:crypto";
17696
17805
  function generateSlug() {
@@ -17698,7 +17807,7 @@ function generateSlug() {
17698
17807
  }
17699
17808
  function getPlansDirectory(stateDir) {
17700
17809
  const plansDir = path28.join(stateDir, "plans");
17701
- fs27.mkdirSync(plansDir, { recursive: true });
17810
+ fs28.mkdirSync(plansDir, { recursive: true });
17702
17811
  return plansDir;
17703
17812
  }
17704
17813
  function getPlanSlug(sessionId, stateDir) {
@@ -17708,7 +17817,7 @@ function getPlanSlug(sessionId, stateDir) {
17708
17817
  for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
17709
17818
  slug = generateSlug();
17710
17819
  const filePath = path28.join(plansDir, `${slug}.md`);
17711
- if (!fs27.existsSync(filePath)) {
17820
+ if (!fs28.existsSync(filePath)) {
17712
17821
  break;
17713
17822
  }
17714
17823
  }
@@ -17726,14 +17835,14 @@ function getPlanFilePath(sessionId, stateDir, agentId) {
17726
17835
  function getPlan(sessionId, stateDir, agentId) {
17727
17836
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
17728
17837
  try {
17729
- return fs27.readFileSync(filePath, "utf-8");
17838
+ return fs28.readFileSync(filePath, "utf-8");
17730
17839
  } catch {
17731
17840
  return null;
17732
17841
  }
17733
17842
  }
17734
17843
  function writePlan(sessionId, stateDir, content, agentId) {
17735
17844
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
17736
- fs27.writeFileSync(filePath, content, "utf-8");
17845
+ fs28.writeFileSync(filePath, content, "utf-8");
17737
17846
  return filePath;
17738
17847
  }
17739
17848
  var MAX_SLUG_RETRIES, planSlugCache;
@@ -17881,7 +17990,7 @@ var init_constants8 = __esm({
17881
17990
  });
17882
17991
 
17883
17992
  // src/utils/tasks.ts
17884
- import * as fs28 from "node:fs";
17993
+ import * as fs29 from "node:fs";
17885
17994
  import * as path29 from "node:path";
17886
17995
  function sanitizePathComponent2(input) {
17887
17996
  return input.replace(/[^a-zA-Z0-9_-]/g, "-");
@@ -17894,7 +18003,7 @@ function getTaskPath(stateDir, listId, taskId) {
17894
18003
  }
17895
18004
  function ensureTasksDir2(stateDir, listId) {
17896
18005
  const dir = getTasksDir2(stateDir, listId);
17897
- fs28.mkdirSync(dir, { recursive: true });
18006
+ fs29.mkdirSync(dir, { recursive: true });
17898
18007
  return dir;
17899
18008
  }
17900
18009
  function getHighWaterMarkPath(stateDir, listId) {
@@ -17902,7 +18011,7 @@ function getHighWaterMarkPath(stateDir, listId) {
17902
18011
  }
17903
18012
  function readHighWaterMark(stateDir, listId) {
17904
18013
  try {
17905
- const content = fs28.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
18014
+ const content = fs29.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
17906
18015
  const value = parseInt(content, 10);
17907
18016
  return isNaN(value) ? 0 : value;
17908
18017
  } catch {
@@ -17910,13 +18019,13 @@ function readHighWaterMark(stateDir, listId) {
17910
18019
  }
17911
18020
  }
17912
18021
  function writeHighWaterMark(stateDir, listId, value) {
17913
- fs28.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
18022
+ fs29.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
17914
18023
  }
17915
18024
  function findHighestTaskIdFromFiles(stateDir, listId) {
17916
18025
  const dir = getTasksDir2(stateDir, listId);
17917
18026
  let files;
17918
18027
  try {
17919
- files = fs28.readdirSync(dir);
18028
+ files = fs29.readdirSync(dir);
17920
18029
  } catch {
17921
18030
  return 0;
17922
18031
  }
@@ -17942,14 +18051,14 @@ function createTask(stateDir, listId, taskData) {
17942
18051
  const id = String(highestId + 1);
17943
18052
  const task = { id, ...taskData };
17944
18053
  const filePath = getTaskPath(stateDir, listId, id);
17945
- fs28.writeFileSync(filePath, JSON.stringify(task, null, 2));
18054
+ fs29.writeFileSync(filePath, JSON.stringify(task, null, 2));
17946
18055
  return id;
17947
18056
  });
17948
18057
  }
17949
18058
  function getTask2(stateDir, listId, taskId) {
17950
18059
  const filePath = getTaskPath(stateDir, listId, taskId);
17951
18060
  try {
17952
- const content = fs28.readFileSync(filePath, "utf-8");
18061
+ const content = fs29.readFileSync(filePath, "utf-8");
17953
18062
  return JSON.parse(content);
17954
18063
  } catch {
17955
18064
  return null;
@@ -17959,7 +18068,7 @@ function listTasks2(stateDir, listId) {
17959
18068
  const dir = getTasksDir2(stateDir, listId);
17960
18069
  let files;
17961
18070
  try {
17962
- files = fs28.readdirSync(dir);
18071
+ files = fs29.readdirSync(dir);
17963
18072
  } catch {
17964
18073
  return [];
17965
18074
  }
@@ -17971,7 +18080,7 @@ function updateTask(stateDir, listId, taskId, updates) {
17971
18080
  if (!existing) return null;
17972
18081
  const updated = { ...existing, ...updates, id: taskId };
17973
18082
  const filePath = getTaskPath(stateDir, listId, taskId);
17974
- fs28.writeFileSync(filePath, JSON.stringify(updated, null, 2));
18083
+ fs29.writeFileSync(filePath, JSON.stringify(updated, null, 2));
17975
18084
  return updated;
17976
18085
  }
17977
18086
  function deleteTask(stateDir, listId, taskId) {
@@ -17985,7 +18094,7 @@ function deleteTask(stateDir, listId, taskId) {
17985
18094
  }
17986
18095
  }
17987
18096
  try {
17988
- fs28.unlinkSync(filePath);
18097
+ fs29.unlinkSync(filePath);
17989
18098
  } catch {
17990
18099
  return false;
17991
18100
  }
@@ -19409,7 +19518,7 @@ var init_task_stop = __esm({
19409
19518
  });
19410
19519
 
19411
19520
  // src/tools/reply-blocklist.ts
19412
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync16, existsSync as existsSync21 } from "node:fs";
19521
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync16, existsSync as existsSync22 } from "node:fs";
19413
19522
  import { join as join28 } from "node:path";
19414
19523
  function ensureLoaded(workspace, configIds) {
19415
19524
  if (loaded) return;
@@ -19420,7 +19529,7 @@ function ensureLoaded(workspace, configIds) {
19420
19529
  }
19421
19530
  const path43 = join28(workspace, ".reply-blocklist.json");
19422
19531
  try {
19423
- if (existsSync21(path43)) {
19532
+ if (existsSync22(path43)) {
19424
19533
  const raw = readFileSync21(path43, "utf-8");
19425
19534
  const parsed = JSON.parse(raw);
19426
19535
  if (parsed.blockedUserIds) {
@@ -20311,15 +20420,15 @@ var init_findRelevantMemoriesEveros = __esm({
20311
20420
  });
20312
20421
 
20313
20422
  // src/config/persona-files.ts
20314
- import { existsSync as existsSync22 } from "node:fs";
20423
+ import { existsSync as existsSync23 } from "node:fs";
20315
20424
  import { join as join32 } from "node:path";
20316
20425
  function resolvePersonaFile(workspace, persona, name) {
20317
20426
  if (persona) {
20318
20427
  const scoped = join32(workspace, "personas", persona, name);
20319
- if (existsSync22(scoped)) return scoped;
20428
+ if (existsSync23(scoped)) return scoped;
20320
20429
  }
20321
20430
  const legacy = join32(workspace, LEGACY_RELATIVE[name] ?? name);
20322
- return existsSync22(legacy) ? legacy : null;
20431
+ return existsSync23(legacy) ? legacy : null;
20323
20432
  }
20324
20433
  var LEGACY_RELATIVE;
20325
20434
  var init_persona_files = __esm({
@@ -20466,7 +20575,7 @@ var init_voiceFastView = __esm({
20466
20575
  });
20467
20576
 
20468
20577
  // src/sender-context.ts
20469
- import { readFileSync as readFileSync24, existsSync as existsSync24 } from "node:fs";
20578
+ import { readFileSync as readFileSync24, existsSync as existsSync25 } from "node:fs";
20470
20579
  import { join as join33 } from "node:path";
20471
20580
  function loadContactMap(workspace) {
20472
20581
  if (contactMap) return contactMap;
@@ -20474,8 +20583,8 @@ function loadContactMap(workspace) {
20474
20583
  externalChanWhitelist = /* @__PURE__ */ new Set();
20475
20584
  try {
20476
20585
  const contactsPath = join33(workspace, "prompts", "contacts.md");
20477
- console.log(`[meta] Loading contacts from ${contactsPath}, exists=${existsSync24(contactsPath)}`);
20478
- if (existsSync24(contactsPath)) {
20586
+ console.log(`[meta] Loading contacts from ${contactsPath}, exists=${existsSync25(contactsPath)}`);
20587
+ if (existsSync25(contactsPath)) {
20479
20588
  const text = readFileSync24(contactsPath, "utf-8");
20480
20589
  const lines = text.split("\n");
20481
20590
  for (const line of lines) {
@@ -20590,6 +20699,7 @@ function buildExtractAutoOnlyPrompt(newMessageCount, existingMemories, skipIndex
20590
20699
  "",
20591
20700
  ...MEMORY_FRONTMATTER_EXAMPLE,
20592
20701
  "",
20702
+ "\u26A0\uFE0F \u6240\u6709\u65E5\u671F\u5FC5\u987B\u542B\u5E74\u4EFD\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u5982 2026-07-26\uFF09\uFF0C\u7981\u6B62\u53EA\u5199\u6708/\u65E5\uFF087/26\u30010726\uFF09\u2014\u2014\u8DE8\u5E74\u4F1A\u6DF7\u4E71\u3002\u6B63\u6587\u4EFB\u4F55\u65E5\u671F\u3001\u6587\u4EF6\u540D\u65E5\u671F\u6807\u7B7E\u90FD\u8981\u542B\u5E74\u4EFD\u3002(All dates MUST include the year, format YYYY-MM-DD. Never write month/day only \u2014 it breaks next year.)",
20593
20703
  "- Organize memory semantically by topic, not chronologically",
20594
20704
  "- Update or remove memories that turn out to be wrong or outdated",
20595
20705
  "- Do not write duplicate memories. First check if there is an existing memory you can update before writing a new one."
@@ -20605,6 +20715,7 @@ function buildExtractAutoOnlyPrompt(newMessageCount, existingMemories, skipIndex
20605
20715
  `**Step 2** \u2014 add a pointer to that file in \`${ENTRYPOINT_NAME}\`. \`${ENTRYPOINT_NAME}\` is an index, not a memory \u2014 each entry should be one line, under ~150 characters: \`- [Title](file.md) \u2014 one-line hook\`. It has no frontmatter. Never write memory content directly into \`${ENTRYPOINT_NAME}\`.`,
20606
20716
  "",
20607
20717
  `- \`${ENTRYPOINT_NAME}\` is always loaded into your system prompt \u2014 lines after 200 will be truncated, so keep the index concise`,
20718
+ "\u26A0\uFE0F \u6240\u6709\u65E5\u671F\u5FC5\u987B\u542B\u5E74\u4EFD\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u5982 2026-07-26\uFF09\uFF0C\u7981\u6B62\u53EA\u5199\u6708/\u65E5\uFF087/26\u30010726\uFF09\u2014\u2014\u8DE8\u5E74\u4F1A\u6DF7\u4E71\u3002\u6B63\u6587\u4EFB\u4F55\u65E5\u671F\u3001\u6587\u4EF6\u540D\u65E5\u671F\u6807\u7B7E\u90FD\u8981\u542B\u5E74\u4EFD\u3002(All dates MUST include the year, format YYYY-MM-DD. Never write month/day only \u2014 it breaks next year.)",
20608
20719
  "- Organize memory semantically by topic, not chronologically",
20609
20720
  "- Update or remove memories that turn out to be wrong or outdated",
20610
20721
  "- Do not write duplicate memories. First check if there is an existing memory you can update before writing a new one."
@@ -20633,7 +20744,7 @@ var extractMemories_exports = {};
20633
20744
  __export(extractMemories_exports, {
20634
20745
  createMemoryExtractor: () => createMemoryExtractor
20635
20746
  });
20636
- import * as fs29 from "fs";
20747
+ import * as fs30 from "fs";
20637
20748
  import * as path30 from "path";
20638
20749
  function isModelVisibleMessage(message) {
20639
20750
  return message.role === "user" || message.role === "assistant";
@@ -20662,8 +20773,8 @@ function getStatePath(workspace) {
20662
20773
  function loadPersistedState(workspace) {
20663
20774
  try {
20664
20775
  const p = getStatePath(workspace);
20665
- if (fs29.existsSync(p)) {
20666
- const data = JSON.parse(fs29.readFileSync(p, "utf-8"));
20776
+ if (fs30.existsSync(p)) {
20777
+ const data = JSON.parse(fs30.readFileSync(p, "utf-8"));
20667
20778
  for (const [sid, ts] of Object.entries(data.lastTs ?? {})) {
20668
20779
  lastTsMap.set(sid, ts);
20669
20780
  }
@@ -20683,7 +20794,7 @@ function persistState(workspace) {
20683
20794
  for (const [sid, ts] of lastTsMap.entries()) lastTs[sid] = ts;
20684
20795
  for (const [sid, ts] of lastExtractTimeMap.entries()) timestamps[sid] = ts;
20685
20796
  const data = JSON.stringify({ lastTs, timestamps }, null, 2);
20686
- fs29.writeFileSync(getStatePath(workspace), data, "utf-8");
20797
+ fs30.writeFileSync(getStatePath(workspace), data, "utf-8");
20687
20798
  } catch (e) {
20688
20799
  console.warn(`[memory] failed to persist extract state: ${e?.message ?? e}`);
20689
20800
  }
@@ -20727,8 +20838,8 @@ function createMemoryExtractor(workspace, enabled) {
20727
20838
  const extractOverridePath = path30.join(workspace, "prompts", "extract.md");
20728
20839
  let systemPrompt;
20729
20840
  try {
20730
- if (fs29.existsSync(extractOverridePath)) {
20731
- systemPrompt = fs29.readFileSync(extractOverridePath, { encoding: "utf-8" });
20841
+ if (fs30.existsSync(extractOverridePath)) {
20842
+ systemPrompt = fs30.readFileSync(extractOverridePath, { encoding: "utf-8" });
20732
20843
  if (existingMemories.length > 0) {
20733
20844
  systemPrompt += `
20734
20845
 
@@ -20854,7 +20965,7 @@ __export(ingest_exports, {
20854
20965
  pushConversation: () => pushConversation,
20855
20966
  toPayload: () => toPayload
20856
20967
  });
20857
- import fs30 from "node:fs";
20968
+ import fs31 from "node:fs";
20858
20969
  import path31 from "node:path";
20859
20970
  async function readConfig() {
20860
20971
  const defaults = {
@@ -20886,8 +20997,8 @@ async function readConfig() {
20886
20997
  function loadPushTs(workspace, sessionId) {
20887
20998
  try {
20888
20999
  const p = path31.join(workspace, PUSH_STATE_FILE);
20889
- if (fs30.existsSync(p)) {
20890
- const data = JSON.parse(fs30.readFileSync(p, "utf-8"));
21000
+ if (fs31.existsSync(p)) {
21001
+ const data = JSON.parse(fs31.readFileSync(p, "utf-8"));
20891
21002
  return typeof data[sessionId] === "number" ? data[sessionId] : 0;
20892
21003
  }
20893
21004
  } catch (e) {
@@ -20900,11 +21011,11 @@ function savePushTs(workspace, sessionId, ts) {
20900
21011
  const p = path31.join(workspace, PUSH_STATE_FILE);
20901
21012
  let data = {};
20902
21013
  try {
20903
- if (fs30.existsSync(p)) data = JSON.parse(fs30.readFileSync(p, "utf-8"));
21014
+ if (fs31.existsSync(p)) data = JSON.parse(fs31.readFileSync(p, "utf-8"));
20904
21015
  } catch {
20905
21016
  }
20906
21017
  data[sessionId] = ts;
20907
- fs30.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
21018
+ fs31.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
20908
21019
  } catch (e) {
20909
21020
  console.warn(`[everos-ingest] save pushTs failed: ${e?.message ?? e}`);
20910
21021
  }
@@ -21739,7 +21850,7 @@ Follow these principles when generating episodic memories:
21739
21850
 
21740
21851
  // src/mem7/core/store.ts
21741
21852
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
21742
- import { mkdirSync as mkdirSync18, readFileSync as readFileSync26, writeFileSync as writeFileSync18, existsSync as existsSync26, readdirSync as readdirSync8 } from "node:fs";
21853
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync26, writeFileSync as writeFileSync18, existsSync as existsSync27, readdirSync as readdirSync8 } from "node:fs";
21743
21854
  import { join as join36 } from "node:path";
21744
21855
  import { createHash as createHash2 } from "node:crypto";
21745
21856
  function contentHash(text) {
@@ -21920,7 +22031,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
21920
22031
  let head;
21921
22032
  let existingBlocks = "";
21922
22033
  let count;
21923
- if (existsSync26(file2)) {
22034
+ if (existsSync27(file2)) {
21924
22035
  const text = readFileSync26(file2, "utf8");
21925
22036
  const fmEnd = text.indexOf("\n---", 3);
21926
22037
  const split = fmEnd >= 0 ? fmEnd + 4 : text.length;
@@ -21974,7 +22085,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
21974
22085
  const [dirName, filePrefix] = dirByPrefix[prefix];
21975
22086
  const file2 = join36(this.root, "users", ownerId, dirName, `${filePrefix}-${dateStr}.md`);
21976
22087
  let max = 0;
21977
- if (existsSync26(file2)) {
22088
+ if (existsSync27(file2)) {
21978
22089
  const re = new RegExp(`${prefix}_${dateStr.replace(/-/g, "")}_(\\d+)`, "g");
21979
22090
  for (const m of readFileSync26(file2, "utf8").matchAll(re)) max = Math.max(max, Number(m[1]));
21980
22091
  }
@@ -22044,11 +22155,11 @@ CREATE TABLE IF NOT EXISTS watermarks (
22044
22155
  const today2 = todayKey(now);
22045
22156
  const out = [];
22046
22157
  const usersDir = join36(this.root, "users");
22047
- if (!existsSync26(usersDir)) return out;
22158
+ if (!existsSync27(usersDir)) return out;
22048
22159
  for (const owner of readdirSync8(usersDir, { withFileTypes: true })) {
22049
22160
  if (!owner.isDirectory()) continue;
22050
22161
  const dir = join36(usersDir, owner.name, ".foresights");
22051
- if (!existsSync26(dir)) continue;
22162
+ if (!existsSync27(dir)) continue;
22052
22163
  for (const f of readdirSync8(dir)) {
22053
22164
  if (!/^foresight-\d{4}-\d{2}-\d{2}\.md$/.test(f)) continue;
22054
22165
  let content;
@@ -23710,7 +23821,6 @@ var init_agent_tools = __esm({
23710
23821
  constructor(store) {
23711
23822
  this.store = store;
23712
23823
  }
23713
- store;
23714
23824
  /** 5 个工具的 JSON Schema 定义(tools.py:190-264 get_tool_definitions 直译) */
23715
23825
  getDefinitions() {
23716
23826
  return [
@@ -24926,7 +25036,7 @@ var init_recall_score = __esm({
24926
25036
  });
24927
25037
 
24928
25038
  // src/memory/proactive/opportunity.ts
24929
- import { readdirSync as readdirSync9, readFileSync as readFileSync32, existsSync as existsSync27 } from "node:fs";
25039
+ import { readdirSync as readdirSync9, readFileSync as readFileSync32, existsSync as existsSync28 } from "node:fs";
24930
25040
  import { join as join43 } from "node:path";
24931
25041
  function normalizeOpportunity(raw) {
24932
25042
  if (!raw || typeof raw !== "object") return null;
@@ -25013,7 +25123,7 @@ function parseForesightEntries(everosRoot, now, userId) {
25013
25123
  let files;
25014
25124
  if (userId) {
25015
25125
  const ownDir = join43(everosRoot, userId, "default_project", "users", userId, ".foresights");
25016
- files = existsSync27(ownDir) ? listForesightMds(ownDir) : findForesightFiles(everosRoot);
25126
+ files = existsSync28(ownDir) ? listForesightMds(ownDir) : findForesightFiles(everosRoot);
25017
25127
  } else {
25018
25128
  files = findForesightFiles(everosRoot);
25019
25129
  }
@@ -25279,8 +25389,6 @@ var init_agent = __esm({
25279
25389
  this.opts = opts;
25280
25390
  this.tools = new GraphTools(store);
25281
25391
  }
25282
- store;
25283
- opts;
25284
25392
  tools;
25285
25393
  /** 生成 UpdatePlan;LLM 失败/parse 失败返回 null(调用方 fallback) */
25286
25394
  async generatePlan(event2, contextIds, mode, now, foresightHits) {
@@ -25500,7 +25608,6 @@ var init_executor3 = __esm({
25500
25608
  constructor(store) {
25501
25609
  this.store = store;
25502
25610
  }
25503
- store;
25504
25611
  edgeReferencedIds = /* @__PURE__ */ new Set();
25505
25612
  titleToIdCache = null;
25506
25613
  /** 本 plan 内被标 resolved/rejected/deferred 的 intent(P6 R1 级联 cancel 用;
@@ -26044,8 +26151,6 @@ var init_intent = __esm({
26044
26151
  this.store = store;
26045
26152
  this.weights = weights;
26046
26153
  }
26047
- store;
26048
- weights;
26049
26154
  select(now, minUrgency = 0.3, maxIntents = 10) {
26050
26155
  const scored = [];
26051
26156
  for (const intent of this.store.getNodesByType("intent")) {
@@ -26146,10 +26251,6 @@ var init_intent = __esm({
26146
26251
  this.persona = persona;
26147
26252
  this.temperature = temperature;
26148
26253
  }
26149
- provider;
26150
- model;
26151
- persona;
26152
- temperature;
26153
26254
  /** intent → 1-3 个 action;LLM 失败/解析失败返回 [](agent.py 异常吞掉语义) */
26154
26255
  async generateActions(args) {
26155
26256
  const max = args.maxActions ?? 3;
@@ -26304,8 +26405,6 @@ var init_sweep = __esm({
26304
26405
  this.deps = deps;
26305
26406
  this.intervalMs = intervalMs;
26306
26407
  }
26307
- deps;
26308
- intervalMs;
26309
26408
  timer = null;
26310
26409
  /** executing 连续增长的轮数(对账告警用) */
26311
26410
  backlogStreak = 0;
@@ -26446,14 +26545,14 @@ ${JSON.stringify(payload, null, 2)}
26446
26545
  });
26447
26546
 
26448
26547
  // src/memory/proactive/proactive-tools.ts
26449
- import { existsSync as existsSync28 } from "node:fs";
26548
+ import { existsSync as existsSync29 } from "node:fs";
26450
26549
  function setProactiveWorkspace(workspace) {
26451
26550
  toolWorkspace = workspace;
26452
26551
  }
26453
26552
  function withStore(fn) {
26454
26553
  if (!toolWorkspace) return null;
26455
26554
  const p = proactiveDbPath(toolWorkspace);
26456
- if (!existsSync28(p)) return null;
26555
+ if (!existsSync29(p)) return null;
26457
26556
  const store = new Persistence(p);
26458
26557
  try {
26459
26558
  return fn(store);
@@ -26707,7 +26806,7 @@ __export(plugin_exports, {
26707
26806
  feedMem7Cell: () => feedMem7Cell
26708
26807
  });
26709
26808
  import { join as join44 } from "node:path";
26710
- import { existsSync as existsSync29, readFileSync as readFileSync34, appendFileSync as appendFileSync2 } from "node:fs";
26809
+ import { existsSync as existsSync30, readFileSync as readFileSync34, appendFileSync as appendFileSync2 } from "node:fs";
26711
26810
  function isFiller(text) {
26712
26811
  const t = text.trim();
26713
26812
  if (t.length >= 5) return false;
@@ -26930,7 +27029,7 @@ var init_plugin = __esm({
26930
27029
  this.actionAgent = new ActionAgent(this.provider, this.config.modelId, persona);
26931
27030
  this.ingestWorkspace = workspace;
26932
27031
  const calDbPath = join44(workspace, ".calendar", "calendar.db");
26933
- this.calDb = existsSync29(calDbPath) ? openDb(workspace) : null;
27032
+ this.calDb = existsSync30(calDbPath) ? openDb(workspace) : null;
26934
27033
  registerCallbackHook("PostToolUse", {
26935
27034
  type: "callback",
26936
27035
  id: "proactive-completion-evidence",
@@ -28162,7 +28261,7 @@ __export(handle_query_exports, {
28162
28261
  resetSessionStartInjection: () => resetSessionStartInjection,
28163
28262
  resolveSystemPrompt: () => resolveSystemPrompt
28164
28263
  });
28165
- import { readFileSync as readFileSync37, existsSync as existsSync30, statSync as statSync13 } from "node:fs";
28264
+ import { readFileSync as readFileSync37, existsSync as existsSync31, statSync as statSync13 } from "node:fs";
28166
28265
  import { join as join48, resolve as resolve8 } from "node:path";
28167
28266
  import * as path32 from "node:path";
28168
28267
  function resolveSystemPrompt(v) {
@@ -28175,7 +28274,7 @@ function loadExternalChanRules(workspace) {
28175
28274
  const path43 = join48(workspace, "prompts", "external-chan-rules.md");
28176
28275
  if (externalChanRulesCache && externalChanRulesCache.path === path43) return externalChanRulesCache;
28177
28276
  let content = "";
28178
- if (existsSync30(path43)) {
28277
+ if (existsSync31(path43)) {
28179
28278
  try {
28180
28279
  content = readFileSync37(path43, "utf-8").trim();
28181
28280
  } catch (e) {
@@ -28254,8 +28353,9 @@ async function handleQueryInner(text, sessionId, channelName, cb, deps, channelT
28254
28353
  deps.engine.updateTokenEstimate(history);
28255
28354
  const modelInputs = deps.modelInputs || ["text"];
28256
28355
  const supportsImages = modelInputs.includes("image");
28257
- if (!supportsImages) {
28258
- const isImageBlock = (b) => b.type === "image" || b.type === "image_url";
28356
+ const supportsVideo = modelInputs.includes("video");
28357
+ if (!supportsImages || !supportsVideo) {
28358
+ const isImageBlock = (b) => !supportsImages && (b.type === "image" || b.type === "image_url") || !supportsVideo && b.type === "video";
28259
28359
  const stripImages = (msgs) => msgs.map((m) => {
28260
28360
  if (Array.isArray(m.content)) {
28261
28361
  const filtered = m.content.filter((b) => !isImageBlock(b));
@@ -28304,7 +28404,7 @@ async function handleQueryInner(text, sessionId, channelName, cb, deps, channelT
28304
28404
  ${t}` : t });
28305
28405
  }
28306
28406
  for (const b of text) {
28307
- if (b.type === "image") contentBlocks.push(b);
28407
+ if (b.type === "image" || b.type === "video") contentBlocks.push(b);
28308
28408
  }
28309
28409
  } else if (text) {
28310
28410
  contentBlocks.push({ type: "text", text: isExternalChan ? `${senderLabel}
@@ -29053,7 +29153,7 @@ __export(cli_ccrun_exports, {
29053
29153
  parseCcRunArgs: () => parseCcRunArgs
29054
29154
  });
29055
29155
  import { randomUUID as randomUUID8 } from "node:crypto";
29056
- import { existsSync as existsSync31, readFileSync as readFileSync38 } from "node:fs";
29156
+ import { existsSync as existsSync32, readFileSync as readFileSync38 } from "node:fs";
29057
29157
  import { join as join50 } from "node:path";
29058
29158
  import * as readline2 from "node:readline";
29059
29159
  function parseCcRunArgs(argv) {
@@ -29200,8 +29300,8 @@ async function runQuery(args) {
29200
29300
  if (!stateDir) {
29201
29301
  const home = process.env.HOME || process.env.USERPROFILE || ".";
29202
29302
  const cwd = process.cwd();
29203
- const { existsSync: existsSync38 } = await import("node:fs");
29204
- if (existsSync38(join50(cwd, "configs"))) stateDir = cwd;
29303
+ const { existsSync: existsSync39 } = await import("node:fs");
29304
+ if (existsSync39(join50(cwd, "configs"))) stateDir = cwd;
29205
29305
  else {
29206
29306
  try {
29207
29307
  const pointer = JSON.parse(readFileSync38(join50(home, ".engine7.json"), "utf-8"));
@@ -29447,7 +29547,7 @@ async function doCcRun(argv) {
29447
29547
  if (!sd) {
29448
29548
  const home = process.env.HOME || process.env.USERPROFILE || ".";
29449
29549
  const cwd = process.cwd();
29450
- if (existsSync31(join50(cwd, "configs"))) sd = cwd;
29550
+ if (existsSync32(join50(cwd, "configs"))) sd = cwd;
29451
29551
  else {
29452
29552
  try {
29453
29553
  const pointer = JSON.parse(readFileSync38(join50(home, ".engine7.json"), "utf-8"));
@@ -29533,7 +29633,7 @@ __export(provision_free_exports, {
29533
29633
  writeIdentityContactEmail: () => writeIdentityContactEmail
29534
29634
  });
29535
29635
  import { randomBytes as randomBytes6, randomUUID as randomUUID9 } from "node:crypto";
29536
- import { chmodSync as chmodSync2, existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync39, writeFileSync as writeFileSync21 } from "node:fs";
29636
+ import { chmodSync as chmodSync2, existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync39, writeFileSync as writeFileSync21 } from "node:fs";
29537
29637
  import { dirname as dirname11, join as join51 } from "node:path";
29538
29638
  import { fileURLToPath as fileURLToPath5 } from "node:url";
29539
29639
  function readContactEmailOf(parsed) {
@@ -29541,7 +29641,7 @@ function readContactEmailOf(parsed) {
29541
29641
  }
29542
29642
  function loadOrCreateInstallIdentity(stateDir) {
29543
29643
  const file2 = join51(stateDir, IDENTITY_FILE);
29544
- if (existsSync32(file2)) {
29644
+ if (existsSync33(file2)) {
29545
29645
  let parsed;
29546
29646
  try {
29547
29647
  parsed = JSON.parse(readFileSync39(file2, "utf8"));
@@ -29576,7 +29676,7 @@ function loadOrCreateInstallIdentity(stateDir) {
29576
29676
  }
29577
29677
  function readInstallIdentityDetailed(stateDir) {
29578
29678
  const file2 = join51(stateDir, IDENTITY_FILE);
29579
- if (!existsSync32(file2)) return { ok: false, reason: "missing" };
29679
+ if (!existsSync33(file2)) return { ok: false, reason: "missing" };
29580
29680
  let text;
29581
29681
  try {
29582
29682
  text = readFileSync39(file2, "utf8");
@@ -29685,7 +29785,7 @@ __export(free_tier_apply_exports, {
29685
29785
  isFreeTierConfig: () => isFreeTierConfig,
29686
29786
  resolveConfigPath: () => resolveConfigPath
29687
29787
  });
29688
- import * as fs31 from "node:fs";
29788
+ import * as fs32 from "node:fs";
29689
29789
  import * as path33 from "node:path";
29690
29790
  function isFreeTierConfig(cfg) {
29691
29791
  const hasProvider = !!cfg?.models?.providers?.[FREE_TIER_PROVIDER_ID];
@@ -29697,6 +29797,7 @@ function applyFreeTier(cfg, opts = {}) {
29697
29797
  if (!def) throw new Error("\u5F15\u64CE\u91CC\u6CA1\u6709 7yi \u8FD9\u4E2A\u5185\u7F6E provider\u2014\u2014PROVIDER_DEFS \u88AB\u52A8\u8FC7\uFF1F");
29698
29798
  const baseUrl = (opts.baseUrl || "").trim() || def.baseUrl;
29699
29799
  const vision = resolveVisionModel(FREE_TIER_PROVIDER_ID, FREE_TIER_PRIMARY);
29800
+ const video = resolveVideoModel(FREE_TIER_PROVIDER_ID, FREE_TIER_PRIMARY);
29700
29801
  cfg.models = cfg.models || {};
29701
29802
  cfg.models.providers = cfg.models.providers || {};
29702
29803
  cfg.models.providers[FREE_TIER_PROVIDER_ID] = {
@@ -29711,6 +29812,7 @@ function applyFreeTier(cfg, opts = {}) {
29711
29812
  cfg.agents.defaults.model = cfg.agents.defaults.model || {};
29712
29813
  cfg.agents.defaults.model.primary = FREE_TIER_PRIMARY;
29713
29814
  if (vision) cfg.agents.defaults.model.vision = vision;
29815
+ if (video) cfg.agents.defaults.model.video = video;
29714
29816
  cfg.agents.defaults.features = cfg.agents.defaults.features || {};
29715
29817
  cfg.agents.defaults.features.selfie = true;
29716
29818
  cfg.agents.defaults.features.eyes = true;
@@ -29736,15 +29838,15 @@ function resolveConfigPath(stateDir, configName) {
29736
29838
  const configsDir = path33.join(stateDir, "configs");
29737
29839
  if (configName) {
29738
29840
  const p = path33.join(configsDir, configName);
29739
- return fs31.existsSync(p) ? p : "";
29841
+ return fs32.existsSync(p) ? p : "";
29740
29842
  }
29741
29843
  const main2 = path33.join(configsDir, "main7.json");
29742
- if (fs31.existsSync(main2)) return main2;
29743
- if (!fs31.existsSync(configsDir)) return "";
29744
- for (const f of fs31.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
29844
+ if (fs32.existsSync(main2)) return main2;
29845
+ if (!fs32.existsSync(configsDir)) return "";
29846
+ for (const f of fs32.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
29745
29847
  const full = path33.join(configsDir, f);
29746
29848
  try {
29747
- if (JSON.parse(fs31.readFileSync(full, "utf8")).models?.providers) return full;
29849
+ if (JSON.parse(fs32.readFileSync(full, "utf8")).models?.providers) return full;
29748
29850
  } catch {
29749
29851
  }
29750
29852
  }
@@ -29753,16 +29855,16 @@ function resolveConfigPath(stateDir, configName) {
29753
29855
  function applyFreeTierToConfig(configPath, opts = {}) {
29754
29856
  let cfg;
29755
29857
  try {
29756
- cfg = JSON.parse(fs31.readFileSync(configPath, "utf8"));
29858
+ cfg = JSON.parse(fs32.readFileSync(configPath, "utf8"));
29757
29859
  } catch (e) {
29758
29860
  throw new Error(`\u8BFB\u53D6 config \u5931\u8D25: ${configPath}\uFF08${e?.message || e}\uFF09`);
29759
29861
  }
29760
29862
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
29761
29863
  const backupPath = `${configPath}.bak-${stamp}`;
29762
- fs31.copyFileSync(configPath, backupPath);
29864
+ fs32.copyFileSync(configPath, backupPath);
29763
29865
  applyFreeTier(cfg, opts);
29764
29866
  try {
29765
- fs31.writeFileSync(configPath, JSON.stringify(cfg, null, 2), "utf8");
29867
+ fs32.writeFileSync(configPath, JSON.stringify(cfg, null, 2), "utf8");
29766
29868
  } catch (e) {
29767
29869
  throw new Error(`\u5199\u5165 config \u5931\u8D25: ${configPath}\uFF08${e?.message || e}\uFF09\uFF1B\u539F\u6587\u4EF6\u672A\u6539\u52A8\uFF0C\u5907\u4EFD\u5728 ${backupPath}`);
29768
29870
  }
@@ -29770,7 +29872,8 @@ function applyFreeTierToConfig(configPath, opts = {}) {
29770
29872
  configPath,
29771
29873
  backupPath,
29772
29874
  primary: cfg.agents.defaults.model.primary,
29773
- vision: cfg.agents.defaults.model.vision ?? null
29875
+ vision: cfg.agents.defaults.model.vision ?? null,
29876
+ video: cfg.agents.defaults.model.video ?? null
29774
29877
  };
29775
29878
  }
29776
29879
  var FREE_TIER_PROVIDER_ID, FREE_TIER_PRIMARY, DEFAULT_FREE_VOICE;
@@ -29791,7 +29894,7 @@ __export(cli_doctor_exports, {
29791
29894
  resolveStateDirFromArgs: () => resolveStateDirFromArgs,
29792
29895
  runDoctor: () => runDoctor
29793
29896
  });
29794
- import * as fs32 from "node:fs";
29897
+ import * as fs33 from "node:fs";
29795
29898
  import * as path34 from "node:path";
29796
29899
  import * as net from "node:net";
29797
29900
  import { fileURLToPath as fileURLToPath6 } from "node:url";
@@ -29799,7 +29902,7 @@ function readVersion() {
29799
29902
  const here = path34.dirname(fileURLToPath6(import.meta.url));
29800
29903
  for (const p of [path34.join(here, "..", "package.json"), path34.join(here, "..", "..", "package.json")]) {
29801
29904
  try {
29802
- return JSON.parse(fs32.readFileSync(p, "utf8")).version || "unknown";
29905
+ return JSON.parse(fs33.readFileSync(p, "utf8")).version || "unknown";
29803
29906
  } catch {
29804
29907
  }
29805
29908
  }
@@ -29845,10 +29948,10 @@ async function runDoctor(stateDir, opts) {
29845
29948
  };
29846
29949
  let config = null;
29847
29950
  try {
29848
- config = JSON.parse(fs32.readFileSync(configPath, "utf8"));
29951
+ config = JSON.parse(fs33.readFileSync(configPath, "utf8"));
29849
29952
  report.configValid = true;
29850
29953
  } catch (e) {
29851
- report.configError = fs32.existsSync(configPath) ? `\u89E3\u6790\u5931\u8D25: ${e.message}` : "config \u4E0D\u5B58\u5728\uFF08\u5148 engine7 init\uFF09";
29954
+ report.configError = fs33.existsSync(configPath) ? `\u89E3\u6790\u5931\u8D25: ${e.message}` : "config \u4E0D\u5B58\u5728\uFF08\u5148 engine7 init\uFF09";
29852
29955
  }
29853
29956
  if (config?.channels) {
29854
29957
  for (const [name, conf] of Object.entries(config.channels)) {
@@ -29858,11 +29961,11 @@ async function runDoctor(stateDir, opts) {
29858
29961
  }
29859
29962
  const cfgBase = path34.basename(report.configPath, ".json") || "main7";
29860
29963
  const candidates = secretsCandidates(stateDir, cfgBase);
29861
- const secretsFile = candidates.find((p) => fs32.existsSync(p)) || candidates[0];
29964
+ const secretsFile = candidates.find((p) => fs33.existsSync(p)) || candidates[0];
29862
29965
  report.secrets.file = secretsFile;
29863
- if (fs32.existsSync(secretsFile)) {
29966
+ if (fs33.existsSync(secretsFile)) {
29864
29967
  report.secrets.exists = true;
29865
- for (const line of fs32.readFileSync(secretsFile, "utf8").split("\n")) {
29968
+ for (const line of fs33.readFileSync(secretsFile, "utf8").split("\n")) {
29866
29969
  const eq = line.indexOf("=");
29867
29970
  if (eq > 0 && !line.startsWith("#")) report.secrets.keys.push(line.slice(0, eq).trim());
29868
29971
  }
@@ -29904,8 +30007,8 @@ async function runDoctor(stateDir, opts) {
29904
30007
  for (const rel of ["workspace/SESSION-STATE.md", "SESSION-STATE.md"]) {
29905
30008
  const p = path34.join(stateDir, rel);
29906
30009
  try {
29907
- if (!fs32.existsSync(p)) continue;
29908
- const head = fs32.readFileSync(p, "utf8").split("\n").slice(0, 10).join("\n");
30010
+ if (!fs33.existsSync(p)) continue;
30011
+ const head = fs33.readFileSync(p, "utf8").split("\n").slice(0, 10).join("\n");
29909
30012
  const m = head.match(/^#{1,3}\s*当前时间\s*$\n+\s*(\d{4}-\d{2}-\d{2})/m);
29910
30013
  if (!m) continue;
29911
30014
  const ageH = (Date.now() - (/* @__PURE__ */ new Date(`${m[1]}T00:00:00Z`)).getTime()) / 36e5;
@@ -29926,11 +30029,11 @@ function resolveStateDirFromArgs(args) {
29926
30029
  if (stateDir) return path34.resolve(stateDir);
29927
30030
  const home = process.env.HOME || process.env.USERPROFILE || ".";
29928
30031
  const cwd = path34.resolve(process.cwd());
29929
- if (fs32.existsSync(path34.join(cwd, "configs"))) return cwd;
30032
+ if (fs33.existsSync(path34.join(cwd, "configs"))) return cwd;
29930
30033
  const pointer = path34.join(home, ".engine7.json");
29931
- if (fs32.existsSync(pointer)) {
30034
+ if (fs33.existsSync(pointer)) {
29932
30035
  try {
29933
- const ptrStateDir = JSON.parse(fs32.readFileSync(pointer, "utf8")).stateDir;
30036
+ const ptrStateDir = JSON.parse(fs33.readFileSync(pointer, "utf8")).stateDir;
29934
30037
  if (typeof ptrStateDir === "string" && ptrStateDir.trim()) return path34.resolve(ptrStateDir);
29935
30038
  } catch {
29936
30039
  }
@@ -29948,7 +30051,7 @@ var init_cli_doctor = __esm({
29948
30051
  });
29949
30052
 
29950
30053
  // src/config/writer.ts
29951
- import fs33 from "node:fs";
30054
+ import fs34 from "node:fs";
29952
30055
  import path35 from "node:path";
29953
30056
  function isNormalized(text) {
29954
30057
  if (text === "") return true;
@@ -29966,11 +30069,11 @@ function isNormalized(text) {
29966
30069
  function rotateBaks(filePath) {
29967
30070
  const dir = path35.dirname(filePath);
29968
30071
  const base = path35.basename(filePath);
29969
- const baks = fs33.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30072
+ const baks = fs34.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
29970
30073
  while (baks.length >= KEEP_BAKS) {
29971
30074
  const victim = baks.shift();
29972
30075
  try {
29973
- fs33.unlinkSync(path35.join(dir, victim));
30076
+ fs34.unlinkSync(path35.join(dir, victim));
29974
30077
  } catch {
29975
30078
  }
29976
30079
  }
@@ -29989,7 +30092,7 @@ function writeFailure(filePath, primary, extra) {
29989
30092
  function renameWithRetry(from, to) {
29990
30093
  for (let attempt = 1; ; attempt++) {
29991
30094
  try {
29992
- fs33.renameSync(from, to);
30095
+ fs34.renameSync(from, to);
29993
30096
  return;
29994
30097
  } catch (err) {
29995
30098
  if (attempt >= RENAME_ATTEMPTS || !RETRYABLE_CODES.has(errCode(err))) throw err;
@@ -30004,32 +30107,32 @@ function commitFile(tmp, filePath) {
30004
30107
  } catch (primaryErr) {
30005
30108
  const old = `${filePath}.old`;
30006
30109
  try {
30007
- fs33.renameSync(filePath, old);
30110
+ fs34.renameSync(filePath, old);
30008
30111
  } catch (err) {
30009
30112
  throw writeFailure(filePath, primaryErr, `\u6539\u540D .old \u5907\u4EFD\u4E5F\u5931\u8D25\uFF08${errCode(err) || "\u672A\u77E5"}\uFF09`);
30010
30113
  }
30011
30114
  try {
30012
- fs33.renameSync(tmp, filePath);
30115
+ fs34.renameSync(tmp, filePath);
30013
30116
  } catch (err) {
30014
30117
  try {
30015
- fs33.renameSync(old, filePath);
30118
+ fs34.renameSync(old, filePath);
30016
30119
  } catch {
30017
30120
  throw writeFailure(filePath, primaryErr, `\u65B0\u5185\u5BB9\u843D\u76D8\u4E0E\u56DE\u6EDA\u90FD\u5931\u8D25\uFF0C\u65E7\u5185\u5BB9\u7559\u5728 ${old}`);
30018
30121
  }
30019
30122
  throw writeFailure(filePath, primaryErr, `\u6362\u540D\u843D\u76D8\u5931\u8D25\uFF08${errCode(err) || "\u672A\u77E5"}\uFF09`);
30020
30123
  }
30021
30124
  try {
30022
- fs33.unlinkSync(old);
30125
+ fs34.unlinkSync(old);
30023
30126
  } catch {
30024
30127
  }
30025
30128
  }
30026
30129
  }
30027
30130
  function writeConfigAtomic(filePath, obj) {
30028
- const existed = fs33.existsSync(filePath);
30131
+ const existed = fs34.existsSync(filePath);
30029
30132
  let prevText = "";
30030
30133
  if (existed) {
30031
30134
  try {
30032
- prevText = fs33.readFileSync(filePath, "utf-8");
30135
+ prevText = fs34.readFileSync(filePath, "utf-8");
30033
30136
  } catch (err) {
30034
30137
  throw writeFailure(filePath, err);
30035
30138
  }
@@ -30037,7 +30140,7 @@ function writeConfigAtomic(filePath, obj) {
30037
30140
  const normalized = !existed || !isNormalized(prevText);
30038
30141
  if (prevText) {
30039
30142
  try {
30040
- fs33.copyFileSync(filePath, `${filePath}.bak-${Date.now()}`);
30143
+ fs34.copyFileSync(filePath, `${filePath}.bak-${Date.now()}`);
30041
30144
  } catch {
30042
30145
  }
30043
30146
  rotateBaks(filePath);
@@ -30045,19 +30148,19 @@ function writeConfigAtomic(filePath, obj) {
30045
30148
  const content = JSON.stringify(obj, null, 2) + "\n";
30046
30149
  const tmp = path35.join(path35.dirname(filePath), `.${path35.basename(filePath)}.tmp-${process.pid}`);
30047
30150
  try {
30048
- const fd = fs33.openSync(tmp, "w");
30151
+ const fd = fs34.openSync(tmp, "w");
30049
30152
  try {
30050
- fs33.writeFileSync(fd, content, "utf-8");
30051
- fs33.fsyncSync(fd);
30153
+ fs34.writeFileSync(fd, content, "utf-8");
30154
+ fs34.fsyncSync(fd);
30052
30155
  } finally {
30053
- fs33.closeSync(fd);
30156
+ fs34.closeSync(fd);
30054
30157
  }
30055
30158
  commitFile(tmp, filePath);
30056
30159
  } catch (err) {
30057
30160
  throw err instanceof ConfigWriteError ? err : writeFailure(filePath, err);
30058
30161
  } finally {
30059
30162
  try {
30060
- fs33.unlinkSync(tmp);
30163
+ fs34.unlinkSync(tmp);
30061
30164
  } catch {
30062
30165
  }
30063
30166
  }
@@ -30083,18 +30186,18 @@ var init_writer2 = __esm({
30083
30186
  });
30084
30187
 
30085
30188
  // src/config/secrets-io.ts
30086
- import fs34 from "node:fs";
30189
+ import fs35 from "node:fs";
30087
30190
  import path36 from "node:path";
30088
30191
  function resolveSecretPath(stateDir, configName) {
30089
30192
  return secretsCandidates(stateDir, configName)[0];
30090
30193
  }
30091
30194
  function resolveSecretReadPath(stateDir, configName) {
30092
- return secretsCandidates(stateDir, configName).find((c) => fs34.existsSync(c)) ?? null;
30195
+ return secretsCandidates(stateDir, configName).find((c) => fs35.existsSync(c)) ?? null;
30093
30196
  }
30094
30197
  function readSecretStatus(stateDir, configName, names) {
30095
30198
  const p = resolveSecretReadPath(stateDir, configName);
30096
30199
  const out = {};
30097
- const text = p ? fs34.readFileSync(p, "utf-8") : "";
30200
+ const text = p ? fs35.readFileSync(p, "utf-8") : "";
30098
30201
  const present = /* @__PURE__ */ new Set();
30099
30202
  for (const line of text.split("\n")) {
30100
30203
  const t = line.trim();
@@ -30117,7 +30220,7 @@ var init_secrets_io = __esm({
30117
30220
  });
30118
30221
 
30119
30222
  // src/config/migrations/index.ts
30120
- import fs35 from "node:fs";
30223
+ import fs36 from "node:fs";
30121
30224
  import path37 from "node:path";
30122
30225
  function registerMigration(m) {
30123
30226
  if (REGISTRY.has(m.name)) {
@@ -30136,19 +30239,19 @@ async function runMigration(name, ctx) {
30136
30239
  function rotateBaks2(filePath) {
30137
30240
  const dir = path37.dirname(filePath);
30138
30241
  const base = path37.basename(filePath);
30139
- const baks = fs35.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30242
+ const baks = fs36.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30140
30243
  while (baks.length > KEEP_BAKS2) {
30141
30244
  const victim = baks.shift();
30142
30245
  try {
30143
- fs35.unlinkSync(path37.join(dir, victim));
30246
+ fs36.unlinkSync(path37.join(dir, victim));
30144
30247
  } catch {
30145
30248
  }
30146
30249
  }
30147
30250
  }
30148
30251
  function backupFile(filePath) {
30149
- if (!fs35.existsSync(filePath)) return null;
30252
+ if (!fs36.existsSync(filePath)) return null;
30150
30253
  const bak = `${filePath}.bak-${Date.now()}`;
30151
- fs35.copyFileSync(filePath, bak);
30254
+ fs36.copyFileSync(filePath, bak);
30152
30255
  rotateBaks2(filePath);
30153
30256
  return bak;
30154
30257
  }
@@ -30162,11 +30265,11 @@ var init_migrations = __esm({
30162
30265
  });
30163
30266
 
30164
30267
  // src/config/migrations/persona.ts
30165
- import fs36 from "node:fs";
30268
+ import fs37 from "node:fs";
30166
30269
  import path38 from "node:path";
30167
30270
  function readFileOrNull(p) {
30168
30271
  try {
30169
- return fs36.readFileSync(p, "utf-8");
30272
+ return fs37.readFileSync(p, "utf-8");
30170
30273
  } catch {
30171
30274
  return null;
30172
30275
  }
@@ -30187,7 +30290,7 @@ var init_persona = __esm({
30187
30290
  const persona = ctx.values?.agents?.defaults?.persona;
30188
30291
  if (typeof persona !== "string" || !persona) return { changed: [] };
30189
30292
  const dir = path38.join(ctx.workspace, "personas", persona);
30190
- if (!fs36.existsSync(dir)) {
30293
+ if (!fs37.existsSync(dir)) {
30191
30294
  return { changed: [] };
30192
30295
  }
30193
30296
  const changed = [];
@@ -30198,10 +30301,10 @@ var init_persona = __esm({
30198
30301
  const legacy = path38.join(ctx.workspace, LEGACY_PATHS[name]);
30199
30302
  const legacyContent = readFileOrNull(legacy);
30200
30303
  if (legacyContent !== null && legacyContent === content) {
30201
- fs36.renameSync(legacy, `${legacy}.migrated-${Date.now()}`);
30304
+ fs37.renameSync(legacy, `${legacy}.migrated-${Date.now()}`);
30202
30305
  changed.push(`${LEGACY_PATHS[name]} \u2192 personas/${persona}/${name}`);
30203
30306
  } else if (legacyContent !== null) {
30204
- fs36.renameSync(legacy, `${legacy}.bak-${Date.now()}`);
30307
+ fs37.renameSync(legacy, `${legacy}.bak-${Date.now()}`);
30205
30308
  changed.push(`${LEGACY_PATHS[name]} \u2192 .bak\uFF08\u5185\u5BB9\u4E0E\u6A21\u677F\u4E0D\u540C\uFF0C\u4FDD\u5B88\u4FDD\u7559\uFF09`);
30206
30309
  }
30207
30310
  }
@@ -30213,7 +30316,7 @@ var init_persona = __esm({
30213
30316
  });
30214
30317
 
30215
30318
  // src/config/migrations/channel-secrets.ts
30216
- import fs37 from "node:fs";
30319
+ import fs38 from "node:fs";
30217
30320
  function envNameFor(dotPath) {
30218
30321
  const declared = getField(dotPath)?.envKey;
30219
30322
  if (declared) return declared;
@@ -30255,15 +30358,15 @@ function planChannelSecretMoves(config) {
30255
30358
  }
30256
30359
  function restoreEnv(envPath, before) {
30257
30360
  try {
30258
- if (before === null) fs37.unlinkSync(envPath);
30259
- else fs37.writeFileSync(envPath, before, "utf8");
30361
+ if (before === null) fs38.unlinkSync(envPath);
30362
+ else fs38.writeFileSync(envPath, before, "utf8");
30260
30363
  } catch {
30261
30364
  }
30262
30365
  }
30263
30366
  function dropBackup(backup) {
30264
30367
  if (backup) {
30265
30368
  try {
30266
- fs37.unlinkSync(backup);
30369
+ fs38.unlinkSync(backup);
30267
30370
  } catch {
30268
30371
  }
30269
30372
  }
@@ -30272,7 +30375,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30272
30375
  const writeConfig = deps.writeConfig ?? ((p, obj) => writeConfigAtomic(p, obj));
30273
30376
  let text;
30274
30377
  try {
30275
- text = fs37.readFileSync(configPath, "utf-8");
30378
+ text = fs38.readFileSync(configPath, "utf-8");
30276
30379
  } catch {
30277
30380
  return { changed: [], backup: null, secretsFile: null };
30278
30381
  }
@@ -30289,7 +30392,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30289
30392
  if (moves.length === 0) return { changed: [], backup: null, secretsFile: null };
30290
30393
  const { stateDir, configName } = resolveConfigIdentity(configPath);
30291
30394
  const envPath = secretsCandidates(stateDir, configName)[0];
30292
- const envBefore = fs37.existsSync(envPath) ? fs37.readFileSync(envPath, "utf-8") : null;
30395
+ const envBefore = fs38.existsSync(envPath) ? fs38.readFileSync(envPath, "utf-8") : null;
30293
30396
  const backup = backupFile(configPath);
30294
30397
  try {
30295
30398
  for (const m of moves) writeSecret(stateDir, configName, m.envName, m.value);
@@ -30310,7 +30413,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30310
30413
  const problem = verify(configPath, envPath, moves);
30311
30414
  if (problem) {
30312
30415
  try {
30313
- if (backup) fs37.copyFileSync(backup, configPath);
30416
+ if (backup) fs38.copyFileSync(backup, configPath);
30314
30417
  } catch {
30315
30418
  }
30316
30419
  restoreEnv(envPath, envBefore);
@@ -30322,7 +30425,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30322
30425
  function verify(configPath, envPath, moves) {
30323
30426
  let cfg;
30324
30427
  try {
30325
- cfg = JSON.parse(fs37.readFileSync(configPath, "utf-8"));
30428
+ cfg = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
30326
30429
  } catch (e) {
30327
30430
  return `config \u8BFB\u4E0D\u56DE\u6765\u4E86\uFF08${e?.message || String(e)}\uFF09`;
30328
30431
  }
@@ -30332,7 +30435,7 @@ function verify(configPath, envPath, moves) {
30332
30435
  }
30333
30436
  let env = "";
30334
30437
  try {
30335
- env = fs37.readFileSync(envPath, "utf-8");
30438
+ env = fs38.readFileSync(envPath, "utf-8");
30336
30439
  } catch (e) {
30337
30440
  return `secrets \u6587\u4EF6\u8BFB\u4E0D\u56DE\u6765\uFF08${e?.message || String(e)}\uFF09`;
30338
30441
  }
@@ -30370,7 +30473,7 @@ __export(cli_config_exports, {
30370
30473
  isSafeConfigName: () => isSafeConfigName,
30371
30474
  runConfigCommand: () => runConfigCommand
30372
30475
  });
30373
- import fs38 from "node:fs";
30476
+ import fs39 from "node:fs";
30374
30477
  import path39 from "node:path";
30375
30478
  function isSafeConfigName(name) {
30376
30479
  return /^[\w.-]+$/.test(name);
@@ -30469,7 +30572,7 @@ function shapeOf(v) {
30469
30572
  function readConfigObject(configPath) {
30470
30573
  let text;
30471
30574
  try {
30472
- text = fs38.readFileSync(configPath, "utf-8");
30575
+ text = fs39.readFileSync(configPath, "utf-8");
30473
30576
  } catch {
30474
30577
  return { obj: {}, corrupt: false };
30475
30578
  }
@@ -30527,7 +30630,7 @@ function findMaskedCredentials(value, prefix, out) {
30527
30630
  function readEnvKeys(file2) {
30528
30631
  const out = [];
30529
30632
  try {
30530
- for (const line of fs38.readFileSync(file2, "utf-8").split("\n")) {
30633
+ for (const line of fs39.readFileSync(file2, "utf-8").split("\n")) {
30531
30634
  const t = line.trim();
30532
30635
  if (!t || t.startsWith("#")) continue;
30533
30636
  const eq = t.indexOf("=");
@@ -30583,7 +30686,7 @@ async function runConfigCommand(args) {
30583
30686
  }
30584
30687
  let parsedPayload;
30585
30688
  try {
30586
- parsedPayload = JSON.parse(fs38.readFileSync(p.file, "utf-8"));
30689
+ parsedPayload = JSON.parse(fs39.readFileSync(p.file, "utf-8"));
30587
30690
  } catch (e) {
30588
30691
  process.stderr.write(`[config] \u8BFB\u4E0D\u4E86 payload: ${e.message}
30589
30692
  `);
@@ -30689,7 +30792,7 @@ async function runConfigCommand(args) {
30689
30792
  }
30690
30793
  if (secretWrites.length > 0) {
30691
30794
  const writePath2 = resolveSecretPath(p.stateDir, p.configName);
30692
- const fallback = fs38.existsSync(writePath2) ? void 0 : secretsCandidates(p.stateDir, p.configName).find((c) => fs38.existsSync(c));
30795
+ const fallback = fs39.existsSync(writePath2) ? void 0 : secretsCandidates(p.stateDir, p.configName).find((c) => fs39.existsSync(c));
30693
30796
  if (fallback) {
30694
30797
  const writing = new Set(secretWrites.map((s) => s.name));
30695
30798
  const others = readEnvKeys(fallback).filter((k) => !writing.has(k));
@@ -30698,11 +30801,11 @@ async function runConfigCommand(args) {
30698
30801
  }
30699
30802
  }
30700
30803
  }
30701
- if (fs38.existsSync(p.configPath) && !isNormalized(fs38.readFileSync(p.configPath, "utf-8"))) {
30804
+ if (fs39.existsSync(p.configPath) && !isNormalized(fs39.readFileSync(p.configPath, "utf-8"))) {
30702
30805
  warnings.push("config \u9996\u6B21\u89C4\u8303\u5316\uFF1A\u884C\u5C3E\u7EDF\u4E00\u4E3A LF\u3001\u7F29\u8FDB\u7EDF\u4E00\u4E3A 2 \u7A7A\u683C\uFF08\u4E00\u6B21\u6027\u5927 diff\uFF09");
30703
30806
  }
30704
30807
  const configDir = path39.dirname(p.configPath);
30705
- if (!fs38.existsSync(configDir)) fs38.mkdirSync(configDir, { recursive: true });
30808
+ if (!fs39.existsSync(configDir)) fs39.mkdirSync(configDir, { recursive: true });
30706
30809
  try {
30707
30810
  writeConfigAtomic(p.configPath, merged);
30708
30811
  } catch (e) {
@@ -30806,14 +30909,14 @@ __export(cli_reconfig_exports, {
30806
30909
  doReconfigFeishu: () => doReconfigFeishu,
30807
30910
  doReconfigWechat: () => doReconfigWechat
30808
30911
  });
30809
- import * as fs39 from "node:fs";
30912
+ import * as fs40 from "node:fs";
30810
30913
  import * as path40 from "node:path";
30811
30914
  function scanForChannelsConfig(configsDir) {
30812
- if (!fs39.existsSync(configsDir)) return "";
30813
- for (const f of fs39.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
30915
+ if (!fs40.existsSync(configsDir)) return "";
30916
+ for (const f of fs40.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
30814
30917
  const full = path40.join(configsDir, f);
30815
30918
  try {
30816
- if (JSON.parse(fs39.readFileSync(full, "utf8")).channels) return full;
30919
+ if (JSON.parse(fs40.readFileSync(full, "utf8")).channels) return full;
30817
30920
  } catch {
30818
30921
  }
30819
30922
  }
@@ -30823,7 +30926,7 @@ function findFeishuConfigFile(stateDir, configName) {
30823
30926
  const configsDir = path40.join(stateDir, "configs");
30824
30927
  if (configName) {
30825
30928
  const p = path40.join(configsDir, configName);
30826
- if (fs39.existsSync(p)) return p;
30929
+ if (fs40.existsSync(p)) return p;
30827
30930
  }
30828
30931
  return scanForChannelsConfig(configsDir);
30829
30932
  }
@@ -30831,16 +30934,16 @@ function findWechatConfigFile(stateDir, configName) {
30831
30934
  const configsDir = path40.join(stateDir, "configs");
30832
30935
  if (configName) {
30833
30936
  const p = path40.join(configsDir, configName);
30834
- return fs39.existsSync(p) ? p : "";
30937
+ return fs40.existsSync(p) ? p : "";
30835
30938
  }
30836
30939
  const scanned = scanForChannelsConfig(configsDir);
30837
30940
  if (scanned) return scanned;
30838
- if (fs39.existsSync(configsDir)) {
30839
- const candidates = fs39.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
30941
+ if (fs40.existsSync(configsDir)) {
30942
+ const candidates = fs40.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
30840
30943
  if (candidates.length) {
30841
30944
  const first = path40.join(configsDir, candidates[0]);
30842
30945
  try {
30843
- JSON.parse(fs39.readFileSync(first, "utf8"));
30946
+ JSON.parse(fs40.readFileSync(first, "utf8"));
30844
30947
  return first;
30845
30948
  } catch {
30846
30949
  }
@@ -30879,11 +30982,11 @@ async function doReconfigFeishu(opts) {
30879
30982
  return 2;
30880
30983
  }
30881
30984
  const configFile = findFeishuConfigFile(stateDir, configName);
30882
- if (configFile && fs39.existsSync(configFile)) {
30985
+ if (configFile && fs40.existsSync(configFile)) {
30883
30986
  if (events) emit3?.({ event: "progress", step: "write_config" });
30884
30987
  let j;
30885
30988
  try {
30886
- j = JSON.parse(fs39.readFileSync(configFile, "utf8"));
30989
+ j = JSON.parse(fs40.readFileSync(configFile, "utf8"));
30887
30990
  } catch (err) {
30888
30991
  if (events) emit3?.({ event: "error", message: `\u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
30889
30992
  else console.error(`\u274C \u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -30901,7 +31004,7 @@ async function doReconfigFeishu(opts) {
30901
31004
  }
30902
31005
  j.channels.feishu = { enabled: true, appId: result.appId, appSecret: secretRef(feishuSecretEnv, result.appSecret), connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" };
30903
31006
  try {
30904
- fs39.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
31007
+ fs40.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
30905
31008
  } catch (err) {
30906
31009
  if (events) emit3?.({ event: "error", message: `\u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
30907
31010
  else console.error(`\u274C \u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -30934,7 +31037,7 @@ async function doReconfigWechat(opts) {
30934
31037
  return 2;
30935
31038
  }
30936
31039
  const configFile = findWechatConfigFile(stateDir, configName);
30937
- if (!configFile || !fs39.existsSync(configFile)) {
31040
+ if (!configFile || !fs40.existsSync(configFile)) {
30938
31041
  console.log("\n\u26A0\uFE0F \u6CA1\u627E\u5230 config \u6587\u4EF6\uFF0C\u8BF7\u624B\u52A8\u628A\u4EE5\u4E0B\u6BB5\u52A0\u8FDB\u4F60\u7684 config \u7684 channels \u91CC\uFF1A");
30939
31042
  console.log(JSON.stringify({ wechat: { enabled: true, token: cred.token, accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } } }, null, 2));
30940
31043
  if (events) emit3?.({ event: "done", channel: "wechat", detail: cred.accountId, restart_required: true });
@@ -30943,7 +31046,7 @@ async function doReconfigWechat(opts) {
30943
31046
  if (events) emit3?.({ event: "progress", step: "write_config" });
30944
31047
  let j;
30945
31048
  try {
30946
- j = JSON.parse(fs39.readFileSync(configFile, "utf8"));
31049
+ j = JSON.parse(fs40.readFileSync(configFile, "utf8"));
30947
31050
  } catch (err) {
30948
31051
  if (events) emit3?.({ event: "error", message: `\u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
30949
31052
  else console.error(`\u274C \u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -30961,7 +31064,7 @@ async function doReconfigWechat(opts) {
30961
31064
  }
30962
31065
  j.channels.wechat = { enabled: true, token: secretRef(wechatSecretEnv, cred.token), accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } };
30963
31066
  try {
30964
- fs39.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
31067
+ fs40.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
30965
31068
  } catch (err) {
30966
31069
  if (events) emit3?.({ event: "error", message: `\u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
30967
31070
  else console.error(`\u274C \u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -30999,19 +31102,19 @@ __export(cli_travel_exports, {
30999
31102
  saveTravelConfig: () => saveTravelConfig
31000
31103
  });
31001
31104
  import * as path41 from "node:path";
31002
- import * as fs40 from "node:fs";
31105
+ import * as fs41 from "node:fs";
31003
31106
  import * as os6 from "node:os";
31004
31107
  import { execSync as execSync2 } from "node:child_process";
31005
31108
  function loadTravelConfig() {
31006
31109
  try {
31007
- if (!fs40.existsSync(CONFIG_PATH)) return null;
31008
- return JSON.parse(fs40.readFileSync(CONFIG_PATH, "utf-8"));
31110
+ if (!fs41.existsSync(CONFIG_PATH)) return null;
31111
+ return JSON.parse(fs41.readFileSync(CONFIG_PATH, "utf-8"));
31009
31112
  } catch {
31010
31113
  return null;
31011
31114
  }
31012
31115
  }
31013
31116
  function saveTravelConfig(cfg) {
31014
- fs40.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
31117
+ fs41.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
31015
31118
  }
31016
31119
  function sanitizeContent(content, dirs) {
31017
31120
  let result = content;
@@ -31051,14 +31154,14 @@ function shouldExclude(name) {
31051
31154
  }
31052
31155
  function collectFiles(rootDir, includeSet, optionalSet) {
31053
31156
  const files = [];
31054
- const entries2 = fs40.readdirSync(rootDir, { withFileTypes: true });
31157
+ const entries2 = fs41.readdirSync(rootDir, { withFileTypes: true });
31055
31158
  for (const entry of entries2) {
31056
31159
  if (shouldExclude(entry.name)) continue;
31057
31160
  const fullPath = path41.join(rootDir, entry.name);
31058
- const realPath = fs40.realpathSync(fullPath);
31161
+ const realPath = fs41.realpathSync(fullPath);
31059
31162
  if (realPath !== fullPath) {
31060
31163
  try {
31061
- const lstat = fs40.lstatSync(fullPath);
31164
+ const lstat = fs41.lstatSync(fullPath);
31062
31165
  if (lstat.isSymbolicLink()) {
31063
31166
  continue;
31064
31167
  }
@@ -31079,12 +31182,12 @@ function collectFiles(rootDir, includeSet, optionalSet) {
31079
31182
  function collectAllFiles(dir) {
31080
31183
  const files = [];
31081
31184
  try {
31082
- const entries2 = fs40.readdirSync(dir, { withFileTypes: true });
31185
+ const entries2 = fs41.readdirSync(dir, { withFileTypes: true });
31083
31186
  for (const entry of entries2) {
31084
31187
  if (shouldExclude(entry.name)) continue;
31085
31188
  const fullPath = path41.join(dir, entry.name);
31086
31189
  try {
31087
- if (fs40.lstatSync(fullPath).isSymbolicLink()) continue;
31190
+ if (fs41.lstatSync(fullPath).isSymbolicLink()) continue;
31088
31191
  } catch {
31089
31192
  }
31090
31193
  if (entry.isDirectory()) {
@@ -31101,11 +31204,11 @@ function readMainEngineUuid(agentsDir) {
31101
31204
  try {
31102
31205
  const platformMapPath = path41.join(agentsDir, "main", "sessions", "platform-map.json");
31103
31206
  const indexMapPath = path41.join(agentsDir, "main", "sessions", "session-index.json");
31104
- if (!fs40.existsSync(platformMapPath) || !fs40.existsSync(indexMapPath)) return null;
31105
- const platformMap = JSON.parse(fs40.readFileSync(platformMapPath, "utf-8"));
31207
+ if (!fs41.existsSync(platformMapPath) || !fs41.existsSync(indexMapPath)) return null;
31208
+ const platformMap = JSON.parse(fs41.readFileSync(platformMapPath, "utf-8"));
31106
31209
  const mainPlatformId = platformMap["scope:main"] || platformMap["main"];
31107
31210
  if (!mainPlatformId) return null;
31108
- const indexMap = JSON.parse(fs40.readFileSync(indexMapPath, "utf-8"));
31211
+ const indexMap = JSON.parse(fs41.readFileSync(indexMapPath, "utf-8"));
31109
31212
  const entry = indexMap[mainPlatformId];
31110
31213
  if (!entry || !entry.file) return null;
31111
31214
  const basename10 = path41.basename(entry.file).replace(/\.jsonl$/, "");
@@ -31116,11 +31219,11 @@ function readMainEngineUuid(agentsDir) {
31116
31219
  }
31117
31220
  function collectRecentSessions(agentsDir, _days = 7) {
31118
31221
  const files = [];
31119
- if (!fs40.existsSync(agentsDir)) return files;
31222
+ if (!fs41.existsSync(agentsDir)) return files;
31120
31223
  const sessionGroups = /* @__PURE__ */ new Map();
31121
31224
  function scanSessionsDir(dir) {
31122
31225
  try {
31123
- const entries2 = fs40.readdirSync(dir, { withFileTypes: true });
31226
+ const entries2 = fs41.readdirSync(dir, { withFileTypes: true });
31124
31227
  for (const entry of entries2) {
31125
31228
  const fullPath = path41.join(dir, entry.name);
31126
31229
  if (entry.isDirectory()) {
@@ -31146,7 +31249,7 @@ function collectRecentSessions(agentsDir, _days = 7) {
31146
31249
  if (entry.name.endsWith(".jsonl")) {
31147
31250
  group.jsonl = fullPath;
31148
31251
  } else {
31149
- const stat4 = fs40.statSync(fullPath);
31252
+ const stat4 = fs41.statSync(fullPath);
31150
31253
  group.archived.push({ file: fullPath, mtime: stat4.mtimeMs });
31151
31254
  }
31152
31255
  }
@@ -31168,7 +31271,7 @@ function collectExportFileSet(stateDir, workspace) {
31168
31271
  const sessionFiles = collectRecentSessions(path41.join(stateDir, "agents"), 7);
31169
31272
  const configsDir = path41.join(stateDir, "configs");
31170
31273
  const configFiles = [];
31171
- if (fs40.existsSync(configsDir)) {
31274
+ if (fs41.existsSync(configsDir)) {
31172
31275
  for (const f of collectAllFiles(configsDir)) {
31173
31276
  if (shouldExclude(path41.basename(f))) continue;
31174
31277
  configFiles.push(f);
@@ -31177,7 +31280,7 @@ function collectExportFileSet(stateDir, workspace) {
31177
31280
  const EVEROS_SKIP = /* @__PURE__ */ new Set([".tmp", ".lock", "import.log", "import_progress.json"]);
31178
31281
  const everosDir = path41.join(stateDir, ".everos");
31179
31282
  const everosFiles = [];
31180
- if (fs40.existsSync(everosDir)) {
31283
+ if (fs41.existsSync(everosDir)) {
31181
31284
  for (const f of collectAllFiles(everosDir)) {
31182
31285
  if (EVEROS_SKIP.has(path41.basename(f))) continue;
31183
31286
  everosFiles.push(f);
@@ -31193,7 +31296,7 @@ async function doExport(opts) {
31193
31296
  console.log(` agent: ${agentName}`);
31194
31297
  console.log(` state: ${stateDir}`);
31195
31298
  console.log(` workspace: ${workspace}`);
31196
- if (!fs40.existsSync(workspace)) {
31299
+ if (!fs41.existsSync(workspace)) {
31197
31300
  console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
31198
31301
  process.exit(1);
31199
31302
  }
@@ -31202,7 +31305,7 @@ async function doExport(opts) {
31202
31305
  console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
31203
31306
  console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
31204
31307
  console.log(` configs: ${configFiles.length}`);
31205
- console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs40.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
31308
+ console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs41.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
31206
31309
  if (dryRun2) {
31207
31310
  console.log(`
31208
31311
  [DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
@@ -31220,25 +31323,25 @@ async function doExport(opts) {
31220
31323
  }
31221
31324
  const version = formatLog().replace(/[-: ]/g, "").slice(0, 12).replace(/(d{8})(d{4})/, "$1-$2");
31222
31325
  const tmpDir = path41.join(os6.tmpdir(), `engine7-export-${agentName}-${version}`);
31223
- fs40.mkdirSync(tmpDir, { recursive: true });
31326
+ fs41.mkdirSync(tmpDir, { recursive: true });
31224
31327
  const stagingDir = path41.join(tmpDir, agentName);
31225
- fs40.mkdirSync(stagingDir, { recursive: true });
31328
+ fs41.mkdirSync(stagingDir, { recursive: true });
31226
31329
  let fileCount = 0;
31227
31330
  let totalSize = 0;
31228
31331
  let copyFail = 0;
31229
31332
  const copyOne = (srcFile, relRoot, destRoot) => {
31230
31333
  const relPath = path41.relative(relRoot, srcFile);
31231
31334
  const destFile = path41.join(destRoot, relPath);
31232
- fs40.mkdirSync(path41.dirname(destFile), { recursive: true });
31335
+ fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31233
31336
  try {
31234
31337
  if (isTextFile(srcFile)) {
31235
- const content = fs40.readFileSync(srcFile, "utf-8");
31236
- fs40.writeFileSync(destFile, sanitizeContent(content, dirs));
31338
+ const content = fs41.readFileSync(srcFile, "utf-8");
31339
+ fs41.writeFileSync(destFile, sanitizeContent(content, dirs));
31237
31340
  } else {
31238
- fs40.copyFileSync(srcFile, destFile);
31341
+ fs41.copyFileSync(srcFile, destFile);
31239
31342
  }
31240
31343
  fileCount++;
31241
- totalSize += fs40.statSync(srcFile).size;
31344
+ totalSize += fs41.statSync(srcFile).size;
31242
31345
  } catch (e) {
31243
31346
  copyFail++;
31244
31347
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
@@ -31248,17 +31351,17 @@ async function doExport(opts) {
31248
31351
  for (const srcFile of sessionFiles) {
31249
31352
  const relPath = path41.relative(stateDir, srcFile);
31250
31353
  const destFile = path41.join(stagingDir, relPath);
31251
- fs40.mkdirSync(path41.dirname(destFile), { recursive: true });
31354
+ fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31252
31355
  try {
31253
- let content = fs40.readFileSync(srcFile, "utf-8");
31356
+ let content = fs41.readFileSync(srcFile, "utf-8");
31254
31357
  content = sanitizeContent(content, dirs);
31255
31358
  const baseName = path41.basename(srcFile);
31256
31359
  if (baseName === "session-index.json" || baseName === "platform-map.json") {
31257
31360
  content = content.split("\\\\").join("/");
31258
31361
  }
31259
- fs40.writeFileSync(destFile, content);
31362
+ fs41.writeFileSync(destFile, content);
31260
31363
  fileCount++;
31261
- totalSize += fs40.statSync(srcFile).size;
31364
+ totalSize += fs41.statSync(srcFile).size;
31262
31365
  } catch (e) {
31263
31366
  copyFail++;
31264
31367
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
@@ -31280,13 +31383,13 @@ async function doExport(opts) {
31280
31383
  totalSize,
31281
31384
  note
31282
31385
  };
31283
- fs40.writeFileSync(path41.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
31386
+ fs41.writeFileSync(path41.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
31284
31387
  const archiveFile = path41.join(tmpDir, `${agentName}-${version}.tar.gz`);
31285
31388
  console.log(`
31286
31389
  \u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
31287
31390
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
31288
31391
  execSync2(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
31289
- const archiveSize = fs40.statSync(archiveFile).size;
31392
+ const archiveSize = fs41.statSync(archiveFile).size;
31290
31393
  console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6${copyFail ? `, \u5931\u8D25 ${copyFail}` : ""})`);
31291
31394
  const cfg = loadTravelConfig();
31292
31395
  if (!cfg || !cfg.githubToken) {
@@ -31317,7 +31420,7 @@ function parseImportArgs(args) {
31317
31420
  }
31318
31421
  async function resolveArchiveForTest(opts) {
31319
31422
  if (opts.archiveFile) {
31320
- if (!fs40.existsSync(opts.archiveFile)) {
31423
+ if (!fs41.existsSync(opts.archiveFile)) {
31321
31424
  throw new Error(`\u672C\u5730\u5305\u4E0D\u5B58\u5728: ${opts.archiveFile}`);
31322
31425
  }
31323
31426
  return opts.archiveFile;
@@ -31330,7 +31433,7 @@ async function doImport(opts) {
31330
31433
  console.log(` agent: ${agentName}`);
31331
31434
  console.log(` target: ${stateDir}`);
31332
31435
  const tmpDir = path41.join(os6.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
31333
- fs40.mkdirSync(tmpDir, { recursive: true });
31436
+ fs41.mkdirSync(tmpDir, { recursive: true });
31334
31437
  const resolved = await resolveArchiveForTest({
31335
31438
  archiveFile: archiveFile || "",
31336
31439
  tmpDir,
@@ -31357,11 +31460,11 @@ async function doImport(opts) {
31357
31460
  execSync2(`"${tarExe}" -xzf "${finalArchive}" -C "${tmpDir}"`, { stdio: "pipe" });
31358
31461
  const stagingDir = path41.join(tmpDir, agentName);
31359
31462
  const manifestPath = path41.join(stagingDir, "manifest.json");
31360
- if (!fs40.existsSync(manifestPath)) {
31463
+ if (!fs41.existsSync(manifestPath)) {
31361
31464
  console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
31362
31465
  process.exit(1);
31363
31466
  }
31364
- const manifest = JSON.parse(fs40.readFileSync(manifestPath, "utf-8"));
31467
+ const manifest = JSON.parse(fs41.readFileSync(manifestPath, "utf-8"));
31365
31468
  const workspace = path41.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
31366
31469
  const engineHome = path41.join(os6.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
31367
31470
  const dirs = { workspace, stateDir: stateDir.replace(/\\/g, "/").replace(/[/\\]+$/, ""), engineHome };
@@ -31371,18 +31474,18 @@ async function doImport(opts) {
31371
31474
  const wsStaging = path41.join(stagingDir, "workspace");
31372
31475
  let restoredCount = 0;
31373
31476
  let skipCount = 0;
31374
- if (fs40.existsSync(wsStaging)) {
31477
+ if (fs41.existsSync(wsStaging)) {
31375
31478
  const allFiles = collectAllFiles(wsStaging);
31376
31479
  for (const srcFile of allFiles) {
31377
31480
  const relPath = path41.relative(wsStaging, srcFile);
31378
31481
  const destFile = path41.join(workspace, relPath);
31379
- fs40.mkdirSync(path41.dirname(destFile), { recursive: true });
31482
+ fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31380
31483
  try {
31381
31484
  if (isTextFile(srcFile)) {
31382
- const content = fs40.readFileSync(srcFile, "utf-8");
31383
- fs40.writeFileSync(destFile, restoreContent(content, dirs));
31485
+ const content = fs41.readFileSync(srcFile, "utf-8");
31486
+ fs41.writeFileSync(destFile, restoreContent(content, dirs));
31384
31487
  } else {
31385
- fs40.copyFileSync(srcFile, destFile);
31488
+ fs41.copyFileSync(srcFile, destFile);
31386
31489
  }
31387
31490
  restoredCount++;
31388
31491
  } catch (e) {
@@ -31392,46 +31495,46 @@ async function doImport(opts) {
31392
31495
  }
31393
31496
  }
31394
31497
  const agentsStaging = path41.join(stagingDir, "agents");
31395
- if (fs40.existsSync(agentsStaging)) {
31498
+ if (fs41.existsSync(agentsStaging)) {
31396
31499
  const sessionFiles = collectAllFiles(agentsStaging);
31397
31500
  for (const srcFile of sessionFiles) {
31398
31501
  const relPath = path41.relative(stagingDir, srcFile);
31399
31502
  const destFile = path41.join(stateDir, relPath);
31400
- fs40.mkdirSync(path41.dirname(destFile), { recursive: true });
31401
- const content = fs40.readFileSync(srcFile, "utf-8");
31402
- fs40.writeFileSync(destFile, restoreContent(content, dirs));
31503
+ fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31504
+ const content = fs41.readFileSync(srcFile, "utf-8");
31505
+ fs41.writeFileSync(destFile, restoreContent(content, dirs));
31403
31506
  restoredCount++;
31404
31507
  }
31405
31508
  }
31406
31509
  const configsStaging = path41.join(stagingDir, "configs");
31407
- if (fs40.existsSync(configsStaging)) {
31510
+ if (fs41.existsSync(configsStaging)) {
31408
31511
  const cfgFiles = collectAllFiles(configsStaging);
31409
31512
  for (const srcFile of cfgFiles) {
31410
31513
  const relPath = path41.relative(stagingDir, srcFile);
31411
31514
  const destFile = path41.join(stateDir, relPath);
31412
- fs40.mkdirSync(path41.dirname(destFile), { recursive: true });
31515
+ fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31413
31516
  if (isTextFile(srcFile)) {
31414
- const content = fs40.readFileSync(srcFile, "utf-8");
31415
- fs40.writeFileSync(destFile, restoreContent(content, dirs));
31517
+ const content = fs41.readFileSync(srcFile, "utf-8");
31518
+ fs41.writeFileSync(destFile, restoreContent(content, dirs));
31416
31519
  } else {
31417
- fs40.copyFileSync(srcFile, destFile);
31520
+ fs41.copyFileSync(srcFile, destFile);
31418
31521
  }
31419
31522
  restoredCount++;
31420
31523
  }
31421
31524
  }
31422
31525
  const everosStaging = path41.join(stagingDir, ".everos");
31423
- if (fs40.existsSync(everosStaging)) {
31526
+ if (fs41.existsSync(everosStaging)) {
31424
31527
  const everosFiles = collectAllFiles(everosStaging);
31425
31528
  for (const srcFile of everosFiles) {
31426
31529
  const relPath = path41.relative(stagingDir, srcFile);
31427
31530
  const destFile = path41.join(stateDir, relPath);
31428
- fs40.mkdirSync(path41.dirname(destFile), { recursive: true });
31531
+ fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31429
31532
  try {
31430
31533
  if (isTextFile(srcFile)) {
31431
- const content = fs40.readFileSync(srcFile, "utf-8");
31432
- fs40.writeFileSync(destFile, restoreContent(content, dirs));
31534
+ const content = fs41.readFileSync(srcFile, "utf-8");
31535
+ fs41.writeFileSync(destFile, restoreContent(content, dirs));
31433
31536
  } else {
31434
- fs40.copyFileSync(srcFile, destFile);
31537
+ fs41.copyFileSync(srcFile, destFile);
31435
31538
  }
31436
31539
  restoredCount++;
31437
31540
  } catch (e) {
@@ -31444,10 +31547,10 @@ async function doImport(opts) {
31444
31547
  console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}${skipCount ? ` (\u8DF3\u8FC7 ${skipCount})` : ""}`);
31445
31548
  const platformConfigName = process.platform === "darwin" ? "xiaoke-mac.json" : "xiaoke-win.json";
31446
31549
  const restoredConfigPath = path41.join(stateDir, "configs", platformConfigName);
31447
- const configToUse = fs40.existsSync(restoredConfigPath) ? restoredConfigPath : path41.join(stateDir, "configs", "xiaoke.json");
31550
+ const configToUse = fs41.existsSync(restoredConfigPath) ? restoredConfigPath : path41.join(stateDir, "configs", "xiaoke.json");
31448
31551
  console.log(`
31449
31552
  \u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config "${configToUse}"`);
31450
- fs40.rmSync(tmpDir, { recursive: true, force: true });
31553
+ fs41.rmSync(tmpDir, { recursive: true, force: true });
31451
31554
  }
31452
31555
  async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
31453
31556
  const repo = `${cfg.githubOwner}/${cfg.repoName}`;
@@ -31477,7 +31580,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
31477
31580
  }
31478
31581
  const release2 = await createRes.json();
31479
31582
  const uploadUrl = release2.upload_url.replace("{?name,label}", "");
31480
- const fileBuffer = fs40.readFileSync(archiveFile);
31583
+ const fileBuffer = fs41.readFileSync(archiveFile);
31481
31584
  const fileName = path41.basename(archiveFile);
31482
31585
  const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
31483
31586
  method: "POST",
@@ -31501,7 +31604,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
31501
31604
  throw e;
31502
31605
  }
31503
31606
  try {
31504
- fs40.rmSync(path41.dirname(archiveFile), { recursive: true, force: true });
31607
+ fs41.rmSync(path41.dirname(archiveFile), { recursive: true, force: true });
31505
31608
  } catch {
31506
31609
  }
31507
31610
  }
@@ -31534,7 +31637,7 @@ async function downloadFromGitHub(cfg, agentName, version, destDir) {
31534
31637
  }
31535
31638
  const buffer = Buffer.from(await downloadRes.arrayBuffer());
31536
31639
  const archiveFile = path41.join(destDir, asset.name);
31537
- fs40.writeFileSync(archiveFile, buffer);
31640
+ fs41.writeFileSync(archiveFile, buffer);
31538
31641
  return archiveFile;
31539
31642
  }
31540
31643
  async function getLatestReleaseTag(cfg, agentName) {
@@ -31634,7 +31737,7 @@ var init_cli_travel = __esm({
31634
31737
 
31635
31738
  // src/cli-init.ts
31636
31739
  import * as path42 from "node:path";
31637
- import * as fs41 from "node:fs";
31740
+ import * as fs42 from "node:fs";
31638
31741
 
31639
31742
  // src/cli-service.ts
31640
31743
  function parseServiceArgs(args) {
@@ -31740,6 +31843,7 @@ function buildConfigValuesFromAnswers(stateDir, a, existing = {}) {
31740
31843
  const primaryProvider = target.providerId;
31741
31844
  const primaryModel = target.modelRef || DEFAULT_PRIMARY_MODEL[a.provider] || `${primaryProvider}/unknown`;
31742
31845
  const visionModel = a.visionModel || resolveVisionModel(primaryProvider, primaryModel, a.providerModels);
31846
+ const videoModel = a.videoModel || resolveVideoModel(primaryProvider, primaryModel, a.providerModels);
31743
31847
  const feishuMode = a.feishu?.mode || "skip";
31744
31848
  const wechatMode = a.wechat?.mode || "skip";
31745
31849
  return {
@@ -31762,6 +31866,7 @@ function buildConfigValuesFromAnswers(stateDir, a, existing = {}) {
31762
31866
  primaryApiKey: a.apiKey || "",
31763
31867
  primaryModel,
31764
31868
  visionModel,
31869
+ videoModel,
31765
31870
  discordEnabled: a.discord?.enabled ?? false,
31766
31871
  discordToken: a.discord?.token || "",
31767
31872
  discordUserId: a.discord?.userId || "",
@@ -31931,6 +32036,11 @@ function getDefaultValues(stateDir) {
31931
32036
  // 沿用旧值前先验 provider:机器已被 P0-2 写坏时,--quick 会把那个幽灵引用原样带下去
31932
32037
  // (向导路径本来就会重算,只有 --quick 走这里)。
31933
32038
  visionModel: existing.visionModel?.startsWith(primaryProvider + "/") ? existing.visionModel : resolveVisionModel(primaryProvider, primaryModel),
32039
+ // 0930:视频模型同样只在本 provider 内推导(主模型自己收 video 就复用;7yi 落
32040
+ // engine7-video)。解析不出返回空串,generateConfig 省略 video 键。
32041
+ // 复跑保留与 visionModel 同一条规则(翀哥 8/28「回车保留」指示):同 provider 的已有值
32042
+ // 原样沿用——用户手改过的 model.video 不该被 --quick 冲掉;跨 provider / 没有的才重推。
32043
+ videoModel: existing.videoModel?.startsWith(primaryProvider + "/") ? existing.videoModel : resolveVideoModel(primaryProvider, primaryModel),
31934
32044
  discordEnabled: existing.discordEnabled ?? false,
31935
32045
  discordToken: existing.discordToken || "",
31936
32046
  discordUserId: existing.discordUserId || "",
@@ -31953,14 +32063,14 @@ function getDefaultValues(stateDir) {
31953
32063
  function loadExistingValues(stateDir) {
31954
32064
  const configPath = path42.join(stateDir, "configs", "main7.json");
31955
32065
  try {
31956
- if (!fs41.existsSync(configPath)) return {};
31957
- const j = JSON.parse(fs41.readFileSync(configPath, "utf8"));
32066
+ if (!fs42.existsSync(configPath)) return {};
32067
+ const j = JSON.parse(fs42.readFileSync(configPath, "utf8"));
31958
32068
  const out = {};
31959
32069
  if (typeof j.timezone === "string" && j.timezone) out.timezone = j.timezone;
31960
32070
  if (j.agents?.defaults?.name) out.agentName = j.agents.defaults.name;
31961
32071
  if (j.agents?.defaults?.persona) out.persona = j.agents.defaults.persona;
31962
32072
  try {
31963
- const wm = fs41.readFileSync(path42.join(stateDir, "workspace", ".work-mode"), "utf8").trim();
32073
+ const wm = fs42.readFileSync(path42.join(stateDir, "workspace", ".work-mode"), "utf8").trim();
31964
32074
  if (wm === "on") out.chatMode = "work";
31965
32075
  else if (wm === "off") out.chatMode = "emotion";
31966
32076
  } catch {
@@ -31990,6 +32100,7 @@ function loadExistingValues(stateDir) {
31990
32100
  out.customModelId = builtin.includes(firstId) ? "" : firstModel;
31991
32101
  }
31992
32102
  if (j.agents?.defaults?.model?.vision) out.visionModel = j.agents.defaults.model.vision;
32103
+ if (j.agents?.defaults?.model?.video) out.videoModel = j.agents.defaults.model.video;
31993
32104
  }
31994
32105
  if (j.channels?.discord) {
31995
32106
  out.discordEnabled = !!j.channels.discord.enabled;
@@ -32016,8 +32127,8 @@ function readSecretsValue(stateDir, envName) {
32016
32127
  try {
32017
32128
  const cfgBase = "main7";
32018
32129
  for (const p of secretsCandidates(stateDir, cfgBase)) {
32019
- if (fs41.existsSync(p)) {
32020
- for (const line of fs41.readFileSync(p, "utf8").split("\n")) {
32130
+ if (fs42.existsSync(p)) {
32131
+ for (const line of fs42.readFileSync(p, "utf8").split("\n")) {
32021
32132
  const eq = line.indexOf("=");
32022
32133
  if (eq > 0 && line.slice(0, eq).trim() === envName) {
32023
32134
  return line.slice(eq + 1).trim();
@@ -32121,6 +32232,7 @@ async function interactiveConfig(rl, defaults) {
32121
32232
  console.log(` \u6CE8\u610F\uFF1AVision \u6A21\u578B\u7528\u4E86\u4E0D\u540C provider\uFF0C\u9700\u8981\u5728 config \u91CC\u8865\u5145\u5BF9\u5E94\u7684 API key`);
32122
32233
  }
32123
32234
  }
32235
+ v.videoModel = resolveVideoModel(v.primaryProvider, v.primaryModel);
32124
32236
  console.log("\n=== \u7B2C\u4E8C\u6B65\uFF1A\u53EF\u9009\u914D\u7F6E\uFF08\u56DE\u8F66\u8DF3\u8FC7\uFF0C\u5DF2\u542F\u7528\u7684\u56DE\u8F66\u4FDD\u7559\uFF09===\n");
32125
32237
  const discordAns = await ask(rl, "\u542F\u7528 Discord? (y/n)", defaults.discordEnabled ? "y" : "n");
32126
32238
  v.discordEnabled = discordAns.toLowerCase() === "y";
@@ -32448,19 +32560,19 @@ function readTemplate(relativePath) {
32448
32560
  path42.join(process.cwd(), "templates", relativePath)
32449
32561
  ];
32450
32562
  for (const p of candidates) {
32451
- if (fs41.existsSync(p)) {
32452
- return fs41.readFileSync(p, "utf-8");
32563
+ if (fs42.existsSync(p)) {
32564
+ return fs42.readFileSync(p, "utf-8");
32453
32565
  }
32454
32566
  }
32455
32567
  throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
32456
32568
  }
32457
32569
  function looksLikeAppInstall(dir) {
32458
- return ["", "install"].some((sub) => fs41.existsSync(path42.join(dir, sub, "Engine7.exe")) && fs41.existsSync(path42.join(dir, sub, "resources", "engine7", "dist", "cli.mjs")));
32570
+ return ["", "install"].some((sub) => fs42.existsSync(path42.join(dir, sub, "Engine7.exe")) && fs42.existsSync(path42.join(dir, sub, "resources", "engine7", "dist", "cli.mjs")));
32459
32571
  }
32460
32572
  var PHOTO_EXTS = [".png", ".jpg", ".jpeg", ".webp"];
32461
32573
  function hasOnlyEngineBookkeeping(dir) {
32462
32574
  try {
32463
- const entries2 = fs41.readdirSync(dir);
32575
+ const entries2 = fs42.readdirSync(dir);
32464
32576
  return entries2.length > 0 && entries2.every((e) => e === "install-identity.json");
32465
32577
  } catch {
32466
32578
  return false;
@@ -32476,11 +32588,11 @@ function dryRun(entries2) {
32476
32588
  function execute(entries2) {
32477
32589
  for (const e of entries2) {
32478
32590
  if (e.type === "dir") {
32479
- fs41.mkdirSync(e.path, { recursive: true });
32591
+ fs42.mkdirSync(e.path, { recursive: true });
32480
32592
  console.log(` \u{1F4C1} ${e.path}`);
32481
32593
  } else {
32482
- fs41.mkdirSync(path42.dirname(e.path), { recursive: true });
32483
- fs41.writeFileSync(e.path, e.content || "", "utf-8");
32594
+ fs42.mkdirSync(path42.dirname(e.path), { recursive: true });
32595
+ fs42.writeFileSync(e.path, e.content || "", "utf-8");
32484
32596
  console.log(` \u{1F4C4} ${e.path}`);
32485
32597
  }
32486
32598
  }
@@ -32515,7 +32627,7 @@ async function main() {
32515
32627
  let ver = "unknown";
32516
32628
  try {
32517
32629
  const pkgPath = path42.join(path42.dirname(__filename2), "..", "package.json");
32518
- ver = JSON.parse(fs41.readFileSync(pkgPath, "utf8")).version || "unknown";
32630
+ ver = JSON.parse(fs42.readFileSync(pkgPath, "utf8")).version || "unknown";
32519
32631
  } catch {
32520
32632
  }
32521
32633
  console.log(`engine7 ${ver}`);
@@ -32579,13 +32691,13 @@ async function main() {
32579
32691
  }
32580
32692
  if (!stateDir) {
32581
32693
  const cwd = path42.resolve(process.cwd());
32582
- if (fs41.existsSync(path42.join(cwd, "configs"))) {
32694
+ if (fs42.existsSync(path42.join(cwd, "configs"))) {
32583
32695
  stateDir = cwd;
32584
32696
  } else {
32585
32697
  const pointer = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
32586
- if (fs41.existsSync(pointer)) {
32698
+ if (fs42.existsSync(pointer)) {
32587
32699
  try {
32588
- stateDir = JSON.parse(fs41.readFileSync(pointer, "utf8")).stateDir || "";
32700
+ stateDir = JSON.parse(fs42.readFileSync(pointer, "utf8")).stateDir || "";
32589
32701
  } catch {
32590
32702
  }
32591
32703
  }
@@ -32610,11 +32722,11 @@ async function main() {
32610
32722
  }
32611
32723
  if (channel === "channels") {
32612
32724
  const configsDir = path42.join(stateDir, "configs");
32613
- if (fs41.existsSync(configsDir)) {
32614
- const files = fs41.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
32725
+ if (fs42.existsSync(configsDir)) {
32726
+ const files = fs42.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
32615
32727
  for (const f of files) {
32616
32728
  try {
32617
- const j = JSON.parse(fs41.readFileSync(path42.join(configsDir, f), "utf8"));
32729
+ const j = JSON.parse(fs42.readFileSync(path42.join(configsDir, f), "utf8"));
32618
32730
  if (!j.channels) continue;
32619
32731
  console.log(`
32620
32732
  \u{1F4C4} ${f}:`);
@@ -32771,16 +32883,16 @@ engine7 start \u2014 \u542F\u52A8 Engine
32771
32883
  if (!configPath2) {
32772
32884
  const defaultCfg = path42.join("configs", "main7.json");
32773
32885
  const homeCfg = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
32774
- if (fs41.existsSync(defaultCfg)) {
32886
+ if (fs42.existsSync(defaultCfg)) {
32775
32887
  configPath2 = defaultCfg;
32776
- } else if (fs41.existsSync(homeCfg)) {
32888
+ } else if (fs42.existsSync(homeCfg)) {
32777
32889
  configPath2 = homeCfg;
32778
32890
  console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
32779
32891
  } else {
32780
32892
  const ptr = readHomePointer();
32781
32893
  if (ptr?.stateDir) {
32782
32894
  const ptrCfg = path42.join(ptr.stateDir, "configs", "main7.json");
32783
- if (fs41.existsSync(ptrCfg)) {
32895
+ if (fs42.existsSync(ptrCfg)) {
32784
32896
  configPath2 = ptrCfg;
32785
32897
  console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
32786
32898
  }
@@ -32793,7 +32905,7 @@ engine7 start \u2014 \u542F\u52A8 Engine
32793
32905
  }
32794
32906
  }
32795
32907
  }
32796
- if (configPath2 && !fs41.existsSync(configPath2)) {
32908
+ if (configPath2 && !fs42.existsSync(configPath2)) {
32797
32909
  console.error(`\u274C config \u6587\u4EF6\u4E0D\u5B58\u5728: ${configPath2}`);
32798
32910
  console.error(" \u7528\u6CD5: engine7 start [configs/xxx.json | --config <path>]");
32799
32911
  process.exit(1);
@@ -32801,13 +32913,13 @@ engine7 start \u2014 \u542F\u52A8 Engine
32801
32913
  const { execSync: execSync3, spawn: spawn5 } = await import("node:child_process");
32802
32914
  let enginePath;
32803
32915
  const localPath = path42.join("node_modules", "engine7", "dist", "main.mjs");
32804
- if (fs41.existsSync(localPath)) {
32916
+ if (fs42.existsSync(localPath)) {
32805
32917
  enginePath = localPath;
32806
32918
  } else {
32807
32919
  const cliPath = path42.resolve(process.argv[1]);
32808
32920
  const distDir = path42.dirname(cliPath);
32809
32921
  const candidate = path42.join(distDir, "main.mjs");
32810
- if (fs41.existsSync(candidate)) {
32922
+ if (fs42.existsSync(candidate)) {
32811
32923
  enginePath = candidate;
32812
32924
  } else {
32813
32925
  try {
@@ -32843,8 +32955,8 @@ engine7 start \u2014 \u542F\u52A8 Engine
32843
32955
  const envForChild = { ...process.env };
32844
32956
  const { stateDir: secretsStateDir, configName: secretsCfgName } = resolveConfigIdentity(configPath2);
32845
32957
  for (const secretPath of secretsCandidates(secretsStateDir, secretsCfgName)) {
32846
- if (fs41.existsSync(secretPath)) {
32847
- const content = fs41.readFileSync(secretPath, "utf-8");
32958
+ if (fs42.existsSync(secretPath)) {
32959
+ const content = fs42.readFileSync(secretPath, "utf-8");
32848
32960
  for (const line of content.split("\n")) {
32849
32961
  const trimmed = line.trim();
32850
32962
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -32919,14 +33031,14 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
32919
33031
  console.error(`\u274C \u672A\u77E5\u6A21\u5F0F: ${mode}\uFF08\u53EF\u9009: archive / drop-last / strip-images\uFF09`);
32920
33032
  process.exit(1);
32921
33033
  }
32922
- const configRaw = JSON.parse(fs41.readFileSync(configPath2, "utf-8"));
33034
+ const configRaw = JSON.parse(fs42.readFileSync(configPath2, "utf-8"));
32923
33035
  const stateDir = configRaw.stateDir;
32924
33036
  if (!stateDir) {
32925
33037
  console.error("\u274C config \u91CC\u6CA1\u6709 stateDir");
32926
33038
  process.exit(1);
32927
33039
  }
32928
33040
  const sessionsDir = path42.join(stateDir, "agents", "main", "sessions");
32929
- if (!fs41.existsSync(sessionsDir)) {
33041
+ if (!fs42.existsSync(sessionsDir)) {
32930
33042
  console.error(`\u274C sessions \u76EE\u5F55\u4E0D\u5B58\u5728: ${sessionsDir}`);
32931
33043
  process.exit(1);
32932
33044
  }
@@ -32937,8 +33049,8 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
32937
33049
  const platformMapPath = path42.join(sessionsDir, "platform-map.json");
32938
33050
  const indexPath = path42.join(sessionsDir, "session-index.json");
32939
33051
  let sessionFileUUID = null;
32940
- if (fs41.existsSync(indexPath)) {
32941
- const index = JSON.parse(fs41.readFileSync(indexPath, "utf-8"));
33052
+ if (fs42.existsSync(indexPath)) {
33053
+ const index = JSON.parse(fs42.readFileSync(indexPath, "utf-8"));
32942
33054
  const entries2 = Object.values(index);
32943
33055
  if (entries2.length > 0) {
32944
33056
  const fileVal = entries2[0].file || "";
@@ -32946,7 +33058,7 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
32946
33058
  }
32947
33059
  }
32948
33060
  if (!sessionFileUUID) {
32949
- const jsonlFiles = fs41.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs41.statSync(path42.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
33061
+ const jsonlFiles = fs42.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs42.statSync(path42.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
32950
33062
  if (jsonlFiles.length === 0) {
32951
33063
  console.error("\u274C \u627E\u4E0D\u5230\u6D3B\u8DC3\u7684 session JSONL \u6587\u4EF6");
32952
33064
  process.exit(1);
@@ -32954,8 +33066,8 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
32954
33066
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
32955
33067
  }
32956
33068
  let jsonlPath = path42.join(sessionsDir, `${sessionFileUUID}.jsonl`);
32957
- if (!fs41.existsSync(jsonlPath)) {
32958
- const jsonlFiles = fs41.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs41.statSync(path42.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
33069
+ if (!fs42.existsSync(jsonlPath)) {
33070
+ const jsonlFiles = fs42.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs42.statSync(path42.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
32959
33071
  if (jsonlFiles.length === 0) {
32960
33072
  console.error(`\u274C JSONL \u6587\u4EF6\u4E0D\u5B58\u5728: ${jsonlPath}`);
32961
33073
  process.exit(1);
@@ -32980,7 +33092,7 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
32980
33092
  }
32981
33093
  }
32982
33094
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
32983
- const { readFileSync: readFileSync45, writeFileSync: writeFileSync26, renameSync: renameSync5 } = fs41;
33095
+ const { readFileSync: readFileSync45, writeFileSync: writeFileSync26, renameSync: renameSync5 } = fs42;
32984
33096
  if (mode === "archive") {
32985
33097
  const archiveName = `${sessionFileUUID}.jsonl.archived.${timestamp}`;
32986
33098
  renameSync5(jsonlPath, path42.join(sessionsDir, archiveName));
@@ -33058,11 +33170,11 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
33058
33170
  \u2705 \u6458\u9664 ${stripped} \u884C\u56FE\u7247\u76F8\u5173\u5185\u5BB9`);
33059
33171
  }
33060
33172
  if (autoRestart) {
33061
- const realCliPath = fs41.realpathSync(process.argv[1]);
33173
+ const realCliPath = fs42.realpathSync(process.argv[1]);
33062
33174
  const cliDir = path42.dirname(realCliPath);
33063
33175
  const pkgRoot = path42.resolve(cliDir, "..");
33064
33176
  let enginePath = path42.join(pkgRoot, "dist", "main.mjs");
33065
- if (!fs41.existsSync(enginePath)) {
33177
+ if (!fs42.existsSync(enginePath)) {
33066
33178
  enginePath = path42.join(cliDir, "main.mjs");
33067
33179
  }
33068
33180
  console.log(`
@@ -33105,16 +33217,16 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33105
33217
  if (!configPath2) {
33106
33218
  const defaultCfg = path42.join(cwd, "configs", "main7.json");
33107
33219
  const homeCfg = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
33108
- if (fs41.existsSync(defaultCfg)) {
33220
+ if (fs42.existsSync(defaultCfg)) {
33109
33221
  configPath2 = defaultCfg;
33110
- } else if (fs41.existsSync(homeCfg)) {
33222
+ } else if (fs42.existsSync(homeCfg)) {
33111
33223
  configPath2 = homeCfg;
33112
33224
  cwd = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
33113
33225
  } else {
33114
33226
  const ptr = readHomePointer();
33115
33227
  if (ptr?.stateDir) {
33116
33228
  const ptrCfg = path42.join(ptr.stateDir, "configs", "main7.json");
33117
- if (fs41.existsSync(ptrCfg)) {
33229
+ if (fs42.existsSync(ptrCfg)) {
33118
33230
  configPath2 = ptrCfg;
33119
33231
  cwd = ptr.stateDir;
33120
33232
  }
@@ -33139,7 +33251,7 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33139
33251
  cliMjs: path42.resolve(engine7Bin),
33140
33252
  configPath: path42.resolve(configPath2)
33141
33253
  });
33142
- fs41.writeFileSync(wrapperPath, wrapperContent);
33254
+ fs42.writeFileSync(wrapperPath, wrapperContent);
33143
33255
  const startupDir = path42.join(
33144
33256
  process.env.APPDATA || path42.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33145
33257
  "Microsoft",
@@ -33148,7 +33260,7 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33148
33260
  "Programs",
33149
33261
  "Startup"
33150
33262
  );
33151
- fs41.mkdirSync(startupDir, { recursive: true });
33263
+ fs42.mkdirSync(startupDir, { recursive: true });
33152
33264
  const vbsPath = path42.join(startupDir, "Engine7.vbs");
33153
33265
  const nodeExePath = nodeExe || process.execPath;
33154
33266
  const cliMjsPath = path42.resolve(engine7Bin);
@@ -33168,15 +33280,15 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33168
33280
  's.Run """' + nodeExePath + '"" ""' + cliMjsPath + '"" start --config ""' + absCfg + '""", 0, False',
33169
33281
  ""
33170
33282
  ].join(String.fromCharCode(13) + String.fromCharCode(10));
33171
- fs41.writeFileSync(vbsPath, vbs);
33283
+ fs42.writeFileSync(vbsPath, vbs);
33172
33284
  console.log(`\u2705 \u5F00\u673A\u81EA\u542F\u52A8\u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939: ${vbsPath}\uFF09`);
33173
33285
  } else if (process.platform === "darwin") {
33174
33286
  const label = "com.engine7.agent";
33175
33287
  const plistDir = path42.join(process.env.HOME, "Library", "LaunchAgents");
33176
- fs41.mkdirSync(plistDir, { recursive: true });
33288
+ fs42.mkdirSync(plistDir, { recursive: true });
33177
33289
  const plistPath = path42.join(plistDir, `${label}.plist`);
33178
33290
  const localCli = path42.join("node_modules", "engine7", "dist", "cli.mjs");
33179
- const cliMjs = fs41.existsSync(localCli) ? path42.resolve(localCli) : path42.join(path42.dirname(path42.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
33291
+ const cliMjs = fs42.existsSync(localCli) ? path42.resolve(localCli) : path42.join(path42.dirname(path42.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
33180
33292
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
33181
33293
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33182
33294
  <plist version="1.0">
@@ -33195,7 +33307,7 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33195
33307
  <key>KeepAlive</key><true/>
33196
33308
  </dict>
33197
33309
  </plist>`;
33198
- fs41.writeFileSync(plistPath, plist);
33310
+ fs42.writeFileSync(plistPath, plist);
33199
33311
  try {
33200
33312
  execSync3(`launchctl load "${plistPath}"`, { stdio: "inherit" });
33201
33313
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
@@ -33207,7 +33319,7 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33207
33319
  } else {
33208
33320
  const svcName = "engine7";
33209
33321
  const svcDir = path42.join(process.env.HOME, ".config", "systemd", "user");
33210
- fs41.mkdirSync(svcDir, { recursive: true });
33322
+ fs42.mkdirSync(svcDir, { recursive: true });
33211
33323
  const svcPath = path42.join(svcDir, `${svcName}.service`);
33212
33324
  const svc = `[Unit]
33213
33325
  Description=Engine 7 Agent
@@ -33222,7 +33334,7 @@ RestartSec=10
33222
33334
 
33223
33335
  [Install]
33224
33336
  WantedBy=default.target`;
33225
- fs41.writeFileSync(svcPath, svc);
33337
+ fs42.writeFileSync(svcPath, svc);
33226
33338
  try {
33227
33339
  execSync3(`systemctl --user daemon-reload`, { stdio: "inherit" });
33228
33340
  execSync3(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
@@ -33248,8 +33360,8 @@ WantedBy=default.target`;
33248
33360
  execSync3(`schtasks /delete /tn "Engine7" /f`, { stdio: "ignore" });
33249
33361
  } catch {
33250
33362
  }
33251
- if (fs41.existsSync(vbsPath)) {
33252
- fs41.rmSync(vbsPath, { force: true });
33363
+ if (fs42.existsSync(vbsPath)) {
33364
+ fs42.rmSync(vbsPath, { force: true });
33253
33365
  console.log(`\u2705 \u5F00\u673A\u81EA\u542F\u52A8\u5DF2\u79FB\u9664\uFF08${vbsPath}\uFF09`);
33254
33366
  } else {
33255
33367
  console.log("\uFF08\u5F00\u673A\u81EA\u542F\u52A8\u672C\u6765\u5C31\u6CA1\u6CE8\u518C\uFF09");
@@ -33261,7 +33373,7 @@ WantedBy=default.target`;
33261
33373
  } catch {
33262
33374
  }
33263
33375
  try {
33264
- fs41.unlinkSync(plistPath);
33376
+ fs42.unlinkSync(plistPath);
33265
33377
  } catch {
33266
33378
  }
33267
33379
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
@@ -33272,7 +33384,7 @@ WantedBy=default.target`;
33272
33384
  }
33273
33385
  const svcPath = path42.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
33274
33386
  try {
33275
- fs41.unlinkSync(svcPath);
33387
+ fs42.unlinkSync(svcPath);
33276
33388
  } catch {
33277
33389
  }
33278
33390
  try {
@@ -33292,10 +33404,10 @@ WantedBy=default.target`;
33292
33404
  "Startup",
33293
33405
  "Engine7.vbs"
33294
33406
  );
33295
- console.log(fs41.existsSync(vbsPath) ? `\u2705 \u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF09: ${vbsPath}` : "\u274C \u672A\u6CE8\u518C");
33407
+ console.log(fs42.existsSync(vbsPath) ? `\u2705 \u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF09: ${vbsPath}` : "\u274C \u672A\u6CE8\u518C");
33296
33408
  } else if (process.platform === "darwin") {
33297
33409
  const plistPath = path42.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
33298
- if (fs41.existsSync(plistPath)) {
33410
+ if (fs42.existsSync(plistPath)) {
33299
33411
  console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
33300
33412
  } else {
33301
33413
  console.log("\u274C \u672A\u5B89\u88C5");
@@ -33328,8 +33440,8 @@ WantedBy=default.target`;
33328
33440
  console.log(`
33329
33441
  \u{1F680} engine7 init`);
33330
33442
  console.log(` state-dir: ${opts.stateDir}`);
33331
- if (fs41.existsSync(opts.stateDir) && !opts.dryRun) {
33332
- const files = fs41.readdirSync(opts.stateDir);
33443
+ if (fs42.existsSync(opts.stateDir) && !opts.dryRun) {
33444
+ const files = fs42.readdirSync(opts.stateDir);
33333
33445
  if (files.length > 0) {
33334
33446
  if (opts.force) {
33335
33447
  if (looksLikeAppInstall(opts.stateDir)) {
@@ -33342,10 +33454,10 @@ WantedBy=default.target`;
33342
33454
  }
33343
33455
  console.log(`
33344
33456
  \u26A0\uFE0F --force: \u6E05\u7A7A\u5DF2\u6709\u76EE\u5F55 ${opts.stateDir}`);
33345
- fs41.rmSync(opts.stateDir, { recursive: true, force: true });
33457
+ fs42.rmSync(opts.stateDir, { recursive: true, force: true });
33346
33458
  } else {
33347
33459
  const existingConfig = path42.join(opts.stateDir, "configs", "main7.json");
33348
- if (fs41.existsSync(existingConfig)) {
33460
+ if (fs42.existsSync(existingConfig)) {
33349
33461
  console.log(`
33350
33462
  \u267B\uFE0F \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E: ${existingConfig}`);
33351
33463
  console.log(` \u2192 \u590D\u8DD1\u6A21\u5F0F\uFF1A\u663E\u793A\u73B0\u6709\u914D\u7F6E\uFF0C\u56DE\u8F66\u4FDD\u7559\uFF0C\u6539\u4E86\u624D\u751F\u6548\uFF08\u4E0D\u4F1A\u6E05\u7A7A\u76EE\u5F55\uFF09`);
@@ -33431,7 +33543,7 @@ WantedBy=default.target`;
33431
33543
  if (!PHOTO_EXTS.includes(ext)) {
33432
33544
  throw new Error(`\u7167\u7247\u683C\u5F0F\u4E0D\u652F\u6301\uFF1A${ext || "(\u6CA1\u6709\u540E\u7F00)"}\u3002\u8BF7\u7528 PNG / JPEG / WebP\u3002`);
33433
33545
  }
33434
- if (!fs41.existsSync(src)) {
33546
+ if (!fs42.existsSync(src)) {
33435
33547
  throw new Error(`\u7167\u7247\u4E0D\u5B58\u5728\uFF1A${src}`);
33436
33548
  }
33437
33549
  const dims = dimsOf2(src);
@@ -33454,7 +33566,7 @@ WantedBy=default.target`;
33454
33566
  dryRun(tree);
33455
33567
  const skillsSrc = findTemplateDir("skills");
33456
33568
  if (skillsSrc) {
33457
- const skills = fs41.readdirSync(skillsSrc);
33569
+ const skills = fs42.readdirSync(skillsSrc);
33458
33570
  for (const s of skills) {
33459
33571
  console.log(` \u{1F4C1} ${path42.join(opts.stateDir, "workspace", "skills", s)}`);
33460
33572
  }
@@ -33462,14 +33574,14 @@ WantedBy=default.target`;
33462
33574
  } else {
33463
33575
  if (values.chatMode === "auto") {
33464
33576
  try {
33465
- fs41.unlinkSync(path42.join(opts.stateDir, "workspace", ".work-mode"));
33577
+ fs42.unlinkSync(path42.join(opts.stateDir, "workspace", ".work-mode"));
33466
33578
  } catch {
33467
33579
  }
33468
33580
  }
33469
33581
  if (photoSrc && values.selfiePhotoRelPath) {
33470
33582
  const dest = path42.join(opts.stateDir, "workspace", values.selfiePhotoRelPath);
33471
- fs41.mkdirSync(path42.dirname(dest), { recursive: true });
33472
- fs41.copyFileSync(photoSrc, dest);
33583
+ fs42.mkdirSync(path42.dirname(dest), { recursive: true });
33584
+ fs42.copyFileSync(photoSrc, dest);
33473
33585
  console.log(` \u{1F5BC} \u5F62\u8C61: ${dest}`);
33474
33586
  }
33475
33587
  if (headlessEmit) headlessEmit({ event: "progress", step: "create_dirs" });
@@ -33499,8 +33611,8 @@ WantedBy=default.target`;
33499
33611
  const skillsSrc = findTemplateDir("skills");
33500
33612
  if (skillsSrc) {
33501
33613
  const skillsDest = path42.join(opts.stateDir, "workspace", "skills");
33502
- fs41.mkdirSync(skillsDest, { recursive: true });
33503
- const skills = fs41.readdirSync(skillsSrc);
33614
+ fs42.mkdirSync(skillsDest, { recursive: true });
33615
+ const skills = fs42.readdirSync(skillsSrc);
33504
33616
  for (const s of skills) {
33505
33617
  copyDirRecursive(path42.join(skillsSrc, s), path42.join(skillsDest, s));
33506
33618
  console.log(` \u{1F4E6} skill: ${s}`);
@@ -33511,7 +33623,7 @@ WantedBy=default.target`;
33511
33623
  `);
33512
33624
  const homePointer = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
33513
33625
  const pointerData = { stateDir: opts.stateDir };
33514
- fs41.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
33626
+ fs42.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
33515
33627
  console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
33516
33628
  console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
33517
33629
  console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
@@ -33524,14 +33636,14 @@ WantedBy=default.target`;
33524
33636
  }
33525
33637
  }
33526
33638
  function copyDirRecursive(src, dest) {
33527
- fs41.mkdirSync(dest, { recursive: true });
33528
- for (const entry of fs41.readdirSync(src, { withFileTypes: true })) {
33639
+ fs42.mkdirSync(dest, { recursive: true });
33640
+ for (const entry of fs42.readdirSync(src, { withFileTypes: true })) {
33529
33641
  const srcPath = path42.join(src, entry.name);
33530
33642
  const destPath = path42.join(dest, entry.name);
33531
33643
  if (entry.isDirectory()) {
33532
33644
  copyDirRecursive(srcPath, destPath);
33533
33645
  } else {
33534
- fs41.copyFileSync(srcPath, destPath);
33646
+ fs42.copyFileSync(srcPath, destPath);
33535
33647
  }
33536
33648
  }
33537
33649
  }
@@ -33542,14 +33654,14 @@ function findTemplateDir(name) {
33542
33654
  path42.join(process.cwd(), "templates", name)
33543
33655
  ];
33544
33656
  for (const p of candidates) {
33545
- if (fs41.existsSync(p)) return p;
33657
+ if (fs42.existsSync(p)) return p;
33546
33658
  }
33547
33659
  return null;
33548
33660
  }
33549
33661
  function readHomePointer() {
33550
33662
  const ptrPath = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
33551
33663
  try {
33552
- return JSON.parse(fs41.readFileSync(ptrPath, "utf-8"));
33664
+ return JSON.parse(fs42.readFileSync(ptrPath, "utf-8"));
33553
33665
  } catch {
33554
33666
  return null;
33555
33667
  }