engine7 7.1.118 → 7.1.120

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
@@ -395,6 +395,17 @@ var init_live = __esm({
395
395
  Object.assign(this.current, newConfig);
396
396
  }
397
397
  /** 改活树上的值;文件承载路径同步持久化(read-modify-write 回 config 文件) */
398
+ /**
399
+ * 改活树 + 落盘。
400
+ *
401
+ * 返回值 = **落盘**是否成功(活树无论成败都已同步——它是先改的)。绝大多数调用点照旧
402
+ * `void liveConfig.set(...)` 不理它;但**要打成功日志的调用点必须 await 这个布尔值**。
403
+ *
404
+ * 为什么把这个信号交出去(1001 审查捞回):本方法本来是 fire-and-forget,落盘失败只在
405
+ * `persistToFile` 里 warn 一行;而启动早段的调用点(两个免费档 fixup)紧接着打了句
406
+ * "免费档补齐 xxx" 的成功日志 ⇒ 配置**没写进文件**却被读成"写好了":进程内生效、托盘
407
+ * 读文件还是旧值、下次启动重放同一句——正是本仓最恨的假信号。
408
+ */
398
409
  async set(dotPath, val) {
399
410
  if (!this.current) throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
400
411
  const keys = dotPath.split(".");
@@ -404,18 +415,18 @@ var init_live = __esm({
404
415
  obj = obj[keys[i]];
405
416
  }
406
417
  obj[keys[keys.length - 1]] = val;
407
- await this.persistToFile(dotPath, val);
418
+ return this.persistToFile(dotPath, val);
408
419
  }
409
- /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
420
+ /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效)。返回是否真的落盘。 */
410
421
  async persistToFile(dotPath, val) {
411
- const fs43 = await import("node:fs");
422
+ const fs44 = await import("node:fs");
412
423
  const cfgPath = this.current?._configFilePath;
413
- if (!cfgPath || !fs43.existsSync(cfgPath)) {
424
+ if (!cfgPath || !fs44.existsSync(cfgPath)) {
414
425
  console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
415
- return;
426
+ return false;
416
427
  }
417
428
  try {
418
- const raw = JSON.parse(fs43.readFileSync(cfgPath, "utf-8"));
429
+ const raw = JSON.parse(fs44.readFileSync(cfgPath, "utf-8"));
419
430
  const keys = dotPath.split(".");
420
431
  let o = raw;
421
432
  for (let i = 0; i < keys.length - 1; i++) {
@@ -423,11 +434,13 @@ var init_live = __esm({
423
434
  o = o[keys[i]];
424
435
  }
425
436
  o[keys[keys.length - 1]] = val;
426
- fs43.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
437
+ fs44.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
427
438
  console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
428
439
  markSelfWrite();
440
+ return true;
429
441
  } catch (e) {
430
442
  console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
443
+ return false;
431
444
  }
432
445
  }
433
446
  /** 是否已初始化 */
@@ -714,8 +727,8 @@ function listSchemaFields() {
714
727
  if (process.env.ENGINE7_INTERNAL === "1") return FIELDS.slice();
715
728
  return FIELDS.filter((f) => !f.internal);
716
729
  }
717
- function getField(path43) {
718
- return FIELDS.find((f) => f.path === path43);
730
+ function getField(path44) {
731
+ return FIELDS.find((f) => f.path === path44);
719
732
  }
720
733
  function pick(obj, dotPath) {
721
734
  let cur = obj;
@@ -1549,6 +1562,16 @@ function secretRef(envKey, value) {
1549
1562
  function isFreeTier(v) {
1550
1563
  return v.freeTier === true || v.primaryProvider === "7yi";
1551
1564
  }
1565
+ function freeTierVoiceConfig(existing) {
1566
+ const mv = existing && typeof existing === "object" ? existing : {};
1567
+ return {
1568
+ ...mv,
1569
+ provider: "relay",
1570
+ relayProviderId: FREE_TIER_PROVIDER_ID,
1571
+ relayModel: "engine7-tts",
1572
+ voice: mv.voice || DEFAULT_FREE_VOICE
1573
+ };
1574
+ }
1552
1575
  function resolveRelayUrl(relayArg, env = process.env) {
1553
1576
  return (relayArg || "").trim() || (env.E7_RELAY_URL || "").trim() || FREE_TIER_RELAY_URL;
1554
1577
  }
@@ -1612,9 +1635,21 @@ function generateConfig(v) {
1612
1635
  },
1613
1636
  // 0917:my_eyes(看图工具)读的是 tools.my_eyes.model,不是 tools.vision——
1614
1637
  // 后者是模板里遗留的死键(全仓零读者),已删。visionModel 解析不出就不写这个块。
1638
+ //
1639
+ // 1001 发语音条(§7.4):免费档必须把这块写全。此前唯一会写 `tools.my_voice` 的是
1640
+ // `applyFreeTier`,而它只从「切换到免费档」那张卡触发——配置已经是免费档时卡片不显示
1641
+ // ⇒ **新装机永远没有这块**:托盘「合成引擎」显示 edge-tts(面板在 provider 缺失时
1642
+ // 默认选它),引擎 `pickProvider` 也落 edge,而 edge 要本机 Python + `edge_tts`
1643
+ // (安装包一个都不带)⇒ 用户第一次说"发条语音"就报错。郭叔 1001 装机实测撞到。
1644
+ // 形状走 `freeTierVoiceConfig()`(唯一源,与 applyFreeTier / 启动补齐同一份)。
1615
1645
  tools: {
1616
1646
  ...v.tavilyKey ? { tavily: { apiKey: v.tavilyKey } } : {},
1617
1647
  ...v.visionModel ? { my_eyes: { model: v.visionModel } } : {},
1648
+ // ⚠️ 判据是 **provider 真的是 7yi**,不是 `isFreeTier(v)`:后者会因 `freeTier:true`
1649
+ // 单独为真(answers 手写坏组合时),而那种 config 里**根本没有 7yi provider 块**,
1650
+ // 写进去就是个悬空引用(第一次发语音报"免费池未配置",把用户指向错误的排查方向)。
1651
+ // 与下面 vision/video 的收口闸同一条纪律:**引用必须落在本次真实写出的 provider 里**。
1652
+ ...v.primaryProvider === FREE_TIER_PROVIDER_ID ? { my_voice: freeTierVoiceConfig() } : {},
1618
1653
  // 自拍(§4.3):免费档必须显式写 provider:'relay'。不写的话 getProvider()
1619
1654
  // 会落回默认值 'fal',而免费装机没有 fal key——第一次自拍就失败。
1620
1655
  // 非免费档只在用户真给了形象时才写这个块,且不替他决定 provider。
@@ -1837,13 +1872,15 @@ function generateConfig(v) {
1837
1872
  }
1838
1873
  return config;
1839
1874
  }
1840
- var SCHEMA_VERSION, FREE_TIER_RELAY_URL, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
1875
+ var SCHEMA_VERSION, FREE_TIER_RELAY_URL, FREE_TIER_PROVIDER_ID, DEFAULT_FREE_VOICE, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
1841
1876
  var init_cli_init_config = __esm({
1842
1877
  "src/cli-init-config.ts"() {
1843
1878
  "use strict";
1844
1879
  init_registry();
1845
1880
  SCHEMA_VERSION = 1;
1846
1881
  FREE_TIER_RELAY_URL = "https://www.twinsun.top:8866";
1882
+ FREE_TIER_PROVIDER_ID = "7yi";
1883
+ DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
1847
1884
  DEFAULT_PRIMARY_MODEL = {
1848
1885
  dashscope: "dashscope/qwen3.8-max",
1849
1886
  minimax: "minimax/MiniMax-M3",
@@ -2073,6 +2110,19 @@ function resolveConfigIdentity(configPath) {
2073
2110
  const stateDir = basename2(cfgDir) === "configs" ? dirname2(cfgDir) : cfgDir;
2074
2111
  return { stateDir, configName: cfgName };
2075
2112
  }
2113
+ function engineStateDirOfConfig(configPath, env = process.env) {
2114
+ let raw;
2115
+ try {
2116
+ raw = JSON.parse(readFileSync3(configPath, "utf-8"));
2117
+ } catch {
2118
+ return null;
2119
+ }
2120
+ if (typeof raw?.stateDir === "string" && raw.stateDir.trim()) return raw.stateDir.trim();
2121
+ const fromEnv = env.ENGINE_STATE_DIR;
2122
+ if (fromEnv && fromEnv.trim()) return fromEnv.trim();
2123
+ if (basename2(dirname2(configPath)) !== "configs") return null;
2124
+ return resolveConfigIdentity(configPath).stateDir;
2125
+ }
2076
2126
  function writeSecretsValue(configPath, envKey, value) {
2077
2127
  const { stateDir, configName } = resolveConfigIdentity(configPath);
2078
2128
  const dir = join3(secretsHome(), ".engine7-secrets");
@@ -2191,8 +2241,8 @@ __export(loader_exports, {
2191
2241
  resolveTimezone: () => resolveTimezone,
2192
2242
  takeLoadWarnings: () => takeLoadWarnings
2193
2243
  });
2194
- import * as fs3 from "node:fs";
2195
- import * as path3 from "node:path";
2244
+ import * as fs4 from "node:fs";
2245
+ import * as path4 from "node:path";
2196
2246
  function parseModelRef(ref) {
2197
2247
  const idx = ref.indexOf("/");
2198
2248
  if (idx <= 0 || idx === ref.length - 1) {
@@ -2232,13 +2282,13 @@ function isUnresolvedEnvRef(value) {
2232
2282
  return typeof value === "string" && ENV_REF_RE.test(value);
2233
2283
  }
2234
2284
  function loadConfig(configPath) {
2235
- const resolvedPath = path3.resolve(
2285
+ const resolvedPath = path4.resolve(
2236
2286
  configPath || process.env.ENGINE_CONFIG || "engine-config.json"
2237
2287
  );
2238
- if (!fs3.existsSync(resolvedPath)) {
2288
+ if (!fs4.existsSync(resolvedPath)) {
2239
2289
  throw new Error(`Config file not found: ${resolvedPath}`);
2240
2290
  }
2241
- const raw = JSON.parse(fs3.readFileSync(resolvedPath, "utf-8"));
2291
+ const raw = JSON.parse(fs4.readFileSync(resolvedPath, "utf-8"));
2242
2292
  const missingEnvKeys = /* @__PURE__ */ new Set();
2243
2293
  const resolveEnv = (node) => {
2244
2294
  if (typeof node === "string") {
@@ -2341,9 +2391,9 @@ function loadConfig(configPath) {
2341
2391
  }
2342
2392
  }
2343
2393
  }
2344
- const stateDir = raw.stateDir || process.env.ENGINE_STATE_DIR || path3.resolve(".engine");
2345
- const workspace = process.env.ENGINE_WORKSPACE || agentDefaults.workspace || path3.join(stateDir, "workspace");
2346
- const mediaDir = raw.mediaDir || path3.join(stateDir, "media", "inbound");
2394
+ const stateDir = raw.stateDir || process.env.ENGINE_STATE_DIR || path4.resolve(".engine");
2395
+ const workspace = process.env.ENGINE_WORKSPACE || agentDefaults.workspace || path4.join(stateDir, "workspace");
2396
+ const mediaDir = raw.mediaDir || path4.join(stateDir, "media", "inbound");
2347
2397
  if (!agentDefaults.features) agentDefaults.features = {};
2348
2398
  for (const [k, v] of Object.entries(FEATURE_DEFAULTS)) {
2349
2399
  if (agentDefaults.features[k] === void 0) {
@@ -2615,17 +2665,17 @@ var init_registry2 = __esm({
2615
2665
  });
2616
2666
 
2617
2667
  // src/calendar/db.ts
2618
- import * as path4 from "node:path";
2619
- import * as fs4 from "node:fs";
2668
+ import * as path5 from "node:path";
2669
+ import * as fs5 from "node:fs";
2620
2670
  import { createRequire as createRequire2 } from "node:module";
2621
2671
  function getSqlite() {
2622
2672
  if (!_sqlite) _sqlite = createRequire2(import.meta.url)("node:sqlite");
2623
2673
  return _sqlite;
2624
2674
  }
2625
2675
  function openDb(workspace) {
2626
- const dir = path4.join(workspace, ".calendar");
2627
- fs4.mkdirSync(dir, { recursive: true });
2628
- const dbPath = path4.join(dir, "calendar.db");
2676
+ const dir = path5.join(workspace, ".calendar");
2677
+ fs5.mkdirSync(dir, { recursive: true });
2678
+ const dbPath = path5.join(dir, "calendar.db");
2629
2679
  const db2 = new DatabaseSync(dbPath);
2630
2680
  db2.exec("PRAGMA journal_mode=WAL");
2631
2681
  db2.exec(`CREATE TABLE IF NOT EXISTS events (
@@ -2699,14 +2749,14 @@ var init_db = __esm({
2699
2749
  });
2700
2750
 
2701
2751
  // src/goals/store.ts
2702
- import fs5 from "node:fs";
2703
- import path5 from "node:path";
2752
+ import fs6 from "node:fs";
2753
+ import path6 from "node:path";
2704
2754
  import crypto from "node:crypto";
2705
2755
  function file(stateDir) {
2706
- return path5.join(stateDir, "goals.json");
2756
+ return path6.join(stateDir, "goals.json");
2707
2757
  }
2708
2758
  function eventFile(stateDir) {
2709
- return path5.join(stateDir, "goal-events.jsonl");
2759
+ return path6.join(stateDir, "goal-events.jsonl");
2710
2760
  }
2711
2761
  function db(stateDir) {
2712
2762
  const d = openDb(stateDir);
@@ -2723,17 +2773,17 @@ function db(stateDir) {
2723
2773
  return d;
2724
2774
  }
2725
2775
  function event(stateDir, goalId, type2, payload = {}) {
2726
- fs5.mkdirSync(stateDir, { recursive: true });
2776
+ fs6.mkdirSync(stateDir, { recursive: true });
2727
2777
  const id = `ge-${Date.now()}-${crypto.randomBytes(3).toString("hex")}`;
2728
2778
  const at = (/* @__PURE__ */ new Date()).toISOString();
2729
- fs5.appendFileSync(eventFile(stateDir), JSON.stringify({ eventId: id, goalId, type: type2, at, ...payload }) + "\n", "utf8");
2779
+ fs6.appendFileSync(eventFile(stateDir), JSON.stringify({ eventId: id, goalId, type: type2, at, ...payload }) + "\n", "utf8");
2730
2780
  const d = db(stateDir);
2731
2781
  d.prepare("INSERT INTO goal_events (event_id, goal_id, type, payload_json, created_at) VALUES (?, ?, ?, ?, ?)").run(id, goalId, type2, JSON.stringify(payload), at);
2732
2782
  d.close?.();
2733
2783
  }
2734
2784
  function read(stateDir) {
2735
2785
  try {
2736
- const v = JSON.parse(fs5.readFileSync(file(stateDir), "utf8"));
2786
+ const v = JSON.parse(fs6.readFileSync(file(stateDir), "utf8"));
2737
2787
  return Array.isArray(v) ? v : [];
2738
2788
  } catch {
2739
2789
  return [];
@@ -2756,7 +2806,7 @@ function listGoals(stateDir) {
2756
2806
  }
2757
2807
  function listGoalEvents(stateDir) {
2758
2808
  try {
2759
- return fs5.readFileSync(eventFile(stateDir), "utf8").split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
2809
+ return fs6.readFileSync(eventFile(stateDir), "utf8").split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
2760
2810
  } catch {
2761
2811
  return [];
2762
2812
  }
@@ -2826,9 +2876,9 @@ function isAutoMemPath(absolutePath, workspace) {
2826
2876
  return normalizedPath.startsWith(getAutoMemPath(workspace));
2827
2877
  }
2828
2878
  async function ensureMemoryDirExists(memoryDir) {
2829
- const fs43 = await import("node:fs");
2879
+ const fs44 = await import("node:fs");
2830
2880
  try {
2831
- await fs43.promises.mkdir(memoryDir, { recursive: true });
2881
+ await fs44.promises.mkdir(memoryDir, { recursive: true });
2832
2882
  } catch (e) {
2833
2883
  const code = e?.code;
2834
2884
  if (code !== "EEXIST") {
@@ -3159,13 +3209,13 @@ __export(prompt_exports, {
3159
3209
  buildSystemPrompt: () => buildSystemPrompt,
3160
3210
  buildVolatileRuntimeContext: () => buildVolatileRuntimeContext
3161
3211
  });
3162
- import * as path6 from "node:path";
3163
- import * as fs6 from "node:fs";
3212
+ import * as path7 from "node:path";
3213
+ import * as fs7 from "node:fs";
3164
3214
  import * as os2 from "node:os";
3165
3215
  function readFileIfExists(filePath) {
3166
3216
  try {
3167
- if (fs6.existsSync(filePath)) {
3168
- return fs6.readFileSync(filePath, "utf-8");
3217
+ if (fs7.existsSync(filePath)) {
3218
+ return fs7.readFileSync(filePath, "utf-8");
3169
3219
  }
3170
3220
  } catch {
3171
3221
  }
@@ -3324,7 +3374,7 @@ function loadStaticFiles(workspace, staticFiles) {
3324
3374
  if (!staticFiles || staticFiles.length === 0) return null;
3325
3375
  const parts = [];
3326
3376
  for (const file2 of staticFiles) {
3327
- const filePath = path6.isAbsolute(file2) ? file2 : path6.join(workspace, file2);
3377
+ const filePath = path7.isAbsolute(file2) ? file2 : path7.join(workspace, file2);
3328
3378
  const content = readFileIfExists(filePath);
3329
3379
  if (content) parts.push(content);
3330
3380
  }
@@ -3343,7 +3393,7 @@ function loadMemoryInstructions(workspace) {
3343
3393
  }
3344
3394
  }
3345
3395
  function resolveBlockContent(block, ctx) {
3346
- const overridePath = path6.join(ctx.workspace, "prompts", `${block.name}.md`);
3396
+ const overridePath = path7.join(ctx.workspace, "prompts", `${block.name}.md`);
3347
3397
  const override = readFileIfExists(overridePath);
3348
3398
  if (override) return override;
3349
3399
  return block.generate(ctx);
@@ -3392,7 +3442,7 @@ function buildCustomPrompt(workspace, config) {
3392
3442
  continue;
3393
3443
  }
3394
3444
  if (name.endsWith(".md")) {
3395
- const filePath = path6.isAbsolute(name) ? name : path6.join(workspace, name);
3445
+ const filePath = path7.isAbsolute(name) ? name : path7.join(workspace, name);
3396
3446
  const content = readFileIfExists(filePath);
3397
3447
  if (content) {
3398
3448
  parts.push(content);
@@ -3508,7 +3558,7 @@ var init_prompt = __esm({
3508
3558
  { name: "tone-style", description: "\u8BED\u6C14\u98CE\u683C\uFF08\u7B80\u6D01\u3001\u4E0D\u7528emoji\uFF09", generate: (_) => getToneAndStyleSection() },
3509
3559
  { name: "output-efficiency", description: "\u8F93\u51FA\u6548\u7387\uFF08\u76F4\u5954\u4E3B\u9898\uFF09", generate: (_) => getOutputEfficiencySection() },
3510
3560
  // OpenClaw 叠加层
3511
- { name: "soul", description: "SOUL.md \u4EBA\u683C\u8EAB\u4EFD", generate: (ctx) => readFileIfExists(path6.join(ctx.workspace, "SOUL.md")) },
3561
+ { name: "soul", description: "SOUL.md \u4EBA\u683C\u8EAB\u4EFD", generate: (ctx) => readFileIfExists(path7.join(ctx.workspace, "SOUL.md")) },
3512
3562
  { name: "static-files", description: "\u914D\u7F6E\u6587\u4EF6\u6307\u5B9A\u7684\u989D\u5916\u6587\u4EF6\uFF08AGENTS/USER/MEMORY\u7B49\uFF09", generate: (ctx) => loadStaticFiles(ctx.workspace, ctx.staticFiles) },
3513
3563
  { name: "auto-memory-instructions", description: "auto memory \u5B8C\u6574\u6307\u4EE4\uFF08\u5B58+\u8BFB+recall\u8BF4\u660E\uFF09", generate: (ctx) => loadMemoryInstructions(ctx.workspace) },
3514
3564
  // Boundary(永远在最后)
@@ -6462,8 +6512,8 @@ var init_attachments = __esm({
6462
6512
  });
6463
6513
 
6464
6514
  // src/utils/context-dump.ts
6465
- import * as fs7 from "node:fs";
6466
- import * as path7 from "node:path";
6515
+ import * as fs8 from "node:fs";
6516
+ import * as path8 from "node:path";
6467
6517
  function dumpApiRequest(opts) {
6468
6518
  const lines = [
6469
6519
  "=== API Request Debug\uFF08\u53D1\u7ED9 LLM \u7684\u6700\u7EC8\u8BF7\u6C42\u4F53\uFF0C\u6BCF\u6B21\u8986\u76D6\u5199\uFF09===",
@@ -6496,7 +6546,7 @@ function dumpApiRequest(opts) {
6496
6546
  lines.push(`[${i}] ${m.role}: (empty)`);
6497
6547
  }
6498
6548
  }
6499
- fs7.writeFileSync(path7.join(opts.workspace, ".context-debug.txt"), lines.join("\n") + "\n", "utf-8");
6549
+ fs8.writeFileSync(path8.join(opts.workspace, ".context-debug.txt"), lines.join("\n") + "\n", "utf-8");
6500
6550
  }
6501
6551
  var init_context_dump = __esm({
6502
6552
  "src/utils/context-dump.ts"() {
@@ -7556,7 +7606,7 @@ var init_contextOverflow = __esm({
7556
7606
  });
7557
7607
 
7558
7608
  // src/utils/path.ts
7559
- import * as path8 from "node:path";
7609
+ import * as path9 from "node:path";
7560
7610
  function fixMsysPath(p) {
7561
7611
  let fixed = p.includes("\\") ? p.replace(/\\/g, "/") : p;
7562
7612
  if (process.platform === "win32") {
@@ -7566,15 +7616,15 @@ function fixMsysPath(p) {
7566
7616
  }
7567
7617
  function resolvePath(p, workspace) {
7568
7618
  const fixed = fixMsysPath(p);
7569
- const resolved = path8.isAbsolute(fixed) ? path8.normalize(fixed) : path8.resolve(workspace, fixed);
7570
- const normalized = path8.normalize(resolved);
7571
- const normalizedWorkspace = path8.normalize(workspace);
7619
+ const resolved = path9.isAbsolute(fixed) ? path9.normalize(fixed) : path9.resolve(workspace, fixed);
7620
+ const normalized = path9.normalize(resolved);
7621
+ const normalizedWorkspace = path9.normalize(workspace);
7572
7622
  if (sandboxOff) return normalized;
7573
- if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path8.sep)) {
7623
+ if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path9.sep)) {
7574
7624
  return normalized;
7575
7625
  }
7576
7626
  for (const allowed of extraAllowedPaths) {
7577
- if (normalized === allowed || normalized.startsWith(allowed + path8.sep)) {
7627
+ if (normalized === allowed || normalized.startsWith(allowed + path9.sep)) {
7578
7628
  return normalized;
7579
7629
  }
7580
7630
  }
@@ -7809,9 +7859,9 @@ __export(BashTool_exports, {
7809
7859
  findShell: () => findShell,
7810
7860
  killChild: () => killChild
7811
7861
  });
7812
- import { spawn as spawn2, execSync } from "node:child_process";
7813
- import * as fs8 from "node:fs";
7814
- import * as path9 from "node:path";
7862
+ import { spawn as spawn2, execSync as execSync2 } from "node:child_process";
7863
+ import * as fs9 from "node:fs";
7864
+ import * as path10 from "node:path";
7815
7865
  function isWslBash(p) {
7816
7866
  const normalized = p.replace(/\//g, "\\").toLowerCase();
7817
7867
  return WSL_PATH_MARKERS.some((m) => normalized.includes(m.toLowerCase()));
@@ -7823,14 +7873,14 @@ function findShell() {
7823
7873
  return cachedShell;
7824
7874
  }
7825
7875
  try {
7826
- const result = execSync("where.exe bash", {
7876
+ const result = execSync2("where.exe bash", {
7827
7877
  encoding: "utf-8",
7828
7878
  timeout: 5e3,
7829
7879
  stdio: ["ignore", "pipe", "ignore"]
7830
7880
  });
7831
7881
  const candidates = result.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
7832
7882
  const nonWsl = candidates.find((p) => !isWslBash(p));
7833
- if (nonWsl && fs8.existsSync(nonWsl)) {
7883
+ if (nonWsl && fs9.existsSync(nonWsl)) {
7834
7884
  cachedShell = { shell: nonWsl, args: ["-c"] };
7835
7885
  return cachedShell;
7836
7886
  }
@@ -7840,10 +7890,10 @@ function findShell() {
7840
7890
  "C:\\Program Files\\Git\\bin\\bash.exe",
7841
7891
  "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
7842
7892
  "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
7843
- path9.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
7893
+ path10.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
7844
7894
  ];
7845
7895
  for (const p of knownPaths) {
7846
- if (p && fs8.existsSync(p)) {
7896
+ if (p && fs9.existsSync(p)) {
7847
7897
  cachedShell = { shell: p, args: ["-c"] };
7848
7898
  return cachedShell;
7849
7899
  }
@@ -7946,8 +7996,8 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
7946
7996
  }
7947
7997
  const MAX_OUTPUT = 100 * 1024;
7948
7998
  const osMod = await import("node:os");
7949
- const outputFile = path9.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
7950
- const outputHandle = await fs8.promises.open(outputFile, "w");
7999
+ const outputFile = path10.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
8000
+ const outputHandle = await fs9.promises.open(outputFile, "w");
7951
8001
  return new Promise((resolve12) => {
7952
8002
  const { shell, args: shellArgs } = findShell();
7953
8003
  const child = spawn2(shell, [...shellArgs, command], {
@@ -7966,21 +8016,21 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
7966
8016
  let fileOutput = "";
7967
8017
  let truncated = false;
7968
8018
  try {
7969
- const st = await fs8.promises.stat(outputFile);
8019
+ const st = await fs9.promises.stat(outputFile);
7970
8020
  if (st.size > MAX_OUTPUT) {
7971
- const rfd = await fs8.promises.open(outputFile, "r");
8021
+ const rfd = await fs9.promises.open(outputFile, "r");
7972
8022
  const buf = Buffer.alloc(MAX_OUTPUT);
7973
8023
  await rfd.read(buf, 0, MAX_OUTPUT, 0);
7974
8024
  await rfd.close();
7975
8025
  fileOutput = buf.toString("utf-8");
7976
8026
  truncated = true;
7977
8027
  } else {
7978
- fileOutput = await fs8.promises.readFile(outputFile, "utf-8");
8028
+ fileOutput = await fs9.promises.readFile(outputFile, "utf-8");
7979
8029
  }
7980
8030
  } catch {
7981
8031
  }
7982
8032
  try {
7983
- await fs8.promises.unlink(outputFile);
8033
+ await fs9.promises.unlink(outputFile);
7984
8034
  } catch {
7985
8035
  }
7986
8036
  const processedStdout = fileOutput.replace(/^(\s*\n)+/, "").trimEnd();
@@ -8057,8 +8107,8 @@ __export(task_manager_exports, {
8057
8107
  });
8058
8108
  import { randomBytes } from "node:crypto";
8059
8109
  import { spawn as spawn3 } from "node:child_process";
8060
- import * as fs9 from "node:fs";
8061
- import * as path10 from "node:path";
8110
+ import * as fs10 from "node:fs";
8111
+ import * as path11 from "node:path";
8062
8112
  function generateTaskId(type2 = "local_bash") {
8063
8113
  const prefix = TASK_ID_PREFIXES[type2] ?? "x";
8064
8114
  const bytes = randomBytes(8);
@@ -8071,42 +8121,42 @@ function generateTaskId(type2 = "local_bash") {
8071
8121
  function getTaskOutputDir() {
8072
8122
  if (_taskOutputDir === void 0) {
8073
8123
  const stateDir = process.env.ENGINE_STATE_DIR || process.cwd();
8074
- _taskOutputDir = path10.join(stateDir, "tasks");
8124
+ _taskOutputDir = path11.join(stateDir, "tasks");
8075
8125
  }
8076
8126
  return _taskOutputDir;
8077
8127
  }
8078
8128
  function getTaskOutputPath(taskId) {
8079
- return path10.join(getTaskOutputDir(), `${taskId}.output`);
8129
+ return path11.join(getTaskOutputDir(), `${taskId}.output`);
8080
8130
  }
8081
8131
  function ensureOutputDir() {
8082
8132
  const dir = getTaskOutputDir();
8083
- if (!fs9.existsSync(dir)) {
8084
- fs9.mkdirSync(dir, { recursive: true });
8133
+ if (!fs10.existsSync(dir)) {
8134
+ fs10.mkdirSync(dir, { recursive: true });
8085
8135
  }
8086
8136
  }
8087
8137
  function initTaskOutput(taskId) {
8088
8138
  ensureOutputDir();
8089
8139
  const outputPath = getTaskOutputPath(taskId);
8090
- fs9.writeFileSync(outputPath, "", "utf-8");
8140
+ fs10.writeFileSync(outputPath, "", "utf-8");
8091
8141
  return outputPath;
8092
8142
  }
8093
8143
  function persistTask(state2) {
8094
8144
  try {
8095
8145
  ensureOutputDir();
8096
8146
  const p = taskIndexPath();
8097
- const existing = fs9.existsSync(p) ? JSON.parse(fs9.readFileSync(p, "utf8")) : [];
8147
+ const existing = fs10.existsSync(p) ? JSON.parse(fs10.readFileSync(p, "utf8")) : [];
8098
8148
  const next = existing.filter((t) => t.id !== state2.id);
8099
8149
  next.push({ ...state2 });
8100
8150
  const tmp = `${p}.${process.pid}.tmp`;
8101
- fs9.writeFileSync(tmp, JSON.stringify(next, null, 2));
8102
- fs9.renameSync(tmp, p);
8151
+ fs10.writeFileSync(tmp, JSON.stringify(next, null, 2));
8152
+ fs10.renameSync(tmp, p);
8103
8153
  } catch (err) {
8104
8154
  console.warn(`[task-manager] persist failed: ${err.message}`);
8105
8155
  }
8106
8156
  }
8107
8157
  function loadPersistedTasks() {
8108
8158
  try {
8109
- const v = JSON.parse(fs9.readFileSync(taskIndexPath(), "utf8"));
8159
+ const v = JSON.parse(fs10.readFileSync(taskIndexPath(), "utf8"));
8110
8160
  return Array.isArray(v) ? v : [];
8111
8161
  } catch {
8112
8162
  return [];
@@ -8116,7 +8166,7 @@ function loadNotificationQueue() {
8116
8166
  if (notificationsLoaded) return;
8117
8167
  notificationsLoaded = true;
8118
8168
  try {
8119
- const value = JSON.parse(fs9.readFileSync(notificationQueuePath(), "utf8"));
8169
+ const value = JSON.parse(fs10.readFileSync(notificationQueuePath(), "utf8"));
8120
8170
  if (Array.isArray(value)) pendingNotifications.push(...value.filter((x) => x && typeof x.notification === "string"));
8121
8171
  } catch {
8122
8172
  }
@@ -8126,8 +8176,8 @@ function persistNotificationQueue() {
8126
8176
  ensureOutputDir();
8127
8177
  const p = notificationQueuePath();
8128
8178
  const tmp = `${p}.${process.pid}.tmp`;
8129
- fs9.writeFileSync(tmp, JSON.stringify(pendingNotifications, null, 2), "utf8");
8130
- fs9.renameSync(tmp, p);
8179
+ fs10.writeFileSync(tmp, JSON.stringify(pendingNotifications, null, 2), "utf8");
8180
+ fs10.renameSync(tmp, p);
8131
8181
  } catch (err) {
8132
8182
  console.warn(`[task-manager] notification persist failed: ${err.message}`);
8133
8183
  }
@@ -8264,14 +8314,14 @@ function spawnBackgroundTask(opts) {
8264
8314
  const taskId = generateTaskId("local_bash");
8265
8315
  const outputPath = initTaskOutput(taskId);
8266
8316
  const { shell, args: shellArgs } = findShell();
8267
- const outputFd = fs9.openSync(outputPath, "w");
8317
+ const outputFd = fs10.openSync(outputPath, "w");
8268
8318
  const child = spawn3(shell, [...shellArgs, opts.command], {
8269
8319
  cwd: opts.cwd,
8270
8320
  env: opts.env || process.env,
8271
8321
  stdio: ["ignore", outputFd, outputFd]
8272
8322
  });
8273
8323
  try {
8274
- fs9.closeSync(outputFd);
8324
+ fs10.closeSync(outputFd);
8275
8325
  } catch {
8276
8326
  }
8277
8327
  processes.set(taskId, child);
@@ -8303,12 +8353,12 @@ function spawnBackgroundTask(opts) {
8303
8353
  let killedForSize = false;
8304
8354
  sizeWatchdog = setInterval(() => {
8305
8355
  if (tasks.get(taskId)?.status !== "running") return;
8306
- fs9.stat(outputPath, (err, st) => {
8356
+ fs10.stat(outputPath, (err, st) => {
8307
8357
  if (err || st.size <= MAX_TASK_OUTPUT_BYTES) return;
8308
8358
  killedForSize = true;
8309
8359
  if (sizeWatchdog) clearInterval(sizeWatchdog);
8310
8360
  try {
8311
- fs9.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
8361
+ fs10.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
8312
8362
  } catch {
8313
8363
  }
8314
8364
  killChild(child);
@@ -8438,16 +8488,16 @@ function getTaskOutput(taskId, maxBytes = 8 * 1024 * 1024) {
8438
8488
  if (!state2) return "";
8439
8489
  try {
8440
8490
  const outputPath = state2.outputFile;
8441
- if (!fs9.existsSync(outputPath)) return "";
8442
- const stat4 = fs9.statSync(outputPath);
8491
+ if (!fs10.existsSync(outputPath)) return "";
8492
+ const stat4 = fs10.statSync(outputPath);
8443
8493
  if (stat4.size <= maxBytes) {
8444
- return fs9.readFileSync(outputPath, "utf-8");
8494
+ return fs10.readFileSync(outputPath, "utf-8");
8445
8495
  }
8446
- const fd = fs9.openSync(outputPath, "r");
8496
+ const fd = fs10.openSync(outputPath, "r");
8447
8497
  const start = stat4.size - maxBytes;
8448
8498
  const buf = Buffer.alloc(maxBytes);
8449
- fs9.readSync(fd, buf, 0, maxBytes, start);
8450
- fs9.closeSync(fd);
8499
+ fs10.readSync(fd, buf, 0, maxBytes, start);
8500
+ fs10.closeSync(fd);
8451
8501
  const content = buf.toString("utf-8");
8452
8502
  const omitted = Math.round((stat4.size - maxBytes) / 1024);
8453
8503
  return `[${omitted}KB of earlier output omitted]
@@ -8461,14 +8511,14 @@ function getTaskOutputDelta(taskId, fromOffset, maxBytes = 8 * 1024 * 1024) {
8461
8511
  if (!state2) return { content: "", newOffset: fromOffset };
8462
8512
  try {
8463
8513
  const outputPath = state2.outputFile;
8464
- if (!fs9.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
8465
- const stat4 = fs9.statSync(outputPath);
8514
+ if (!fs10.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
8515
+ const stat4 = fs10.statSync(outputPath);
8466
8516
  if (fromOffset >= stat4.size) return { content: "", newOffset: stat4.size };
8467
8517
  const readLen = Math.min(maxBytes, stat4.size - fromOffset);
8468
8518
  const buf = Buffer.alloc(readLen);
8469
- const fd = fs9.openSync(outputPath, "r");
8470
- fs9.readSync(fd, buf, 0, readLen, fromOffset);
8471
- fs9.closeSync(fd);
8519
+ const fd = fs10.openSync(outputPath, "r");
8520
+ fs10.readSync(fd, buf, 0, readLen, fromOffset);
8521
+ fs10.closeSync(fd);
8472
8522
  return { content: buf.toString("utf-8"), newOffset: fromOffset + readLen };
8473
8523
  } catch {
8474
8524
  return { content: "", newOffset: fromOffset };
@@ -8478,8 +8528,8 @@ function getTaskOutputSize(taskId) {
8478
8528
  const state2 = tasks.get(taskId);
8479
8529
  if (!state2) return 0;
8480
8530
  try {
8481
- if (!fs9.existsSync(state2.outputFile)) return 0;
8482
- return fs9.statSync(state2.outputFile).size;
8531
+ if (!fs10.existsSync(state2.outputFile)) return 0;
8532
+ return fs10.statSync(state2.outputFile).size;
8483
8533
  } catch {
8484
8534
  return 0;
8485
8535
  }
@@ -8517,10 +8567,10 @@ var init_task_manager = __esm({
8517
8567
  MAX_TASK_OUTPUT_BYTES = 5 * 1024 * 1024 * 1024;
8518
8568
  tasks = /* @__PURE__ */ new Map();
8519
8569
  processes = /* @__PURE__ */ new Map();
8520
- taskIndexPath = () => path10.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "index.json");
8570
+ taskIndexPath = () => path11.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "index.json");
8521
8571
  pendingNotifications = [];
8522
8572
  notificationsLoaded = false;
8523
- notificationQueuePath = () => path10.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "notifications.json");
8573
+ notificationQueuePath = () => path11.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "notifications.json");
8524
8574
  notificationCallback = null;
8525
8575
  DEAD_LETTER_MAX_ATTEMPTS = 10;
8526
8576
  RETRY_BASE_MS = 1e3;
@@ -8662,8 +8712,8 @@ __export(context_analyzer_exports, {
8662
8712
  formatContextReport: () => formatContextReport,
8663
8713
  scanMemoryFiles: () => scanMemoryFiles
8664
8714
  });
8665
- import * as fs10 from "node:fs";
8666
- import * as path11 from "node:path";
8715
+ import * as fs11 from "node:fs";
8716
+ import * as path12 from "node:path";
8667
8717
  function estimateMessageTokens2(m) {
8668
8718
  let tokens = 0;
8669
8719
  if (typeof m.content === "string") {
@@ -8773,9 +8823,9 @@ function breakdownMessages(messages) {
8773
8823
  }
8774
8824
  async function scanMemoryFiles(workspace) {
8775
8825
  const files = [];
8776
- const soul = readFileIfExists2(path11.join(workspace, "SOUL.md"));
8826
+ const soul = readFileIfExists2(path12.join(workspace, "SOUL.md"));
8777
8827
  if (soul) files.push({ path: "SOUL.md", tokens: roughTokenCountEstimation(soul), stable: true });
8778
- const agents = readFileIfExists2(path11.join(workspace, "AGENTS.md"));
8828
+ const agents = readFileIfExists2(path12.join(workspace, "AGENTS.md"));
8779
8829
  if (agents) files.push({ path: "AGENTS.md", tokens: roughTokenCountEstimation(agents), stable: true });
8780
8830
  try {
8781
8831
  const { buildMemoryPrompt: buildMemoryPrompt2 } = await Promise.resolve().then(() => (init_memdir(), memdir_exports));
@@ -8791,7 +8841,7 @@ async function scanMemoryFiles(workspace) {
8791
8841
  }
8792
8842
  function readFileIfExists2(filePath) {
8793
8843
  try {
8794
- if (fs10.existsSync(filePath)) return fs10.readFileSync(filePath, "utf-8");
8844
+ if (fs11.existsSync(filePath)) return fs11.readFileSync(filePath, "utf-8");
8795
8845
  } catch {
8796
8846
  }
8797
8847
  return null;
@@ -9770,8 +9820,8 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
9770
9820
  });
9771
9821
 
9772
9822
  // src/session/writer.ts
9773
- import * as fs11 from "node:fs";
9774
- import * as path12 from "node:path";
9823
+ import * as fs12 from "node:fs";
9824
+ import * as path13 from "node:path";
9775
9825
  import * as crypto2 from "node:crypto";
9776
9826
  function assistantWriteParamsFrom(m) {
9777
9827
  const anyM = m;
@@ -9807,7 +9857,7 @@ var init_writer = __esm({
9807
9857
  this.sessionId = sessionId || crypto2.randomUUID();
9808
9858
  this.engineSessionId = "";
9809
9859
  const filename = `${this.sessionId}.jsonl`;
9810
- this.filePath = path12.join(sessionsDir, filename);
9860
+ this.filePath = path13.join(sessionsDir, filename);
9811
9861
  }
9812
9862
  get id() {
9813
9863
  return this.sessionId;
@@ -9818,9 +9868,9 @@ var init_writer = __esm({
9818
9868
  /** 打开文件写入 header(新文件才写 header) */
9819
9869
  open(cwd, engineSessionId) {
9820
9870
  this.engineSessionId = engineSessionId || "";
9821
- fs11.mkdirSync(path12.dirname(this.filePath), { recursive: true });
9822
- const fileExists = fs11.existsSync(this.filePath) && fs11.statSync(this.filePath).size > 0;
9823
- this.stream = fs11.createWriteStream(this.filePath, { flags: "a" });
9871
+ fs12.mkdirSync(path13.dirname(this.filePath), { recursive: true });
9872
+ const fileExists = fs12.existsSync(this.filePath) && fs12.statSync(this.filePath).size > 0;
9873
+ this.stream = fs12.createWriteStream(this.filePath, { flags: "a" });
9824
9874
  this.stream.on("error", (err) => {
9825
9875
  console.error(`[SessionWriter] write error on ${this.filePath}:`, err.message);
9826
9876
  });
@@ -10023,17 +10073,17 @@ var init_writer = __esm({
10023
10073
  this.stream.end();
10024
10074
  this.stream = null;
10025
10075
  }
10026
- if (!fs11.existsSync(this.filePath)) return null;
10027
- const fileSize = fs11.statSync(this.filePath).size;
10076
+ if (!fs12.existsSync(this.filePath)) return null;
10077
+ const fileSize = fs12.statSync(this.filePath).size;
10028
10078
  if (fileSize === 0) return null;
10029
10079
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
10030
10080
  const archivedPath = `${this.filePath}.${reason}.${ts}`;
10031
- fs11.renameSync(this.filePath, archivedPath);
10081
+ fs12.renameSync(this.filePath, archivedPath);
10032
10082
  const sizeMB = (fileSize / 1024 / 1024).toFixed(1);
10033
- console.log(`[SessionWriter] Archived JSONL: ${path12.basename(this.filePath)} \u2192 ${path12.basename(archivedPath)} (${sizeMB}MB)`);
10083
+ console.log(`[SessionWriter] Archived JSONL: ${path13.basename(this.filePath)} \u2192 ${path13.basename(archivedPath)} (${sizeMB}MB)`);
10034
10084
  const postBoundaryData = this.readPostBoundaryFromArchived(archivedPath);
10035
- const dir = path12.dirname(this.filePath);
10036
- fs11.mkdirSync(dir, { recursive: true });
10085
+ const dir = path13.dirname(this.filePath);
10086
+ fs12.mkdirSync(dir, { recursive: true });
10037
10087
  const header = {
10038
10088
  type: "session",
10039
10089
  version: 3,
@@ -10047,8 +10097,8 @@ var init_writer = __esm({
10047
10097
  if (postBoundaryData.length > 0) {
10048
10098
  initialData += postBoundaryData.toString("utf-8");
10049
10099
  }
10050
- fs11.writeFileSync(this.filePath, initialData, "utf-8");
10051
- this.stream = fs11.createWriteStream(this.filePath, { flags: "a" });
10100
+ fs12.writeFileSync(this.filePath, initialData, "utf-8");
10101
+ this.stream = fs12.createWriteStream(this.filePath, { flags: "a" });
10052
10102
  this.stream.on("error", (err) => {
10053
10103
  console.error(`[SessionWriter] write error on ${this.filePath}:`, err.message);
10054
10104
  });
@@ -10058,10 +10108,10 @@ var init_writer = __esm({
10058
10108
  * 从归档文件中读取最后一个 compact_boundary 之后的内容
10059
10109
  */
10060
10110
  readPostBoundaryFromArchived(archivedPath) {
10061
- const fileSize = fs11.statSync(archivedPath).size;
10111
+ const fileSize = fs12.statSync(archivedPath).size;
10062
10112
  if (fileSize === 0) return Buffer.alloc(0);
10063
10113
  if (fileSize <= 5 * 1024 * 1024) {
10064
- const content = fs11.readFileSync(archivedPath, "utf-8");
10114
+ const content = fs12.readFileSync(archivedPath, "utf-8");
10065
10115
  const lines = content.split("\n");
10066
10116
  let lastBoundaryIdx = -1;
10067
10117
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -10078,11 +10128,11 @@ var init_writer = __esm({
10078
10128
  {
10079
10129
  const probeSize = Math.min(fileSize, 1024 * 1024);
10080
10130
  const probeBuf = Buffer.allocUnsafe(probeSize);
10081
- const probeFd = fs11.openSync(archivedPath, "r");
10131
+ const probeFd = fs12.openSync(archivedPath, "r");
10082
10132
  let hasBoundary = false;
10083
10133
  let probed = 0;
10084
10134
  while (probed < fileSize) {
10085
- const n = fs11.readSync(probeFd, probeBuf, 0, Math.min(probeSize, fileSize - probed), probed);
10135
+ const n = fs12.readSync(probeFd, probeBuf, 0, Math.min(probeSize, fileSize - probed), probed);
10086
10136
  if (n === 0) break;
10087
10137
  if (probeBuf.subarray(0, n).includes(Buffer.from(boundaryMarker))) {
10088
10138
  hasBoundary = true;
@@ -10090,19 +10140,19 @@ var init_writer = __esm({
10090
10140
  }
10091
10141
  probed += n;
10092
10142
  }
10093
- fs11.closeSync(probeFd);
10143
+ fs12.closeSync(probeFd);
10094
10144
  if (!hasBoundary) return Buffer.alloc(0);
10095
10145
  }
10096
10146
  const outBuf = Buffer.allocUnsafe(Math.min(fileSize, 8 * 1024 * 1024));
10097
10147
  let outLen = 0;
10098
10148
  const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
10099
- const fd = fs11.openSync(archivedPath, "r");
10149
+ const fd = fs12.openSync(archivedPath, "r");
10100
10150
  try {
10101
10151
  let filePos = 0;
10102
10152
  let carryBuf;
10103
10153
  let carryLen = 0;
10104
10154
  while (filePos < fileSize) {
10105
- const bytesRead = fs11.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
10155
+ const bytesRead = fs12.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
10106
10156
  if (bytesRead === 0) break;
10107
10157
  filePos += bytesRead;
10108
10158
  let scanBuf;
@@ -10151,7 +10201,7 @@ var init_writer = __esm({
10151
10201
  }
10152
10202
  }
10153
10203
  } finally {
10154
- fs11.closeSync(fd);
10204
+ fs12.closeSync(fd);
10155
10205
  }
10156
10206
  return outBuf.subarray(0, outLen);
10157
10207
  }
@@ -10163,15 +10213,15 @@ var init_writer = __esm({
10163
10213
  */
10164
10214
  readLastId() {
10165
10215
  try {
10166
- const stat4 = fs11.statSync(this.filePath);
10216
+ const stat4 = fs12.statSync(this.filePath);
10167
10217
  if (stat4.size === 0) return null;
10168
10218
  const readSize = Math.min(stat4.size, 4096);
10169
10219
  const buf = Buffer.alloc(readSize);
10170
- const fd = fs11.openSync(this.filePath, "r");
10220
+ const fd = fs12.openSync(this.filePath, "r");
10171
10221
  try {
10172
- fs11.readSync(fd, buf, 0, readSize, stat4.size - readSize);
10222
+ fs12.readSync(fd, buf, 0, readSize, stat4.size - readSize);
10173
10223
  } finally {
10174
- fs11.closeSync(fd);
10224
+ fs12.closeSync(fd);
10175
10225
  }
10176
10226
  const text = buf.toString("utf-8");
10177
10227
  const lines = text.split("\n").filter((l) => l.trim().length > 0);
@@ -10218,11 +10268,11 @@ var init_writer = __esm({
10218
10268
  });
10219
10269
 
10220
10270
  // src/session/reader.ts
10221
- import * as fs12 from "node:fs";
10222
- import * as path13 from "node:path";
10271
+ import * as fs13 from "node:fs";
10272
+ import * as path14 from "node:path";
10223
10273
  import * as readline from "node:readline";
10224
10274
  async function readSessionHeader(filePath) {
10225
- const stream = fs12.createReadStream(filePath, { encoding: "utf-8" });
10275
+ const stream = fs13.createReadStream(filePath, { encoding: "utf-8" });
10226
10276
  const rl = readline.createInterface({ input: stream });
10227
10277
  return new Promise((resolve12) => {
10228
10278
  let resolved = false;
@@ -10253,7 +10303,7 @@ async function readSessionHeader(filePath) {
10253
10303
  });
10254
10304
  }
10255
10305
  async function readLargeFilePostBoundary(filePath) {
10256
- const stat4 = fs12.statSync(filePath);
10306
+ const stat4 = fs13.statSync(filePath);
10257
10307
  const fileSize = stat4.size;
10258
10308
  const boundaryMarker = '"compact_boundary"';
10259
10309
  const CHUNK_SIZE = TRANSCRIPT_READ_CHUNK_SIZE;
@@ -10261,13 +10311,13 @@ async function readLargeFilePostBoundary(filePath) {
10261
10311
  let outLen = 0;
10262
10312
  let boundaryStartOffset = 0;
10263
10313
  const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
10264
- const fd = fs12.openSync(filePath, "r");
10314
+ const fd = fs13.openSync(filePath, "r");
10265
10315
  try {
10266
10316
  let filePos = 0;
10267
10317
  let carryBuf;
10268
10318
  let carryLen = 0;
10269
10319
  while (filePos < fileSize) {
10270
- const bytesRead = fs12.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
10320
+ const bytesRead = fs13.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
10271
10321
  if (bytesRead === 0) break;
10272
10322
  filePos += bytesRead;
10273
10323
  let scanBuf;
@@ -10319,7 +10369,7 @@ async function readLargeFilePostBoundary(filePath) {
10319
10369
  }
10320
10370
  }
10321
10371
  } finally {
10322
- fs12.closeSync(fd);
10372
+ fs13.closeSync(fd);
10323
10373
  }
10324
10374
  const postBoundaryText = outBuf.subarray(0, outLen).toString("utf-8");
10325
10375
  return postBoundaryText.split("\n").filter((l) => l.trim().length > 0);
@@ -10443,7 +10493,7 @@ function recoverOrphanedParallelToolResults(allEntries, chain, byUuid, seen) {
10443
10493
  return result;
10444
10494
  }
10445
10495
  async function readSessionHistory(filePath) {
10446
- const stat4 = fs12.statSync(filePath);
10496
+ const stat4 = fs13.statSync(filePath);
10447
10497
  const fileSize = stat4.size;
10448
10498
  if (fileSize > MAX_TRANSCRIPT_READ_BYTES) {
10449
10499
  console.warn(`[reader] Session file exceeds 50MB limit (${(fileSize / 1024 / 1024).toFixed(1)}MB), using chunked fd read with boundary skip`);
@@ -10482,7 +10532,7 @@ async function readSessionHistory(filePath) {
10482
10532
  return [...sessionStarts, ...filtered, ...restAttachments];
10483
10533
  }
10484
10534
  async function readAllLines(filePath) {
10485
- const stream = fs12.createReadStream(filePath, { encoding: "utf-8" });
10535
+ const stream = fs13.createReadStream(filePath, { encoding: "utf-8" });
10486
10536
  const rl = readline.createInterface({ input: stream });
10487
10537
  const lines = [];
10488
10538
  return new Promise((resolve12, reject) => {
@@ -10636,12 +10686,12 @@ function extractText(content) {
10636
10686
  return content.filter((b) => b.type === "text").map((b) => b.text || "").join("") || null;
10637
10687
  }
10638
10688
  function listSessions(sessionsDir) {
10639
- if (!fs12.existsSync(sessionsDir)) return [];
10640
- const files = fs12.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
10641
- file: path13.join(sessionsDir, f),
10689
+ if (!fs13.existsSync(sessionsDir)) return [];
10690
+ const files = fs13.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
10691
+ file: path14.join(sessionsDir, f),
10642
10692
  id: f.replace(/\.jsonl.*$/, ""),
10643
10693
  // strip .jsonl and everything after (archived suffix)
10644
- modified: new Date(fs12.statSync(path13.join(sessionsDir, f)).mtimeMs)
10694
+ modified: new Date(fs13.statSync(path14.join(sessionsDir, f)).mtimeMs)
10645
10695
  })).sort((a, b) => b.modified.getTime() - a.modified.getTime());
10646
10696
  return files;
10647
10697
  }
@@ -10662,8 +10712,8 @@ __export(session_manager_exports, {
10662
10712
  SessionManager: () => SessionManager,
10663
10713
  alignRestoreHeadToTurnBoundary: () => alignRestoreHeadToTurnBoundary
10664
10714
  });
10665
- import * as path14 from "node:path";
10666
- import * as fs13 from "node:fs";
10715
+ import * as path15 from "node:path";
10716
+ import * as fs14 from "node:fs";
10667
10717
  import * as crypto3 from "node:crypto";
10668
10718
  function alignRestoreHeadToTurnBoundary(messages, minKeep = RESTORE_MIN_KEEP_MESSAGES) {
10669
10719
  const isTurnBoundary = (m) => isAttachmentMessage(m) ? true : m.role === "user";
@@ -10702,24 +10752,24 @@ var init_session_manager = __esm({
10702
10752
  constructor(config) {
10703
10753
  this.config = config;
10704
10754
  this.scopeConfig = config.scopeConfig;
10705
- this.sessionsDir = path14.join(config.stateDir, "agents", "main", "sessions");
10706
- this.indexPath = path14.join(this.sessionsDir, "session-index.json");
10707
- this.platformMapPath = path14.join(this.sessionsDir, "platform-map.json");
10708
- fs13.mkdirSync(this.sessionsDir, { recursive: true });
10755
+ this.sessionsDir = path15.join(config.stateDir, "agents", "main", "sessions");
10756
+ this.indexPath = path15.join(this.sessionsDir, "session-index.json");
10757
+ this.platformMapPath = path15.join(this.sessionsDir, "platform-map.json");
10758
+ fs14.mkdirSync(this.sessionsDir, { recursive: true });
10709
10759
  }
10710
10760
  // === 索引操作 ===
10711
10761
  loadIndex() {
10712
10762
  try {
10713
- if (fs13.existsSync(this.indexPath)) {
10714
- const raw = fs13.readFileSync(this.indexPath, "utf-8");
10763
+ if (fs14.existsSync(this.indexPath)) {
10764
+ const raw = fs14.readFileSync(this.indexPath, "utf-8");
10715
10765
  const obj = JSON.parse(raw);
10716
10766
  this.index = new Map(Object.entries(obj));
10717
10767
  let fixed = 0;
10718
10768
  for (const [key, entry] of this.index) {
10719
- if (fs13.existsSync(entry.file)) continue;
10720
- const basename10 = path14.basename(entry.file);
10721
- const localPath = path14.join(this.sessionsDir, basename10);
10722
- if (fs13.existsSync(localPath)) {
10769
+ if (fs14.existsSync(entry.file)) continue;
10770
+ const basename10 = path15.basename(entry.file);
10771
+ const localPath = path15.join(this.sessionsDir, basename10);
10772
+ if (fs14.existsSync(localPath)) {
10723
10773
  entry.file = localPath;
10724
10774
  fixed++;
10725
10775
  }
@@ -10738,7 +10788,7 @@ var init_session_manager = __esm({
10738
10788
  try {
10739
10789
  const obj = {};
10740
10790
  for (const [k, v] of this.index) obj[k] = v;
10741
- fs13.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
10791
+ fs14.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
10742
10792
  } catch (err) {
10743
10793
  console.error(`[session] Failed to save index: ${err.message}`);
10744
10794
  }
@@ -10746,8 +10796,8 @@ var init_session_manager = __esm({
10746
10796
  // === 平台映射 ===
10747
10797
  loadPlatformMap() {
10748
10798
  try {
10749
- if (fs13.existsSync(this.platformMapPath)) {
10750
- const raw = fs13.readFileSync(this.platformMapPath, "utf-8");
10799
+ if (fs14.existsSync(this.platformMapPath)) {
10800
+ const raw = fs14.readFileSync(this.platformMapPath, "utf-8");
10751
10801
  const obj = JSON.parse(raw);
10752
10802
  this.platformMap = new Map(Object.entries(obj));
10753
10803
  console.log(`[session] Platform map loaded: ${this.platformMap.size} entries`);
@@ -10759,7 +10809,7 @@ var init_session_manager = __esm({
10759
10809
  try {
10760
10810
  const obj = {};
10761
10811
  for (const [k, v] of this.platformMap) obj[k] = v;
10762
- fs13.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
10812
+ fs14.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
10763
10813
  } catch (err) {
10764
10814
  console.error(`[session] Failed to save platform map: ${err.message}`);
10765
10815
  }
@@ -10798,17 +10848,17 @@ var init_session_manager = __esm({
10798
10848
  */
10799
10849
  getSessionFilePath(sessionId) {
10800
10850
  const entry = this.index.get(sessionId);
10801
- if (entry && fs13.existsSync(entry.file)) return entry.file;
10802
- const direct = path14.join(this.sessionsDir, `${sessionId}.jsonl`);
10803
- return fs13.existsSync(direct) ? direct : null;
10851
+ if (entry && fs14.existsSync(entry.file)) return entry.file;
10852
+ const direct = path15.join(this.sessionsDir, `${sessionId}.jsonl`);
10853
+ return fs14.existsSync(direct) ? direct : null;
10804
10854
  }
10805
10855
  // === Writer 管理 ===
10806
10856
  getWriter(sessionId) {
10807
10857
  let writer = this.writers.get(sessionId);
10808
10858
  if (!writer) {
10809
10859
  const existing = this.index.get(sessionId);
10810
- if (existing && fs13.existsSync(existing.file)) {
10811
- const existingFileId = path14.basename(existing.file, ".jsonl");
10860
+ if (existing && fs14.existsSync(existing.file)) {
10861
+ const existingFileId = path15.basename(existing.file, ".jsonl");
10812
10862
  writer = new SessionWriter(this.sessionsDir, existingFileId);
10813
10863
  writer.open(this.config.workspace, sessionId);
10814
10864
  } else {
@@ -10820,7 +10870,7 @@ var init_session_manager = __esm({
10820
10870
  this.saveIndex();
10821
10871
  this.writers.set(sessionId, writer);
10822
10872
  this.onWriterCreated?.(writer, sessionId);
10823
- console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path14.basename(writer.path)}`);
10873
+ console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path15.basename(writer.path)}`);
10824
10874
  }
10825
10875
  return writer;
10826
10876
  }
@@ -10839,7 +10889,7 @@ var init_session_manager = __esm({
10839
10889
  if (!writer) return null;
10840
10890
  try {
10841
10891
  this.lastArchiveCheck = Date.now();
10842
- const stat4 = fs13.statSync(writer.path);
10892
+ const stat4 = fs14.statSync(writer.path);
10843
10893
  if (stat4.size < threshold) return null;
10844
10894
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
10845
10895
  const thresholdMB = (threshold / 1024 / 1024).toFixed(1);
@@ -10848,10 +10898,10 @@ var init_session_manager = __esm({
10848
10898
  if (archivedPath) {
10849
10899
  this.index.set(sessionId, { file: writer.path, updatedAt: Date.now() });
10850
10900
  this.saveIndex();
10851
- const newSize = fs13.statSync(writer.path).size;
10901
+ const newSize = fs14.statSync(writer.path).size;
10852
10902
  const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
10853
- console.log(`[session] Archive complete: ${path14.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
10854
- const fileId = path14.basename(writer.path).replace(/\.jsonl$/, "");
10903
+ console.log(`[session] Archive complete: ${path15.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
10904
+ const fileId = path15.basename(writer.path).replace(/\.jsonl$/, "");
10855
10905
  this.purgeOldArchives(fileId, 3);
10856
10906
  return archivedPath;
10857
10907
  }
@@ -10867,15 +10917,15 @@ var init_session_manager = __esm({
10867
10917
  purgeOldArchives(sessionId, keepCount = 3) {
10868
10918
  try {
10869
10919
  const dir = this.sessionsDir;
10870
- if (!fs13.existsSync(dir)) return;
10871
- const allFiles = fs13.readdirSync(dir);
10920
+ if (!fs14.existsSync(dir)) return;
10921
+ const allFiles = fs14.readdirSync(dir);
10872
10922
  const archiveFiles = allFiles.filter((f) => {
10873
10923
  if (!f.startsWith(sessionId)) return false;
10874
10924
  return f.includes(".archived.") || f.includes(".compaction.");
10875
10925
  }).map((f) => ({
10876
10926
  name: f,
10877
- path: path14.join(dir, f),
10878
- mtime: fs13.statSync(path14.join(dir, f)).mtimeMs
10927
+ path: path15.join(dir, f),
10928
+ mtime: fs14.statSync(path15.join(dir, f)).mtimeMs
10879
10929
  })).sort((a, b) => b.mtime - a.mtime);
10880
10930
  console.log(`[session] purgeOldArchives: sessionId=${sessionId.substring(0, 8)}... found=${archiveFiles.length} keep=${keepCount}`);
10881
10931
  if (archiveFiles.length <= keepCount) return;
@@ -10885,7 +10935,7 @@ var init_session_manager = __esm({
10885
10935
  console.log(`[session] Skipping archived (kept for history): ${f.name}`);
10886
10936
  continue;
10887
10937
  }
10888
- fs13.unlinkSync(f.path);
10938
+ fs14.unlinkSync(f.path);
10889
10939
  console.log(`[session] Purged old archive: ${f.name}`);
10890
10940
  }
10891
10941
  if (toDelete.length > 0) {
@@ -10934,29 +10984,29 @@ var init_session_manager = __esm({
10934
10984
  /** 列出 session 的所有文件(当前 + 归档),按修改时间排序 */
10935
10985
  findAllSessionFiles(sessionId) {
10936
10986
  const results = [];
10937
- const mainFile = path14.join(this.sessionsDir, `${sessionId}.jsonl`);
10938
- if (fs13.existsSync(mainFile)) {
10987
+ const mainFile = path15.join(this.sessionsDir, `${sessionId}.jsonl`);
10988
+ if (fs14.existsSync(mainFile)) {
10939
10989
  results.push(mainFile);
10940
10990
  }
10941
- if (fs13.existsSync(this.sessionsDir)) {
10942
- const compactionFiles = fs13.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
10991
+ if (fs14.existsSync(this.sessionsDir)) {
10992
+ const compactionFiles = fs14.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
10943
10993
  name: f,
10944
- path: path14.join(this.sessionsDir, f),
10945
- mtime: fs13.statSync(path14.join(this.sessionsDir, f)).mtimeMs
10994
+ path: path15.join(this.sessionsDir, f),
10995
+ mtime: fs14.statSync(path15.join(this.sessionsDir, f)).mtimeMs
10946
10996
  })).sort((a, b) => b.mtime - a.mtime);
10947
10997
  if (compactionFiles.length > 0) {
10948
10998
  results.push(compactionFiles[0].path);
10949
10999
  }
10950
11000
  }
10951
11001
  results.sort((a, b) => {
10952
- const ta = fs13.statSync(a).mtimeMs;
10953
- const tb = fs13.statSync(b).mtimeMs;
11002
+ const ta = fs14.statSync(a).mtimeMs;
11003
+ const tb = fs14.statSync(b).mtimeMs;
10954
11004
  return ta - tb;
10955
11005
  });
10956
11006
  return results;
10957
11007
  }
10958
11008
  async findSessionFiles(sessionId) {
10959
- if (!fs13.existsSync(this.sessionsDir)) {
11009
+ if (!fs14.existsSync(this.sessionsDir)) {
10960
11010
  console.log(`[session:find] SESSIONS_DIR not found: ${this.sessionsDir}`);
10961
11011
  return [];
10962
11012
  }
@@ -10968,15 +11018,15 @@ var init_session_manager = __esm({
10968
11018
  return mappedFiles;
10969
11019
  }
10970
11020
  const indexedEntry = this.index.get(mappedId);
10971
- if (indexedEntry && fs13.existsSync(indexedEntry.file)) {
10972
- const fileUuid = path14.basename(indexedEntry.file, ".jsonl");
11021
+ if (indexedEntry && fs14.existsSync(indexedEntry.file)) {
11022
+ const fileUuid = path15.basename(indexedEntry.file, ".jsonl");
10973
11023
  return this.findAllSessionFiles(fileUuid);
10974
11024
  }
10975
11025
  }
10976
11026
  const allFiles = this.findAllSessionFiles(sessionId);
10977
11027
  if (allFiles.length > 0) {
10978
11028
  const labels = allFiles.map((f) => {
10979
- const base = path14.basename(f);
11029
+ const base = path15.basename(f);
10980
11030
  return base.endsWith(".jsonl") ? base : `${base} (archived)`;
10981
11031
  });
10982
11032
  console.log(`[session:find] Found ${allFiles.length} file(s) for ${sessionId}: ${labels.join(", ")}`);
@@ -10984,9 +11034,9 @@ var init_session_manager = __esm({
10984
11034
  }
10985
11035
  const indexed = this.index.get(sessionId);
10986
11036
  if (indexed) {
10987
- console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs13.existsSync(indexed.file)})`);
10988
- if (fs13.existsSync(indexed.file)) {
10989
- return this.findAllSessionFiles(path14.basename(indexed.file, ".jsonl"));
11037
+ console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs14.existsSync(indexed.file)})`);
11038
+ if (fs14.existsSync(indexed.file)) {
11039
+ return this.findAllSessionFiles(path15.basename(indexed.file, ".jsonl"));
10990
11040
  }
10991
11041
  } else {
10992
11042
  console.log(`[session:find] Index miss: ${sessionId} (index has ${this.index.size} entries)`);
@@ -11015,8 +11065,8 @@ var init_session_manager = __esm({
11015
11065
  return [];
11016
11066
  }
11017
11067
  files.sort((a, b) => {
11018
- const ta = fs13.statSync(a).mtimeMs;
11019
- const tb = fs13.statSync(b).mtimeMs;
11068
+ const ta = fs14.statSync(a).mtimeMs;
11069
+ const tb = fs14.statSync(b).mtimeMs;
11020
11070
  return ta - tb;
11021
11071
  });
11022
11072
  const latestFile = files[files.length - 1];
@@ -11024,7 +11074,7 @@ var init_session_manager = __esm({
11024
11074
  if (!currentEntry || currentEntry.file !== latestFile) {
11025
11075
  this.index.set(sessionId, { file: latestFile, updatedAt: Date.now() });
11026
11076
  this.saveIndex();
11027
- console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path14.basename(latestFile)}`);
11077
+ console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path15.basename(latestFile)}`);
11028
11078
  }
11029
11079
  const allMessages = [];
11030
11080
  for (const file2 of files) {
@@ -11063,7 +11113,7 @@ var init_session_manager = __esm({
11063
11113
  if (isAttachmentMessage(m) && m.attachment.type === "relevant_memories") {
11064
11114
  for (const mem of m.attachment.memories) {
11065
11115
  rawCount++;
11066
- restoredPaths.add(path14.resolve(mem.path));
11116
+ restoredPaths.add(path15.resolve(mem.path));
11067
11117
  }
11068
11118
  }
11069
11119
  }
@@ -11095,15 +11145,15 @@ var init_session_manager = __esm({
11095
11145
  */
11096
11146
  rotateMainSession() {
11097
11147
  const entry = this.index.get("main");
11098
- if (!entry || !fs13.existsSync(entry.file)) return;
11099
- const oldFileId = path14.basename(entry.file, ".jsonl");
11100
- const stat4 = fs13.statSync(entry.file);
11148
+ if (!entry || !fs14.existsSync(entry.file)) return;
11149
+ const oldFileId = path15.basename(entry.file, ".jsonl");
11150
+ const stat4 = fs14.statSync(entry.file);
11101
11151
  if (stat4.size < 1024) return;
11102
11152
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
11103
11153
  const archivedPath = `${entry.file}.archived.${ts}`;
11104
- fs13.renameSync(entry.file, archivedPath);
11154
+ fs14.renameSync(entry.file, archivedPath);
11105
11155
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
11106
- console.log(`[session] Archived: ${path14.basename(entry.file)} \u2192 ${path14.basename(archivedPath)} (${sizeMB}MB)`);
11156
+ console.log(`[session] Archived: ${path15.basename(entry.file)} \u2192 ${path15.basename(archivedPath)} (${sizeMB}MB)`);
11107
11157
  const newWriter = new SessionWriter(this.sessionsDir);
11108
11158
  newWriter.open(this.config.workspace, "main");
11109
11159
  newWriter.writeModelChange(this.config.providerId, this.config.model);
@@ -11112,7 +11162,7 @@ var init_session_manager = __esm({
11112
11162
  this.index.set("main", { file: newPath, updatedAt: Date.now() });
11113
11163
  this.saveIndex();
11114
11164
  this.purgeOldArchives(oldFileId, 3);
11115
- console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path14.basename(newPath)}`);
11165
+ console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path15.basename(newPath)}`);
11116
11166
  }
11117
11167
  // === 迁移 ===
11118
11168
  /** 迁移旧索引:session-index.json 里有 "discord:xxx" 格式的 key 时,生成 UUID 替换 */
@@ -11177,15 +11227,15 @@ var init_session_manager = __esm({
11177
11227
  });
11178
11228
 
11179
11229
  // src/tools/read.ts
11180
- import * as fs14 from "node:fs";
11181
- import * as path15 from "node:path";
11230
+ import * as fs15 from "node:fs";
11231
+ import * as path16 from "node:path";
11182
11232
  function isBlockedDevicePath(filePath) {
11183
11233
  if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
11184
11234
  if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
11185
11235
  return false;
11186
11236
  }
11187
11237
  function checkReadLoop(filePath, offset, limit) {
11188
- const stat4 = fs14.statSync(filePath);
11238
+ const stat4 = fs15.statSync(filePath);
11189
11239
  const mtimeMs = stat4.mtimeMs;
11190
11240
  const prev = readHistory.get(filePath);
11191
11241
  if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
@@ -11199,19 +11249,19 @@ function checkReadLoop(filePath, offset, limit) {
11199
11249
  return null;
11200
11250
  }
11201
11251
  function readFileContent(filePath) {
11202
- const fd = fs14.openSync(filePath, "r");
11252
+ const fd = fs15.openSync(filePath, "r");
11203
11253
  const bom = Buffer.alloc(2);
11204
- fs14.readSync(fd, bom, 0, 2, 0);
11205
- fs14.closeSync(fd);
11254
+ fs15.readSync(fd, bom, 0, 2, 0);
11255
+ fs15.closeSync(fd);
11206
11256
  let encoding = "utf8";
11207
11257
  if (bom[0] === 255 && bom[1] === 254) {
11208
11258
  encoding = "utf16le";
11209
11259
  }
11210
- const stat4 = fs14.statSync(filePath);
11260
+ const stat4 = fs15.statSync(filePath);
11211
11261
  if (stat4.size > MAX_FILE_SIZE) {
11212
11262
  throw new Error(`\u6587\u4EF6\u592A\u5927 (${(stat4.size / 1024).toFixed(1)}KB)\uFF0C\u8D85\u8FC7 ${MAX_FILE_SIZE / 1024}KB \u9650\u5236\u3002\u8BF7\u4F7F\u7528 offset + limit \u5206\u6BB5\u8BFB\u53D6\u3002`);
11213
11263
  }
11214
- const raw = fs14.readFileSync(filePath, encoding);
11264
+ const raw = fs15.readFileSync(filePath, encoding);
11215
11265
  const content = raw.toString().replaceAll("\r\n", "\n");
11216
11266
  return { content, encoding };
11217
11267
  }
@@ -11353,11 +11403,11 @@ Usage:
11353
11403
  } catch (e) {
11354
11404
  return { content: e.message, isError: true };
11355
11405
  }
11356
- if (!fs14.existsSync(filePath)) {
11406
+ if (!fs15.existsSync(filePath)) {
11357
11407
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
11358
11408
  }
11359
- const stat4 = fs14.statSync(filePath);
11360
- const baseName = path15.basename(filePath).toUpperCase();
11409
+ const stat4 = fs15.statSync(filePath);
11410
+ const baseName = path16.basename(filePath).toUpperCase();
11361
11411
  if (BLOCKED_BASENAMES.has(baseName)) {
11362
11412
  return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
11363
11413
  }
@@ -11365,11 +11415,11 @@ Usage:
11365
11415
  return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
11366
11416
  }
11367
11417
  if (stat4.isDirectory()) {
11368
- const entries2 = fs14.readdirSync(filePath);
11418
+ const entries2 = fs15.readdirSync(filePath);
11369
11419
  const items = entries2.map((e) => {
11370
- const full = path15.join(filePath, e);
11420
+ const full = path16.join(filePath, e);
11371
11421
  try {
11372
- const s = fs14.statSync(full);
11422
+ const s = fs15.statSync(full);
11373
11423
  return s.isDirectory() ? `${e}/` : e;
11374
11424
  } catch {
11375
11425
  return e;
@@ -11378,7 +11428,7 @@ Usage:
11378
11428
  return { content: `\u76EE\u5F55 (${entries2.length} \u9879):
11379
11429
  ${items.join("\n")}` };
11380
11430
  }
11381
- const ext = path15.extname(filePath).toLowerCase();
11431
+ const ext = path16.extname(filePath).toLowerCase();
11382
11432
  if (BINARY_EXTENSIONS.has(ext)) {
11383
11433
  return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
11384
11434
  }
@@ -11425,22 +11475,22 @@ ${result}` : result };
11425
11475
  });
11426
11476
 
11427
11477
  // src/tools/write.ts
11428
- import * as fs15 from "node:fs";
11429
- import * as path16 from "node:path";
11478
+ import * as fs16 from "node:fs";
11479
+ import * as path17 from "node:path";
11430
11480
  function isBlockedPath(filePath) {
11431
11481
  return BLOCKED_PATTERNS.some((p) => p.test(filePath));
11432
11482
  }
11433
11483
  function atomicWrite(filePath, content) {
11434
11484
  const tmpPath = filePath + ".tmp." + Date.now() + ".write";
11435
- fs15.writeFileSync(tmpPath, content, "utf-8");
11485
+ fs16.writeFileSync(tmpPath, content, "utf-8");
11436
11486
  try {
11437
- fs15.renameSync(tmpPath, filePath);
11487
+ fs16.renameSync(tmpPath, filePath);
11438
11488
  } catch (e) {
11439
11489
  try {
11440
- fs15.unlinkSync(tmpPath);
11490
+ fs16.unlinkSync(tmpPath);
11441
11491
  } catch {
11442
11492
  }
11443
- fs15.writeFileSync(filePath, content, "utf-8");
11493
+ fs16.writeFileSync(filePath, content, "utf-8");
11444
11494
  }
11445
11495
  }
11446
11496
  function simpleDiff(oldContent, newContent) {
@@ -11534,15 +11584,15 @@ Usage:
11534
11584
  }
11535
11585
  const rawContent = args.content;
11536
11586
  const content = rawContent.replaceAll("\r\n", "\n");
11537
- if (fs15.existsSync(filePath) && fs15.statSync(filePath).isDirectory()) {
11587
+ if (fs16.existsSync(filePath) && fs16.statSync(filePath).isDirectory()) {
11538
11588
  return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
11539
11589
  }
11540
11590
  let oldContent = null;
11541
11591
  let isCreate = true;
11542
- if (fs15.existsSync(filePath)) {
11592
+ if (fs16.existsSync(filePath)) {
11543
11593
  isCreate = false;
11544
11594
  try {
11545
- oldContent = fs15.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
11595
+ oldContent = fs16.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
11546
11596
  } catch {
11547
11597
  isCreate = true;
11548
11598
  }
@@ -11558,10 +11608,10 @@ Usage:
11558
11608
  isError: true
11559
11609
  };
11560
11610
  }
11561
- const currentStat = fs15.statSync(filePath);
11611
+ const currentStat = fs16.statSync(filePath);
11562
11612
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
11563
11613
  if (lastWriteTime > readState.timestamp) {
11564
- const currentContent = fs15.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
11614
+ const currentContent = fs16.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
11565
11615
  if (currentContent !== oldContent) {
11566
11616
  return {
11567
11617
  content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
@@ -11570,9 +11620,9 @@ Usage:
11570
11620
  }
11571
11621
  }
11572
11622
  }
11573
- const dir = path16.dirname(filePath);
11623
+ const dir = path17.dirname(filePath);
11574
11624
  try {
11575
- fs15.mkdirSync(dir, { recursive: true });
11625
+ fs16.mkdirSync(dir, { recursive: true });
11576
11626
  } catch (e) {
11577
11627
  return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
11578
11628
  }
@@ -11581,11 +11631,11 @@ Usage:
11581
11631
  } catch (e) {
11582
11632
  return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
11583
11633
  }
11584
- readFileState.set(filePath, { timestamp: fs15.statSync(filePath).mtimeMs });
11634
+ readFileState.set(filePath, { timestamp: fs16.statSync(filePath).mtimeMs });
11585
11635
  const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
11586
11636
  const lines = content.split("\n").length;
11587
11637
  const chars = content.length;
11588
- const stat4 = fs15.statSync(filePath);
11638
+ const stat4 = fs16.statSync(filePath);
11589
11639
  let diff = "";
11590
11640
  if (!isCreate && oldContent !== null) {
11591
11641
  diff = `
@@ -11604,8 +11654,8 @@ ${simpleDiff(oldContent, content)}`;
11604
11654
  });
11605
11655
 
11606
11656
  // src/tools/edit.ts
11607
- import * as fs16 from "node:fs";
11608
- import * as path17 from "node:path";
11657
+ import * as fs17 from "node:fs";
11658
+ import * as path18 from "node:path";
11609
11659
  function normalizeQuotes(str) {
11610
11660
  return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
11611
11661
  }
@@ -11758,7 +11808,7 @@ Usage:
11758
11808
  }
11759
11809
  let fileContent = null;
11760
11810
  try {
11761
- const stat4 = fs16.statSync(filePath);
11811
+ const stat4 = fs17.statSync(filePath);
11762
11812
  if (stat4.isDirectory()) {
11763
11813
  return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
11764
11814
  }
@@ -11768,21 +11818,21 @@ Usage:
11768
11818
  } catch (e) {
11769
11819
  if (e.code === "ENOENT") {
11770
11820
  if (oldString === "") {
11771
- const dir = path17.dirname(filePath);
11772
- fs16.mkdirSync(dir, { recursive: true });
11773
- fs16.writeFileSync(filePath, newString, "utf-8");
11774
- readFileState.set(filePath, { timestamp: fs16.statSync(filePath).mtimeMs });
11821
+ const dir = path18.dirname(filePath);
11822
+ fs17.mkdirSync(dir, { recursive: true });
11823
+ fs17.writeFileSync(filePath, newString, "utf-8");
11824
+ readFileState.set(filePath, { timestamp: fs17.statSync(filePath).mtimeMs });
11775
11825
  return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
11776
11826
  }
11777
11827
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
11778
11828
  }
11779
11829
  throw e;
11780
11830
  }
11781
- const rawContent = fs16.readFileSync(filePath, "utf-8");
11831
+ const rawContent = fs17.readFileSync(filePath, "utf-8");
11782
11832
  fileContent = rawContent.replaceAll("\r\n", "\n");
11783
11833
  if (oldString === "" && fileContent.trim() === "") {
11784
- fs16.writeFileSync(filePath, newString, "utf-8");
11785
- readFileState.set(filePath, { timestamp: fs16.statSync(filePath).mtimeMs });
11834
+ fs17.writeFileSync(filePath, newString, "utf-8");
11835
+ readFileState.set(filePath, { timestamp: fs17.statSync(filePath).mtimeMs });
11786
11836
  return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
11787
11837
  }
11788
11838
  const readState = readFileState.get(filePath);
@@ -11792,11 +11842,11 @@ Usage:
11792
11842
  isError: true
11793
11843
  };
11794
11844
  }
11795
- const currentStat = fs16.statSync(filePath);
11845
+ const currentStat = fs17.statSync(filePath);
11796
11846
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
11797
11847
  if (lastWriteTime > readState.timestamp) {
11798
11848
  if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
11799
- if (fileContent !== fs16.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
11849
+ if (fileContent !== fs17.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
11800
11850
  return {
11801
11851
  content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
11802
11852
  isError: true
@@ -11828,8 +11878,8 @@ ${preview}
11828
11878
  const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
11829
11879
  const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
11830
11880
  const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
11831
- fs16.writeFileSync(filePath, newContent, "utf-8");
11832
- readFileState.set(filePath, { timestamp: fs16.statSync(filePath).mtimeMs });
11881
+ fs17.writeFileSync(filePath, newContent, "utf-8");
11882
+ readFileState.set(filePath, { timestamp: fs17.statSync(filePath).mtimeMs });
11833
11883
  const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
11834
11884
  const count = replaceAll ? matchCount : 1;
11835
11885
  const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
@@ -11846,8 +11896,8 @@ ${diffView}`
11846
11896
  });
11847
11897
 
11848
11898
  // src/tools/glob.ts
11849
- import * as fs17 from "node:fs";
11850
- import * as path18 from "node:path";
11899
+ import * as fs18 from "node:fs";
11900
+ import * as path19 from "node:path";
11851
11901
  function globMatch(pattern, filename) {
11852
11902
  const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
11853
11903
  try {
@@ -11867,18 +11917,18 @@ function findFiles(dir, pattern, limit, baseDir) {
11867
11917
  }
11868
11918
  let entries2;
11869
11919
  try {
11870
- entries2 = fs17.readdirSync(currentDir, { withFileTypes: true });
11920
+ entries2 = fs18.readdirSync(currentDir, { withFileTypes: true });
11871
11921
  } catch {
11872
11922
  return;
11873
11923
  }
11874
11924
  for (const entry of entries2) {
11875
11925
  if (truncated) return;
11876
- const fullPath = path18.join(currentDir, entry.name);
11926
+ const fullPath = path19.join(currentDir, entry.name);
11877
11927
  if (entry.isDirectory()) {
11878
11928
  if (VCS_DIRS.has(entry.name)) continue;
11879
11929
  walk(fullPath);
11880
11930
  } else if (entry.isFile()) {
11881
- const relativePath = path18.relative(baseDir, fullPath).replace(/\\/g, "/");
11931
+ const relativePath = path19.relative(baseDir, fullPath).replace(/\\/g, "/");
11882
11932
  const patternsToTry = [pattern];
11883
11933
  if (pattern.startsWith("**/")) {
11884
11934
  patternsToTry.push(pattern.slice(3));
@@ -11888,7 +11938,7 @@ function findFiles(dir, pattern, limit, baseDir) {
11888
11938
  );
11889
11939
  if (matched) {
11890
11940
  try {
11891
- const stat4 = fs17.statSync(fullPath);
11941
+ const stat4 = fs18.statSync(fullPath);
11892
11942
  results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
11893
11943
  } catch {
11894
11944
  }
@@ -11905,7 +11955,7 @@ function findFiles(dir, pattern, limit, baseDir) {
11905
11955
  };
11906
11956
  }
11907
11957
  function toRelativePath(absolutePath, cwd) {
11908
- if (absolutePath.startsWith(cwd + path18.sep)) {
11958
+ if (absolutePath.startsWith(cwd + path19.sep)) {
11909
11959
  return absolutePath.slice(cwd.length + 1);
11910
11960
  }
11911
11961
  return absolutePath;
@@ -11938,10 +11988,10 @@ var init_glob = __esm({
11938
11988
  const searchPath = args.path ? resolvePath(args.path, ctx.workspace) : ctx.workspace;
11939
11989
  const pattern = args.pattern;
11940
11990
  const limit = args.limit || DEFAULT_LIMIT;
11941
- if (!fs17.existsSync(searchPath)) {
11991
+ if (!fs18.existsSync(searchPath)) {
11942
11992
  return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
11943
11993
  }
11944
- if (!fs17.statSync(searchPath).isDirectory()) {
11994
+ if (!fs18.statSync(searchPath).isDirectory()) {
11945
11995
  return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
11946
11996
  }
11947
11997
  const start = Date.now();
@@ -11965,7 +12015,7 @@ ${filenames.join("\n")}${truncatedNote}`
11965
12015
 
11966
12016
  // src/tools/grep.ts
11967
12017
  import { execFile } from "node:child_process";
11968
- import * as path19 from "node:path";
12018
+ import * as path20 from "node:path";
11969
12019
  function ripGrep(args, searchPath, signal) {
11970
12020
  return new Promise((resolve12) => {
11971
12021
  const fullArgs = [...args, searchPath];
@@ -11997,7 +12047,7 @@ function applyHeadLimit(items, limit, offset = 0) {
11997
12047
  };
11998
12048
  }
11999
12049
  function toRelativePath2(absolutePath, cwd) {
12000
- if (absolutePath.startsWith(cwd + path19.sep)) {
12050
+ if (absolutePath.startsWith(cwd + path20.sep)) {
12001
12051
  return absolutePath.slice(cwd.length + 1);
12002
12052
  }
12003
12053
  if (absolutePath.startsWith(cwd)) {
@@ -13247,7 +13297,7 @@ async function acquireLock(inboxPath) {
13247
13297
  for (let i = 0; i < LOCK_RETRIES; i++) {
13248
13298
  if (await isLockStale(lockPath2)) {
13249
13299
  try {
13250
- await import("node:fs/promises").then((fs43) => fs43.rm(lockPath2, { force: true }));
13300
+ await import("node:fs/promises").then((fs44) => fs44.rm(lockPath2, { force: true }));
13251
13301
  } catch {
13252
13302
  }
13253
13303
  }
@@ -13255,7 +13305,7 @@ async function acquireLock(inboxPath) {
13255
13305
  await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
13256
13306
  return async () => {
13257
13307
  try {
13258
- await import("node:fs/promises").then((fs43) => fs43.rm(lockPath2, { force: true }));
13308
+ await import("node:fs/promises").then((fs44) => fs44.rm(lockPath2, { force: true }));
13259
13309
  } catch {
13260
13310
  }
13261
13311
  };
@@ -14498,12 +14548,12 @@ Examples:
14498
14548
  });
14499
14549
 
14500
14550
  // src/tools/msg-husband.ts
14501
- import fs18 from "node:fs";
14502
- import path20 from "node:path";
14551
+ import fs19 from "node:fs";
14552
+ import path21 from "node:path";
14503
14553
  function getHusbandFeishuId(workspace) {
14504
- const contactsPath = path20.join(workspace, "prompts", "contacts.md");
14554
+ const contactsPath = path21.join(workspace, "prompts", "contacts.md");
14505
14555
  try {
14506
- const text = fs18.readFileSync(contactsPath, "utf-8");
14556
+ const text = fs19.readFileSync(contactsPath, "utf-8");
14507
14557
  const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
14508
14558
  return m ? m[1] : null;
14509
14559
  } catch {
@@ -14656,8 +14706,8 @@ Examples:
14656
14706
  if (!to && !resolvedChannelId) {
14657
14707
  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 };
14658
14708
  }
14659
- const fs43 = await import("node:fs");
14660
- if (!fs43.existsSync(filePath)) {
14709
+ const fs44 = await import("node:fs");
14710
+ if (!fs44.existsSync(filePath)) {
14661
14711
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
14662
14712
  }
14663
14713
  const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
@@ -14685,7 +14735,7 @@ Examples:
14685
14735
  md: "text/markdown"
14686
14736
  };
14687
14737
  const mimeType = mimeTypeMap[ext] || "application/octet-stream";
14688
- const stat4 = fs43.statSync(filePath);
14738
+ const stat4 = fs44.statSync(filePath);
14689
14739
  const sizeMB = stat4.size / 1024 / 1024;
14690
14740
  if (sizeMB > 25) {
14691
14741
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
@@ -14714,8 +14764,8 @@ Examples:
14714
14764
  });
14715
14765
 
14716
14766
  // src/tools/my-eyes.ts
14717
- import * as fs19 from "node:fs";
14718
- import * as path21 from "node:path";
14767
+ import * as fs20 from "node:fs";
14768
+ import * as path22 from "node:path";
14719
14769
  function extractUsage(data) {
14720
14770
  try {
14721
14771
  const u = data?.usage ?? data?.usageMetadata;
@@ -14730,9 +14780,9 @@ function extractUsage(data) {
14730
14780
  }
14731
14781
  }
14732
14782
  function resolveLatestImage(specifiedPath, mediaDir) {
14733
- if (specifiedPath && fs19.existsSync(specifiedPath)) return specifiedPath;
14734
- if (!fs19.existsSync(mediaDir)) return null;
14735
- const files = fs19.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp|mp4|mov)$/i.test(f)).map((f) => ({ name: f, p: path21.join(mediaDir, f), mtime: fs19.statSync(path21.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
14783
+ if (specifiedPath && fs20.existsSync(specifiedPath)) return specifiedPath;
14784
+ if (!fs20.existsSync(mediaDir)) return null;
14785
+ const files = fs20.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp|mp4|mov)$/i.test(f)).map((f) => ({ name: f, p: path22.join(mediaDir, f), mtime: fs20.statSync(path22.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
14736
14786
  return files[0]?.p || null;
14737
14787
  }
14738
14788
  var MIME_MAP, VIDEO_EXT, VIDEO_MAX_BYTES;
@@ -14780,15 +14830,15 @@ var init_my_eyes = __esm({
14780
14830
  if (!provider?.streamChat) {
14781
14831
  return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
14782
14832
  }
14783
- const mediaDir = path21.join(ctx.stateDir, "media", "inbound");
14833
+ const mediaDir = path22.join(ctx.stateDir, "media", "inbound");
14784
14834
  const imagePath = resolveLatestImage(args.image_path, mediaDir);
14785
14835
  if (!imagePath) {
14786
14836
  return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
14787
14837
  }
14788
14838
  const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
14789
- const ext = path21.extname(imagePath).toLowerCase();
14839
+ const ext = path22.extname(imagePath).toLowerCase();
14790
14840
  if (VIDEO_EXT.test(imagePath)) {
14791
- const stat4 = fs19.statSync(imagePath);
14841
+ const stat4 = fs20.statSync(imagePath);
14792
14842
  if (stat4.size > VIDEO_MAX_BYTES) {
14793
14843
  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
14844
  }
@@ -14802,7 +14852,7 @@ var init_my_eyes = __esm({
14802
14852
  }
14803
14853
  const explicit = liveConfig.get("tools.my_eyes.videoBaseUrl");
14804
14854
  const baseUrl = explicit || vProviderCfg.baseUrl.replace(/\/anthropic\/?$/, "/v1").replace(/\/$/, "");
14805
- const vidB64 = fs19.readFileSync(imagePath).toString("base64");
14855
+ const vidB64 = fs20.readFileSync(imagePath).toString("base64");
14806
14856
  try {
14807
14857
  const res = await fetch(`${baseUrl}/chat/completions`, {
14808
14858
  method: "POST",
@@ -14833,7 +14883,7 @@ var init_my_eyes = __esm({
14833
14883
  }
14834
14884
  }
14835
14885
  const mime = MIME_MAP[ext] || "jpeg";
14836
- const imgB64 = fs19.readFileSync(imagePath).toString("base64");
14886
+ const imgB64 = fs20.readFileSync(imagePath).toString("base64");
14837
14887
  const userMsg = {
14838
14888
  role: "user",
14839
14889
  content: [
@@ -14868,7 +14918,7 @@ var init_my_eyes = __esm({
14868
14918
  });
14869
14919
 
14870
14920
  // src/tools/opus-encoder.ts
14871
- import * as fs20 from "node:fs";
14921
+ import * as fs21 from "node:fs";
14872
14922
  function oggCrc32(buf) {
14873
14923
  let crc = 0;
14874
14924
  for (let i = 0; i < buf.length; i++) {
@@ -14928,7 +14978,7 @@ async function wavToOggOpusNative(wavPath) {
14928
14978
  const mod = await import("@discordjs/opus");
14929
14979
  const OpusEncoder = mod.OpusEncoder ?? mod.default?.OpusEncoder;
14930
14980
  if (!OpusEncoder) throw new Error("@discordjs/opus export shape unexpected");
14931
- const wav = parseWav(fs20.readFileSync(wavPath));
14981
+ const wav = parseWav(fs21.readFileSync(wavPath));
14932
14982
  if (wav.channels !== 1) throw new Error(`unsupported ${wav.channels}ch (need mono)`);
14933
14983
  if (!NATIVE_RATES.includes(wav.sampleRate)) throw new Error(`unsupported rate ${wav.sampleRate}`);
14934
14984
  if (wav.pcm.length === 0) throw new Error("empty pcm data");
@@ -14964,7 +15014,7 @@ async function wavToOggOpusNative(wavPath) {
14964
15014
  }
14965
15015
  ogg.page(cur, pageGranule, false, true);
14966
15016
  const oggPath = wavPath.replace(/\.wav$/, ".ogg");
14967
- fs20.writeFileSync(oggPath, ogg.finish());
15017
+ fs21.writeFileSync(oggPath, ogg.finish());
14968
15018
  return oggPath;
14969
15019
  }
14970
15020
  var FRAME_MS, PRESKIP_48K, OPUS_RATE, NATIVE_RATES, BITRATE, CRC_TABLE, OggWriter;
@@ -15072,8 +15122,8 @@ var init_voice_chat_tts_daemon = __esm({
15072
15122
  import { execFile as execFile2 } from "node:child_process";
15073
15123
  import { createInterface as createInterface2 } from "node:readline";
15074
15124
  import { promisify } from "node:util";
15075
- import * as fs21 from "node:fs";
15076
- import * as path22 from "node:path";
15125
+ import * as fs22 from "node:fs";
15126
+ import * as path23 from "node:path";
15077
15127
  import * as os4 from "node:os";
15078
15128
  function wavDurationSec(buf) {
15079
15129
  if (buf.length < 12 || buf.toString("ascii", 0, 4) !== "RIFF" || buf.toString("ascii", 8, 12) !== "WAVE") {
@@ -15128,8 +15178,8 @@ function resolvePython(configuredPath) {
15128
15178
  // LOCALAPPDATA 缺席(非 Windows / 精简环境)时**不加这两个候选**:
15129
15179
  // 拼出来会是相对路径 'Microsoft/WindowsApps/python.exe',那可能撞上 cwd 里的东西。
15130
15180
  ...localAppData ? [
15131
- path22.join(localAppData, "Microsoft", "WindowsApps", "python3.exe"),
15132
- path22.join(localAppData, "Microsoft", "WindowsApps", "python.exe")
15181
+ path23.join(localAppData, "Microsoft", "WindowsApps", "python3.exe"),
15182
+ path23.join(localAppData, "Microsoft", "WindowsApps", "python.exe")
15133
15183
  ] : []
15134
15184
  ];
15135
15185
  for (const c of candidates) {
@@ -15149,8 +15199,8 @@ async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction
15149
15199
  }
15150
15200
  async function ttsCosyvoiceStream(text, cfg, onChunk) {
15151
15201
  const { apiKey, model, voice, workspaceId, instruction } = cfg;
15152
- fs21.mkdirSync(VOICE_DIR, { recursive: true });
15153
- const output = path22.join(VOICE_DIR, `tts_${Date.now()}.wav`);
15202
+ fs22.mkdirSync(VOICE_DIR, { recursive: true });
15203
+ const output = path23.join(VOICE_DIR, `tts_${Date.now()}.wav`);
15154
15204
  const script = `
15155
15205
  import sys, json, base64, threading
15156
15206
  import dashscope
@@ -15235,7 +15285,7 @@ print('EOS')
15235
15285
  header.writeUInt16LE(16, 34);
15236
15286
  header.write("data", 36);
15237
15287
  header.writeUInt32LE(pcm.length, 40);
15238
- fs21.writeFileSync(output, Buffer.concat([header, pcm]));
15288
+ fs22.writeFileSync(output, Buffer.concat([header, pcm]));
15239
15289
  return output;
15240
15290
  }
15241
15291
  async function ttsQwen3Local(text, cfg, onChunk) {
@@ -15287,9 +15337,9 @@ async function ttsQwen3Opus(text, cfg) {
15287
15337
  const ogg = Buffer.from(await res.arrayBuffer());
15288
15338
  if (ogg.length < 20) throw new Error("qwen3-3060 opus: empty output");
15289
15339
  const durationMs = parseInt(res.headers.get("x-duration-ms") || "0", 10);
15290
- fs21.mkdirSync(VOICE_DIR, { recursive: true });
15291
- const oggPath = path22.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
15292
- fs21.writeFileSync(oggPath, ogg);
15340
+ fs22.mkdirSync(VOICE_DIR, { recursive: true });
15341
+ const oggPath = path23.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
15342
+ fs22.writeFileSync(oggPath, ogg);
15293
15343
  return { oggPath, durationMs };
15294
15344
  }
15295
15345
  async function ttsGptsovits(text, c) {
@@ -15301,8 +15351,8 @@ async function ttsGptsovits(text, c) {
15301
15351
  "gptsovits \u672A\u914D\u7F6E\uFF1A\u9700\u8981 tools.my_voice \u91CC\u7684 gptsovitsUrl / gptsovitsRefWav / gptsovitsRefText\u3002\u53C2\u8003\u97F3\u9891\u4E0E\u53C2\u8003\u6587\u672C**\u5FC5\u987B\u9010\u5B57\u5BF9\u5E94**\uFF0C\u5426\u5219\u5408\u6210\u51FA\u6765\u7684\u58F0\u97F3\u4F1A\u5E26\u6742\u97F3\uFF080925 \u8E29\u8FC7\u88C1\u574F ref.wav \u7684\u5751\uFF09\u3002"
15302
15352
  );
15303
15353
  }
15304
- fs21.mkdirSync(VOICE_DIR, { recursive: true });
15305
- const output = path22.join(VOICE_DIR, `tts_${Date.now()}.wav`);
15354
+ fs22.mkdirSync(VOICE_DIR, { recursive: true });
15355
+ const output = path23.join(VOICE_DIR, `tts_${Date.now()}.wav`);
15306
15356
  const params = new URLSearchParams({
15307
15357
  text,
15308
15358
  text_language: "zh",
@@ -15313,12 +15363,12 @@ async function ttsGptsovits(text, c) {
15313
15363
  const res = await fetch(`${url}/?${params}`);
15314
15364
  if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
15315
15365
  const buf = Buffer.from(await res.arrayBuffer());
15316
- fs21.writeFileSync(output, buf);
15366
+ fs22.writeFileSync(output, buf);
15317
15367
  return output;
15318
15368
  }
15319
15369
  async function ttsEdge(text) {
15320
- fs21.mkdirSync(VOICE_DIR, { recursive: true });
15321
- const output = path22.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
15370
+ fs22.mkdirSync(VOICE_DIR, { recursive: true });
15371
+ const output = path23.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
15322
15372
  const script = `
15323
15373
  import asyncio, edge_tts, sys
15324
15374
  async def main():
@@ -15356,8 +15406,8 @@ async function synthQwen3(text, _sink) {
15356
15406
  const pcmChunks = [];
15357
15407
  await ttsQwen3Local(text, { url: c.url, voice: c.voice, lang: c.lang }, (pcm2) => pcmChunks.push(pcm2));
15358
15408
  const pcm = Buffer.concat(pcmChunks);
15359
- fs21.mkdirSync(VOICE_DIR, { recursive: true });
15360
- const wavPath = path22.join(VOICE_DIR, `tts_${Date.now()}.wav`);
15409
+ fs22.mkdirSync(VOICE_DIR, { recursive: true });
15410
+ const wavPath = path23.join(VOICE_DIR, `tts_${Date.now()}.wav`);
15361
15411
  const header = Buffer.alloc(44);
15362
15412
  header.write("RIFF", 0);
15363
15413
  header.writeUInt32LE(36 + pcm.length, 4);
@@ -15372,7 +15422,7 @@ async function synthQwen3(text, _sink) {
15372
15422
  header.writeUInt16LE(16, 34);
15373
15423
  header.write("data", 36);
15374
15424
  header.writeUInt32LE(pcm.length, 40);
15375
- fs21.writeFileSync(wavPath, Buffer.concat([header, pcm]));
15425
+ fs22.writeFileSync(wavPath, Buffer.concat([header, pcm]));
15376
15426
  return { path: wavPath, format: "wav", unit: unit(text), voice: c.voice };
15377
15427
  }
15378
15428
  }
@@ -15388,7 +15438,7 @@ var init_impl = __esm({
15388
15438
  init_well_formed();
15389
15439
  init_voice_chat_tts_daemon();
15390
15440
  execFileAsync = promisify(execFile2);
15391
- VOICE_DIR = path22.join(os4.tmpdir(), "engine-voice");
15441
+ VOICE_DIR = path23.join(os4.tmpdir(), "engine-voice");
15392
15442
  _pyCache = null;
15393
15443
  EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
15394
15444
  unit = (text) => ({ kind: "chars", amount: [...text].length });
@@ -15402,9 +15452,9 @@ var init_impl = __esm({
15402
15452
  });
15403
15453
 
15404
15454
  // src/tools/tts/relay.ts
15405
- import * as fs22 from "node:fs";
15455
+ import * as fs23 from "node:fs";
15406
15456
  import * as os5 from "node:os";
15407
- import * as path23 from "node:path";
15457
+ import * as path24 from "node:path";
15408
15458
  async function synthRelay(text, cfg) {
15409
15459
  const res = await fetchFn(`${cfg.baseUrl}/audio/speech`, {
15410
15460
  method: "POST",
@@ -15422,9 +15472,9 @@ async function synthRelay(text, cfg) {
15422
15472
  }
15423
15473
  const buf = Buffer.from(await res.arrayBuffer());
15424
15474
  if (buf.length < 20) throw new Error(`relay tts: \u54CD\u5E94\u4F53\u53EA\u6709 ${buf.length} \u5B57\u8282\uFF0C\u4E0D\u662F\u6709\u6548\u97F3\u9891`);
15425
- fs22.mkdirSync(VOICE_DIR2, { recursive: true });
15426
- const out = path23.join(VOICE_DIR2, `tts_relay_${Date.now()}.mp3`);
15427
- fs22.writeFileSync(out, buf);
15475
+ fs23.mkdirSync(VOICE_DIR2, { recursive: true });
15476
+ const out = path24.join(VOICE_DIR2, `tts_relay_${Date.now()}.mp3`);
15477
+ fs23.writeFileSync(out, buf);
15428
15478
  return {
15429
15479
  path: out,
15430
15480
  format: "mp3",
@@ -15437,7 +15487,7 @@ var VOICE_DIR2, fetchFn;
15437
15487
  var init_relay = __esm({
15438
15488
  "src/tools/tts/relay.ts"() {
15439
15489
  "use strict";
15440
- VOICE_DIR2 = path23.join(os5.tmpdir(), "engine-voice");
15490
+ VOICE_DIR2 = path24.join(os5.tmpdir(), "engine-voice");
15441
15491
  fetchFn = fetch;
15442
15492
  }
15443
15493
  });
@@ -15562,7 +15612,7 @@ var init_providers = __esm({
15562
15612
  if (r.warning) console.warn(`[my-voice] ${r.warning}`);
15563
15613
  if (!r.voice) {
15564
15614
  throw new TtsConfigError(
15565
- "relay TTS \u7F3A\u97F3\u8272\uFF1Atools.my_voice.voice \u662F\u7A7A\u7684\uFF0C\u4E0A\u6E38\u4F1A\u62D2\u3002\u514D\u8D39\u6863\u88C5\u673A\u5E94\u5DF2\u7531 applyFreeTier \u586B\u597D\u9ED8\u8BA4\u97F3\u8272\u3002"
15615
+ "relay TTS \u7F3A\u97F3\u8272\uFF1Atools.my_voice.voice \u662F\u7A7A\u7684\uFF0C\u4E0A\u6E38\u4F1A\u62D2\u3002\u514D\u8D39\u6863\u88C5\u673A\u5E94\u5DF2\u81EA\u52A8\u586B\u597D\u9ED8\u8BA4\u97F3\u8272\uFF08\u65B0\u88C5\u673A generateConfig / \u8001\u88C5\u673A\u542F\u52A8\u8865\u9F50 / \u5207\u6362\u514D\u8D39\u6863 applyFreeTier \u4E09\u6761\u8DEF\uFF0C\u89C1 cli-init-config.ts \u7684 freeTierVoiceConfig\uFF09\u3002"
15566
15616
  );
15567
15617
  }
15568
15618
  try {
@@ -15608,13 +15658,13 @@ var init_providers = __esm({
15608
15658
  });
15609
15659
 
15610
15660
  // src/utils/ffmpeg-path.ts
15611
- import * as fs23 from "node:fs";
15661
+ import * as fs24 from "node:fs";
15612
15662
  function resolveFfmpegPath() {
15613
15663
  const env = (process.env.E7_FFMPEG_PATH || "").trim();
15614
- if (env && fs23.existsSync(env)) return env;
15664
+ if (env && fs24.existsSync(env)) return env;
15615
15665
  try {
15616
15666
  const p = __require("@ffmpeg-installer/ffmpeg")?.path;
15617
- if (p && fs23.existsSync(p)) return p;
15667
+ if (p && fs24.existsSync(p)) return p;
15618
15668
  } catch {
15619
15669
  }
15620
15670
  return "ffmpeg";
@@ -15628,8 +15678,8 @@ var init_ffmpeg_path = __esm({
15628
15678
  // src/tools/my-voice.ts
15629
15679
  import { execFile as execFile3 } from "node:child_process";
15630
15680
  import { promisify as promisify2 } from "node:util";
15631
- import * as fs24 from "node:fs";
15632
- import * as path24 from "node:path";
15681
+ import * as fs25 from "node:fs";
15682
+ import * as path25 from "node:path";
15633
15683
  async function toWav24kWithDuration(audioPath) {
15634
15684
  let wavPath = audioPath;
15635
15685
  if (!audioPath.endsWith(".wav")) {
@@ -15646,15 +15696,15 @@ async function toWav24kWithDuration(audioPath) {
15646
15696
  "pcm_s16le",
15647
15697
  wavPath
15648
15698
  ], { timeout: 3e4 });
15649
- if (!fs24.existsSync(wavPath) || fs24.statSync(wavPath).size < 44) {
15699
+ if (!fs25.existsSync(wavPath) || fs25.statSync(wavPath).size < 44) {
15650
15700
  throw new Error("toWav24k produced empty output");
15651
15701
  }
15652
15702
  try {
15653
- fs24.unlinkSync(audioPath);
15703
+ fs25.unlinkSync(audioPath);
15654
15704
  } catch {
15655
15705
  }
15656
15706
  }
15657
- const durationSec = wavDurationSec(fs24.readFileSync(wavPath));
15707
+ const durationSec = wavDurationSec(fs25.readFileSync(wavPath));
15658
15708
  return { wavPath, durationSec };
15659
15709
  }
15660
15710
  async function compressWav(wavPath) {
@@ -15672,7 +15722,7 @@ async function compressWav(wavPath) {
15672
15722
  "+faststart",
15673
15723
  m4aPath
15674
15724
  ], { timeout: 3e4 });
15675
- fs24.unlinkSync(wavPath);
15725
+ fs25.unlinkSync(wavPath);
15676
15726
  return m4aPath;
15677
15727
  } catch {
15678
15728
  return wavPath;
@@ -15699,10 +15749,10 @@ async function wavToOggOpus(wavPath) {
15699
15749
  oggPath
15700
15750
  ], { timeout: 3e4 });
15701
15751
  }
15702
- if (!fs24.existsSync(oggPath) || fs24.statSync(oggPath).size < 20) {
15752
+ if (!fs25.existsSync(oggPath) || fs25.statSync(oggPath).size < 20) {
15703
15753
  throw new Error("ogg/opus encode produced empty output");
15704
15754
  }
15705
- fs24.unlinkSync(wavPath);
15755
+ fs25.unlinkSync(wavPath);
15706
15756
  return oggPath;
15707
15757
  }
15708
15758
  async function sendVoiceToMulticaIssue(text, issueId, opts) {
@@ -15717,7 +15767,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
15717
15767
  } catch (e) {
15718
15768
  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 };
15719
15769
  }
15720
- if (!audioPath || !fs24.existsSync(audioPath)) {
15770
+ if (!audioPath || !fs25.existsSync(audioPath)) {
15721
15771
  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 };
15722
15772
  }
15723
15773
  if (audioPath.endsWith(".wav")) {
@@ -15727,21 +15777,21 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
15727
15777
  console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
15728
15778
  }
15729
15779
  }
15730
- const ext = path24.extname(audioPath).toLowerCase();
15731
- const sizeKB = fs24.statSync(audioPath).size / 1024;
15780
+ const ext = path25.extname(audioPath).toLowerCase();
15781
+ const sizeKB = fs25.statSync(audioPath).size / 1024;
15732
15782
  const voiceFile = `voice_${Date.now()}${ext}`;
15733
- const cwdCopy = path24.join(process.cwd(), voiceFile);
15783
+ const cwdCopy = path25.join(process.cwd(), voiceFile);
15734
15784
  try {
15735
- fs24.copyFileSync(audioPath, cwdCopy);
15785
+ fs25.copyFileSync(audioPath, cwdCopy);
15736
15786
  } catch (e) {
15737
15787
  try {
15738
- fs24.unlinkSync(audioPath);
15788
+ fs25.unlinkSync(audioPath);
15739
15789
  } catch {
15740
15790
  }
15741
15791
  return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
15742
15792
  }
15743
15793
  try {
15744
- fs24.unlinkSync(audioPath);
15794
+ fs25.unlinkSync(audioPath);
15745
15795
  } catch {
15746
15796
  }
15747
15797
  const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
@@ -15770,13 +15820,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
15770
15820
  }
15771
15821
  if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
15772
15822
  try {
15773
- fs24.unlinkSync(cwdCopy);
15823
+ fs25.unlinkSync(cwdCopy);
15774
15824
  } catch {
15775
15825
  }
15776
15826
  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)` };
15777
15827
  } catch (e) {
15778
15828
  try {
15779
- fs24.unlinkSync(cwdCopy);
15829
+ fs25.unlinkSync(cwdCopy);
15780
15830
  } catch {
15781
15831
  }
15782
15832
  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 };
@@ -15811,7 +15861,7 @@ var init_my_voice = __esm({
15811
15861
  description: "TTS engine. relay = 7yi \u4E2D\u8F6C\u7AD9\uFF08\u514D\u8D39\u6863\u9ED8\u8BA4\uFF09\uFF0Ccosyvoice = \u767E\u70BC API\uFF0Cgptsovits = \u672C\u5730\u514B\u9686\uFF0Cqwen3-3060 = \u672C\u5730 GGML\uFF0Cedge = \u515C\u5E95\u3002"
15812
15862
  },
15813
15863
  channel: { type: "string", enum: ["weixin", "feishu", "discord"], description: "Target channel. Default: current channel." },
15814
- to: { type: "string", description: "Recipient ID. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\u3002\u4E0D\u786E\u5B9A\u5C31\u5148 read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002multaca \u4EFB\u52A1\u91CC\u4E0D\u9700\u8981\u586B to\u2014\u2014\u8BED\u97F3\u4F1A\u6302\u5230\u5F53\u524D issue \u8BC4\u8BBA\uFF0C\u586B issueId \u6307\u5B9A\u76EE\u6807 issue\u3002" },
15864
+ to: { type: "string", description: 'Recipient ID, ONLY when sending to someone else. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\uFF1B\u53D1\u7ED9\u522B\u4EBA\u524D read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002**\u53D1\u7ED9\u5F53\u524D\u5BF9\u8BDD\u7684\u4EBA\uFF08"\u53D1\u7ED9\u6211/\u53D1\u6761\u8BED\u97F3"\uFF09\u4E0D\u8981\u586B to**\u2014\u2014\u7559\u7A7A\u5373\u53D1\u5F53\u524D\u4F1A\u8BDD\uFF0C\u8FD9\u662F\u9ED8\u8BA4\u4E5F\u662F\u66F4\u7A33\u7684\u8DEF\uFF08\u90E8\u5206\u79DF\u6237\u4F1A\u62D2"\u6309\u7528\u6237 ID \u76F4\u53D1"\uFF0C\u89C1 1001 \u6848\u4F8B\uFF09\u3002multaca \u4EFB\u52A1\u91CC\u4E0D\u9700\u8981\u586B to\u2014\u2014\u8BED\u97F3\u4F1A\u6302\u5230\u5F53\u524D issue \u8BC4\u8BBA\uFF0C\u586B issueId \u6307\u5B9A\u76EE\u6807 issue\u3002' },
15815
15865
  issueId: { type: "string", description: 'multaca headless \u4E13\u7528\uFF1A\u76EE\u6807 issue ID\uFF08\u4EFB\u52A1 prompt \u91CC\u7684 "Your assigned issue ID"\uFF09\u3002\u666E\u901A\u98DE\u4E66/\u5FAE\u4FE1\u573A\u666F\u4E0D\u8981\u586B\u3002' },
15816
15866
  caption: { type: "string", description: "Optional text to accompany the voice message." }
15817
15867
  },
@@ -15906,10 +15956,10 @@ var init_my_voice = __esm({
15906
15956
  audioPath = await compressWav(audioPath);
15907
15957
  }
15908
15958
  }
15909
- const ext = path24.extname(audioPath).toLowerCase();
15959
+ const ext = path25.extname(audioPath).toLowerCase();
15910
15960
  const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
15911
15961
  const mimeType = mimeMap[ext] || "audio/mpeg";
15912
- const sizeKB = fs24.statSync(audioPath).size / 1024;
15962
+ const sizeKB = fs25.statSync(audioPath).size / 1024;
15913
15963
  try {
15914
15964
  await mgr.sendFile(resolvedChannel, target, caption, {
15915
15965
  path: audioPath,
@@ -15918,12 +15968,13 @@ var init_my_voice = __esm({
15918
15968
  ...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
15919
15969
  });
15920
15970
  try {
15921
- fs24.unlinkSync(audioPath);
15971
+ fs25.unlinkSync(audioPath);
15922
15972
  } catch {
15923
15973
  }
15924
15974
  return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
15925
15975
  } catch (err) {
15926
- return { content: `Voice send failed: ${err.message}`, isError: true };
15976
+ const toHint = args.to ? '\u3002\u26A0\uFE0F \u8FD9\u6B21\u5E26\u7684\u662F to=\u6536\u4EF6\u4EBA ID\uFF1A\u82E5\u6536\u4EF6\u4EBA\u5C31\u662F**\u5F53\u524D\u5BF9\u8BDD\u7684\u4EBA**\uFF0C\u53BB\u6389 to \u91CD\u8BD5\u2014\u2014\u5F15\u64CE\u4F1A\u53D1\u7ED9\u5F53\u524D\u4F1A\u8BDD\uFF0C\u90E8\u5206\u79DF\u6237\u4F1A\u62D2"\u6309\u7528\u6237 ID \u76F4\u53D1"\uFF08\u98DE\u4E66 230101\uFF09' : "";
15977
+ return { content: `Voice send failed: ${err.message}${toHint}`, isError: true };
15927
15978
  }
15928
15979
  },
15929
15980
  isConcurrencySafe: () => false,
@@ -15940,8 +15991,8 @@ __export(my_selfie_exports, {
15940
15991
  dimsOf: () => dimsOf,
15941
15992
  resolvePortraitDesc: () => resolvePortraitDesc
15942
15993
  });
15943
- import * as fs25 from "node:fs";
15944
- import * as path25 from "node:path";
15994
+ import * as fs26 from "node:fs";
15995
+ import * as path26 from "node:path";
15945
15996
  function getProxyDispatcher2() {
15946
15997
  const cfg = liveConfig.all();
15947
15998
  const proxy = cfg.providers?.xai?.proxy;
@@ -15955,7 +16006,7 @@ function getProxyDispatcher2() {
15955
16006
  }
15956
16007
  function dimsOf(p) {
15957
16008
  try {
15958
- const b = fs25.readFileSync(p);
16009
+ const b = fs26.readFileSync(p);
15959
16010
  let w = 0, h = 0;
15960
16011
  if (b.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
15961
16012
  w = b.readUInt32BE(16);
@@ -16068,9 +16119,9 @@ function registerPortrait(relPath, name) {
16068
16119
  const cur = cfg?.tools?.my_selfie?.references || cfg?.my_selfie?.references || [];
16069
16120
  const next = Array.isArray(cur) ? cur.filter((r) => r?.name !== name) : [];
16070
16121
  next.unshift({ name, path: relPath });
16071
- const path43 = cfg?.tools?.my_selfie ? "tools.my_selfie.references" : "my_selfie.references";
16072
- void liveConfig.set(path43, next);
16073
- console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${path43}[0] = ${relPath}`);
16122
+ const path44 = cfg?.tools?.my_selfie ? "tools.my_selfie.references" : "my_selfie.references";
16123
+ void liveConfig.set(path44, next);
16124
+ console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${path44}[0] = ${relPath}`);
16074
16125
  } catch (e) {
16075
16126
  console.warn(`[my-selfie] \u5199\u5165 references \u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u51FA\u56FE\uFF09: ${e.message}`);
16076
16127
  }
@@ -16368,10 +16419,10 @@ var init_my_selfie = __esm({
16368
16419
  const REFERENCES = getReferences(ctx);
16369
16420
  const refName = args.reference || "default";
16370
16421
  const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
16371
- let refPath = path25.join(ctx.workspace, refEntry.p);
16422
+ let refPath = path26.join(ctx.workspace, refEntry.p);
16372
16423
  const adoptImg = args.referenceImage?.trim();
16373
16424
  if (adoptImg) {
16374
- if (!fs25.existsSync(adoptImg)) {
16425
+ if (!fs26.existsSync(adoptImg)) {
16375
16426
  return { content: `\u627E\u4E0D\u5230\u90A3\u5F20\u56FE\uFF1A${adoptImg}`, isError: true };
16376
16427
  }
16377
16428
  const acheck = dimsOf(adoptImg);
@@ -16382,16 +16433,16 @@ var init_my_selfie = __esm({
16382
16433
  isError: true
16383
16434
  };
16384
16435
  }
16385
- const adir = path25.join(ctx.workspace, "images");
16386
- if (!fs25.existsSync(adir)) fs25.mkdirSync(adir, { recursive: true });
16387
- const aext = (path25.extname(adoptImg) || ".png").toLowerCase();
16436
+ const adir = path26.join(ctx.workspace, "images");
16437
+ if (!fs26.existsSync(adir)) fs26.mkdirSync(adir, { recursive: true });
16438
+ const aext = (path26.extname(adoptImg) || ".png").toLowerCase();
16388
16439
  const afname = `portrait_${Date.now()}${aext}`;
16389
- fs25.copyFileSync(adoptImg, path25.join(adir, afname));
16440
+ fs26.copyFileSync(adoptImg, path26.join(adir, afname));
16390
16441
  registerPortrait(`images/${afname}`, refName);
16391
- refPath = path25.join(adir, afname);
16442
+ refPath = path26.join(adir, afname);
16392
16443
  console.log(`[my-selfie] \u91C7\u7EB3\u73B0\u6210\u56FE\u5F53\u5F62\u8C61\uFF1Aimages/${afname}${acheck ? ` (${acheck})` : ""}`);
16393
16444
  }
16394
- if (provider !== "autodl" && !fs25.existsSync(refPath)) {
16445
+ if (provider !== "autodl" && !fs26.existsSync(refPath)) {
16395
16446
  const cfgAll = liveConfig.all();
16396
16447
  const portraitDesc = resolvePortraitDesc(
16397
16448
  args.portrait,
@@ -16416,16 +16467,16 @@ var init_my_selfie = __esm({
16416
16467
  } catch (e) {
16417
16468
  return { content: `\u5851\u9020\u5F62\u8C61\u5931\u8D25\uFF1A${e.message}`, isError: true };
16418
16469
  }
16419
- const pdir = path25.join(ctx.workspace, "images");
16420
- if (!fs25.existsSync(pdir)) fs25.mkdirSync(pdir, { recursive: true });
16470
+ const pdir = path26.join(ctx.workspace, "images");
16471
+ if (!fs26.existsSync(pdir)) fs26.mkdirSync(pdir, { recursive: true });
16421
16472
  const pfname = `portrait_${Date.now()}.png`;
16422
- fs25.writeFileSync(path25.join(pdir, pfname), portraitBuf);
16473
+ fs26.writeFileSync(path26.join(pdir, pfname), portraitBuf);
16423
16474
  registerPortrait(`images/${pfname}`, refName);
16424
- refPath = path25.join(pdir, pfname);
16475
+ refPath = path26.join(pdir, pfname);
16425
16476
  console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u5B58 images/${pfname}\uFF0C\u7EE7\u7EED\u8FD9\u6B21\u81EA\u62CD`);
16426
16477
  }
16427
16478
  const resolution = args.resolution || DEFAULT_RESOLUTION;
16428
- const refB64 = fs25.existsSync(refPath) ? fs25.readFileSync(refPath).toString("base64") : "";
16479
+ const refB64 = fs26.existsSync(refPath) ? fs26.readFileSync(refPath).toString("base64") : "";
16429
16480
  let imageBuffer;
16430
16481
  try {
16431
16482
  if (provider === "autodl") {
@@ -16441,7 +16492,7 @@ var init_my_selfie = __esm({
16441
16492
  return { content: `Error: relay provider \u672A\u914D\u7F6E\u3002config \u91CC\u8981\u6709 models.providers.${cfgAll?.my_selfie?.relayProviderId || "7yi"} \u7684 baseUrl \u548C apiKey\u3002`, isError: true };
16442
16493
  }
16443
16494
  const model = cfgAll?.my_selfie?.relayModel || cfgAll?.tools?.my_selfie?.relayModel || "engine7-img-free";
16444
- const ext = path25.extname(refPath).toLowerCase();
16495
+ const ext = path26.extname(refPath).toLowerCase();
16445
16496
  const mime = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
16446
16497
  imageBuffer = await generateWithRelay(refB64, fullPrompt, mime, relay.baseUrl, relay.apiKey, model);
16447
16498
  } else {
@@ -16450,11 +16501,11 @@ var init_my_selfie = __esm({
16450
16501
  } catch (err) {
16451
16502
  return { content: `Selfie generation failed: ${err.message}`, isError: true };
16452
16503
  }
16453
- const imagesDir = path25.join(ctx.workspace, "images");
16454
- if (!fs25.existsSync(imagesDir)) fs25.mkdirSync(imagesDir, { recursive: true });
16504
+ const imagesDir = path26.join(ctx.workspace, "images");
16505
+ if (!fs26.existsSync(imagesDir)) fs26.mkdirSync(imagesDir, { recursive: true });
16455
16506
  const filename = `selfie_${Date.now()}.jpg`;
16456
- const outputPath = path25.join(imagesDir, filename);
16457
- fs25.writeFileSync(outputPath, imageBuffer);
16507
+ const outputPath = path26.join(imagesDir, filename);
16508
+ fs26.writeFileSync(outputPath, imageBuffer);
16458
16509
  const mgr = ctx.channelManager;
16459
16510
  if (mgr) {
16460
16511
  const resolvedChannel = ctx.channel || "feishu";
@@ -16465,11 +16516,11 @@ var init_my_selfie = __esm({
16465
16516
  mimeType: "image/jpeg"
16466
16517
  });
16467
16518
  } catch (err) {
16468
- return { content: `Selfie generated but send failed: ${err.message}. Image: ${path25.resolve(outputPath)}`, isError: false };
16519
+ return { content: `Selfie generated but send failed: ${err.message}. Image: ${path26.resolve(outputPath)}`, isError: false };
16469
16520
  }
16470
16521
  return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
16471
16522
  }
16472
- return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path25.resolve(outputPath)}` };
16523
+ return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path26.resolve(outputPath)}` };
16473
16524
  },
16474
16525
  isConcurrencySafe: () => false,
16475
16526
  interruptBehavior: () => "block",
@@ -17299,8 +17350,8 @@ var init_calendar = __esm({
17299
17350
  });
17300
17351
 
17301
17352
  // src/tools/service.ts
17302
- import * as fs26 from "node:fs";
17303
- import * as path26 from "node:path";
17353
+ import * as fs27 from "node:fs";
17354
+ import * as path27 from "node:path";
17304
17355
  import { exec, spawn as spawn4 } from "node:child_process";
17305
17356
  import { promisify as promisify3 } from "node:util";
17306
17357
  function getServices() {
@@ -17308,9 +17359,9 @@ function getServices() {
17308
17359
  }
17309
17360
  function serviceLogPath(fileName) {
17310
17361
  const stateDir = String(liveConfig.get("stateDir") ?? "");
17311
- const logDir = path26.join(stateDir, "logs");
17312
- if (!fs26.existsSync(logDir)) fs26.mkdirSync(logDir, { recursive: true });
17313
- return path26.join(logDir, fileName);
17362
+ const logDir = path27.join(stateDir, "logs");
17363
+ if (!fs27.existsSync(logDir)) fs27.mkdirSync(logDir, { recursive: true });
17364
+ return path27.join(logDir, fileName);
17314
17365
  }
17315
17366
  async function runCmd(cmd, timeoutMs = 15e3) {
17316
17367
  try {
@@ -17525,24 +17576,24 @@ var init_constants5 = __esm({
17525
17576
  });
17526
17577
 
17527
17578
  // src/tools/TodoWriteTool/TodoWriteTool.ts
17528
- import fs27 from "node:fs";
17529
- import path27 from "node:path";
17579
+ import fs28 from "node:fs";
17580
+ import path28 from "node:path";
17530
17581
  function todoFilePath(sessionId) {
17531
- return path27.join(todosDir, `${sessionId}.json`);
17582
+ return path28.join(todosDir, `${sessionId}.json`);
17532
17583
  }
17533
17584
  function loadTodos(sessionId) {
17534
17585
  if (!todosDir) return [];
17535
17586
  try {
17536
17587
  const filePath = todoFilePath(sessionId);
17537
- if (!fs27.existsSync(filePath)) return [];
17538
- return JSON.parse(fs27.readFileSync(filePath, "utf-8"));
17588
+ if (!fs28.existsSync(filePath)) return [];
17589
+ return JSON.parse(fs28.readFileSync(filePath, "utf-8"));
17539
17590
  } catch {
17540
17591
  return [];
17541
17592
  }
17542
17593
  }
17543
17594
  function saveTodos(sessionId, todos) {
17544
17595
  if (!todosDir) return;
17545
- fs27.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
17596
+ fs28.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
17546
17597
  }
17547
17598
  var todosDir;
17548
17599
  var init_TodoWriteTool = __esm({
@@ -17799,15 +17850,15 @@ var init_constants7 = __esm({
17799
17850
  });
17800
17851
 
17801
17852
  // src/utils/plans.ts
17802
- import * as fs28 from "node:fs";
17803
- import * as path28 from "node:path";
17853
+ import * as fs29 from "node:fs";
17854
+ import * as path29 from "node:path";
17804
17855
  import * as crypto4 from "node:crypto";
17805
17856
  function generateSlug() {
17806
17857
  return crypto4.randomBytes(4).toString("hex");
17807
17858
  }
17808
17859
  function getPlansDirectory(stateDir) {
17809
- const plansDir = path28.join(stateDir, "plans");
17810
- fs28.mkdirSync(plansDir, { recursive: true });
17860
+ const plansDir = path29.join(stateDir, "plans");
17861
+ fs29.mkdirSync(plansDir, { recursive: true });
17811
17862
  return plansDir;
17812
17863
  }
17813
17864
  function getPlanSlug(sessionId, stateDir) {
@@ -17816,8 +17867,8 @@ function getPlanSlug(sessionId, stateDir) {
17816
17867
  const plansDir = getPlansDirectory(stateDir);
17817
17868
  for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
17818
17869
  slug = generateSlug();
17819
- const filePath = path28.join(plansDir, `${slug}.md`);
17820
- if (!fs28.existsSync(filePath)) {
17870
+ const filePath = path29.join(plansDir, `${slug}.md`);
17871
+ if (!fs29.existsSync(filePath)) {
17821
17872
  break;
17822
17873
  }
17823
17874
  }
@@ -17828,21 +17879,21 @@ function getPlanSlug(sessionId, stateDir) {
17828
17879
  function getPlanFilePath(sessionId, stateDir, agentId) {
17829
17880
  const slug = getPlanSlug(sessionId, stateDir);
17830
17881
  if (!agentId) {
17831
- return path28.join(getPlansDirectory(stateDir), `${slug}.md`);
17882
+ return path29.join(getPlansDirectory(stateDir), `${slug}.md`);
17832
17883
  }
17833
- return path28.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
17884
+ return path29.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
17834
17885
  }
17835
17886
  function getPlan(sessionId, stateDir, agentId) {
17836
17887
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
17837
17888
  try {
17838
- return fs28.readFileSync(filePath, "utf-8");
17889
+ return fs29.readFileSync(filePath, "utf-8");
17839
17890
  } catch {
17840
17891
  return null;
17841
17892
  }
17842
17893
  }
17843
17894
  function writePlan(sessionId, stateDir, content, agentId) {
17844
17895
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
17845
- fs28.writeFileSync(filePath, content, "utf-8");
17896
+ fs29.writeFileSync(filePath, content, "utf-8");
17846
17897
  return filePath;
17847
17898
  }
17848
17899
  var MAX_SLUG_RETRIES, planSlugCache;
@@ -17990,28 +18041,28 @@ var init_constants8 = __esm({
17990
18041
  });
17991
18042
 
17992
18043
  // src/utils/tasks.ts
17993
- import * as fs29 from "node:fs";
17994
- import * as path29 from "node:path";
18044
+ import * as fs30 from "node:fs";
18045
+ import * as path30 from "node:path";
17995
18046
  function sanitizePathComponent2(input) {
17996
18047
  return input.replace(/[^a-zA-Z0-9_-]/g, "-");
17997
18048
  }
17998
18049
  function getTasksDir2(stateDir, listId) {
17999
- return path29.join(stateDir, "tasks", sanitizePathComponent2(listId));
18050
+ return path30.join(stateDir, "tasks", sanitizePathComponent2(listId));
18000
18051
  }
18001
18052
  function getTaskPath(stateDir, listId, taskId) {
18002
- return path29.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
18053
+ return path30.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
18003
18054
  }
18004
18055
  function ensureTasksDir2(stateDir, listId) {
18005
18056
  const dir = getTasksDir2(stateDir, listId);
18006
- fs29.mkdirSync(dir, { recursive: true });
18057
+ fs30.mkdirSync(dir, { recursive: true });
18007
18058
  return dir;
18008
18059
  }
18009
18060
  function getHighWaterMarkPath(stateDir, listId) {
18010
- return path29.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
18061
+ return path30.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
18011
18062
  }
18012
18063
  function readHighWaterMark(stateDir, listId) {
18013
18064
  try {
18014
- const content = fs29.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
18065
+ const content = fs30.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
18015
18066
  const value = parseInt(content, 10);
18016
18067
  return isNaN(value) ? 0 : value;
18017
18068
  } catch {
@@ -18019,13 +18070,13 @@ function readHighWaterMark(stateDir, listId) {
18019
18070
  }
18020
18071
  }
18021
18072
  function writeHighWaterMark(stateDir, listId, value) {
18022
- fs29.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
18073
+ fs30.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
18023
18074
  }
18024
18075
  function findHighestTaskIdFromFiles(stateDir, listId) {
18025
18076
  const dir = getTasksDir2(stateDir, listId);
18026
18077
  let files;
18027
18078
  try {
18028
- files = fs29.readdirSync(dir);
18079
+ files = fs30.readdirSync(dir);
18029
18080
  } catch {
18030
18081
  return 0;
18031
18082
  }
@@ -18051,14 +18102,14 @@ function createTask(stateDir, listId, taskData) {
18051
18102
  const id = String(highestId + 1);
18052
18103
  const task = { id, ...taskData };
18053
18104
  const filePath = getTaskPath(stateDir, listId, id);
18054
- fs29.writeFileSync(filePath, JSON.stringify(task, null, 2));
18105
+ fs30.writeFileSync(filePath, JSON.stringify(task, null, 2));
18055
18106
  return id;
18056
18107
  });
18057
18108
  }
18058
18109
  function getTask2(stateDir, listId, taskId) {
18059
18110
  const filePath = getTaskPath(stateDir, listId, taskId);
18060
18111
  try {
18061
- const content = fs29.readFileSync(filePath, "utf-8");
18112
+ const content = fs30.readFileSync(filePath, "utf-8");
18062
18113
  return JSON.parse(content);
18063
18114
  } catch {
18064
18115
  return null;
@@ -18068,7 +18119,7 @@ function listTasks2(stateDir, listId) {
18068
18119
  const dir = getTasksDir2(stateDir, listId);
18069
18120
  let files;
18070
18121
  try {
18071
- files = fs29.readdirSync(dir);
18122
+ files = fs30.readdirSync(dir);
18072
18123
  } catch {
18073
18124
  return [];
18074
18125
  }
@@ -18080,7 +18131,7 @@ function updateTask(stateDir, listId, taskId, updates) {
18080
18131
  if (!existing) return null;
18081
18132
  const updated = { ...existing, ...updates, id: taskId };
18082
18133
  const filePath = getTaskPath(stateDir, listId, taskId);
18083
- fs29.writeFileSync(filePath, JSON.stringify(updated, null, 2));
18134
+ fs30.writeFileSync(filePath, JSON.stringify(updated, null, 2));
18084
18135
  return updated;
18085
18136
  }
18086
18137
  function deleteTask(stateDir, listId, taskId) {
@@ -18094,7 +18145,7 @@ function deleteTask(stateDir, listId, taskId) {
18094
18145
  }
18095
18146
  }
18096
18147
  try {
18097
- fs29.unlinkSync(filePath);
18148
+ fs30.unlinkSync(filePath);
18098
18149
  } catch {
18099
18150
  return false;
18100
18151
  }
@@ -19527,10 +19578,10 @@ function ensureLoaded(workspace, configIds) {
19527
19578
  if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
19528
19579
  }
19529
19580
  }
19530
- const path43 = join28(workspace, ".reply-blocklist.json");
19581
+ const path44 = join28(workspace, ".reply-blocklist.json");
19531
19582
  try {
19532
- if (existsSync22(path43)) {
19533
- const raw = readFileSync21(path43, "utf-8");
19583
+ if (existsSync22(path44)) {
19584
+ const raw = readFileSync21(path44, "utf-8");
19534
19585
  const parsed = JSON.parse(raw);
19535
19586
  if (parsed.blockedUserIds) {
19536
19587
  for (const id of parsed.blockedUserIds) {
@@ -19546,9 +19597,9 @@ function ensureLoaded(workspace, configIds) {
19546
19597
  loaded = true;
19547
19598
  }
19548
19599
  function save(workspace) {
19549
- const path43 = join28(workspace, ".reply-blocklist.json");
19600
+ const path44 = join28(workspace, ".reply-blocklist.json");
19550
19601
  try {
19551
- writeFileSync16(path43, JSON.stringify(state, null, 2), "utf-8");
19602
+ writeFileSync16(path44, JSON.stringify(state, null, 2), "utf-8");
19552
19603
  } catch (err) {
19553
19604
  console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
19554
19605
  }
@@ -20744,8 +20795,8 @@ var extractMemories_exports = {};
20744
20795
  __export(extractMemories_exports, {
20745
20796
  createMemoryExtractor: () => createMemoryExtractor
20746
20797
  });
20747
- import * as fs30 from "fs";
20748
- import * as path30 from "path";
20798
+ import * as fs31 from "fs";
20799
+ import * as path31 from "path";
20749
20800
  function isModelVisibleMessage(message) {
20750
20801
  return message.role === "user" || message.role === "assistant";
20751
20802
  }
@@ -20768,13 +20819,13 @@ function getMemoryTools() {
20768
20819
  return allDefs.filter((d) => MEMORY_TOOL_NAMES.includes(d.function.name));
20769
20820
  }
20770
20821
  function getStatePath(workspace) {
20771
- return path30.join(workspace, STATE_FILE);
20822
+ return path31.join(workspace, STATE_FILE);
20772
20823
  }
20773
20824
  function loadPersistedState(workspace) {
20774
20825
  try {
20775
20826
  const p = getStatePath(workspace);
20776
- if (fs30.existsSync(p)) {
20777
- const data = JSON.parse(fs30.readFileSync(p, "utf-8"));
20827
+ if (fs31.existsSync(p)) {
20828
+ const data = JSON.parse(fs31.readFileSync(p, "utf-8"));
20778
20829
  for (const [sid, ts] of Object.entries(data.lastTs ?? {})) {
20779
20830
  lastTsMap.set(sid, ts);
20780
20831
  }
@@ -20794,7 +20845,7 @@ function persistState(workspace) {
20794
20845
  for (const [sid, ts] of lastTsMap.entries()) lastTs[sid] = ts;
20795
20846
  for (const [sid, ts] of lastExtractTimeMap.entries()) timestamps[sid] = ts;
20796
20847
  const data = JSON.stringify({ lastTs, timestamps }, null, 2);
20797
- fs30.writeFileSync(getStatePath(workspace), data, "utf-8");
20848
+ fs31.writeFileSync(getStatePath(workspace), data, "utf-8");
20798
20849
  } catch (e) {
20799
20850
  console.warn(`[memory] failed to persist extract state: ${e?.message ?? e}`);
20800
20851
  }
@@ -20835,11 +20886,11 @@ function createMemoryExtractor(workspace, enabled) {
20835
20886
  const existingMemories = formatMemoryManifest(
20836
20887
  await scanMemoryFiles2(memoryDir, new AbortController().signal)
20837
20888
  );
20838
- const extractOverridePath = path30.join(workspace, "prompts", "extract.md");
20889
+ const extractOverridePath = path31.join(workspace, "prompts", "extract.md");
20839
20890
  let systemPrompt;
20840
20891
  try {
20841
- if (fs30.existsSync(extractOverridePath)) {
20842
- systemPrompt = fs30.readFileSync(extractOverridePath, { encoding: "utf-8" });
20892
+ if (fs31.existsSync(extractOverridePath)) {
20893
+ systemPrompt = fs31.readFileSync(extractOverridePath, { encoding: "utf-8" });
20843
20894
  if (existingMemories.length > 0) {
20844
20895
  systemPrompt += `
20845
20896
 
@@ -20965,8 +21016,8 @@ __export(ingest_exports, {
20965
21016
  pushConversation: () => pushConversation,
20966
21017
  toPayload: () => toPayload
20967
21018
  });
20968
- import fs31 from "node:fs";
20969
- import path31 from "node:path";
21019
+ import fs32 from "node:fs";
21020
+ import path32 from "node:path";
20970
21021
  async function readConfig() {
20971
21022
  const defaults = {
20972
21023
  url: "http://127.0.0.1:8100",
@@ -20996,9 +21047,9 @@ async function readConfig() {
20996
21047
  }
20997
21048
  function loadPushTs(workspace, sessionId) {
20998
21049
  try {
20999
- const p = path31.join(workspace, PUSH_STATE_FILE);
21000
- if (fs31.existsSync(p)) {
21001
- const data = JSON.parse(fs31.readFileSync(p, "utf-8"));
21050
+ const p = path32.join(workspace, PUSH_STATE_FILE);
21051
+ if (fs32.existsSync(p)) {
21052
+ const data = JSON.parse(fs32.readFileSync(p, "utf-8"));
21002
21053
  return typeof data[sessionId] === "number" ? data[sessionId] : 0;
21003
21054
  }
21004
21055
  } catch (e) {
@@ -21008,14 +21059,14 @@ function loadPushTs(workspace, sessionId) {
21008
21059
  }
21009
21060
  function savePushTs(workspace, sessionId, ts) {
21010
21061
  try {
21011
- const p = path31.join(workspace, PUSH_STATE_FILE);
21062
+ const p = path32.join(workspace, PUSH_STATE_FILE);
21012
21063
  let data = {};
21013
21064
  try {
21014
- if (fs31.existsSync(p)) data = JSON.parse(fs31.readFileSync(p, "utf-8"));
21065
+ if (fs32.existsSync(p)) data = JSON.parse(fs32.readFileSync(p, "utf-8"));
21015
21066
  } catch {
21016
21067
  }
21017
21068
  data[sessionId] = ts;
21018
- fs31.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
21069
+ fs32.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
21019
21070
  } catch (e) {
21020
21071
  console.warn(`[everos-ingest] save pushTs failed: ${e?.message ?? e}`);
21021
21072
  }
@@ -27940,11 +27991,11 @@ async function readLastConsolidatedAt(memoryDir) {
27940
27991
  }
27941
27992
  }
27942
27993
  async function tryAcquireConsolidationLock(memoryDir) {
27943
- const path43 = lockPath(memoryDir);
27994
+ const path44 = lockPath(memoryDir);
27944
27995
  let mtimeMs;
27945
27996
  let holderPid;
27946
27997
  try {
27947
- const [s, raw] = await Promise.all([stat3(path43), readFile5(path43, "utf8")]);
27998
+ const [s, raw] = await Promise.all([stat3(path44), readFile5(path44, "utf8")]);
27948
27999
  mtimeMs = s.mtimeMs;
27949
28000
  const parsed = parseInt(raw.trim(), 10);
27950
28001
  holderPid = Number.isFinite(parsed) ? parsed : void 0;
@@ -27957,10 +28008,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
27957
28008
  }
27958
28009
  }
27959
28010
  await mkdir3(memoryDir, { recursive: true });
27960
- await writeFile4(path43, String(process.pid));
28011
+ await writeFile4(path44, String(process.pid));
27961
28012
  let verify2;
27962
28013
  try {
27963
- verify2 = await readFile5(path43, "utf8");
28014
+ verify2 = await readFile5(path44, "utf8");
27964
28015
  } catch {
27965
28016
  return null;
27966
28017
  }
@@ -27968,15 +28019,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
27968
28019
  return mtimeMs ?? 0;
27969
28020
  }
27970
28021
  async function rollbackConsolidationLock(memoryDir, priorMtime) {
27971
- const path43 = lockPath(memoryDir);
28022
+ const path44 = lockPath(memoryDir);
27972
28023
  try {
27973
28024
  if (priorMtime === 0) {
27974
- await unlink(path43);
28025
+ await unlink(path44);
27975
28026
  return;
27976
28027
  }
27977
- await writeFile4(path43, "");
28028
+ await writeFile4(path44, "");
27978
28029
  const t = priorMtime / 1e3;
27979
- await utimes(path43, t, t);
28030
+ await utimes(path44, t, t);
27980
28031
  } catch (e) {
27981
28032
  console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
27982
28033
  }
@@ -28263,7 +28314,7 @@ __export(handle_query_exports, {
28263
28314
  });
28264
28315
  import { readFileSync as readFileSync37, existsSync as existsSync31, statSync as statSync13 } from "node:fs";
28265
28316
  import { join as join48, resolve as resolve8 } from "node:path";
28266
- import * as path32 from "node:path";
28317
+ import * as path33 from "node:path";
28267
28318
  function resolveSystemPrompt(v) {
28268
28319
  return typeof v === "function" ? v() : v || "";
28269
28320
  }
@@ -28271,18 +28322,18 @@ function resetSessionStartInjection(sessionId) {
28271
28322
  sessionStartDone.delete(sessionId);
28272
28323
  }
28273
28324
  function loadExternalChanRules(workspace) {
28274
- const path43 = join48(workspace, "prompts", "external-chan-rules.md");
28275
- if (externalChanRulesCache && externalChanRulesCache.path === path43) return externalChanRulesCache;
28325
+ const path44 = join48(workspace, "prompts", "external-chan-rules.md");
28326
+ if (externalChanRulesCache && externalChanRulesCache.path === path44) return externalChanRulesCache;
28276
28327
  let content = "";
28277
- if (existsSync31(path43)) {
28328
+ if (existsSync31(path44)) {
28278
28329
  try {
28279
- content = readFileSync37(path43, "utf-8").trim();
28330
+ content = readFileSync37(path44, "utf-8").trim();
28280
28331
  } catch (e) {
28281
28332
  console.warn(`[external-chan-rules] Failed to load: ${e}`);
28282
28333
  }
28283
28334
  }
28284
- externalChanRulesCache = { path: path43, content };
28285
- console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path43}`);
28335
+ externalChanRulesCache = { path: path44, content };
28336
+ console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path44}`);
28286
28337
  return externalChanRulesCache;
28287
28338
  }
28288
28339
  function getExternalChanRulesBlock(inboundMeta, workspace) {
@@ -29097,7 +29148,7 @@ stack: ${err.stack ?? "(none)"}`);
29097
29148
  }
29098
29149
  } catch (err) {
29099
29150
  try {
29100
- (await import("node:fs")).appendFileSync(join48(process.env.ENGINE7_STATE_DIR || path32.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
29151
+ (await import("node:fs")).appendFileSync(join48(process.env.ENGINE7_STATE_DIR || path33.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
29101
29152
  stack: ${err.stack ?? "(none)"}
29102
29153
  `);
29103
29154
  } catch {
@@ -29785,8 +29836,8 @@ __export(free_tier_apply_exports, {
29785
29836
  isFreeTierConfig: () => isFreeTierConfig,
29786
29837
  resolveConfigPath: () => resolveConfigPath
29787
29838
  });
29788
- import * as fs32 from "node:fs";
29789
- import * as path33 from "node:path";
29839
+ import * as fs33 from "node:fs";
29840
+ import * as path34 from "node:path";
29790
29841
  function isFreeTierConfig(cfg) {
29791
29842
  const hasProvider = !!cfg?.models?.providers?.[FREE_TIER_PROVIDER_ID];
29792
29843
  const primary = String(cfg?.agents?.defaults?.model?.primary || "");
@@ -29822,31 +29873,23 @@ function applyFreeTier(cfg, opts = {}) {
29822
29873
  const mv = cfg.tools.my_voice || null;
29823
29874
  const existingProvider = typeof mv?.provider === "string" ? mv.provider : "";
29824
29875
  if (!mv || existingProvider === "relay") {
29825
- cfg.tools.my_voice = {
29826
- ...mv || {},
29827
- provider: "relay",
29828
- relayProviderId: FREE_TIER_PROVIDER_ID,
29829
- // '7yi'
29830
- relayModel: "engine7-tts",
29831
- // 有块就不夺 ⇒ 走到这里时 mv 要么不存在、要么 voice 就是 relay 的;非 relay 的块已跳过
29832
- voice: mv?.voice || DEFAULT_FREE_VOICE
29833
- };
29876
+ cfg.tools.my_voice = freeTierVoiceConfig(mv);
29834
29877
  }
29835
29878
  return cfg;
29836
29879
  }
29837
29880
  function resolveConfigPath(stateDir, configName) {
29838
- const configsDir = path33.join(stateDir, "configs");
29881
+ const configsDir = path34.join(stateDir, "configs");
29839
29882
  if (configName) {
29840
- const p = path33.join(configsDir, configName);
29841
- return fs32.existsSync(p) ? p : "";
29842
- }
29843
- const main2 = path33.join(configsDir, "main7.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"))) {
29847
- const full = path33.join(configsDir, f);
29883
+ const p = path34.join(configsDir, configName);
29884
+ return fs33.existsSync(p) ? p : "";
29885
+ }
29886
+ const main2 = path34.join(configsDir, "main7.json");
29887
+ if (fs33.existsSync(main2)) return main2;
29888
+ if (!fs33.existsSync(configsDir)) return "";
29889
+ for (const f of fs33.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
29890
+ const full = path34.join(configsDir, f);
29848
29891
  try {
29849
- if (JSON.parse(fs32.readFileSync(full, "utf8")).models?.providers) return full;
29892
+ if (JSON.parse(fs33.readFileSync(full, "utf8")).models?.providers) return full;
29850
29893
  } catch {
29851
29894
  }
29852
29895
  }
@@ -29855,16 +29898,16 @@ function resolveConfigPath(stateDir, configName) {
29855
29898
  function applyFreeTierToConfig(configPath, opts = {}) {
29856
29899
  let cfg;
29857
29900
  try {
29858
- cfg = JSON.parse(fs32.readFileSync(configPath, "utf8"));
29901
+ cfg = JSON.parse(fs33.readFileSync(configPath, "utf8"));
29859
29902
  } catch (e) {
29860
29903
  throw new Error(`\u8BFB\u53D6 config \u5931\u8D25: ${configPath}\uFF08${e?.message || e}\uFF09`);
29861
29904
  }
29862
29905
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
29863
29906
  const backupPath = `${configPath}.bak-${stamp}`;
29864
- fs32.copyFileSync(configPath, backupPath);
29907
+ fs33.copyFileSync(configPath, backupPath);
29865
29908
  applyFreeTier(cfg, opts);
29866
29909
  try {
29867
- fs32.writeFileSync(configPath, JSON.stringify(cfg, null, 2), "utf8");
29910
+ fs33.writeFileSync(configPath, JSON.stringify(cfg, null, 2), "utf8");
29868
29911
  } catch (e) {
29869
29912
  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}`);
29870
29913
  }
@@ -29876,15 +29919,14 @@ function applyFreeTierToConfig(configPath, opts = {}) {
29876
29919
  video: cfg.agents.defaults.model.video ?? null
29877
29920
  };
29878
29921
  }
29879
- var FREE_TIER_PROVIDER_ID, FREE_TIER_PRIMARY, DEFAULT_FREE_VOICE;
29922
+ var FREE_TIER_PRIMARY;
29880
29923
  var init_free_tier_apply = __esm({
29881
29924
  "src/free-tier-apply.ts"() {
29882
29925
  "use strict";
29883
29926
  init_cli_init_config();
29884
29927
  init_provision_free();
29885
- FREE_TIER_PROVIDER_ID = "7yi";
29928
+ init_cli_init_config();
29886
29929
  FREE_TIER_PRIMARY = "7yi/engine7-free";
29887
- DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
29888
29930
  }
29889
29931
  });
29890
29932
 
@@ -29894,15 +29936,15 @@ __export(cli_doctor_exports, {
29894
29936
  resolveStateDirFromArgs: () => resolveStateDirFromArgs,
29895
29937
  runDoctor: () => runDoctor
29896
29938
  });
29897
- import * as fs33 from "node:fs";
29898
- import * as path34 from "node:path";
29939
+ import * as fs34 from "node:fs";
29940
+ import * as path35 from "node:path";
29899
29941
  import * as net from "node:net";
29900
29942
  import { fileURLToPath as fileURLToPath6 } from "node:url";
29901
29943
  function readVersion() {
29902
- const here = path34.dirname(fileURLToPath6(import.meta.url));
29903
- for (const p of [path34.join(here, "..", "package.json"), path34.join(here, "..", "..", "package.json")]) {
29944
+ const here = path35.dirname(fileURLToPath6(import.meta.url));
29945
+ for (const p of [path35.join(here, "..", "package.json"), path35.join(here, "..", "..", "package.json")]) {
29904
29946
  try {
29905
- return JSON.parse(fs33.readFileSync(p, "utf8")).version || "unknown";
29947
+ return JSON.parse(fs34.readFileSync(p, "utf8")).version || "unknown";
29906
29948
  } catch {
29907
29949
  }
29908
29950
  }
@@ -29932,7 +29974,7 @@ function probePort(port, timeoutMs) {
29932
29974
  });
29933
29975
  }
29934
29976
  async function runDoctor(stateDir, opts) {
29935
- const configPath = path34.join(stateDir, "configs", "main7.json");
29977
+ const configPath = path35.join(stateDir, "configs", "main7.json");
29936
29978
  const report = {
29937
29979
  version: readVersion(),
29938
29980
  stateDir,
@@ -29948,10 +29990,10 @@ async function runDoctor(stateDir, opts) {
29948
29990
  };
29949
29991
  let config = null;
29950
29992
  try {
29951
- config = JSON.parse(fs33.readFileSync(configPath, "utf8"));
29993
+ config = JSON.parse(fs34.readFileSync(configPath, "utf8"));
29952
29994
  report.configValid = true;
29953
29995
  } catch (e) {
29954
- report.configError = fs33.existsSync(configPath) ? `\u89E3\u6790\u5931\u8D25: ${e.message}` : "config \u4E0D\u5B58\u5728\uFF08\u5148 engine7 init\uFF09";
29996
+ report.configError = fs34.existsSync(configPath) ? `\u89E3\u6790\u5931\u8D25: ${e.message}` : "config \u4E0D\u5B58\u5728\uFF08\u5148 engine7 init\uFF09";
29955
29997
  }
29956
29998
  if (config?.channels) {
29957
29999
  for (const [name, conf] of Object.entries(config.channels)) {
@@ -29959,13 +30001,13 @@ async function runDoctor(stateDir, opts) {
29959
30001
  report.channels.push({ name, enabled: !!c.enabled, hasCredentials: channelHasCredentials(name, c) });
29960
30002
  }
29961
30003
  }
29962
- const cfgBase = path34.basename(report.configPath, ".json") || "main7";
30004
+ const cfgBase = path35.basename(report.configPath, ".json") || "main7";
29963
30005
  const candidates = secretsCandidates(stateDir, cfgBase);
29964
- const secretsFile = candidates.find((p) => fs33.existsSync(p)) || candidates[0];
30006
+ const secretsFile = candidates.find((p) => fs34.existsSync(p)) || candidates[0];
29965
30007
  report.secrets.file = secretsFile;
29966
- if (fs33.existsSync(secretsFile)) {
30008
+ if (fs34.existsSync(secretsFile)) {
29967
30009
  report.secrets.exists = true;
29968
- for (const line of fs33.readFileSync(secretsFile, "utf8").split("\n")) {
30010
+ for (const line of fs34.readFileSync(secretsFile, "utf8").split("\n")) {
29969
30011
  const eq = line.indexOf("=");
29970
30012
  if (eq > 0 && !line.startsWith("#")) report.secrets.keys.push(line.slice(0, eq).trim());
29971
30013
  }
@@ -30005,10 +30047,10 @@ async function runDoctor(stateDir, opts) {
30005
30047
  report.missingEnvKeys = [...missing].sort();
30006
30048
  const stale = [];
30007
30049
  for (const rel of ["workspace/SESSION-STATE.md", "SESSION-STATE.md"]) {
30008
- const p = path34.join(stateDir, rel);
30050
+ const p = path35.join(stateDir, rel);
30009
30051
  try {
30010
- if (!fs33.existsSync(p)) continue;
30011
- const head = fs33.readFileSync(p, "utf8").split("\n").slice(0, 10).join("\n");
30052
+ if (!fs34.existsSync(p)) continue;
30053
+ const head = fs34.readFileSync(p, "utf8").split("\n").slice(0, 10).join("\n");
30012
30054
  const m = head.match(/^#{1,3}\s*当前时间\s*$\n+\s*(\d{4}-\d{2}-\d{2})/m);
30013
30055
  if (!m) continue;
30014
30056
  const ageH = (Date.now() - (/* @__PURE__ */ new Date(`${m[1]}T00:00:00Z`)).getTime()) / 36e5;
@@ -30026,19 +30068,19 @@ function resolveStateDirFromArgs(args) {
30026
30068
  for (let i = 0; i < args.length; i++) {
30027
30069
  if (args[i] === "--state-dir" && args[i + 1]) stateDir = args[++i].trim();
30028
30070
  }
30029
- if (stateDir) return path34.resolve(stateDir);
30071
+ if (stateDir) return path35.resolve(stateDir);
30030
30072
  const home = process.env.HOME || process.env.USERPROFILE || ".";
30031
- const cwd = path34.resolve(process.cwd());
30032
- if (fs33.existsSync(path34.join(cwd, "configs"))) return cwd;
30033
- const pointer = path34.join(home, ".engine7.json");
30034
- if (fs33.existsSync(pointer)) {
30073
+ const cwd = path35.resolve(process.cwd());
30074
+ if (fs34.existsSync(path35.join(cwd, "configs"))) return cwd;
30075
+ const pointer = path35.join(home, ".engine7.json");
30076
+ if (fs34.existsSync(pointer)) {
30035
30077
  try {
30036
- const ptrStateDir = JSON.parse(fs33.readFileSync(pointer, "utf8")).stateDir;
30037
- if (typeof ptrStateDir === "string" && ptrStateDir.trim()) return path34.resolve(ptrStateDir);
30078
+ const ptrStateDir = JSON.parse(fs34.readFileSync(pointer, "utf8")).stateDir;
30079
+ if (typeof ptrStateDir === "string" && ptrStateDir.trim()) return path35.resolve(ptrStateDir);
30038
30080
  } catch {
30039
30081
  }
30040
30082
  }
30041
- return path34.join(home, ".engine7");
30083
+ return path35.join(home, ".engine7");
30042
30084
  }
30043
30085
  var init_cli_doctor = __esm({
30044
30086
  "src/cli-doctor.ts"() {
@@ -30051,8 +30093,8 @@ var init_cli_doctor = __esm({
30051
30093
  });
30052
30094
 
30053
30095
  // src/config/writer.ts
30054
- import fs34 from "node:fs";
30055
- import path35 from "node:path";
30096
+ import fs35 from "node:fs";
30097
+ import path36 from "node:path";
30056
30098
  function isNormalized(text) {
30057
30099
  if (text === "") return true;
30058
30100
  if (text.includes("\r")) return false;
@@ -30067,13 +30109,13 @@ function isNormalized(text) {
30067
30109
  return minIndent === 2 || minIndent === Infinity;
30068
30110
  }
30069
30111
  function rotateBaks(filePath) {
30070
- const dir = path35.dirname(filePath);
30071
- const base = path35.basename(filePath);
30072
- const baks = fs34.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30112
+ const dir = path36.dirname(filePath);
30113
+ const base = path36.basename(filePath);
30114
+ const baks = fs35.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30073
30115
  while (baks.length >= KEEP_BAKS) {
30074
30116
  const victim = baks.shift();
30075
30117
  try {
30076
- fs34.unlinkSync(path35.join(dir, victim));
30118
+ fs35.unlinkSync(path36.join(dir, victim));
30077
30119
  } catch {
30078
30120
  }
30079
30121
  }
@@ -30092,7 +30134,7 @@ function writeFailure(filePath, primary, extra) {
30092
30134
  function renameWithRetry(from, to) {
30093
30135
  for (let attempt = 1; ; attempt++) {
30094
30136
  try {
30095
- fs34.renameSync(from, to);
30137
+ fs35.renameSync(from, to);
30096
30138
  return;
30097
30139
  } catch (err) {
30098
30140
  if (attempt >= RENAME_ATTEMPTS || !RETRYABLE_CODES.has(errCode(err))) throw err;
@@ -30107,32 +30149,32 @@ function commitFile(tmp, filePath) {
30107
30149
  } catch (primaryErr) {
30108
30150
  const old = `${filePath}.old`;
30109
30151
  try {
30110
- fs34.renameSync(filePath, old);
30152
+ fs35.renameSync(filePath, old);
30111
30153
  } catch (err) {
30112
30154
  throw writeFailure(filePath, primaryErr, `\u6539\u540D .old \u5907\u4EFD\u4E5F\u5931\u8D25\uFF08${errCode(err) || "\u672A\u77E5"}\uFF09`);
30113
30155
  }
30114
30156
  try {
30115
- fs34.renameSync(tmp, filePath);
30157
+ fs35.renameSync(tmp, filePath);
30116
30158
  } catch (err) {
30117
30159
  try {
30118
- fs34.renameSync(old, filePath);
30160
+ fs35.renameSync(old, filePath);
30119
30161
  } catch {
30120
30162
  throw writeFailure(filePath, primaryErr, `\u65B0\u5185\u5BB9\u843D\u76D8\u4E0E\u56DE\u6EDA\u90FD\u5931\u8D25\uFF0C\u65E7\u5185\u5BB9\u7559\u5728 ${old}`);
30121
30163
  }
30122
30164
  throw writeFailure(filePath, primaryErr, `\u6362\u540D\u843D\u76D8\u5931\u8D25\uFF08${errCode(err) || "\u672A\u77E5"}\uFF09`);
30123
30165
  }
30124
30166
  try {
30125
- fs34.unlinkSync(old);
30167
+ fs35.unlinkSync(old);
30126
30168
  } catch {
30127
30169
  }
30128
30170
  }
30129
30171
  }
30130
30172
  function writeConfigAtomic(filePath, obj) {
30131
- const existed = fs34.existsSync(filePath);
30173
+ const existed = fs35.existsSync(filePath);
30132
30174
  let prevText = "";
30133
30175
  if (existed) {
30134
30176
  try {
30135
- prevText = fs34.readFileSync(filePath, "utf-8");
30177
+ prevText = fs35.readFileSync(filePath, "utf-8");
30136
30178
  } catch (err) {
30137
30179
  throw writeFailure(filePath, err);
30138
30180
  }
@@ -30140,27 +30182,27 @@ function writeConfigAtomic(filePath, obj) {
30140
30182
  const normalized = !existed || !isNormalized(prevText);
30141
30183
  if (prevText) {
30142
30184
  try {
30143
- fs34.copyFileSync(filePath, `${filePath}.bak-${Date.now()}`);
30185
+ fs35.copyFileSync(filePath, `${filePath}.bak-${Date.now()}`);
30144
30186
  } catch {
30145
30187
  }
30146
30188
  rotateBaks(filePath);
30147
30189
  }
30148
30190
  const content = JSON.stringify(obj, null, 2) + "\n";
30149
- const tmp = path35.join(path35.dirname(filePath), `.${path35.basename(filePath)}.tmp-${process.pid}`);
30191
+ const tmp = path36.join(path36.dirname(filePath), `.${path36.basename(filePath)}.tmp-${process.pid}`);
30150
30192
  try {
30151
- const fd = fs34.openSync(tmp, "w");
30193
+ const fd = fs35.openSync(tmp, "w");
30152
30194
  try {
30153
- fs34.writeFileSync(fd, content, "utf-8");
30154
- fs34.fsyncSync(fd);
30195
+ fs35.writeFileSync(fd, content, "utf-8");
30196
+ fs35.fsyncSync(fd);
30155
30197
  } finally {
30156
- fs34.closeSync(fd);
30198
+ fs35.closeSync(fd);
30157
30199
  }
30158
30200
  commitFile(tmp, filePath);
30159
30201
  } catch (err) {
30160
30202
  throw err instanceof ConfigWriteError ? err : writeFailure(filePath, err);
30161
30203
  } finally {
30162
30204
  try {
30163
- fs34.unlinkSync(tmp);
30205
+ fs35.unlinkSync(tmp);
30164
30206
  } catch {
30165
30207
  }
30166
30208
  }
@@ -30186,18 +30228,18 @@ var init_writer2 = __esm({
30186
30228
  });
30187
30229
 
30188
30230
  // src/config/secrets-io.ts
30189
- import fs35 from "node:fs";
30190
- import path36 from "node:path";
30231
+ import fs36 from "node:fs";
30232
+ import path37 from "node:path";
30191
30233
  function resolveSecretPath(stateDir, configName) {
30192
30234
  return secretsCandidates(stateDir, configName)[0];
30193
30235
  }
30194
30236
  function resolveSecretReadPath(stateDir, configName) {
30195
- return secretsCandidates(stateDir, configName).find((c) => fs35.existsSync(c)) ?? null;
30237
+ return secretsCandidates(stateDir, configName).find((c) => fs36.existsSync(c)) ?? null;
30196
30238
  }
30197
30239
  function readSecretStatus(stateDir, configName, names) {
30198
30240
  const p = resolveSecretReadPath(stateDir, configName);
30199
30241
  const out = {};
30200
- const text = p ? fs35.readFileSync(p, "utf-8") : "";
30242
+ const text = p ? fs36.readFileSync(p, "utf-8") : "";
30201
30243
  const present = /* @__PURE__ */ new Set();
30202
30244
  for (const line of text.split("\n")) {
30203
30245
  const t = line.trim();
@@ -30210,7 +30252,7 @@ function readSecretStatus(stateDir, configName, names) {
30210
30252
  return out;
30211
30253
  }
30212
30254
  function writeSecret(stateDir, configName, name, value) {
30213
- writeSecretsValue(path36.join(stateDir, "configs", `${configName}.json`), name, value);
30255
+ writeSecretsValue(path37.join(stateDir, "configs", `${configName}.json`), name, value);
30214
30256
  }
30215
30257
  var init_secrets_io = __esm({
30216
30258
  "src/config/secrets-io.ts"() {
@@ -30220,8 +30262,8 @@ var init_secrets_io = __esm({
30220
30262
  });
30221
30263
 
30222
30264
  // src/config/migrations/index.ts
30223
- import fs36 from "node:fs";
30224
- import path37 from "node:path";
30265
+ import fs37 from "node:fs";
30266
+ import path38 from "node:path";
30225
30267
  function registerMigration(m) {
30226
30268
  if (REGISTRY.has(m.name)) {
30227
30269
  throw new Error(`[migrations] \u8FC1\u79FB "${m.name}" \u91CD\u590D\u6CE8\u518C\u2014\u2014\u540C\u540D\u4F1A\u6309 import \u987A\u5E8F\u9759\u9ED8\u8986\u76D6`);
@@ -30237,21 +30279,21 @@ async function runMigration(name, ctx) {
30237
30279
  return await m.run(ctx);
30238
30280
  }
30239
30281
  function rotateBaks2(filePath) {
30240
- const dir = path37.dirname(filePath);
30241
- const base = path37.basename(filePath);
30242
- const baks = fs36.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30282
+ const dir = path38.dirname(filePath);
30283
+ const base = path38.basename(filePath);
30284
+ const baks = fs37.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
30243
30285
  while (baks.length > KEEP_BAKS2) {
30244
30286
  const victim = baks.shift();
30245
30287
  try {
30246
- fs36.unlinkSync(path37.join(dir, victim));
30288
+ fs37.unlinkSync(path38.join(dir, victim));
30247
30289
  } catch {
30248
30290
  }
30249
30291
  }
30250
30292
  }
30251
30293
  function backupFile(filePath) {
30252
- if (!fs36.existsSync(filePath)) return null;
30294
+ if (!fs37.existsSync(filePath)) return null;
30253
30295
  const bak = `${filePath}.bak-${Date.now()}`;
30254
- fs36.copyFileSync(filePath, bak);
30296
+ fs37.copyFileSync(filePath, bak);
30255
30297
  rotateBaks2(filePath);
30256
30298
  return bak;
30257
30299
  }
@@ -30265,11 +30307,11 @@ var init_migrations = __esm({
30265
30307
  });
30266
30308
 
30267
30309
  // src/config/migrations/persona.ts
30268
- import fs37 from "node:fs";
30269
- import path38 from "node:path";
30310
+ import fs38 from "node:fs";
30311
+ import path39 from "node:path";
30270
30312
  function readFileOrNull(p) {
30271
30313
  try {
30272
- return fs37.readFileSync(p, "utf-8");
30314
+ return fs38.readFileSync(p, "utf-8");
30273
30315
  } catch {
30274
30316
  return null;
30275
30317
  }
@@ -30289,22 +30331,22 @@ var init_persona = __esm({
30289
30331
  run(ctx) {
30290
30332
  const persona = ctx.values?.agents?.defaults?.persona;
30291
30333
  if (typeof persona !== "string" || !persona) return { changed: [] };
30292
- const dir = path38.join(ctx.workspace, "personas", persona);
30293
- if (!fs37.existsSync(dir)) {
30334
+ const dir = path39.join(ctx.workspace, "personas", persona);
30335
+ if (!fs38.existsSync(dir)) {
30294
30336
  return { changed: [] };
30295
30337
  }
30296
30338
  const changed = [];
30297
30339
  for (const name of POINTER_FILES) {
30298
- const src = path38.join(dir, name);
30340
+ const src = path39.join(dir, name);
30299
30341
  const content = readFileOrNull(src);
30300
30342
  if (content === null) continue;
30301
- const legacy = path38.join(ctx.workspace, LEGACY_PATHS[name]);
30343
+ const legacy = path39.join(ctx.workspace, LEGACY_PATHS[name]);
30302
30344
  const legacyContent = readFileOrNull(legacy);
30303
30345
  if (legacyContent !== null && legacyContent === content) {
30304
- fs37.renameSync(legacy, `${legacy}.migrated-${Date.now()}`);
30346
+ fs38.renameSync(legacy, `${legacy}.migrated-${Date.now()}`);
30305
30347
  changed.push(`${LEGACY_PATHS[name]} \u2192 personas/${persona}/${name}`);
30306
30348
  } else if (legacyContent !== null) {
30307
- fs37.renameSync(legacy, `${legacy}.bak-${Date.now()}`);
30349
+ fs38.renameSync(legacy, `${legacy}.bak-${Date.now()}`);
30308
30350
  changed.push(`${LEGACY_PATHS[name]} \u2192 .bak\uFF08\u5185\u5BB9\u4E0E\u6A21\u677F\u4E0D\u540C\uFF0C\u4FDD\u5B88\u4FDD\u7559\uFF09`);
30309
30351
  }
30310
30352
  }
@@ -30316,7 +30358,7 @@ var init_persona = __esm({
30316
30358
  });
30317
30359
 
30318
30360
  // src/config/migrations/channel-secrets.ts
30319
- import fs38 from "node:fs";
30361
+ import fs39 from "node:fs";
30320
30362
  function envNameFor(dotPath) {
30321
30363
  const declared = getField(dotPath)?.envKey;
30322
30364
  if (declared) return declared;
@@ -30358,15 +30400,15 @@ function planChannelSecretMoves(config) {
30358
30400
  }
30359
30401
  function restoreEnv(envPath, before) {
30360
30402
  try {
30361
- if (before === null) fs38.unlinkSync(envPath);
30362
- else fs38.writeFileSync(envPath, before, "utf8");
30403
+ if (before === null) fs39.unlinkSync(envPath);
30404
+ else fs39.writeFileSync(envPath, before, "utf8");
30363
30405
  } catch {
30364
30406
  }
30365
30407
  }
30366
30408
  function dropBackup(backup) {
30367
30409
  if (backup) {
30368
30410
  try {
30369
- fs38.unlinkSync(backup);
30411
+ fs39.unlinkSync(backup);
30370
30412
  } catch {
30371
30413
  }
30372
30414
  }
@@ -30375,7 +30417,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30375
30417
  const writeConfig = deps.writeConfig ?? ((p, obj) => writeConfigAtomic(p, obj));
30376
30418
  let text;
30377
30419
  try {
30378
- text = fs38.readFileSync(configPath, "utf-8");
30420
+ text = fs39.readFileSync(configPath, "utf-8");
30379
30421
  } catch {
30380
30422
  return { changed: [], backup: null, secretsFile: null };
30381
30423
  }
@@ -30392,7 +30434,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30392
30434
  if (moves.length === 0) return { changed: [], backup: null, secretsFile: null };
30393
30435
  const { stateDir, configName } = resolveConfigIdentity(configPath);
30394
30436
  const envPath = secretsCandidates(stateDir, configName)[0];
30395
- const envBefore = fs38.existsSync(envPath) ? fs38.readFileSync(envPath, "utf-8") : null;
30437
+ const envBefore = fs39.existsSync(envPath) ? fs39.readFileSync(envPath, "utf-8") : null;
30396
30438
  const backup = backupFile(configPath);
30397
30439
  try {
30398
30440
  for (const m of moves) writeSecret(stateDir, configName, m.envName, m.value);
@@ -30413,7 +30455,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30413
30455
  const problem = verify(configPath, envPath, moves);
30414
30456
  if (problem) {
30415
30457
  try {
30416
- if (backup) fs38.copyFileSync(backup, configPath);
30458
+ if (backup) fs39.copyFileSync(backup, configPath);
30417
30459
  } catch {
30418
30460
  }
30419
30461
  restoreEnv(envPath, envBefore);
@@ -30425,7 +30467,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
30425
30467
  function verify(configPath, envPath, moves) {
30426
30468
  let cfg;
30427
30469
  try {
30428
- cfg = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
30470
+ cfg = JSON.parse(fs39.readFileSync(configPath, "utf-8"));
30429
30471
  } catch (e) {
30430
30472
  return `config \u8BFB\u4E0D\u56DE\u6765\u4E86\uFF08${e?.message || String(e)}\uFF09`;
30431
30473
  }
@@ -30435,7 +30477,7 @@ function verify(configPath, envPath, moves) {
30435
30477
  }
30436
30478
  let env = "";
30437
30479
  try {
30438
- env = fs38.readFileSync(envPath, "utf-8");
30480
+ env = fs39.readFileSync(envPath, "utf-8");
30439
30481
  } catch (e) {
30440
30482
  return `secrets \u6587\u4EF6\u8BFB\u4E0D\u56DE\u6765\uFF08${e?.message || String(e)}\uFF09`;
30441
30483
  }
@@ -30473,14 +30515,14 @@ __export(cli_config_exports, {
30473
30515
  isSafeConfigName: () => isSafeConfigName,
30474
30516
  runConfigCommand: () => runConfigCommand
30475
30517
  });
30476
- import fs39 from "node:fs";
30477
- import path39 from "node:path";
30518
+ import fs40 from "node:fs";
30519
+ import path40 from "node:path";
30478
30520
  function isSafeConfigName(name) {
30479
30521
  return /^[\w.-]+$/.test(name);
30480
30522
  }
30481
30523
  function sameDir(a, b) {
30482
30524
  const norm = (s) => {
30483
- const r = path39.resolve(s);
30525
+ const r = path40.resolve(s);
30484
30526
  return process.platform === "win32" ? r.toLowerCase() : r;
30485
30527
  };
30486
30528
  return norm(a) === norm(b);
@@ -30508,7 +30550,7 @@ function parseArgs(args) {
30508
30550
  badArgs.push(a);
30509
30551
  }
30510
30552
  if (config) {
30511
- const configPath = path39.resolve(config);
30553
+ const configPath = path40.resolve(config);
30512
30554
  if (!/\.json$/i.test(configPath)) {
30513
30555
  return {
30514
30556
  stateDir,
@@ -30532,9 +30574,9 @@ function parseArgs(args) {
30532
30574
  }
30533
30575
  return { stateDir: ident.stateDir, configPath, configName: ident.configName, file: file2, badArgs };
30534
30576
  }
30535
- if (!stateDir) stateDir = process.env.ENGINE_STATE_DIR || path39.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
30577
+ if (!stateDir) stateDir = process.env.ENGINE_STATE_DIR || path40.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
30536
30578
  const configName = CONFIG_NAME;
30537
- return { stateDir, configPath: path39.join(stateDir, "configs", `${configName}.json`), configName, file: file2, badArgs };
30579
+ return { stateDir, configPath: path40.join(stateDir, "configs", `${configName}.json`), configName, file: file2, badArgs };
30538
30580
  }
30539
30581
  function emit2(obj) {
30540
30582
  process.stdout.write(JSON.stringify(obj) + "\n");
@@ -30572,7 +30614,7 @@ function shapeOf(v) {
30572
30614
  function readConfigObject(configPath) {
30573
30615
  let text;
30574
30616
  try {
30575
- text = fs39.readFileSync(configPath, "utf-8");
30617
+ text = fs40.readFileSync(configPath, "utf-8");
30576
30618
  } catch {
30577
30619
  return { obj: {}, corrupt: false };
30578
30620
  }
@@ -30630,7 +30672,7 @@ function findMaskedCredentials(value, prefix, out) {
30630
30672
  function readEnvKeys(file2) {
30631
30673
  const out = [];
30632
30674
  try {
30633
- for (const line of fs39.readFileSync(file2, "utf-8").split("\n")) {
30675
+ for (const line of fs40.readFileSync(file2, "utf-8").split("\n")) {
30634
30676
  const t = line.trim();
30635
30677
  if (!t || t.startsWith("#")) continue;
30636
30678
  const eq = t.indexOf("=");
@@ -30686,7 +30728,7 @@ async function runConfigCommand(args) {
30686
30728
  }
30687
30729
  let parsedPayload;
30688
30730
  try {
30689
- parsedPayload = JSON.parse(fs39.readFileSync(p.file, "utf-8"));
30731
+ parsedPayload = JSON.parse(fs40.readFileSync(p.file, "utf-8"));
30690
30732
  } catch (e) {
30691
30733
  process.stderr.write(`[config] \u8BFB\u4E0D\u4E86 payload: ${e.message}
30692
30734
  `);
@@ -30792,7 +30834,7 @@ async function runConfigCommand(args) {
30792
30834
  }
30793
30835
  if (secretWrites.length > 0) {
30794
30836
  const writePath2 = resolveSecretPath(p.stateDir, p.configName);
30795
- const fallback = fs39.existsSync(writePath2) ? void 0 : secretsCandidates(p.stateDir, p.configName).find((c) => fs39.existsSync(c));
30837
+ const fallback = fs40.existsSync(writePath2) ? void 0 : secretsCandidates(p.stateDir, p.configName).find((c) => fs40.existsSync(c));
30796
30838
  if (fallback) {
30797
30839
  const writing = new Set(secretWrites.map((s) => s.name));
30798
30840
  const others = readEnvKeys(fallback).filter((k) => !writing.has(k));
@@ -30801,11 +30843,11 @@ async function runConfigCommand(args) {
30801
30843
  }
30802
30844
  }
30803
30845
  }
30804
- if (fs39.existsSync(p.configPath) && !isNormalized(fs39.readFileSync(p.configPath, "utf-8"))) {
30846
+ if (fs40.existsSync(p.configPath) && !isNormalized(fs40.readFileSync(p.configPath, "utf-8"))) {
30805
30847
  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");
30806
30848
  }
30807
- const configDir = path39.dirname(p.configPath);
30808
- if (!fs39.existsSync(configDir)) fs39.mkdirSync(configDir, { recursive: true });
30849
+ const configDir = path40.dirname(p.configPath);
30850
+ if (!fs40.existsSync(configDir)) fs40.mkdirSync(configDir, { recursive: true });
30809
30851
  try {
30810
30852
  writeConfigAtomic(p.configPath, merged);
30811
30853
  } catch (e) {
@@ -30820,7 +30862,7 @@ async function runConfigCommand(args) {
30820
30862
  warnings.push(`secrets \u5199\u5165\u5931\u8D25\uFF08${s.name}\uFF09\uFF1A${e?.message || String(e)}\u2014\u2014config \u5DF2\u5199\u5165`);
30821
30863
  }
30822
30864
  }
30823
- const workspace = path39.join(p.stateDir, "workspace");
30865
+ const workspace = path40.join(p.stateDir, "workspace");
30824
30866
  const ctx = { workspace, stateDir: p.stateDir, values: nested, all: merged, configPath: p.configPath };
30825
30867
  for (const dotPath of [...new Set(changed)]) {
30826
30868
  const migrationName = getField(dotPath)?.migration;
@@ -30909,41 +30951,41 @@ __export(cli_reconfig_exports, {
30909
30951
  doReconfigFeishu: () => doReconfigFeishu,
30910
30952
  doReconfigWechat: () => doReconfigWechat
30911
30953
  });
30912
- import * as fs40 from "node:fs";
30913
- import * as path40 from "node:path";
30954
+ import * as fs41 from "node:fs";
30955
+ import * as path41 from "node:path";
30914
30956
  function scanForChannelsConfig(configsDir) {
30915
- if (!fs40.existsSync(configsDir)) return "";
30916
- for (const f of fs40.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
30917
- const full = path40.join(configsDir, f);
30957
+ if (!fs41.existsSync(configsDir)) return "";
30958
+ for (const f of fs41.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
30959
+ const full = path41.join(configsDir, f);
30918
30960
  try {
30919
- if (JSON.parse(fs40.readFileSync(full, "utf8")).channels) return full;
30961
+ if (JSON.parse(fs41.readFileSync(full, "utf8")).channels) return full;
30920
30962
  } catch {
30921
30963
  }
30922
30964
  }
30923
30965
  return "";
30924
30966
  }
30925
30967
  function findFeishuConfigFile(stateDir, configName) {
30926
- const configsDir = path40.join(stateDir, "configs");
30968
+ const configsDir = path41.join(stateDir, "configs");
30927
30969
  if (configName) {
30928
- const p = path40.join(configsDir, configName);
30929
- if (fs40.existsSync(p)) return p;
30970
+ const p = path41.join(configsDir, configName);
30971
+ if (fs41.existsSync(p)) return p;
30930
30972
  }
30931
30973
  return scanForChannelsConfig(configsDir);
30932
30974
  }
30933
30975
  function findWechatConfigFile(stateDir, configName) {
30934
- const configsDir = path40.join(stateDir, "configs");
30976
+ const configsDir = path41.join(stateDir, "configs");
30935
30977
  if (configName) {
30936
- const p = path40.join(configsDir, configName);
30937
- return fs40.existsSync(p) ? p : "";
30978
+ const p = path41.join(configsDir, configName);
30979
+ return fs41.existsSync(p) ? p : "";
30938
30980
  }
30939
30981
  const scanned = scanForChannelsConfig(configsDir);
30940
30982
  if (scanned) return scanned;
30941
- if (fs40.existsSync(configsDir)) {
30942
- const candidates = fs40.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
30983
+ if (fs41.existsSync(configsDir)) {
30984
+ const candidates = fs41.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
30943
30985
  if (candidates.length) {
30944
- const first = path40.join(configsDir, candidates[0]);
30986
+ const first = path41.join(configsDir, candidates[0]);
30945
30987
  try {
30946
- JSON.parse(fs40.readFileSync(first, "utf8"));
30988
+ JSON.parse(fs41.readFileSync(first, "utf8"));
30947
30989
  return first;
30948
30990
  } catch {
30949
30991
  }
@@ -30982,11 +31024,11 @@ async function doReconfigFeishu(opts) {
30982
31024
  return 2;
30983
31025
  }
30984
31026
  const configFile = findFeishuConfigFile(stateDir, configName);
30985
- if (configFile && fs40.existsSync(configFile)) {
31027
+ if (configFile && fs41.existsSync(configFile)) {
30986
31028
  if (events) emit3?.({ event: "progress", step: "write_config" });
30987
31029
  let j;
30988
31030
  try {
30989
- j = JSON.parse(fs40.readFileSync(configFile, "utf8"));
31031
+ j = JSON.parse(fs41.readFileSync(configFile, "utf8"));
30990
31032
  } catch (err) {
30991
31033
  if (events) emit3?.({ event: "error", message: `\u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
30992
31034
  else console.error(`\u274C \u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -31004,7 +31046,7 @@ async function doReconfigFeishu(opts) {
31004
31046
  }
31005
31047
  j.channels.feishu = { enabled: true, appId: result.appId, appSecret: secretRef(feishuSecretEnv, result.appSecret), connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" };
31006
31048
  try {
31007
- fs40.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
31049
+ fs41.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
31008
31050
  } catch (err) {
31009
31051
  if (events) emit3?.({ event: "error", message: `\u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
31010
31052
  else console.error(`\u274C \u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -31037,7 +31079,7 @@ async function doReconfigWechat(opts) {
31037
31079
  return 2;
31038
31080
  }
31039
31081
  const configFile = findWechatConfigFile(stateDir, configName);
31040
- if (!configFile || !fs40.existsSync(configFile)) {
31082
+ if (!configFile || !fs41.existsSync(configFile)) {
31041
31083
  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");
31042
31084
  console.log(JSON.stringify({ wechat: { enabled: true, token: cred.token, accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } } }, null, 2));
31043
31085
  if (events) emit3?.({ event: "done", channel: "wechat", detail: cred.accountId, restart_required: true });
@@ -31046,7 +31088,7 @@ async function doReconfigWechat(opts) {
31046
31088
  if (events) emit3?.({ event: "progress", step: "write_config" });
31047
31089
  let j;
31048
31090
  try {
31049
- j = JSON.parse(fs40.readFileSync(configFile, "utf8"));
31091
+ j = JSON.parse(fs41.readFileSync(configFile, "utf8"));
31050
31092
  } catch (err) {
31051
31093
  if (events) emit3?.({ event: "error", message: `\u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
31052
31094
  else console.error(`\u274C \u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -31064,7 +31106,7 @@ async function doReconfigWechat(opts) {
31064
31106
  }
31065
31107
  j.channels.wechat = { enabled: true, token: secretRef(wechatSecretEnv, cred.token), accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } };
31066
31108
  try {
31067
- fs40.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
31109
+ fs41.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
31068
31110
  } catch (err) {
31069
31111
  if (events) emit3?.({ event: "error", message: `\u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
31070
31112
  else console.error(`\u274C \u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
@@ -31101,20 +31143,20 @@ __export(cli_travel_exports, {
31101
31143
  resolveArchiveForTest: () => resolveArchiveForTest,
31102
31144
  saveTravelConfig: () => saveTravelConfig
31103
31145
  });
31104
- import * as path41 from "node:path";
31105
- import * as fs41 from "node:fs";
31146
+ import * as path42 from "node:path";
31147
+ import * as fs42 from "node:fs";
31106
31148
  import * as os6 from "node:os";
31107
- import { execSync as execSync2 } from "node:child_process";
31149
+ import { execSync as execSync3 } from "node:child_process";
31108
31150
  function loadTravelConfig() {
31109
31151
  try {
31110
- if (!fs41.existsSync(CONFIG_PATH)) return null;
31111
- return JSON.parse(fs41.readFileSync(CONFIG_PATH, "utf-8"));
31152
+ if (!fs42.existsSync(CONFIG_PATH)) return null;
31153
+ return JSON.parse(fs42.readFileSync(CONFIG_PATH, "utf-8"));
31112
31154
  } catch {
31113
31155
  return null;
31114
31156
  }
31115
31157
  }
31116
31158
  function saveTravelConfig(cfg) {
31117
- fs41.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
31159
+ fs42.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
31118
31160
  }
31119
31161
  function sanitizeContent(content, dirs) {
31120
31162
  let result = content;
@@ -31139,7 +31181,7 @@ function restoreContent(content, dirs) {
31139
31181
  return result;
31140
31182
  }
31141
31183
  function isTextFile(filePath) {
31142
- const ext = path41.extname(filePath).toLowerCase();
31184
+ const ext = path42.extname(filePath).toLowerCase();
31143
31185
  return TEXT_EXTENSIONS.has(ext);
31144
31186
  }
31145
31187
  function shouldExclude(name) {
@@ -31154,14 +31196,14 @@ function shouldExclude(name) {
31154
31196
  }
31155
31197
  function collectFiles(rootDir, includeSet, optionalSet) {
31156
31198
  const files = [];
31157
- const entries2 = fs41.readdirSync(rootDir, { withFileTypes: true });
31199
+ const entries2 = fs42.readdirSync(rootDir, { withFileTypes: true });
31158
31200
  for (const entry of entries2) {
31159
31201
  if (shouldExclude(entry.name)) continue;
31160
- const fullPath = path41.join(rootDir, entry.name);
31161
- const realPath = fs41.realpathSync(fullPath);
31202
+ const fullPath = path42.join(rootDir, entry.name);
31203
+ const realPath = fs42.realpathSync(fullPath);
31162
31204
  if (realPath !== fullPath) {
31163
31205
  try {
31164
- const lstat = fs41.lstatSync(fullPath);
31206
+ const lstat = fs42.lstatSync(fullPath);
31165
31207
  if (lstat.isSymbolicLink()) {
31166
31208
  continue;
31167
31209
  }
@@ -31182,12 +31224,12 @@ function collectFiles(rootDir, includeSet, optionalSet) {
31182
31224
  function collectAllFiles(dir) {
31183
31225
  const files = [];
31184
31226
  try {
31185
- const entries2 = fs41.readdirSync(dir, { withFileTypes: true });
31227
+ const entries2 = fs42.readdirSync(dir, { withFileTypes: true });
31186
31228
  for (const entry of entries2) {
31187
31229
  if (shouldExclude(entry.name)) continue;
31188
- const fullPath = path41.join(dir, entry.name);
31230
+ const fullPath = path42.join(dir, entry.name);
31189
31231
  try {
31190
- if (fs41.lstatSync(fullPath).isSymbolicLink()) continue;
31232
+ if (fs42.lstatSync(fullPath).isSymbolicLink()) continue;
31191
31233
  } catch {
31192
31234
  }
31193
31235
  if (entry.isDirectory()) {
@@ -31202,16 +31244,16 @@ function collectAllFiles(dir) {
31202
31244
  }
31203
31245
  function readMainEngineUuid(agentsDir) {
31204
31246
  try {
31205
- const platformMapPath = path41.join(agentsDir, "main", "sessions", "platform-map.json");
31206
- const indexMapPath = path41.join(agentsDir, "main", "sessions", "session-index.json");
31207
- if (!fs41.existsSync(platformMapPath) || !fs41.existsSync(indexMapPath)) return null;
31208
- const platformMap = JSON.parse(fs41.readFileSync(platformMapPath, "utf-8"));
31247
+ const platformMapPath = path42.join(agentsDir, "main", "sessions", "platform-map.json");
31248
+ const indexMapPath = path42.join(agentsDir, "main", "sessions", "session-index.json");
31249
+ if (!fs42.existsSync(platformMapPath) || !fs42.existsSync(indexMapPath)) return null;
31250
+ const platformMap = JSON.parse(fs42.readFileSync(platformMapPath, "utf-8"));
31209
31251
  const mainPlatformId = platformMap["scope:main"] || platformMap["main"];
31210
31252
  if (!mainPlatformId) return null;
31211
- const indexMap = JSON.parse(fs41.readFileSync(indexMapPath, "utf-8"));
31253
+ const indexMap = JSON.parse(fs42.readFileSync(indexMapPath, "utf-8"));
31212
31254
  const entry = indexMap[mainPlatformId];
31213
31255
  if (!entry || !entry.file) return null;
31214
- const basename10 = path41.basename(entry.file).replace(/\.jsonl$/, "");
31256
+ const basename10 = path42.basename(entry.file).replace(/\.jsonl$/, "");
31215
31257
  return basename10;
31216
31258
  } catch {
31217
31259
  return null;
@@ -31219,13 +31261,13 @@ function readMainEngineUuid(agentsDir) {
31219
31261
  }
31220
31262
  function collectRecentSessions(agentsDir, _days = 7) {
31221
31263
  const files = [];
31222
- if (!fs41.existsSync(agentsDir)) return files;
31264
+ if (!fs42.existsSync(agentsDir)) return files;
31223
31265
  const sessionGroups = /* @__PURE__ */ new Map();
31224
31266
  function scanSessionsDir(dir) {
31225
31267
  try {
31226
- const entries2 = fs41.readdirSync(dir, { withFileTypes: true });
31268
+ const entries2 = fs42.readdirSync(dir, { withFileTypes: true });
31227
31269
  for (const entry of entries2) {
31228
- const fullPath = path41.join(dir, entry.name);
31270
+ const fullPath = path42.join(dir, entry.name);
31229
31271
  if (entry.isDirectory()) {
31230
31272
  scanSessionsDir(fullPath);
31231
31273
  continue;
@@ -31249,7 +31291,7 @@ function collectRecentSessions(agentsDir, _days = 7) {
31249
31291
  if (entry.name.endsWith(".jsonl")) {
31250
31292
  group.jsonl = fullPath;
31251
31293
  } else {
31252
- const stat4 = fs41.statSync(fullPath);
31294
+ const stat4 = fs42.statSync(fullPath);
31253
31295
  group.archived.push({ file: fullPath, mtime: stat4.mtimeMs });
31254
31296
  }
31255
31297
  }
@@ -31268,21 +31310,21 @@ function collectRecentSessions(agentsDir, _days = 7) {
31268
31310
  }
31269
31311
  function collectExportFileSet(stateDir, workspace) {
31270
31312
  const wsFiles = collectFiles(workspace, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL);
31271
- const sessionFiles = collectRecentSessions(path41.join(stateDir, "agents"), 7);
31272
- const configsDir = path41.join(stateDir, "configs");
31313
+ const sessionFiles = collectRecentSessions(path42.join(stateDir, "agents"), 7);
31314
+ const configsDir = path42.join(stateDir, "configs");
31273
31315
  const configFiles = [];
31274
- if (fs41.existsSync(configsDir)) {
31316
+ if (fs42.existsSync(configsDir)) {
31275
31317
  for (const f of collectAllFiles(configsDir)) {
31276
- if (shouldExclude(path41.basename(f))) continue;
31318
+ if (shouldExclude(path42.basename(f))) continue;
31277
31319
  configFiles.push(f);
31278
31320
  }
31279
31321
  }
31280
31322
  const EVEROS_SKIP = /* @__PURE__ */ new Set([".tmp", ".lock", "import.log", "import_progress.json"]);
31281
- const everosDir = path41.join(stateDir, ".everos");
31323
+ const everosDir = path42.join(stateDir, ".everos");
31282
31324
  const everosFiles = [];
31283
- if (fs41.existsSync(everosDir)) {
31325
+ if (fs42.existsSync(everosDir)) {
31284
31326
  for (const f of collectAllFiles(everosDir)) {
31285
- if (EVEROS_SKIP.has(path41.basename(f))) continue;
31327
+ if (EVEROS_SKIP.has(path42.basename(f))) continue;
31286
31328
  everosFiles.push(f);
31287
31329
  }
31288
31330
  }
@@ -31290,13 +31332,13 @@ function collectExportFileSet(stateDir, workspace) {
31290
31332
  }
31291
31333
  async function doExport(opts) {
31292
31334
  const { agentName, stateDir, note, dryRun: dryRun2 } = opts;
31293
- const workspace = (opts.workspace || path41.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
31294
- const engineHome = path41.join(os6.homedir(), ".engine7").replace(/[/\\]+$/, "");
31335
+ const workspace = (opts.workspace || path42.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
31336
+ const engineHome = path42.join(os6.homedir(), ".engine7").replace(/[/\\]+$/, "");
31295
31337
  console.log(`\u{1F4E6} engine7 export`);
31296
31338
  console.log(` agent: ${agentName}`);
31297
31339
  console.log(` state: ${stateDir}`);
31298
31340
  console.log(` workspace: ${workspace}`);
31299
- if (!fs41.existsSync(workspace)) {
31341
+ if (!fs42.existsSync(workspace)) {
31300
31342
  console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
31301
31343
  process.exit(1);
31302
31344
  }
@@ -31305,16 +31347,16 @@ async function doExport(opts) {
31305
31347
  console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
31306
31348
  console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
31307
31349
  console.log(` configs: ${configFiles.length}`);
31308
- console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs41.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
31350
+ console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs42.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
31309
31351
  if (dryRun2) {
31310
31352
  console.log(`
31311
31353
  [DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
31312
- wsFiles.slice(0, 20).forEach((f) => console.log(` ${path41.relative(workspace, f)}`));
31354
+ wsFiles.slice(0, 20).forEach((f) => console.log(` ${path42.relative(workspace, f)}`));
31313
31355
  if (wsFiles.length > 20) console.log(` ... \u8FD8\u6709 ${wsFiles.length - 20} \u4E2A\u6587\u4EF6`);
31314
31356
  if (everosFiles.length > 0) {
31315
31357
  console.log(`
31316
31358
  [DRY RUN] everos (${everosFiles.length} \u6587\u4EF6):`);
31317
- everosFiles.slice(0, 10).forEach((f) => console.log(` ${path41.relative(stateDir, f)}`));
31359
+ everosFiles.slice(0, 10).forEach((f) => console.log(` ${path42.relative(stateDir, f)}`));
31318
31360
  if (everosFiles.length > 10) console.log(` ... \u8FD8\u6709 ${everosFiles.length - 10} \u4E2A\u6587\u4EF6`);
31319
31361
  }
31320
31362
  console.log(`
@@ -31322,46 +31364,46 @@ async function doExport(opts) {
31322
31364
  return;
31323
31365
  }
31324
31366
  const version = formatLog().replace(/[-: ]/g, "").slice(0, 12).replace(/(d{8})(d{4})/, "$1-$2");
31325
- const tmpDir = path41.join(os6.tmpdir(), `engine7-export-${agentName}-${version}`);
31326
- fs41.mkdirSync(tmpDir, { recursive: true });
31327
- const stagingDir = path41.join(tmpDir, agentName);
31328
- fs41.mkdirSync(stagingDir, { recursive: true });
31367
+ const tmpDir = path42.join(os6.tmpdir(), `engine7-export-${agentName}-${version}`);
31368
+ fs42.mkdirSync(tmpDir, { recursive: true });
31369
+ const stagingDir = path42.join(tmpDir, agentName);
31370
+ fs42.mkdirSync(stagingDir, { recursive: true });
31329
31371
  let fileCount = 0;
31330
31372
  let totalSize = 0;
31331
31373
  let copyFail = 0;
31332
31374
  const copyOne = (srcFile, relRoot, destRoot) => {
31333
- const relPath = path41.relative(relRoot, srcFile);
31334
- const destFile = path41.join(destRoot, relPath);
31335
- fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31375
+ const relPath = path42.relative(relRoot, srcFile);
31376
+ const destFile = path42.join(destRoot, relPath);
31377
+ fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
31336
31378
  try {
31337
31379
  if (isTextFile(srcFile)) {
31338
- const content = fs41.readFileSync(srcFile, "utf-8");
31339
- fs41.writeFileSync(destFile, sanitizeContent(content, dirs));
31380
+ const content = fs42.readFileSync(srcFile, "utf-8");
31381
+ fs42.writeFileSync(destFile, sanitizeContent(content, dirs));
31340
31382
  } else {
31341
- fs41.copyFileSync(srcFile, destFile);
31383
+ fs42.copyFileSync(srcFile, destFile);
31342
31384
  }
31343
31385
  fileCount++;
31344
- totalSize += fs41.statSync(srcFile).size;
31386
+ totalSize += fs42.statSync(srcFile).size;
31345
31387
  } catch (e) {
31346
31388
  copyFail++;
31347
31389
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
31348
31390
  }
31349
31391
  };
31350
- for (const srcFile of wsFiles) copyOne(srcFile, workspace, path41.join(stagingDir, "workspace"));
31392
+ for (const srcFile of wsFiles) copyOne(srcFile, workspace, path42.join(stagingDir, "workspace"));
31351
31393
  for (const srcFile of sessionFiles) {
31352
- const relPath = path41.relative(stateDir, srcFile);
31353
- const destFile = path41.join(stagingDir, relPath);
31354
- fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31394
+ const relPath = path42.relative(stateDir, srcFile);
31395
+ const destFile = path42.join(stagingDir, relPath);
31396
+ fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
31355
31397
  try {
31356
- let content = fs41.readFileSync(srcFile, "utf-8");
31398
+ let content = fs42.readFileSync(srcFile, "utf-8");
31357
31399
  content = sanitizeContent(content, dirs);
31358
- const baseName = path41.basename(srcFile);
31400
+ const baseName = path42.basename(srcFile);
31359
31401
  if (baseName === "session-index.json" || baseName === "platform-map.json") {
31360
31402
  content = content.split("\\\\").join("/");
31361
31403
  }
31362
- fs41.writeFileSync(destFile, content);
31404
+ fs42.writeFileSync(destFile, content);
31363
31405
  fileCount++;
31364
- totalSize += fs41.statSync(srcFile).size;
31406
+ totalSize += fs42.statSync(srcFile).size;
31365
31407
  } catch (e) {
31366
31408
  copyFail++;
31367
31409
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
@@ -31383,13 +31425,13 @@ async function doExport(opts) {
31383
31425
  totalSize,
31384
31426
  note
31385
31427
  };
31386
- fs41.writeFileSync(path41.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
31387
- const archiveFile = path41.join(tmpDir, `${agentName}-${version}.tar.gz`);
31428
+ fs42.writeFileSync(path42.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
31429
+ const archiveFile = path42.join(tmpDir, `${agentName}-${version}.tar.gz`);
31388
31430
  console.log(`
31389
31431
  \u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
31390
31432
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
31391
- execSync2(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
31392
- const archiveSize = fs41.statSync(archiveFile).size;
31433
+ execSync3(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
31434
+ const archiveSize = fs42.statSync(archiveFile).size;
31393
31435
  console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6${copyFail ? `, \u5931\u8D25 ${copyFail}` : ""})`);
31394
31436
  const cfg = loadTravelConfig();
31395
31437
  if (!cfg || !cfg.githubToken) {
@@ -31415,12 +31457,12 @@ function parseImportArgs(args) {
31415
31457
  else if (args[i] === "--dry-run") dryRun2 = true;
31416
31458
  }
31417
31459
  if (!stateDir) throw new Error("import \u9700\u8981 --state-dir <path>");
31418
- if (!agentName) agentName = path41.basename(stateDir);
31460
+ if (!agentName) agentName = path42.basename(stateDir);
31419
31461
  return { stateDir, agentName, version, archiveFile, dryRun: dryRun2 };
31420
31462
  }
31421
31463
  async function resolveArchiveForTest(opts) {
31422
31464
  if (opts.archiveFile) {
31423
- if (!fs41.existsSync(opts.archiveFile)) {
31465
+ if (!fs42.existsSync(opts.archiveFile)) {
31424
31466
  throw new Error(`\u672C\u5730\u5305\u4E0D\u5B58\u5728: ${opts.archiveFile}`);
31425
31467
  }
31426
31468
  return opts.archiveFile;
@@ -31432,8 +31474,8 @@ async function doImport(opts) {
31432
31474
  console.log(`\u{1F4E5} engine7 import`);
31433
31475
  console.log(` agent: ${agentName}`);
31434
31476
  console.log(` target: ${stateDir}`);
31435
- const tmpDir = path41.join(os6.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
31436
- fs41.mkdirSync(tmpDir, { recursive: true });
31477
+ const tmpDir = path42.join(os6.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
31478
+ fs42.mkdirSync(tmpDir, { recursive: true });
31437
31479
  const resolved = await resolveArchiveForTest({
31438
31480
  archiveFile: archiveFile || "",
31439
31481
  tmpDir,
@@ -31457,100 +31499,100 @@ async function doImport(opts) {
31457
31499
  }
31458
31500
  console.log(`\u{1F4C2} \u89E3\u5305\u4E2D...`);
31459
31501
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
31460
- execSync2(`"${tarExe}" -xzf "${finalArchive}" -C "${tmpDir}"`, { stdio: "pipe" });
31461
- const stagingDir = path41.join(tmpDir, agentName);
31462
- const manifestPath = path41.join(stagingDir, "manifest.json");
31463
- if (!fs41.existsSync(manifestPath)) {
31502
+ execSync3(`"${tarExe}" -xzf "${finalArchive}" -C "${tmpDir}"`, { stdio: "pipe" });
31503
+ const stagingDir = path42.join(tmpDir, agentName);
31504
+ const manifestPath = path42.join(stagingDir, "manifest.json");
31505
+ if (!fs42.existsSync(manifestPath)) {
31464
31506
  console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
31465
31507
  process.exit(1);
31466
31508
  }
31467
- const manifest = JSON.parse(fs41.readFileSync(manifestPath, "utf-8"));
31468
- const workspace = path41.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
31469
- const engineHome = path41.join(os6.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
31509
+ const manifest = JSON.parse(fs42.readFileSync(manifestPath, "utf-8"));
31510
+ const workspace = path42.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
31511
+ const engineHome = path42.join(os6.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
31470
31512
  const dirs = { workspace, stateDir: stateDir.replace(/\\/g, "/").replace(/[/\\]+$/, ""), engineHome };
31471
31513
  console.log(` \u7248\u672C: ${manifest.version}`);
31472
31514
  console.log(` \u521B\u5EFA: ${manifest.createdAt}`);
31473
31515
  console.log(` \u6587\u4EF6\u6570: ${manifest.fileCount}`);
31474
- const wsStaging = path41.join(stagingDir, "workspace");
31516
+ const wsStaging = path42.join(stagingDir, "workspace");
31475
31517
  let restoredCount = 0;
31476
31518
  let skipCount = 0;
31477
- if (fs41.existsSync(wsStaging)) {
31519
+ if (fs42.existsSync(wsStaging)) {
31478
31520
  const allFiles = collectAllFiles(wsStaging);
31479
31521
  for (const srcFile of allFiles) {
31480
- const relPath = path41.relative(wsStaging, srcFile);
31481
- const destFile = path41.join(workspace, relPath);
31482
- fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31522
+ const relPath = path42.relative(wsStaging, srcFile);
31523
+ const destFile = path42.join(workspace, relPath);
31524
+ fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
31483
31525
  try {
31484
31526
  if (isTextFile(srcFile)) {
31485
- const content = fs41.readFileSync(srcFile, "utf-8");
31486
- fs41.writeFileSync(destFile, restoreContent(content, dirs));
31527
+ const content = fs42.readFileSync(srcFile, "utf-8");
31528
+ fs42.writeFileSync(destFile, restoreContent(content, dirs));
31487
31529
  } else {
31488
- fs41.copyFileSync(srcFile, destFile);
31530
+ fs42.copyFileSync(srcFile, destFile);
31489
31531
  }
31490
31532
  restoredCount++;
31491
31533
  } catch (e) {
31492
31534
  skipCount++;
31493
- console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path41.relative(wsStaging, srcFile)} (${e.code || e.message})`);
31535
+ console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path42.relative(wsStaging, srcFile)} (${e.code || e.message})`);
31494
31536
  }
31495
31537
  }
31496
31538
  }
31497
- const agentsStaging = path41.join(stagingDir, "agents");
31498
- if (fs41.existsSync(agentsStaging)) {
31539
+ const agentsStaging = path42.join(stagingDir, "agents");
31540
+ if (fs42.existsSync(agentsStaging)) {
31499
31541
  const sessionFiles = collectAllFiles(agentsStaging);
31500
31542
  for (const srcFile of sessionFiles) {
31501
- const relPath = path41.relative(stagingDir, srcFile);
31502
- const destFile = path41.join(stateDir, relPath);
31503
- fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31504
- const content = fs41.readFileSync(srcFile, "utf-8");
31505
- fs41.writeFileSync(destFile, restoreContent(content, dirs));
31543
+ const relPath = path42.relative(stagingDir, srcFile);
31544
+ const destFile = path42.join(stateDir, relPath);
31545
+ fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
31546
+ const content = fs42.readFileSync(srcFile, "utf-8");
31547
+ fs42.writeFileSync(destFile, restoreContent(content, dirs));
31506
31548
  restoredCount++;
31507
31549
  }
31508
31550
  }
31509
- const configsStaging = path41.join(stagingDir, "configs");
31510
- if (fs41.existsSync(configsStaging)) {
31551
+ const configsStaging = path42.join(stagingDir, "configs");
31552
+ if (fs42.existsSync(configsStaging)) {
31511
31553
  const cfgFiles = collectAllFiles(configsStaging);
31512
31554
  for (const srcFile of cfgFiles) {
31513
- const relPath = path41.relative(stagingDir, srcFile);
31514
- const destFile = path41.join(stateDir, relPath);
31515
- fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31555
+ const relPath = path42.relative(stagingDir, srcFile);
31556
+ const destFile = path42.join(stateDir, relPath);
31557
+ fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
31516
31558
  if (isTextFile(srcFile)) {
31517
- const content = fs41.readFileSync(srcFile, "utf-8");
31518
- fs41.writeFileSync(destFile, restoreContent(content, dirs));
31559
+ const content = fs42.readFileSync(srcFile, "utf-8");
31560
+ fs42.writeFileSync(destFile, restoreContent(content, dirs));
31519
31561
  } else {
31520
- fs41.copyFileSync(srcFile, destFile);
31562
+ fs42.copyFileSync(srcFile, destFile);
31521
31563
  }
31522
31564
  restoredCount++;
31523
31565
  }
31524
31566
  }
31525
- const everosStaging = path41.join(stagingDir, ".everos");
31526
- if (fs41.existsSync(everosStaging)) {
31567
+ const everosStaging = path42.join(stagingDir, ".everos");
31568
+ if (fs42.existsSync(everosStaging)) {
31527
31569
  const everosFiles = collectAllFiles(everosStaging);
31528
31570
  for (const srcFile of everosFiles) {
31529
- const relPath = path41.relative(stagingDir, srcFile);
31530
- const destFile = path41.join(stateDir, relPath);
31531
- fs41.mkdirSync(path41.dirname(destFile), { recursive: true });
31571
+ const relPath = path42.relative(stagingDir, srcFile);
31572
+ const destFile = path42.join(stateDir, relPath);
31573
+ fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
31532
31574
  try {
31533
31575
  if (isTextFile(srcFile)) {
31534
- const content = fs41.readFileSync(srcFile, "utf-8");
31535
- fs41.writeFileSync(destFile, restoreContent(content, dirs));
31576
+ const content = fs42.readFileSync(srcFile, "utf-8");
31577
+ fs42.writeFileSync(destFile, restoreContent(content, dirs));
31536
31578
  } else {
31537
- fs41.copyFileSync(srcFile, destFile);
31579
+ fs42.copyFileSync(srcFile, destFile);
31538
31580
  }
31539
31581
  restoredCount++;
31540
31582
  } catch (e) {
31541
31583
  skipCount++;
31542
- console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path41.relative(everosStaging, srcFile)} (${e.code || e.message})`);
31584
+ console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path42.relative(everosStaging, srcFile)} (${e.code || e.message})`);
31543
31585
  }
31544
31586
  }
31545
31587
  console.log(` everos: ${everosFiles.length} \u6587\u4EF6\u5DF2\u6062\u590D`);
31546
31588
  }
31547
31589
  console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}${skipCount ? ` (\u8DF3\u8FC7 ${skipCount})` : ""}`);
31548
31590
  const platformConfigName = process.platform === "darwin" ? "xiaoke-mac.json" : "xiaoke-win.json";
31549
- const restoredConfigPath = path41.join(stateDir, "configs", platformConfigName);
31550
- const configToUse = fs41.existsSync(restoredConfigPath) ? restoredConfigPath : path41.join(stateDir, "configs", "xiaoke.json");
31591
+ const restoredConfigPath = path42.join(stateDir, "configs", platformConfigName);
31592
+ const configToUse = fs42.existsSync(restoredConfigPath) ? restoredConfigPath : path42.join(stateDir, "configs", "xiaoke.json");
31551
31593
  console.log(`
31552
31594
  \u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config "${configToUse}"`);
31553
- fs41.rmSync(tmpDir, { recursive: true, force: true });
31595
+ fs42.rmSync(tmpDir, { recursive: true, force: true });
31554
31596
  }
31555
31597
  async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
31556
31598
  const repo = `${cfg.githubOwner}/${cfg.repoName}`;
@@ -31580,8 +31622,8 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
31580
31622
  }
31581
31623
  const release2 = await createRes.json();
31582
31624
  const uploadUrl = release2.upload_url.replace("{?name,label}", "");
31583
- const fileBuffer = fs41.readFileSync(archiveFile);
31584
- const fileName = path41.basename(archiveFile);
31625
+ const fileBuffer = fs42.readFileSync(archiveFile);
31626
+ const fileName = path42.basename(archiveFile);
31585
31627
  const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
31586
31628
  method: "POST",
31587
31629
  headers: {
@@ -31604,7 +31646,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
31604
31646
  throw e;
31605
31647
  }
31606
31648
  try {
31607
- fs41.rmSync(path41.dirname(archiveFile), { recursive: true, force: true });
31649
+ fs42.rmSync(path42.dirname(archiveFile), { recursive: true, force: true });
31608
31650
  } catch {
31609
31651
  }
31610
31652
  }
@@ -31636,8 +31678,8 @@ async function downloadFromGitHub(cfg, agentName, version, destDir) {
31636
31678
  throw new Error(`\u4E0B\u8F7D asset \u5931\u8D25: ${downloadRes.status}`);
31637
31679
  }
31638
31680
  const buffer = Buffer.from(await downloadRes.arrayBuffer());
31639
- const archiveFile = path41.join(destDir, asset.name);
31640
- fs41.writeFileSync(archiveFile, buffer);
31681
+ const archiveFile = path42.join(destDir, asset.name);
31682
+ fs42.writeFileSync(archiveFile, buffer);
31641
31683
  return archiveFile;
31642
31684
  }
31643
31685
  async function getLatestReleaseTag(cfg, agentName) {
@@ -31663,7 +31705,7 @@ var init_cli_travel = __esm({
31663
31705
  "src/cli-travel.ts"() {
31664
31706
  "use strict";
31665
31707
  init_clock();
31666
- CONFIG_PATH = path41.join(os6.homedir(), ".engine7-travel.json");
31708
+ CONFIG_PATH = path42.join(os6.homedir(), ".engine7-travel.json");
31667
31709
  PATH_PLACEHOLDERS = [
31668
31710
  { placeholder: "{{WORKSPACE}}", getOriginal: (d) => d.workspace },
31669
31711
  { placeholder: "{{ENGINE_HOME}}", getOriginal: (d) => d.engineHome },
@@ -31736,8 +31778,8 @@ var init_cli_travel = __esm({
31736
31778
  });
31737
31779
 
31738
31780
  // src/cli-init.ts
31739
- import * as path42 from "node:path";
31740
- import * as fs42 from "node:fs";
31781
+ import * as path43 from "node:path";
31782
+ import * as fs43 from "node:fs";
31741
31783
 
31742
31784
  // src/cli-service.ts
31743
31785
  function parseServiceArgs(args) {
@@ -31892,6 +31934,136 @@ function buildConfigValuesFromAnswers(stateDir, a, existing = {}) {
31892
31934
 
31893
31935
  // src/cli-init.ts
31894
31936
  init_secrets_env();
31937
+
31938
+ // src/pid-lock.ts
31939
+ import fs3 from "node:fs";
31940
+ import path3 from "node:path";
31941
+ import { execSync } from "node:child_process";
31942
+ function enginePidFile(stateDir) {
31943
+ return path3.join(stateDir, ".engine.pid");
31944
+ }
31945
+ function isEngineImage(text) {
31946
+ return /node|engine7|electron/i.test(text);
31947
+ }
31948
+ function isPidAlive(pid) {
31949
+ try {
31950
+ process.kill(pid, 0);
31951
+ return true;
31952
+ } catch {
31953
+ return false;
31954
+ }
31955
+ }
31956
+ function probeImage(pid) {
31957
+ try {
31958
+ if (process.platform === "win32") {
31959
+ return execSync(`tasklist /FI "PID eq ${pid}" /NH /FO CSV`, {
31960
+ encoding: "utf-8",
31961
+ timeout: 3e3,
31962
+ stdio: ["ignore", "pipe", "ignore"]
31963
+ });
31964
+ }
31965
+ if (process.platform === "darwin") {
31966
+ return execSync(`ps -p ${pid} -o comm=`, {
31967
+ encoding: "utf-8",
31968
+ timeout: 3e3,
31969
+ stdio: ["ignore", "pipe", "ignore"]
31970
+ });
31971
+ }
31972
+ return fs3.readFileSync(`/proc/${pid}/comm`, "utf-8");
31973
+ } catch {
31974
+ return null;
31975
+ }
31976
+ }
31977
+ function probeEngineImage(pid) {
31978
+ return isEngineImage(probeImage(pid) ?? "");
31979
+ }
31980
+ function isCliWrapperImage(text) {
31981
+ return /node/i.test(text);
31982
+ }
31983
+ function probeIsCliWrapper(pid) {
31984
+ return isCliWrapperImage(probeImage(pid) ?? "");
31985
+ }
31986
+ function readOwnEnginePidText(stateDir) {
31987
+ try {
31988
+ return fs3.readFileSync(enginePidFile(stateDir), "utf-8");
31989
+ } catch (err) {
31990
+ if (err?.code !== "ENOENT") console.warn(`[pid-lock] read lock failed: ${err.message}`);
31991
+ return null;
31992
+ }
31993
+ }
31994
+ function pickOwnEnginePid(probe) {
31995
+ const pid = parseInt((probe.pidFileContent ?? "").trim(), 10);
31996
+ if (!Number.isInteger(pid) || pid <= 0) return null;
31997
+ if (pid === probe.myPid) return null;
31998
+ if (!probe.isAlive(pid)) return null;
31999
+ if (!probe.isEngineImage(pid)) return null;
32000
+ return pid;
32001
+ }
32002
+ function ownEnginePid(stateDir, myPid = process.pid) {
32003
+ return pickOwnEnginePid({
32004
+ pidFileContent: readOwnEnginePidText(stateDir),
32005
+ myPid,
32006
+ isAlive: isPidAlive,
32007
+ isEngineImage: probeEngineImage
32008
+ });
32009
+ }
32010
+ function killOwnEngineForStateDir(stateDir) {
32011
+ const pid = ownEnginePid(stateDir);
32012
+ if (pid === null) return null;
32013
+ killTree(pid);
32014
+ return pid;
32015
+ }
32016
+ async function waitForPidGone(pid, timeoutMs = 5e3) {
32017
+ const t0 = Date.now();
32018
+ while (Date.now() - t0 < timeoutMs) {
32019
+ if (!isPidAlive(pid)) return true;
32020
+ await new Promise((r) => setTimeout(r, 100));
32021
+ }
32022
+ return !isPidAlive(pid);
32023
+ }
32024
+ function pickParentPid(procStatus, psOutput) {
32025
+ const fromProc = Number(/PPid:\s*(\d+)/.exec(procStatus ?? "")?.[1] ?? NaN);
32026
+ if (Number.isInteger(fromProc) && fromProc > 0) return fromProc;
32027
+ const fromPs = Number((psOutput ?? "").trim());
32028
+ return Number.isInteger(fromPs) && fromPs > 0 ? fromPs : 0;
32029
+ }
32030
+ function killTree(pid) {
32031
+ try {
32032
+ if (process.platform === "win32") {
32033
+ execSync(`taskkill /PID ${pid} /T /F`, { stdio: "ignore", timeout: 8e3 });
32034
+ try {
32035
+ const parentPid = parseInt(execSync(`wmic process where ProcessId=${pid} get ParentProcessId /value`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).match(/ParentProcessId=(\d+)/)?.[1] ?? "0", 10);
32036
+ if (parentPid && parentPid !== process.ppid && probeIsCliWrapper(parentPid)) {
32037
+ execSync(`taskkill /PID ${parentPid} /F`, { stdio: "ignore", timeout: 3e3 });
32038
+ }
32039
+ } catch {
32040
+ }
32041
+ } else {
32042
+ process.kill(pid, "SIGKILL");
32043
+ let parentPid = 0;
32044
+ try {
32045
+ parentPid = pickParentPid(fs3.readFileSync(`/proc/${pid}/status`, "utf-8"), null);
32046
+ } catch {
32047
+ }
32048
+ if (!parentPid) {
32049
+ try {
32050
+ parentPid = pickParentPid(null, execSync(`ps -p ${pid} -o ppid=`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }));
32051
+ } catch {
32052
+ }
32053
+ }
32054
+ if (parentPid > 1 && parentPid !== process.ppid && probeIsCliWrapper(parentPid)) {
32055
+ try {
32056
+ process.kill(parentPid, "SIGKILL");
32057
+ } catch {
32058
+ }
32059
+ }
32060
+ }
32061
+ } catch (err) {
32062
+ console.warn(`[pid-lock] kill ${pid} failed: ${err.message}`);
32063
+ }
32064
+ }
32065
+
32066
+ // src/cli-init.ts
31895
32067
  init_clock();
31896
32068
  init_cli_init_config();
31897
32069
  init_registry();
@@ -31910,7 +32082,7 @@ function describeCurrentToken(v) {
31910
32082
  return /^(?:env:|{{\s*)[A-Z0-9_]+/.test(v) ? "\u5DF2\u5B58\u5728 secrets \u4E2D" : v.slice(0, 12) + "...";
31911
32083
  }
31912
32084
  var __filename2 = fileURLToPath7(import.meta.url);
31913
- var __dirname = path42.dirname(__filename2);
32085
+ var __dirname = path43.dirname(__filename2);
31914
32086
  function parseArgs2() {
31915
32087
  const args = process.argv.slice(2);
31916
32088
  let stateDir = "";
@@ -31937,10 +32109,10 @@ function parseArgs2() {
31937
32109
  }
31938
32110
  }
31939
32111
  if (!stateDir) {
31940
- stateDir = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
32112
+ stateDir = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
31941
32113
  console.log(` \u4F7F\u7528\u9ED8\u8BA4\u76EE\u5F55: ${stateDir}`);
31942
32114
  }
31943
- stateDir = path42.resolve(stateDir);
32115
+ stateDir = path43.resolve(stateDir);
31944
32116
  return { stateDir, quick, dryRun: dryRun2, force, answersPath };
31945
32117
  }
31946
32118
  function printHelp() {
@@ -32061,16 +32233,16 @@ function getDefaultValues(stateDir) {
32061
32233
  };
32062
32234
  }
32063
32235
  function loadExistingValues(stateDir) {
32064
- const configPath = path42.join(stateDir, "configs", "main7.json");
32236
+ const configPath = path43.join(stateDir, "configs", "main7.json");
32065
32237
  try {
32066
- if (!fs42.existsSync(configPath)) return {};
32067
- const j = JSON.parse(fs42.readFileSync(configPath, "utf8"));
32238
+ if (!fs43.existsSync(configPath)) return {};
32239
+ const j = JSON.parse(fs43.readFileSync(configPath, "utf8"));
32068
32240
  const out = {};
32069
32241
  if (typeof j.timezone === "string" && j.timezone) out.timezone = j.timezone;
32070
32242
  if (j.agents?.defaults?.name) out.agentName = j.agents.defaults.name;
32071
32243
  if (j.agents?.defaults?.persona) out.persona = j.agents.defaults.persona;
32072
32244
  try {
32073
- const wm = fs42.readFileSync(path42.join(stateDir, "workspace", ".work-mode"), "utf8").trim();
32245
+ const wm = fs43.readFileSync(path43.join(stateDir, "workspace", ".work-mode"), "utf8").trim();
32074
32246
  if (wm === "on") out.chatMode = "work";
32075
32247
  else if (wm === "off") out.chatMode = "emotion";
32076
32248
  } catch {
@@ -32127,8 +32299,8 @@ function readSecretsValue(stateDir, envName) {
32127
32299
  try {
32128
32300
  const cfgBase = "main7";
32129
32301
  for (const p of secretsCandidates(stateDir, cfgBase)) {
32130
- if (fs42.existsSync(p)) {
32131
- for (const line of fs42.readFileSync(p, "utf8").split("\n")) {
32302
+ if (fs43.existsSync(p)) {
32303
+ for (const line of fs43.readFileSync(p, "utf8").split("\n")) {
32132
32304
  const eq = line.indexOf("=");
32133
32305
  if (eq > 0 && line.slice(0, eq).trim() === envName) {
32134
32306
  return line.slice(eq + 1).trim();
@@ -32362,29 +32534,29 @@ async function configureWechat(rl, v) {
32362
32534
  }
32363
32535
  function buildDirTree(v) {
32364
32536
  const d = v.stateDir;
32365
- const w = path42.join(d, "workspace");
32537
+ const w = path43.join(d, "workspace");
32366
32538
  return [
32367
32539
  // 目录
32368
- { path: path42.join(d, "configs"), type: "dir" },
32369
- { path: path42.join(d, "state", "agents", "main", "sessions"), type: "dir" },
32370
- { path: path42.join(w, "prompts"), type: "dir" },
32371
- { path: path42.join(w, "memory", "daily"), type: "dir" },
32372
- { path: path42.join(w, "docs", "research"), type: "dir" },
32373
- { path: path42.join(w, "docs", "todo"), type: "dir" },
32374
- { path: path42.join(w, "docs", "decisions"), type: "dir" },
32375
- { path: path42.join(w, "docs", "knowledge"), type: "dir" },
32376
- { path: path42.join(w, "docs", "sop"), type: "dir" },
32377
- { path: path42.join(d, "logs"), type: "dir" },
32378
- { path: path42.join(d, "media", "inbound"), type: "dir" },
32540
+ { path: path43.join(d, "configs"), type: "dir" },
32541
+ { path: path43.join(d, "state", "agents", "main", "sessions"), type: "dir" },
32542
+ { path: path43.join(w, "prompts"), type: "dir" },
32543
+ { path: path43.join(w, "memory", "daily"), type: "dir" },
32544
+ { path: path43.join(w, "docs", "research"), type: "dir" },
32545
+ { path: path43.join(w, "docs", "todo"), type: "dir" },
32546
+ { path: path43.join(w, "docs", "decisions"), type: "dir" },
32547
+ { path: path43.join(w, "docs", "knowledge"), type: "dir" },
32548
+ { path: path43.join(w, "docs", "sop"), type: "dir" },
32549
+ { path: path43.join(d, "logs"), type: "dir" },
32550
+ { path: path43.join(d, "media", "inbound"), type: "dir" },
32379
32551
  // workspace 文件
32380
32552
  {
32381
- path: path42.join(w, "SESSION-STATE.md"),
32553
+ path: path43.join(w, "SESSION-STATE.md"),
32382
32554
  type: "file",
32383
32555
  content: readTemplate("workspace/SESSION-STATE.md")
32384
32556
  },
32385
- { path: path42.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
32557
+ { path: path43.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
32386
32558
  {
32387
- path: path42.join(w, "SOUL.md"),
32559
+ path: path43.join(w, "SOUL.md"),
32388
32560
  type: "file",
32389
32561
  // 0917:SOUL 按人设取模板(templates/workspace/souls/<persona>.md),
32390
32562
  // 单一人设模板缺失时回退通用骨架(workspace/SOUL.md)
@@ -32396,12 +32568,12 @@ function buildDirTree(v) {
32396
32568
  }
32397
32569
  })()
32398
32570
  },
32399
- { path: path42.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
32571
+ { path: path43.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
32400
32572
  {
32401
32573
  // 0920 翀哥拍板:EMOTION.md 模板按人设装(templates/workspace/emotion/<persona>.md)
32402
32574
  // 冷启动默认带"想 TA 了就直接发(msg_send)"那段(写在每份模板 §一)
32403
32575
  // 单一人设模板缺失时回退通用骨架(emotion/_default.md)
32404
- path: path42.join(w, "EMOTION.md"),
32576
+ path: path43.join(w, "EMOTION.md"),
32405
32577
  type: "file",
32406
32578
  content: (() => {
32407
32579
  try {
@@ -32412,39 +32584,39 @@ function buildDirTree(v) {
32412
32584
  })()
32413
32585
  },
32414
32586
  {
32415
- path: path42.join(w, "prompts", "contacts.md"),
32587
+ path: path43.join(w, "prompts", "contacts.md"),
32416
32588
  type: "file",
32417
32589
  content: readTemplate("workspace/prompts/contacts.md").replace("{{DISCORD_USER_ID}}", v.discordUserId || "YOUR_DISCORD_ID").replace("{{FEISHU_OPEN_ID}}", v.feishuOpenId || "YOUR_FEISHU_OPEN_ID")
32418
32590
  },
32419
- { path: path42.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
32591
+ { path: path43.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
32420
32592
  {
32421
32593
  // 0925:proactive 到期处理规则。此前仓内**零模板**——那份规则只在私有部署的
32422
32594
  // stateDir 里手工存在,装机用户吃的是引擎内置兜底文案(那份也没点名工具)。
32423
32595
  // 结果:agent 用正文写判定、不调工具,判定全部不落库。
32424
32596
  // 注意 readTemplate 找不到模板会 **throw**,所以本文件与 templates/ 下那份必须成对存在。
32425
- path: path42.join(w, "prompts", "proactive.md"),
32597
+ path: path43.join(w, "prompts", "proactive.md"),
32426
32598
  type: "file",
32427
32599
  content: readTemplate("workspace/prompts/proactive.md")
32428
32600
  },
32429
32601
  {
32430
32602
  // 0917:inner-voice 定制 prompt 按人设装(templates/workspace/inner-voice/<persona>.md)
32431
- path: path42.join(w, "prompts", "my-inner-voice.md"),
32603
+ path: path43.join(w, "prompts", "my-inner-voice.md"),
32432
32604
  type: "file",
32433
32605
  content: readTemplate(`workspace/inner-voice/${v.persona}.md`).replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
32434
32606
  },
32435
- { path: path42.join(w, "MEMORY.md"), type: "file", content: "# MEMORY.md \u2014 \u8BB0\u5FC6\u6587\u4EF6\u7D22\u5F15\n\n> \u6700\u540E\u66F4\u65B0\uFF1A\u521D\u59CB\u5316\n" },
32436
- { path: path42.join(w, "USER.md"), type: "file", content: "# USER.md \u2014 \u7528\u6237\u4FE1\u606F\n\n\uFF08\u5728\u8FD9\u91CC\u8BB0\u5F55\u7528\u6237\u7684\u504F\u597D\u3001\u80CC\u666F\u7B49\uFF09\n" },
32607
+ { path: path43.join(w, "MEMORY.md"), type: "file", content: "# MEMORY.md \u2014 \u8BB0\u5FC6\u6587\u4EF6\u7D22\u5F15\n\n> \u6700\u540E\u66F4\u65B0\uFF1A\u521D\u59CB\u5316\n" },
32608
+ { path: path43.join(w, "USER.md"), type: "file", content: "# USER.md \u2014 \u7528\u6237\u4FE1\u606F\n\n\uFF08\u5728\u8FD9\u91CC\u8BB0\u5F55\u7528\u6237\u7684\u504F\u597D\u3001\u80CC\u666F\u7B49\uFF09\n" },
32437
32609
  // 情绪状态机(0917):脚本 + hook 接线 + 人设情绪表(用户在 init 选的 persona)
32438
32610
  //
32439
32611
  // 0920 起装的是 **.mjs 版**(原来是 .py,见下面 hook 命令那段)。老装机的 workspace
32440
32612
  // 里那份 .py 不动它——没被引用就不会跑,删了反而无据可查。
32441
32613
  {
32442
- path: path42.join(w, "scripts", "emotion_state_machine.mjs"),
32614
+ path: path43.join(w, "scripts", "emotion_state_machine.mjs"),
32443
32615
  type: "file",
32444
32616
  content: readTemplate("workspace/scripts/emotion_state_machine.mjs")
32445
32617
  },
32446
32618
  {
32447
- path: path42.join(w, ".hooks.json"),
32619
+ path: path43.join(w, ".hooks.json"),
32448
32620
  type: "file",
32449
32621
  content: JSON.stringify({
32450
32622
  hooks: {
@@ -32459,26 +32631,26 @@ function buildDirTree(v) {
32459
32631
  // (hook 的 env 是 {...process.env} 继承的),所以它就是个 node。
32460
32632
  // 与 `service install --node-exe` 同一个路子。
32461
32633
  // 路径两侧都加引号:stateDir 可能带空格(C:\Users\Foo Bar\...)。
32462
- { hooks: [{ type: "command", command: '"${E7_NODE}" "' + path42.join(w, "scripts", "emotion_state_machine.mjs") + '"' }] }
32634
+ { hooks: [{ type: "command", command: '"${E7_NODE}" "' + path43.join(w, "scripts", "emotion_state_machine.mjs") + '"' }] }
32463
32635
  ]
32464
32636
  }
32465
32637
  }, null, 2) + "\n"
32466
32638
  },
32467
32639
  {
32468
- path: path42.join(w, ".emotion_states.json"),
32640
+ path: path43.join(w, ".emotion_states.json"),
32469
32641
  type: "file",
32470
32642
  content: readTemplate(`workspace/emotion-states/${v.persona}.json`)
32471
32643
  },
32472
32644
  // 模式档位(0920):与 /work 命令写的是同一个文件,读端只认 on/off,
32473
32645
  // 没有这个键就是 auto。auto 刻意不写——写个 "auto" 进去反而多一种除了这里没人认得的状态。
32474
32646
  ...v.chatMode === "work" || v.chatMode === "emotion" ? [{
32475
- path: path42.join(w, ".work-mode"),
32647
+ path: path43.join(w, ".work-mode"),
32476
32648
  type: "file",
32477
32649
  content: v.chatMode === "work" ? "on" : "off"
32478
32650
  }] : [],
32479
32651
  // package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
32480
32652
  {
32481
- path: path42.join(d, "package.json"),
32653
+ path: path43.join(d, "package.json"),
32482
32654
  type: "file",
32483
32655
  content: JSON.stringify({
32484
32656
  name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
@@ -32489,7 +32661,7 @@ function buildDirTree(v) {
32489
32661
  },
32490
32662
  // 启动脚本(根据 OS 生成)
32491
32663
  ...process.platform === "win32" ? [{
32492
- path: path42.join(d, "start.cmd"),
32664
+ path: path43.join(d, "start.cmd"),
32493
32665
  type: "file",
32494
32666
  content: `@echo off
32495
32667
  rem Engine 7 startup script
@@ -32521,7 +32693,7 @@ if %ERRORLEVEL% NEQ 0 (
32521
32693
  )
32522
32694
  `
32523
32695
  }] : [{
32524
- path: path42.join(d, "start.sh"),
32696
+ path: path43.join(d, "start.sh"),
32525
32697
  type: "file",
32526
32698
  content: `#!/bin/bash
32527
32699
  # Engine 7 startup script
@@ -32555,24 +32727,24 @@ node "$ENGINE7_BIN" --engine-config "$CFG_ABS"
32555
32727
  }
32556
32728
  function readTemplate(relativePath) {
32557
32729
  const candidates = [
32558
- path42.join(__dirname, "..", "templates", relativePath),
32559
- path42.join(__dirname, "..", "..", "templates", relativePath),
32560
- path42.join(process.cwd(), "templates", relativePath)
32730
+ path43.join(__dirname, "..", "templates", relativePath),
32731
+ path43.join(__dirname, "..", "..", "templates", relativePath),
32732
+ path43.join(process.cwd(), "templates", relativePath)
32561
32733
  ];
32562
32734
  for (const p of candidates) {
32563
- if (fs42.existsSync(p)) {
32564
- return fs42.readFileSync(p, "utf-8");
32735
+ if (fs43.existsSync(p)) {
32736
+ return fs43.readFileSync(p, "utf-8");
32565
32737
  }
32566
32738
  }
32567
32739
  throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
32568
32740
  }
32569
32741
  function looksLikeAppInstall(dir) {
32570
- return ["", "install"].some((sub) => fs42.existsSync(path42.join(dir, sub, "Engine7.exe")) && fs42.existsSync(path42.join(dir, sub, "resources", "engine7", "dist", "cli.mjs")));
32742
+ return ["", "install"].some((sub) => fs43.existsSync(path43.join(dir, sub, "Engine7.exe")) && fs43.existsSync(path43.join(dir, sub, "resources", "engine7", "dist", "cli.mjs")));
32571
32743
  }
32572
32744
  var PHOTO_EXTS = [".png", ".jpg", ".jpeg", ".webp"];
32573
32745
  function hasOnlyEngineBookkeeping(dir) {
32574
32746
  try {
32575
- const entries2 = fs42.readdirSync(dir);
32747
+ const entries2 = fs43.readdirSync(dir);
32576
32748
  return entries2.length > 0 && entries2.every((e) => e === "install-identity.json");
32577
32749
  } catch {
32578
32750
  return false;
@@ -32588,11 +32760,11 @@ function dryRun(entries2) {
32588
32760
  function execute(entries2) {
32589
32761
  for (const e of entries2) {
32590
32762
  if (e.type === "dir") {
32591
- fs42.mkdirSync(e.path, { recursive: true });
32763
+ fs43.mkdirSync(e.path, { recursive: true });
32592
32764
  console.log(` \u{1F4C1} ${e.path}`);
32593
32765
  } else {
32594
- fs42.mkdirSync(path42.dirname(e.path), { recursive: true });
32595
- fs42.writeFileSync(e.path, e.content || "", "utf-8");
32766
+ fs43.mkdirSync(path43.dirname(e.path), { recursive: true });
32767
+ fs43.writeFileSync(e.path, e.content || "", "utf-8");
32596
32768
  console.log(` \u{1F4C4} ${e.path}`);
32597
32769
  }
32598
32770
  }
@@ -32626,8 +32798,8 @@ async function main() {
32626
32798
  if (subcommand === "--version" || subcommand === "-v") {
32627
32799
  let ver = "unknown";
32628
32800
  try {
32629
- const pkgPath = path42.join(path42.dirname(__filename2), "..", "package.json");
32630
- ver = JSON.parse(fs42.readFileSync(pkgPath, "utf8")).version || "unknown";
32801
+ const pkgPath = path43.join(path43.dirname(__filename2), "..", "package.json");
32802
+ ver = JSON.parse(fs43.readFileSync(pkgPath, "utf8")).version || "unknown";
32631
32803
  } catch {
32632
32804
  }
32633
32805
  console.log(`engine7 ${ver}`);
@@ -32656,14 +32828,14 @@ async function main() {
32656
32828
  relay = resolveRelayUrl(relay, process.env);
32657
32829
  if (!relayFromArg) console.error(` \u4E2D\u8F6C\u7AD9: ${relay}\uFF08\u8981\u6362\u5730\u5740\u7528 --relay <\u5730\u5740>\uFF09`);
32658
32830
  const { resolveStateDirFromArgs: resolveStateDirFromArgs2 } = await Promise.resolve().then(() => (init_cli_doctor(), cli_doctor_exports));
32659
- stateDir = stateDir ? path42.resolve(stateDir) : resolveStateDirFromArgs2(args.slice(1));
32831
+ stateDir = stateDir ? path43.resolve(stateDir) : resolveStateDirFromArgs2(args.slice(1));
32660
32832
  try {
32661
32833
  const { provisionFreeToken: provisionFreeToken2 } = await Promise.resolve().then(() => (init_provision_free(), provision_free_exports));
32662
32834
  const result = await provisionFreeToken2({
32663
32835
  relayBaseUrl: relay,
32664
32836
  stateDir,
32665
32837
  // 和 init 写 config 的路径一致(cli-init.ts 里 configPath 就是这么拼的)
32666
- configPath: path42.join(stateDir, "configs", "main7.json")
32838
+ configPath: path43.join(stateDir, "configs", "main7.json")
32667
32839
  });
32668
32840
  console.log(JSON.stringify(result, null, 2));
32669
32841
  process.exit(0);
@@ -32690,18 +32862,18 @@ async function main() {
32690
32862
  else if (args[i] === "--base-url" && args[i + 1]) relayBaseUrl = args[++i].trim();
32691
32863
  }
32692
32864
  if (!stateDir) {
32693
- const cwd = path42.resolve(process.cwd());
32694
- if (fs42.existsSync(path42.join(cwd, "configs"))) {
32865
+ const cwd = path43.resolve(process.cwd());
32866
+ if (fs43.existsSync(path43.join(cwd, "configs"))) {
32695
32867
  stateDir = cwd;
32696
32868
  } else {
32697
- const pointer = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
32698
- if (fs42.existsSync(pointer)) {
32869
+ const pointer = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
32870
+ if (fs43.existsSync(pointer)) {
32699
32871
  try {
32700
- stateDir = JSON.parse(fs42.readFileSync(pointer, "utf8")).stateDir || "";
32872
+ stateDir = JSON.parse(fs43.readFileSync(pointer, "utf8")).stateDir || "";
32701
32873
  } catch {
32702
32874
  }
32703
32875
  }
32704
- if (!stateDir) stateDir = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
32876
+ if (!stateDir) stateDir = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
32705
32877
  }
32706
32878
  }
32707
32879
  if (!target && !isLegacyAddchannel) {
@@ -32721,12 +32893,12 @@ async function main() {
32721
32893
  process.exit(0);
32722
32894
  }
32723
32895
  if (channel === "channels") {
32724
- const configsDir = path42.join(stateDir, "configs");
32725
- if (fs42.existsSync(configsDir)) {
32726
- const files = fs42.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
32896
+ const configsDir = path43.join(stateDir, "configs");
32897
+ if (fs43.existsSync(configsDir)) {
32898
+ const files = fs43.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
32727
32899
  for (const f of files) {
32728
32900
  try {
32729
- const j = JSON.parse(fs42.readFileSync(path42.join(configsDir, f), "utf8"));
32901
+ const j = JSON.parse(fs43.readFileSync(path43.join(configsDir, f), "utf8"));
32730
32902
  if (!j.channels) continue;
32731
32903
  console.log(`
32732
32904
  \u{1F4C4} ${f}:`);
@@ -32763,7 +32935,7 @@ async function main() {
32763
32935
  }
32764
32936
  const configFile = resolveConfigPath2(stateDir, configName);
32765
32937
  if (!configFile) {
32766
- fail2(`\u6CA1\u627E\u5230\u53EF\u6539\u7684 config\uFF1A\u5728 ${path42.join(stateDir, "configs")} \u4E0B\u65E2\u6CA1\u6709 main7.json\uFF0C\u4E5F\u6CA1\u6709\u542B models.providers \u7684 json\u3002\u7528 --config <\u6587\u4EF6\u540D> \u6307\u5B9A\u3002`);
32938
+ fail2(`\u6CA1\u627E\u5230\u53EF\u6539\u7684 config\uFF1A\u5728 ${path43.join(stateDir, "configs")} \u4E0B\u65E2\u6CA1\u6709 main7.json\uFF0C\u4E5F\u6CA1\u6709\u542B models.providers \u7684 json\u3002\u7528 --config <\u6587\u4EF6\u540D> \u6307\u5B9A\u3002`);
32767
32939
  }
32768
32940
  if (!readSecretsValue(stateDir, FREE_TIER_ENV_KEY2)) {
32769
32941
  fail2(`\u514D\u8D39\u6863\u7F3A\u5C11\u4EE4\u724C\uFF1Asecrets \u91CC\u6CA1\u6709 ${FREE_TIER_ENV_KEY2}\u3002\u5148\u9886\u53F7\uFF1A
@@ -32830,8 +33002,8 @@ async function main() {
32830
33002
  else if (args[i] === "--note" && args[i + 1]) note = args[++i];
32831
33003
  else if (args[i] === "--dry-run") dryRun2 = true;
32832
33004
  }
32833
- if (!exportStateDir) exportStateDir = path42.resolve(process.cwd());
32834
- if (!agentName) agentName = path42.basename(exportStateDir);
33005
+ if (!exportStateDir) exportStateDir = path43.resolve(process.cwd());
33006
+ if (!agentName) agentName = path43.basename(exportStateDir);
32835
33007
  await doExport2({ agentName, stateDir: exportStateDir, note, dryRun: dryRun2 });
32836
33008
  process.exit(0);
32837
33009
  }
@@ -32853,7 +33025,7 @@ async function main() {
32853
33025
  console.error("\u274C import \u9700\u8981 --state-dir <path>");
32854
33026
  process.exit(1);
32855
33027
  }
32856
- if (!agentName) agentName = path42.basename(importStateDir);
33028
+ if (!agentName) agentName = path43.basename(importStateDir);
32857
33029
  await doImport2({ agentName, stateDir: importStateDir, version, archiveFile: archiveFile || void 0, dryRun: dryRun2 });
32858
33030
  process.exit(0);
32859
33031
  }
@@ -32881,18 +33053,18 @@ engine7 start \u2014 \u542F\u52A8 Engine
32881
33053
  }
32882
33054
  }
32883
33055
  if (!configPath2) {
32884
- const defaultCfg = path42.join("configs", "main7.json");
32885
- const homeCfg = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
32886
- if (fs42.existsSync(defaultCfg)) {
33056
+ const defaultCfg = path43.join("configs", "main7.json");
33057
+ const homeCfg = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
33058
+ if (fs43.existsSync(defaultCfg)) {
32887
33059
  configPath2 = defaultCfg;
32888
- } else if (fs42.existsSync(homeCfg)) {
33060
+ } else if (fs43.existsSync(homeCfg)) {
32889
33061
  configPath2 = homeCfg;
32890
33062
  console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
32891
33063
  } else {
32892
33064
  const ptr = readHomePointer();
32893
33065
  if (ptr?.stateDir) {
32894
- const ptrCfg = path42.join(ptr.stateDir, "configs", "main7.json");
32895
- if (fs42.existsSync(ptrCfg)) {
33066
+ const ptrCfg = path43.join(ptr.stateDir, "configs", "main7.json");
33067
+ if (fs43.existsSync(ptrCfg)) {
32896
33068
  configPath2 = ptrCfg;
32897
33069
  console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
32898
33070
  }
@@ -32905,26 +33077,26 @@ engine7 start \u2014 \u542F\u52A8 Engine
32905
33077
  }
32906
33078
  }
32907
33079
  }
32908
- if (configPath2 && !fs42.existsSync(configPath2)) {
33080
+ if (configPath2 && !fs43.existsSync(configPath2)) {
32909
33081
  console.error(`\u274C config \u6587\u4EF6\u4E0D\u5B58\u5728: ${configPath2}`);
32910
33082
  console.error(" \u7528\u6CD5: engine7 start [configs/xxx.json | --config <path>]");
32911
33083
  process.exit(1);
32912
33084
  }
32913
- const { execSync: execSync3, spawn: spawn5 } = await import("node:child_process");
33085
+ const { execSync: execSync4, spawn: spawn5 } = await import("node:child_process");
32914
33086
  let enginePath;
32915
- const localPath = path42.join("node_modules", "engine7", "dist", "main.mjs");
32916
- if (fs42.existsSync(localPath)) {
33087
+ const localPath = path43.join("node_modules", "engine7", "dist", "main.mjs");
33088
+ if (fs43.existsSync(localPath)) {
32917
33089
  enginePath = localPath;
32918
33090
  } else {
32919
- const cliPath = path42.resolve(process.argv[1]);
32920
- const distDir = path42.dirname(cliPath);
32921
- const candidate = path42.join(distDir, "main.mjs");
32922
- if (fs42.existsSync(candidate)) {
33091
+ const cliPath = path43.resolve(process.argv[1]);
33092
+ const distDir = path43.dirname(cliPath);
33093
+ const candidate = path43.join(distDir, "main.mjs");
33094
+ if (fs43.existsSync(candidate)) {
32923
33095
  enginePath = candidate;
32924
33096
  } else {
32925
33097
  try {
32926
- const globalRoot = execSync3("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
32927
- enginePath = path42.join(globalRoot, "engine7", "dist", "main.mjs");
33098
+ const globalRoot = execSync4("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
33099
+ enginePath = path43.join(globalRoot, "engine7", "dist", "main.mjs");
32928
33100
  } catch {
32929
33101
  console.error("\u274C \u627E\u4E0D\u5230 engine7 main.mjs");
32930
33102
  process.exit(1);
@@ -32934,29 +33106,23 @@ engine7 start \u2014 \u542F\u52A8 Engine
32934
33106
  console.log(label);
32935
33107
  console.log(` config: ${configPath2}`);
32936
33108
  console.log(` engine: ${enginePath}`);
32937
- const configName = path42.basename(configPath2);
32938
- const configAbs = path42.resolve(configPath2);
32939
- const myPid = process.pid;
33109
+ const configAbs = path43.resolve(configPath2);
32940
33110
  try {
32941
- if (process.platform === "win32") {
32942
- execSync3(`powershell -Command "Get-WmiObject Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine.Contains('${configAbs}') -and $_.CommandLine -like '*dist*' -and $_.ProcessId -ne ${myPid} } | ForEach-Object { Write-Host '[start] Killing PID' $_.ProcessId; Stop-Process -Id $_.ProcessId -Force }"`, { stdio: "inherit" });
32943
- } else {
32944
- const psOut = execSync3(`ps -axo pid=,command= | grep -F 'dist/main.mjs' | grep -F '${configAbs}' | grep -vF 'ps -axo' | awk '{print $1}' 2>/dev/null || true`, { encoding: "utf-8" }).trim();
32945
- const otherPids = psOut.split("\n").map((p) => p.trim()).filter((p) => p && /^\d+$/.test(p) && p !== String(myPid)).join("\n").trim();
32946
- if (otherPids) {
32947
- console.log(`[start] Killing existing engine (PID: ${otherPids})...`);
32948
- execSync3(`echo "${otherPids}" | xargs kill -9 2>/dev/null || true`);
32949
- await new Promise((r) => setTimeout(r, 2e3));
32950
- }
33111
+ const stateDir = engineStateDirOfConfig(configAbs);
33112
+ const killed = stateDir ? killOwnEngineForStateDir(stateDir) : null;
33113
+ if (killed !== null) {
33114
+ console.log(`[start] Killing existing engine (PID: ${killed})...`);
33115
+ await waitForPidGone(killed);
32951
33116
  }
32952
- } catch {
33117
+ } catch (err) {
33118
+ console.warn(`[start] \u6740\u65E7\u8FDB\u7A0B\u5931\u8D25\uFF08\u4E0D\u6321\u542F\u52A8\uFF09\uFF1A${err.message}`);
32953
33119
  }
32954
33120
  console.log("");
32955
33121
  const envForChild = { ...process.env };
32956
33122
  const { stateDir: secretsStateDir, configName: secretsCfgName } = resolveConfigIdentity(configPath2);
32957
33123
  for (const secretPath of secretsCandidates(secretsStateDir, secretsCfgName)) {
32958
- if (fs42.existsSync(secretPath)) {
32959
- const content = fs42.readFileSync(secretPath, "utf-8");
33124
+ if (fs43.existsSync(secretPath)) {
33125
+ const content = fs43.readFileSync(secretPath, "utf-8");
32960
33126
  for (const line of content.split("\n")) {
32961
33127
  const trimmed = line.trim();
32962
33128
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -33004,7 +33170,6 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
33004
33170
  process.exit(0);
33005
33171
  }
33006
33172
  if (action === "reset") {
33007
- const { execSync: execSync3 } = await import("node:child_process");
33008
33173
  let configPath2 = "";
33009
33174
  let mode = "archive";
33010
33175
  let dropN = 3;
@@ -33031,14 +33196,14 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
33031
33196
  console.error(`\u274C \u672A\u77E5\u6A21\u5F0F: ${mode}\uFF08\u53EF\u9009: archive / drop-last / strip-images\uFF09`);
33032
33197
  process.exit(1);
33033
33198
  }
33034
- const configRaw = JSON.parse(fs42.readFileSync(configPath2, "utf-8"));
33199
+ const configRaw = JSON.parse(fs43.readFileSync(configPath2, "utf-8"));
33035
33200
  const stateDir = configRaw.stateDir;
33036
33201
  if (!stateDir) {
33037
33202
  console.error("\u274C config \u91CC\u6CA1\u6709 stateDir");
33038
33203
  process.exit(1);
33039
33204
  }
33040
- const sessionsDir = path42.join(stateDir, "agents", "main", "sessions");
33041
- if (!fs42.existsSync(sessionsDir)) {
33205
+ const sessionsDir = path43.join(stateDir, "agents", "main", "sessions");
33206
+ if (!fs43.existsSync(sessionsDir)) {
33042
33207
  console.error(`\u274C sessions \u76EE\u5F55\u4E0D\u5B58\u5728: ${sessionsDir}`);
33043
33208
  process.exit(1);
33044
33209
  }
@@ -33046,56 +33211,54 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
33046
33211
  console.log(` config: ${configPath2}`);
33047
33212
  console.log(` mode: ${mode}`);
33048
33213
  if (mode === "drop-last") console.log(` n: ${dropN}`);
33049
- const platformMapPath = path42.join(sessionsDir, "platform-map.json");
33050
- const indexPath = path42.join(sessionsDir, "session-index.json");
33214
+ const platformMapPath = path43.join(sessionsDir, "platform-map.json");
33215
+ const indexPath = path43.join(sessionsDir, "session-index.json");
33051
33216
  let sessionFileUUID = null;
33052
- if (fs42.existsSync(indexPath)) {
33053
- const index = JSON.parse(fs42.readFileSync(indexPath, "utf-8"));
33217
+ if (fs43.existsSync(indexPath)) {
33218
+ const index = JSON.parse(fs43.readFileSync(indexPath, "utf-8"));
33054
33219
  const entries2 = Object.values(index);
33055
33220
  if (entries2.length > 0) {
33056
33221
  const fileVal = entries2[0].file || "";
33057
- sessionFileUUID = path42.isAbsolute(fileVal) ? path42.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
33222
+ sessionFileUUID = path43.isAbsolute(fileVal) ? path43.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
33058
33223
  }
33059
33224
  }
33060
33225
  if (!sessionFileUUID) {
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);
33226
+ const jsonlFiles = fs43.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs43.statSync(path43.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
33062
33227
  if (jsonlFiles.length === 0) {
33063
33228
  console.error("\u274C \u627E\u4E0D\u5230\u6D3B\u8DC3\u7684 session JSONL \u6587\u4EF6");
33064
33229
  process.exit(1);
33065
33230
  }
33066
33231
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
33067
33232
  }
33068
- let jsonlPath = path42.join(sessionsDir, `${sessionFileUUID}.jsonl`);
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);
33233
+ let jsonlPath = path43.join(sessionsDir, `${sessionFileUUID}.jsonl`);
33234
+ if (!fs43.existsSync(jsonlPath)) {
33235
+ const jsonlFiles = fs43.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs43.statSync(path43.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
33071
33236
  if (jsonlFiles.length === 0) {
33072
33237
  console.error(`\u274C JSONL \u6587\u4EF6\u4E0D\u5B58\u5728: ${jsonlPath}`);
33073
33238
  process.exit(1);
33074
33239
  }
33075
33240
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
33076
- jsonlPath = path42.join(sessionsDir, `${sessionFileUUID}.jsonl`);
33241
+ jsonlPath = path43.join(sessionsDir, `${sessionFileUUID}.jsonl`);
33077
33242
  }
33078
33243
  console.log(` file: ${jsonlPath}`);
33079
- const configName = path42.basename(configPath2);
33080
33244
  if (autoRestart) {
33081
33245
  try {
33082
- const myPid = process.pid;
33083
- const pids = execSync3(`pgrep -f "dist/main.mjs.*${configName}" 2>/dev/null || true`, { encoding: "utf-8" }).trim();
33084
- const otherPids = pids.split("\n").filter((p) => p && p.trim() !== String(myPid)).join("\n").trim();
33085
- if (otherPids) {
33246
+ const stateDir2 = engineStateDirOfConfig(path43.resolve(configPath2));
33247
+ const killed = stateDir2 ? killOwnEngineForStateDir(stateDir2) : null;
33248
+ if (killed !== null) {
33086
33249
  console.log(`
33087
- Killing engine (PID: ${otherPids})...`);
33088
- execSync3(`echo "${otherPids}" | xargs kill -9 2>/dev/null || true`);
33089
- await new Promise((r) => setTimeout(r, 2e3));
33250
+ Killing engine (PID: ${killed})...`);
33251
+ await waitForPidGone(killed);
33090
33252
  }
33091
- } catch {
33253
+ } catch (err) {
33254
+ console.warn(`[session] \u6740\u65E7\u8FDB\u7A0B\u5931\u8D25\uFF08\u4E0D\u6321\u91CD\u7F6E\uFF09\uFF1A${err.message}`);
33092
33255
  }
33093
33256
  }
33094
33257
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
33095
- const { readFileSync: readFileSync45, writeFileSync: writeFileSync26, renameSync: renameSync5 } = fs42;
33258
+ const { readFileSync: readFileSync45, writeFileSync: writeFileSync26, renameSync: renameSync5 } = fs43;
33096
33259
  if (mode === "archive") {
33097
33260
  const archiveName = `${sessionFileUUID}.jsonl.archived.${timestamp}`;
33098
- renameSync5(jsonlPath, path42.join(sessionsDir, archiveName));
33261
+ renameSync5(jsonlPath, path43.join(sessionsDir, archiveName));
33099
33262
  console.log(`
33100
33263
  \u2705 \u5F52\u6863\u5B8C\u6210: ${archiveName}`);
33101
33264
  console.log(` \u91CD\u542F\u540E\u5C06\u4ECE\u7A7A\u767D\u4F1A\u8BDD\u5F00\u59CB`);
@@ -33170,12 +33333,12 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
33170
33333
  \u2705 \u6458\u9664 ${stripped} \u884C\u56FE\u7247\u76F8\u5173\u5185\u5BB9`);
33171
33334
  }
33172
33335
  if (autoRestart) {
33173
- const realCliPath = fs42.realpathSync(process.argv[1]);
33174
- const cliDir = path42.dirname(realCliPath);
33175
- const pkgRoot = path42.resolve(cliDir, "..");
33176
- let enginePath = path42.join(pkgRoot, "dist", "main.mjs");
33177
- if (!fs42.existsSync(enginePath)) {
33178
- enginePath = path42.join(cliDir, "main.mjs");
33336
+ const realCliPath = fs43.realpathSync(process.argv[1]);
33337
+ const cliDir = path43.dirname(realCliPath);
33338
+ const pkgRoot = path43.resolve(cliDir, "..");
33339
+ let enginePath = path43.join(pkgRoot, "dist", "main.mjs");
33340
+ if (!fs43.existsSync(enginePath)) {
33341
+ enginePath = path43.join(cliDir, "main.mjs");
33179
33342
  }
33180
33343
  console.log(`
33181
33344
  \u{1F680} \u62C9\u8D77 engine...`);
@@ -33215,18 +33378,18 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33215
33378
  let configPath2 = cfg;
33216
33379
  let cwd = svcCwd;
33217
33380
  if (!configPath2) {
33218
- const defaultCfg = path42.join(cwd, "configs", "main7.json");
33219
- const homeCfg = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
33220
- if (fs42.existsSync(defaultCfg)) {
33381
+ const defaultCfg = path43.join(cwd, "configs", "main7.json");
33382
+ const homeCfg = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
33383
+ if (fs43.existsSync(defaultCfg)) {
33221
33384
  configPath2 = defaultCfg;
33222
- } else if (fs42.existsSync(homeCfg)) {
33385
+ } else if (fs43.existsSync(homeCfg)) {
33223
33386
  configPath2 = homeCfg;
33224
- cwd = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
33387
+ cwd = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
33225
33388
  } else {
33226
33389
  const ptr = readHomePointer();
33227
33390
  if (ptr?.stateDir) {
33228
- const ptrCfg = path42.join(ptr.stateDir, "configs", "main7.json");
33229
- if (fs42.existsSync(ptrCfg)) {
33391
+ const ptrCfg = path43.join(ptr.stateDir, "configs", "main7.json");
33392
+ if (fs43.existsSync(ptrCfg)) {
33230
33393
  configPath2 = ptrCfg;
33231
33394
  cwd = ptr.stateDir;
33232
33395
  }
@@ -33239,32 +33402,32 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33239
33402
  }
33240
33403
  }
33241
33404
  }
33242
- const { execSync: execSync3 } = await import("node:child_process");
33405
+ const { execSync: execSync4 } = await import("node:child_process");
33243
33406
  const engine7Bin = process.argv[1];
33244
33407
  if (action === "install") {
33245
33408
  if (process.platform === "win32") {
33246
33409
  const taskName = "Engine7";
33247
- const wrapperPath = path42.join(cwd, "engine7-start.cmd");
33410
+ const wrapperPath = path43.join(cwd, "engine7-start.cmd");
33248
33411
  const wrapperContent = buildServiceWrapper({
33249
33412
  cwd,
33250
33413
  nodeExe: nodeExe || void 0,
33251
- cliMjs: path42.resolve(engine7Bin),
33252
- configPath: path42.resolve(configPath2)
33414
+ cliMjs: path43.resolve(engine7Bin),
33415
+ configPath: path43.resolve(configPath2)
33253
33416
  });
33254
- fs42.writeFileSync(wrapperPath, wrapperContent);
33255
- const startupDir = path42.join(
33256
- process.env.APPDATA || path42.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33417
+ fs43.writeFileSync(wrapperPath, wrapperContent);
33418
+ const startupDir = path43.join(
33419
+ process.env.APPDATA || path43.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33257
33420
  "Microsoft",
33258
33421
  "Windows",
33259
33422
  "Start Menu",
33260
33423
  "Programs",
33261
33424
  "Startup"
33262
33425
  );
33263
- fs42.mkdirSync(startupDir, { recursive: true });
33264
- const vbsPath = path42.join(startupDir, "Engine7.vbs");
33426
+ fs43.mkdirSync(startupDir, { recursive: true });
33427
+ const vbsPath = path43.join(startupDir, "Engine7.vbs");
33265
33428
  const nodeExePath = nodeExe || process.execPath;
33266
- const cliMjsPath = path42.resolve(engine7Bin);
33267
- const absCfg = path42.resolve(configPath2);
33429
+ const cliMjsPath = path43.resolve(engine7Bin);
33430
+ const absCfg = path43.resolve(configPath2);
33268
33431
  const vbs = [
33269
33432
  "' Engine 7 \u5F00\u673A\u81EA\u542F\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF0C\u514D\u7BA1\u7406\u5458\uFF09",
33270
33433
  'Set fso = CreateObject("Scripting.FileSystemObject")',
@@ -33280,15 +33443,15 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33280
33443
  's.Run """' + nodeExePath + '"" ""' + cliMjsPath + '"" start --config ""' + absCfg + '""", 0, False',
33281
33444
  ""
33282
33445
  ].join(String.fromCharCode(13) + String.fromCharCode(10));
33283
- fs42.writeFileSync(vbsPath, vbs);
33446
+ fs43.writeFileSync(vbsPath, vbs);
33284
33447
  console.log(`\u2705 \u5F00\u673A\u81EA\u542F\u52A8\u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939: ${vbsPath}\uFF09`);
33285
33448
  } else if (process.platform === "darwin") {
33286
33449
  const label = "com.engine7.agent";
33287
- const plistDir = path42.join(process.env.HOME, "Library", "LaunchAgents");
33288
- fs42.mkdirSync(plistDir, { recursive: true });
33289
- const plistPath = path42.join(plistDir, `${label}.plist`);
33290
- const localCli = path42.join("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");
33450
+ const plistDir = path43.join(process.env.HOME, "Library", "LaunchAgents");
33451
+ fs43.mkdirSync(plistDir, { recursive: true });
33452
+ const plistPath = path43.join(plistDir, `${label}.plist`);
33453
+ const localCli = path43.join("node_modules", "engine7", "dist", "cli.mjs");
33454
+ const cliMjs = fs43.existsSync(localCli) ? path43.resolve(localCli) : path43.join(path43.dirname(path43.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
33292
33455
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
33293
33456
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33294
33457
  <plist version="1.0">
@@ -33300,16 +33463,16 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33300
33463
  <string>${cliMjs}</string>
33301
33464
  <string>start</string>
33302
33465
  <string>--config</string>
33303
- <string>${path42.resolve(configPath2)}</string>
33466
+ <string>${path43.resolve(configPath2)}</string>
33304
33467
  </array>
33305
33468
  <key>WorkingDirectory</key><string>${cwd}</string>
33306
33469
  <key>RunAtLoad</key><true/>
33307
33470
  <key>KeepAlive</key><true/>
33308
33471
  </dict>
33309
33472
  </plist>`;
33310
- fs42.writeFileSync(plistPath, plist);
33473
+ fs43.writeFileSync(plistPath, plist);
33311
33474
  try {
33312
- execSync3(`launchctl load "${plistPath}"`, { stdio: "inherit" });
33475
+ execSync4(`launchctl load "${plistPath}"`, { stdio: "inherit" });
33313
33476
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
33314
33477
  console.log(` ${plistPath}`);
33315
33478
  } catch {
@@ -33318,9 +33481,9 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
33318
33481
  }
33319
33482
  } else {
33320
33483
  const svcName = "engine7";
33321
- const svcDir = path42.join(process.env.HOME, ".config", "systemd", "user");
33322
- fs42.mkdirSync(svcDir, { recursive: true });
33323
- const svcPath = path42.join(svcDir, `${svcName}.service`);
33484
+ const svcDir = path43.join(process.env.HOME, ".config", "systemd", "user");
33485
+ fs43.mkdirSync(svcDir, { recursive: true });
33486
+ const svcPath = path43.join(svcDir, `${svcName}.service`);
33324
33487
  const svc = `[Unit]
33325
33488
  Description=Engine 7 Agent
33326
33489
  After=network.target
@@ -33328,16 +33491,16 @@ After=network.target
33328
33491
  [Service]
33329
33492
  Type=simple
33330
33493
  WorkingDirectory=${cwd}
33331
- ExecStart=${process.execPath} ${engine7Bin} start --config ${path42.resolve(configPath2)}
33494
+ ExecStart=${process.execPath} ${engine7Bin} start --config ${path43.resolve(configPath2)}
33332
33495
  Restart=on-failure
33333
33496
  RestartSec=10
33334
33497
 
33335
33498
  [Install]
33336
33499
  WantedBy=default.target`;
33337
- fs42.writeFileSync(svcPath, svc);
33500
+ fs43.writeFileSync(svcPath, svc);
33338
33501
  try {
33339
- execSync3(`systemctl --user daemon-reload`, { stdio: "inherit" });
33340
- execSync3(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
33502
+ execSync4(`systemctl --user daemon-reload`, { stdio: "inherit" });
33503
+ execSync4(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
33341
33504
  console.log(`\u2705 systemd \u7528\u6237\u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
33342
33505
  console.log(` ${svcPath}`);
33343
33506
  } catch {
@@ -33347,8 +33510,8 @@ WantedBy=default.target`;
33347
33510
  }
33348
33511
  } else if (action === "uninstall") {
33349
33512
  if (process.platform === "win32") {
33350
- const vbsPath = path42.join(
33351
- process.env.APPDATA || path42.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33513
+ const vbsPath = path43.join(
33514
+ process.env.APPDATA || path43.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33352
33515
  "Microsoft",
33353
33516
  "Windows",
33354
33517
  "Start Menu",
@@ -33357,46 +33520,46 @@ WantedBy=default.target`;
33357
33520
  "Engine7.vbs"
33358
33521
  );
33359
33522
  try {
33360
- execSync3(`schtasks /delete /tn "Engine7" /f`, { stdio: "ignore" });
33523
+ execSync4(`schtasks /delete /tn "Engine7" /f`, { stdio: "ignore" });
33361
33524
  } catch {
33362
33525
  }
33363
- if (fs42.existsSync(vbsPath)) {
33364
- fs42.rmSync(vbsPath, { force: true });
33526
+ if (fs43.existsSync(vbsPath)) {
33527
+ fs43.rmSync(vbsPath, { force: true });
33365
33528
  console.log(`\u2705 \u5F00\u673A\u81EA\u542F\u52A8\u5DF2\u79FB\u9664\uFF08${vbsPath}\uFF09`);
33366
33529
  } else {
33367
33530
  console.log("\uFF08\u5F00\u673A\u81EA\u542F\u52A8\u672C\u6765\u5C31\u6CA1\u6CE8\u518C\uFF09");
33368
33531
  }
33369
33532
  } else if (process.platform === "darwin") {
33370
- const plistPath = path42.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
33533
+ const plistPath = path43.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
33371
33534
  try {
33372
- execSync3(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
33535
+ execSync4(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
33373
33536
  } catch {
33374
33537
  }
33375
33538
  try {
33376
- fs42.unlinkSync(plistPath);
33539
+ fs43.unlinkSync(plistPath);
33377
33540
  } catch {
33378
33541
  }
33379
33542
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
33380
33543
  } else {
33381
33544
  try {
33382
- execSync3(`systemctl --user disable engine7`, { stdio: "inherit" });
33545
+ execSync4(`systemctl --user disable engine7`, { stdio: "inherit" });
33383
33546
  } catch {
33384
33547
  }
33385
- const svcPath = path42.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
33548
+ const svcPath = path43.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
33386
33549
  try {
33387
- fs42.unlinkSync(svcPath);
33550
+ fs43.unlinkSync(svcPath);
33388
33551
  } catch {
33389
33552
  }
33390
33553
  try {
33391
- execSync3(`systemctl --user daemon-reload`, { stdio: "inherit" });
33554
+ execSync4(`systemctl --user daemon-reload`, { stdio: "inherit" });
33392
33555
  } catch {
33393
33556
  }
33394
33557
  console.log(`\u2705 systemd \u7528\u6237\u670D\u52A1\u5DF2\u5220\u9664`);
33395
33558
  }
33396
33559
  } else if (action === "status") {
33397
33560
  if (process.platform === "win32") {
33398
- const vbsPath = path42.join(
33399
- process.env.APPDATA || path42.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33561
+ const vbsPath = path43.join(
33562
+ process.env.APPDATA || path43.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
33400
33563
  "Microsoft",
33401
33564
  "Windows",
33402
33565
  "Start Menu",
@@ -33404,17 +33567,17 @@ WantedBy=default.target`;
33404
33567
  "Startup",
33405
33568
  "Engine7.vbs"
33406
33569
  );
33407
- console.log(fs42.existsSync(vbsPath) ? `\u2705 \u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF09: ${vbsPath}` : "\u274C \u672A\u6CE8\u518C");
33570
+ console.log(fs43.existsSync(vbsPath) ? `\u2705 \u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF09: ${vbsPath}` : "\u274C \u672A\u6CE8\u518C");
33408
33571
  } else if (process.platform === "darwin") {
33409
- const plistPath = path42.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
33410
- if (fs42.existsSync(plistPath)) {
33572
+ const plistPath = path43.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
33573
+ if (fs43.existsSync(plistPath)) {
33411
33574
  console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
33412
33575
  } else {
33413
33576
  console.log("\u274C \u672A\u5B89\u88C5");
33414
33577
  }
33415
33578
  } else {
33416
33579
  try {
33417
- execSync3(`systemctl --user is-enabled engine7`, { stdio: "inherit" });
33580
+ execSync4(`systemctl --user is-enabled engine7`, { stdio: "inherit" });
33418
33581
  } catch {
33419
33582
  console.log("\u274C \u672A\u5B89\u88C5");
33420
33583
  }
@@ -33440,8 +33603,8 @@ WantedBy=default.target`;
33440
33603
  console.log(`
33441
33604
  \u{1F680} engine7 init`);
33442
33605
  console.log(` state-dir: ${opts.stateDir}`);
33443
- if (fs42.existsSync(opts.stateDir) && !opts.dryRun) {
33444
- const files = fs42.readdirSync(opts.stateDir);
33606
+ if (fs43.existsSync(opts.stateDir) && !opts.dryRun) {
33607
+ const files = fs43.readdirSync(opts.stateDir);
33445
33608
  if (files.length > 0) {
33446
33609
  if (opts.force) {
33447
33610
  if (looksLikeAppInstall(opts.stateDir)) {
@@ -33454,10 +33617,10 @@ WantedBy=default.target`;
33454
33617
  }
33455
33618
  console.log(`
33456
33619
  \u26A0\uFE0F --force: \u6E05\u7A7A\u5DF2\u6709\u76EE\u5F55 ${opts.stateDir}`);
33457
- fs42.rmSync(opts.stateDir, { recursive: true, force: true });
33620
+ fs43.rmSync(opts.stateDir, { recursive: true, force: true });
33458
33621
  } else {
33459
- const existingConfig = path42.join(opts.stateDir, "configs", "main7.json");
33460
- if (fs42.existsSync(existingConfig)) {
33622
+ const existingConfig = path43.join(opts.stateDir, "configs", "main7.json");
33623
+ if (fs43.existsSync(existingConfig)) {
33461
33624
  console.log(`
33462
33625
  \u267B\uFE0F \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E: ${existingConfig}`);
33463
33626
  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`);
@@ -33538,12 +33701,12 @@ WantedBy=default.target`;
33538
33701
  let photoSrc = "";
33539
33702
  if (answers?.selfie?.photoPath) {
33540
33703
  const { dimsOf: dimsOf2 } = await Promise.resolve().then(() => (init_my_selfie(), my_selfie_exports));
33541
- const src = path42.resolve(answers.selfie.photoPath.trim());
33542
- const ext = path42.extname(src).toLowerCase();
33704
+ const src = path43.resolve(answers.selfie.photoPath.trim());
33705
+ const ext = path43.extname(src).toLowerCase();
33543
33706
  if (!PHOTO_EXTS.includes(ext)) {
33544
33707
  throw new Error(`\u7167\u7247\u683C\u5F0F\u4E0D\u652F\u6301\uFF1A${ext || "(\u6CA1\u6709\u540E\u7F00)"}\u3002\u8BF7\u7528 PNG / JPEG / WebP\u3002`);
33545
33708
  }
33546
- if (!fs42.existsSync(src)) {
33709
+ if (!fs43.existsSync(src)) {
33547
33710
  throw new Error(`\u7167\u7247\u4E0D\u5B58\u5728\uFF1A${src}`);
33548
33711
  }
33549
33712
  const dims = dimsOf2(src);
@@ -33554,7 +33717,7 @@ WantedBy=default.target`;
33554
33717
  photoSrc = src;
33555
33718
  }
33556
33719
  const config = generateConfig(values);
33557
- const configPath = path42.join(opts.stateDir, "configs", "main7.json");
33720
+ const configPath = path43.join(opts.stateDir, "configs", "main7.json");
33558
33721
  const tree = buildDirTree(values);
33559
33722
  if (headlessEmit) headlessEmit({ event: "progress", step: "write_config" });
33560
33723
  tree.push({
@@ -33566,22 +33729,22 @@ WantedBy=default.target`;
33566
33729
  dryRun(tree);
33567
33730
  const skillsSrc = findTemplateDir("skills");
33568
33731
  if (skillsSrc) {
33569
- const skills = fs42.readdirSync(skillsSrc);
33732
+ const skills = fs43.readdirSync(skillsSrc);
33570
33733
  for (const s of skills) {
33571
- console.log(` \u{1F4C1} ${path42.join(opts.stateDir, "workspace", "skills", s)}`);
33734
+ console.log(` \u{1F4C1} ${path43.join(opts.stateDir, "workspace", "skills", s)}`);
33572
33735
  }
33573
33736
  }
33574
33737
  } else {
33575
33738
  if (values.chatMode === "auto") {
33576
33739
  try {
33577
- fs42.unlinkSync(path42.join(opts.stateDir, "workspace", ".work-mode"));
33740
+ fs43.unlinkSync(path43.join(opts.stateDir, "workspace", ".work-mode"));
33578
33741
  } catch {
33579
33742
  }
33580
33743
  }
33581
33744
  if (photoSrc && values.selfiePhotoRelPath) {
33582
- const dest = path42.join(opts.stateDir, "workspace", values.selfiePhotoRelPath);
33583
- fs42.mkdirSync(path42.dirname(dest), { recursive: true });
33584
- fs42.copyFileSync(photoSrc, dest);
33745
+ const dest = path43.join(opts.stateDir, "workspace", values.selfiePhotoRelPath);
33746
+ fs43.mkdirSync(path43.dirname(dest), { recursive: true });
33747
+ fs43.copyFileSync(photoSrc, dest);
33585
33748
  console.log(` \u{1F5BC} \u5F62\u8C61: ${dest}`);
33586
33749
  }
33587
33750
  if (headlessEmit) headlessEmit({ event: "progress", step: "create_dirs" });
@@ -33610,58 +33773,58 @@ WantedBy=default.target`;
33610
33773
  if (headlessEmit) headlessEmit({ event: "progress", step: "copy_skills" });
33611
33774
  const skillsSrc = findTemplateDir("skills");
33612
33775
  if (skillsSrc) {
33613
- const skillsDest = path42.join(opts.stateDir, "workspace", "skills");
33614
- fs42.mkdirSync(skillsDest, { recursive: true });
33615
- const skills = fs42.readdirSync(skillsSrc);
33776
+ const skillsDest = path43.join(opts.stateDir, "workspace", "skills");
33777
+ fs43.mkdirSync(skillsDest, { recursive: true });
33778
+ const skills = fs43.readdirSync(skillsSrc);
33616
33779
  for (const s of skills) {
33617
- copyDirRecursive(path42.join(skillsSrc, s), path42.join(skillsDest, s));
33780
+ copyDirRecursive(path43.join(skillsSrc, s), path43.join(skillsDest, s));
33618
33781
  console.log(` \u{1F4E6} skill: ${s}`);
33619
33782
  }
33620
33783
  }
33621
33784
  console.log(`
33622
33785
  \u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
33623
33786
  `);
33624
- const homePointer = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
33787
+ const homePointer = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
33625
33788
  const pointerData = { stateDir: opts.stateDir };
33626
- fs42.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
33789
+ fs43.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
33627
33790
  console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
33628
33791
  console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
33629
33792
  console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
33630
33793
  console.log(` 2. \u542F\u52A8 Engine: engine7 start\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
33631
33794
  console.log(` 3. \u5F00\u673A\u81EA\u542F: engine7 service install\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
33632
- console.log(` 4. \u67E5\u770B workspace: ${path42.join(opts.stateDir, "workspace")}`);
33795
+ console.log(` 4. \u67E5\u770B workspace: ${path43.join(opts.stateDir, "workspace")}`);
33633
33796
  if (headlessEmit) {
33634
33797
  headlessEmit({ event: "done", stateDir: opts.stateDir.replace(/\\/g, "/"), configPath: configPath.replace(/\\/g, "/") });
33635
33798
  }
33636
33799
  }
33637
33800
  }
33638
33801
  function copyDirRecursive(src, dest) {
33639
- fs42.mkdirSync(dest, { recursive: true });
33640
- for (const entry of fs42.readdirSync(src, { withFileTypes: true })) {
33641
- const srcPath = path42.join(src, entry.name);
33642
- const destPath = path42.join(dest, entry.name);
33802
+ fs43.mkdirSync(dest, { recursive: true });
33803
+ for (const entry of fs43.readdirSync(src, { withFileTypes: true })) {
33804
+ const srcPath = path43.join(src, entry.name);
33805
+ const destPath = path43.join(dest, entry.name);
33643
33806
  if (entry.isDirectory()) {
33644
33807
  copyDirRecursive(srcPath, destPath);
33645
33808
  } else {
33646
- fs42.copyFileSync(srcPath, destPath);
33809
+ fs43.copyFileSync(srcPath, destPath);
33647
33810
  }
33648
33811
  }
33649
33812
  }
33650
33813
  function findTemplateDir(name) {
33651
33814
  const candidates = [
33652
- path42.join(__dirname, "..", "templates", name),
33653
- path42.join(__dirname, "..", "..", "templates", name),
33654
- path42.join(process.cwd(), "templates", name)
33815
+ path43.join(__dirname, "..", "templates", name),
33816
+ path43.join(__dirname, "..", "..", "templates", name),
33817
+ path43.join(process.cwd(), "templates", name)
33655
33818
  ];
33656
33819
  for (const p of candidates) {
33657
- if (fs42.existsSync(p)) return p;
33820
+ if (fs43.existsSync(p)) return p;
33658
33821
  }
33659
33822
  return null;
33660
33823
  }
33661
33824
  function readHomePointer() {
33662
- const ptrPath = path42.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
33825
+ const ptrPath = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
33663
33826
  try {
33664
- return JSON.parse(fs42.readFileSync(ptrPath, "utf-8"));
33827
+ return JSON.parse(fs43.readFileSync(ptrPath, "utf-8"));
33665
33828
  } catch {
33666
33829
  return null;
33667
33830
  }