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/main.mjs CHANGED
@@ -124,6 +124,17 @@ var init_live = __esm({
124
124
  Object.assign(this.current, newConfig);
125
125
  }
126
126
  /** 改活树上的值;文件承载路径同步持久化(read-modify-write 回 config 文件) */
127
+ /**
128
+ * 改活树 + 落盘。
129
+ *
130
+ * 返回值 = **落盘**是否成功(活树无论成败都已同步——它是先改的)。绝大多数调用点照旧
131
+ * `void liveConfig.set(...)` 不理它;但**要打成功日志的调用点必须 await 这个布尔值**。
132
+ *
133
+ * 为什么把这个信号交出去(1001 审查捞回):本方法本来是 fire-and-forget,落盘失败只在
134
+ * `persistToFile` 里 warn 一行;而启动早段的调用点(两个免费档 fixup)紧接着打了句
135
+ * "免费档补齐 xxx" 的成功日志 ⇒ 配置**没写进文件**却被读成"写好了":进程内生效、托盘
136
+ * 读文件还是旧值、下次启动重放同一句——正是本仓最恨的假信号。
137
+ */
127
138
  async set(dotPath, val) {
128
139
  if (!this.current) throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
129
140
  const keys = dotPath.split(".");
@@ -133,15 +144,15 @@ var init_live = __esm({
133
144
  obj = obj[keys[i]];
134
145
  }
135
146
  obj[keys[keys.length - 1]] = val;
136
- await this.persistToFile(dotPath, val);
147
+ return this.persistToFile(dotPath, val);
137
148
  }
138
- /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
149
+ /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效)。返回是否真的落盘。 */
139
150
  async persistToFile(dotPath, val) {
140
151
  const fs60 = await import("node:fs");
141
152
  const cfgPath = this.current?._configFilePath;
142
153
  if (!cfgPath || !fs60.existsSync(cfgPath)) {
143
154
  console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
144
- return;
155
+ return false;
145
156
  }
146
157
  try {
147
158
  const raw = JSON.parse(fs60.readFileSync(cfgPath, "utf-8"));
@@ -155,8 +166,10 @@ var init_live = __esm({
155
166
  fs60.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
156
167
  console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
157
168
  markSelfWrite();
169
+ return true;
158
170
  } catch (e) {
159
171
  console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
172
+ return false;
160
173
  }
161
174
  }
162
175
  /** 是否已初始化 */
@@ -8310,30 +8323,30 @@ __export(teamHelpers_exports, {
8310
8323
  writeTeamFile: () => writeTeamFile,
8311
8324
  writeTeamFileAsync: () => writeTeamFileAsync
8312
8325
  });
8313
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
8326
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
8314
8327
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
8315
- import { join as join16 } from "node:path";
8328
+ import { join as join17 } from "node:path";
8316
8329
  function initTeamDirs(stateDir) {
8317
8330
  _stateDir = stateDir;
8318
8331
  }
8319
8332
  function getTeamsDir() {
8320
- return join16(_stateDir, "teams");
8333
+ return join17(_stateDir, "teams");
8321
8334
  }
8322
8335
  function getTasksDir() {
8323
- return join16(_stateDir, "tasks");
8336
+ return join17(_stateDir, "tasks");
8324
8337
  }
8325
8338
  function sanitizeName(name) {
8326
8339
  return name.replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
8327
8340
  }
8328
8341
  function getTeamDir(teamName) {
8329
- return join16(getTeamsDir(), sanitizeName(teamName));
8342
+ return join17(getTeamsDir(), sanitizeName(teamName));
8330
8343
  }
8331
8344
  function getTeamFilePath(teamName) {
8332
- return join16(getTeamDir(teamName), "config.json");
8345
+ return join17(getTeamDir(teamName), "config.json");
8333
8346
  }
8334
8347
  function readTeamFile(teamName) {
8335
8348
  try {
8336
- const content = readFileSync11(getTeamFilePath(teamName), "utf-8");
8349
+ const content = readFileSync12(getTeamFilePath(teamName), "utf-8");
8337
8350
  return JSON.parse(content);
8338
8351
  } catch (e) {
8339
8352
  if (e?.code === "ENOENT") return null;
@@ -8353,8 +8366,8 @@ async function readTeamFileAsync(teamName) {
8353
8366
  }
8354
8367
  function writeTeamFile(teamName, teamFile) {
8355
8368
  const teamDir = getTeamDir(teamName);
8356
- mkdirSync8(teamDir, { recursive: true });
8357
- writeFileSync5(getTeamFilePath(teamName), JSON.stringify(teamFile, null, 2));
8369
+ mkdirSync9(teamDir, { recursive: true });
8370
+ writeFileSync6(getTeamFilePath(teamName), JSON.stringify(teamFile, null, 2));
8358
8371
  }
8359
8372
  async function writeTeamFileAsync(teamName, teamFile) {
8360
8373
  const teamDir = getTeamDir(teamName);
@@ -8434,7 +8447,7 @@ async function cleanupTeamDirectories(teamName) {
8434
8447
  } catch (error) {
8435
8448
  console.warn(`[teamHelpers] Failed to clean up team directory ${teamDir}: ${error.message}`);
8436
8449
  }
8437
- const tasksDir = join16(getTasksDir(), sanitizedName);
8450
+ const tasksDir = join17(getTasksDir(), sanitizedName);
8438
8451
  try {
8439
8452
  await rm(tasksDir, { recursive: true, force: true });
8440
8453
  console.log(`[teamHelpers] Cleaned up tasks directory: ${tasksDir}`);
@@ -8443,8 +8456,8 @@ async function cleanupTeamDirectories(teamName) {
8443
8456
  }
8444
8457
  }
8445
8458
  function ensureTasksDir(taskListId) {
8446
- const dir = join16(getTasksDir(), taskListId);
8447
- mkdirSync8(dir, { recursive: true });
8459
+ const dir = join17(getTasksDir(), taskListId);
8460
+ mkdirSync9(dir, { recursive: true });
8448
8461
  }
8449
8462
  function setLeaderTeamName(name) {
8450
8463
  _leaderTeamName = name;
@@ -8489,9 +8502,9 @@ __export(teammateMailbox_exports, {
8489
8502
  writeToMailbox: () => writeToMailbox
8490
8503
  });
8491
8504
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
8492
- import { join as join17 } from "node:path";
8505
+ import { join as join18 } from "node:path";
8493
8506
  function getTeamsDir2() {
8494
- return join17(process.env.ENGINE_STATE_DIR || ".", "teams");
8507
+ return join18(process.env.ENGINE_STATE_DIR || ".", "teams");
8495
8508
  }
8496
8509
  function sanitizePathComponent(s) {
8497
8510
  return s.replace(/[^a-zA-Z0-9_-]/g, "-");
@@ -8500,12 +8513,12 @@ function getInboxPath(agentName, teamName) {
8500
8513
  const team = teamName || "default";
8501
8514
  const safeTeam = sanitizePathComponent(team);
8502
8515
  const safeAgentName = sanitizePathComponent(agentName);
8503
- return join17(getTeamsDir2(), safeTeam, "inboxes", `${safeAgentName}.json`);
8516
+ return join18(getTeamsDir2(), safeTeam, "inboxes", `${safeAgentName}.json`);
8504
8517
  }
8505
8518
  async function ensureInboxDir(teamName) {
8506
8519
  const team = teamName || "default";
8507
8520
  const safeTeam = sanitizePathComponent(team);
8508
- const inboxDir = join17(getTeamsDir2(), safeTeam, "inboxes");
8521
+ const inboxDir = join18(getTeamsDir2(), safeTeam, "inboxes");
8509
8522
  await mkdir2(inboxDir, { recursive: true });
8510
8523
  }
8511
8524
  async function sleep2(ms) {
@@ -8814,7 +8827,7 @@ var init_inboxPoller = __esm({
8814
8827
 
8815
8828
  // src/memory/memdir/memoryScan.ts
8816
8829
  import { readdir, stat as stat2, readFile as readFile3 } from "node:fs/promises";
8817
- import { basename as basename4, join as join18, sep as sep3 } from "node:path";
8830
+ import { basename as basename4, join as join19, sep as sep3 } from "node:path";
8818
8831
  function isArchivedPath(relativePath) {
8819
8832
  return relativePath.split(sep3).includes("archive");
8820
8833
  }
@@ -8864,7 +8877,7 @@ async function scanMemoryFiles2(memoryDir, signal, maxFiles) {
8864
8877
  );
8865
8878
  const headerResults = await Promise.allSettled(
8866
8879
  mdFiles.map(async (relativePath) => {
8867
- const filePath = join18(memoryDir, relativePath);
8880
+ const filePath = join19(memoryDir, relativePath);
8868
8881
  const { content, mtimeMs } = await readFileHeader(
8869
8882
  filePath,
8870
8883
  FRONTMATTER_MAX_LINES,
@@ -9798,8 +9811,8 @@ var init_filters = __esm({
9798
9811
 
9799
9812
  // src/mem7/core/vector-store.ts
9800
9813
  import { Schema, Field, Utf8, Float32, Int64, FixedSizeList, TimestampMicrosecond, List } from "apache-arrow";
9801
- import { mkdirSync as mkdirSync9 } from "node:fs";
9802
- import { join as join23 } from "node:path";
9814
+ import { mkdirSync as mkdirSync10 } from "node:fs";
9815
+ import { join as join24 } from "node:path";
9803
9816
  function lanceSpecifierFor(platform2, arch) {
9804
9817
  return platform2 === "darwin" && arch === "x64" ? "@engine7/lancedb-intel" : "@lancedb/lancedb";
9805
9818
  }
@@ -9895,13 +9908,13 @@ var init_vector_store = __esm({
9895
9908
  dir;
9896
9909
  tables = /* @__PURE__ */ new Map();
9897
9910
  constructor(stateDir) {
9898
- this.dir = join23(mem7Root(stateDir), "index", "lancedb");
9911
+ this.dir = join24(mem7Root(stateDir), "index", "lancedb");
9899
9912
  }
9900
9913
  async conn() {
9901
9914
  if (!this.db) {
9902
9915
  const lance = await loadLance();
9903
9916
  if (!lance) throw new Mem7VectorUnavailableError();
9904
- mkdirSync9(this.dir, { recursive: true });
9917
+ mkdirSync10(this.dir, { recursive: true });
9905
9918
  this.db = await lance.connect(this.dir);
9906
9919
  }
9907
9920
  return this.db;
@@ -10190,14 +10203,14 @@ Follow these principles when generating episodic memories:
10190
10203
 
10191
10204
  // src/mem7/core/store.ts
10192
10205
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
10193
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync7, existsSync as existsSync16, readdirSync as readdirSync2 } from "node:fs";
10194
- import { join as join24 } from "node:path";
10206
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync17, writeFileSync as writeFileSync8, existsSync as existsSync17, readdirSync as readdirSync2 } from "node:fs";
10207
+ import { join as join25 } from "node:path";
10195
10208
  import { createHash as createHash2 } from "node:crypto";
10196
10209
  function contentHash(text) {
10197
10210
  return createHash2("sha256").update(text.replace(/\s+/g, "")).digest("hex").slice(0, 40);
10198
10211
  }
10199
10212
  function mem7Root(stateDir) {
10200
- return join24(stateDir, "mem7");
10213
+ return join25(stateDir, "mem7");
10201
10214
  }
10202
10215
  var SCHEMA, Mem7Store;
10203
10216
  var init_store2 = __esm({
@@ -10233,8 +10246,8 @@ CREATE TABLE IF NOT EXISTS watermarks (
10233
10246
  constructor(stateDir) {
10234
10247
  this.stateDir = stateDir;
10235
10248
  this.root = mem7Root(stateDir);
10236
- mkdirSync10(join24(this.root, "index"), { recursive: true });
10237
- this.db = new DatabaseSync2(join24(this.root, "index", "mem7.db"));
10249
+ mkdirSync11(join25(this.root, "index"), { recursive: true });
10250
+ this.db = new DatabaseSync2(join25(this.root, "index", "mem7.db"));
10238
10251
  this.db.exec("PRAGMA journal_mode=WAL");
10239
10252
  this.db.exec(SCHEMA);
10240
10253
  }
@@ -10365,14 +10378,14 @@ CREATE TABLE IF NOT EXISTS watermarks (
10365
10378
  /** md 追加通用:frontmatter(存在则更新计数)+ 既有 entry 块全保留 + 追加新块 */
10366
10379
  appendMd(ownerId, dirName, filePrefix, type2, dateStr, entries2, render) {
10367
10380
  if (entries2.length === 0) return;
10368
- const dir = join24(this.root, "users", ownerId, dirName);
10369
- mkdirSync10(dir, { recursive: true });
10370
- const file2 = join24(dir, `${filePrefix}-${dateStr}.md`);
10381
+ const dir = join25(this.root, "users", ownerId, dirName);
10382
+ mkdirSync11(dir, { recursive: true });
10383
+ const file2 = join25(dir, `${filePrefix}-${dateStr}.md`);
10371
10384
  let head;
10372
10385
  let existingBlocks = "";
10373
10386
  let count;
10374
- if (existsSync16(file2)) {
10375
- const text = readFileSync16(file2, "utf8");
10387
+ if (existsSync17(file2)) {
10388
+ const text = readFileSync17(file2, "utf8");
10376
10389
  const fmEnd = text.indexOf("\n---", 3);
10377
10390
  const split = fmEnd >= 0 ? fmEnd + 4 : text.length;
10378
10391
  head = text.slice(0, split);
@@ -10403,7 +10416,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
10403
10416
  count++;
10404
10417
  }
10405
10418
  head = head.replace(/entry_count: \d+/, `entry_count: ${count}`).replace(/last_appended_at: '[^']*'/, `last_appended_at: '${formatMdTimestamp()}'`);
10406
- writeFileSync7(file2, head + "\n\n" + blocks.join("\n\n") + "\n", "utf8");
10419
+ writeFileSync8(file2, head + "\n\n" + blocks.join("\n\n") + "\n", "utf8");
10407
10420
  }
10408
10421
  /**
10409
10422
  * entry_id:前缀_YYYYMMDD_六位序号。
@@ -10423,11 +10436,11 @@ CREATE TABLE IF NOT EXISTS watermarks (
10423
10436
  af: [".atomic_facts", "atomic-facts"]
10424
10437
  };
10425
10438
  const [dirName, filePrefix] = dirByPrefix[prefix];
10426
- const file2 = join24(this.root, "users", ownerId, dirName, `${filePrefix}-${dateStr}.md`);
10439
+ const file2 = join25(this.root, "users", ownerId, dirName, `${filePrefix}-${dateStr}.md`);
10427
10440
  let max = 0;
10428
- if (existsSync16(file2)) {
10441
+ if (existsSync17(file2)) {
10429
10442
  const re = new RegExp(`${prefix}_${dateStr.replace(/-/g, "")}_(\\d+)`, "g");
10430
- for (const m of readFileSync16(file2, "utf8").matchAll(re)) max = Math.max(max, Number(m[1]));
10443
+ for (const m of readFileSync17(file2, "utf8").matchAll(re)) max = Math.max(max, Number(m[1]));
10431
10444
  }
10432
10445
  return max;
10433
10446
  }
@@ -10494,17 +10507,17 @@ CREATE TABLE IF NOT EXISTS watermarks (
10494
10507
  getOpenPredictions(now, limit = 50) {
10495
10508
  const today3 = todayKey(now);
10496
10509
  const out = [];
10497
- const usersDir = join24(this.root, "users");
10498
- if (!existsSync16(usersDir)) return out;
10510
+ const usersDir = join25(this.root, "users");
10511
+ if (!existsSync17(usersDir)) return out;
10499
10512
  for (const owner of readdirSync2(usersDir, { withFileTypes: true })) {
10500
10513
  if (!owner.isDirectory()) continue;
10501
- const dir = join24(usersDir, owner.name, ".foresights");
10502
- if (!existsSync16(dir)) continue;
10514
+ const dir = join25(usersDir, owner.name, ".foresights");
10515
+ if (!existsSync17(dir)) continue;
10503
10516
  for (const f of readdirSync2(dir)) {
10504
10517
  if (!/^foresight-\d{4}-\d{2}-\d{2}\.md$/.test(f)) continue;
10505
10518
  let content;
10506
10519
  try {
10507
- content = readFileSync16(join24(dir, f), "utf8");
10520
+ content = readFileSync17(join25(dir, f), "utf8");
10508
10521
  } catch {
10509
10522
  continue;
10510
10523
  }
@@ -10583,9 +10596,9 @@ var init_ingest2 = __esm({
10583
10596
  });
10584
10597
 
10585
10598
  // src/mem7/core/ids.ts
10586
- import { randomBytes as randomBytes3 } from "node:crypto";
10599
+ import { randomBytes as randomBytes4 } from "node:crypto";
10587
10600
  function hex(len) {
10588
- return randomBytes3(Math.ceil(len / 2)).toString("hex").slice(0, len);
10601
+ return randomBytes4(Math.ceil(len / 2)).toString("hex").slice(0, len);
10589
10602
  }
10590
10603
  function randomCellId() {
10591
10604
  return `mc_${hex(12)}`;
@@ -10597,9 +10610,9 @@ var init_ids = __esm({
10597
10610
  });
10598
10611
 
10599
10612
  // src/mem7/core/boundary.ts
10600
- import { readFileSync as readFileSync17 } from "node:fs";
10601
- import { join as join25, dirname as dirname4 } from "node:path";
10602
- import { fileURLToPath as fileURLToPath2 } from "node:url";
10613
+ import { readFileSync as readFileSync18 } from "node:fs";
10614
+ import { join as join26, dirname as dirname5 } from "node:path";
10615
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
10603
10616
  function renderBoundaryInput(messages) {
10604
10617
  return messages.map((m, i) => `[${i + 1}] [${new Date(m.tsMs).toISOString()}] ${m.senderName ?? m.senderId}: ${m.text}`).join("\n");
10605
10618
  }
@@ -10692,14 +10705,14 @@ var init_boundary = __esm({
10692
10705
  HARD_TOKEN_LIMIT = 8192;
10693
10706
  HARD_MSG_LIMIT = 50;
10694
10707
  RETRIES = 3;
10695
- PROMPT2 = readFileSync17(join25(dirname4(fileURLToPath2(import.meta.url)), "prompts", "boundary.md"), "utf8");
10708
+ PROMPT2 = readFileSync18(join26(dirname5(fileURLToPath3(import.meta.url)), "prompts", "boundary.md"), "utf8");
10696
10709
  }
10697
10710
  });
10698
10711
 
10699
10712
  // src/mem7/core/episode.ts
10700
- import { readFileSync as readFileSync18 } from "node:fs";
10701
- import { join as join26, dirname as dirname5 } from "node:path";
10702
- import { fileURLToPath as fileURLToPath3 } from "node:url";
10713
+ import { readFileSync as readFileSync19 } from "node:fs";
10714
+ import { join as join27, dirname as dirname6 } from "node:path";
10715
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
10703
10716
  function renderConversation(cell) {
10704
10717
  return cell.messages.map((m) => `
10705
10718
  {
@@ -10755,14 +10768,14 @@ var init_episode = __esm({
10755
10768
  "use strict";
10756
10769
  init_prompt_render();
10757
10770
  RETRIES2 = 2;
10758
- PROMPT3 = readFileSync18(join26(dirname5(fileURLToPath3(import.meta.url)), "prompts", "episode.md"), "utf8");
10771
+ PROMPT3 = readFileSync19(join27(dirname6(fileURLToPath4(import.meta.url)), "prompts", "episode.md"), "utf8");
10759
10772
  }
10760
10773
  });
10761
10774
 
10762
10775
  // src/mem7/core/atomic-facts.ts
10763
- import { readFileSync as readFileSync19 } from "node:fs";
10764
- import { join as join27, dirname as dirname6 } from "node:path";
10765
- import { fileURLToPath as fileURLToPath4 } from "node:url";
10776
+ import { readFileSync as readFileSync20 } from "node:fs";
10777
+ import { join as join28, dirname as dirname7 } from "node:path";
10778
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
10766
10779
  async function extractAtomicFacts(cell, provider, model) {
10767
10780
  const userPrompt = renderPrompt(PROMPT4, {
10768
10781
  INPUT_TEXT: renderConversationText(cell.messages),
@@ -10797,14 +10810,14 @@ var init_atomic_facts = __esm({
10797
10810
  init_episode();
10798
10811
  init_prompt_render();
10799
10812
  RETRIES3 = 5;
10800
- PROMPT4 = readFileSync19(join27(dirname6(fileURLToPath4(import.meta.url)), "prompts", "atomic-facts-memcell.md"), "utf8");
10813
+ PROMPT4 = readFileSync20(join28(dirname7(fileURLToPath5(import.meta.url)), "prompts", "atomic-facts-memcell.md"), "utf8");
10801
10814
  }
10802
10815
  });
10803
10816
 
10804
10817
  // src/mem7/core/foresight.ts
10805
- import { readFileSync as readFileSync20 } from "node:fs";
10806
- import { join as join28, dirname as dirname7 } from "node:path";
10807
- import { fileURLToPath as fileURLToPath5 } from "node:url";
10818
+ import { readFileSync as readFileSync21 } from "node:fs";
10819
+ import { join as join29, dirname as dirname8 } from "node:path";
10820
+ import { fileURLToPath as fileURLToPath6 } from "node:url";
10808
10821
  function cleanDateString(dateStr) {
10809
10822
  if (typeof dateStr !== "string" || !dateStr) return null;
10810
10823
  const cleaned = dateStr.replace(/[^\d-]/g, "");
@@ -10887,7 +10900,7 @@ var init_foresight = __esm({
10887
10900
  MAX_COUNT = 10;
10888
10901
  MIN_COUNT = 4;
10889
10902
  TEMPERATURE = 0.3;
10890
- PROMPT5 = readFileSync20(join28(dirname7(fileURLToPath5(import.meta.url)), "prompts", "foresight.md"), "utf8");
10903
+ PROMPT5 = readFileSync21(join29(dirname8(fileURLToPath6(import.meta.url)), "prompts", "foresight.md"), "utf8");
10891
10904
  }
10892
10905
  });
10893
10906
 
@@ -11088,7 +11101,7 @@ var init_mem7 = __esm({
11088
11101
  });
11089
11102
 
11090
11103
  // src/memory/proactive/config.ts
11091
- import { join as join29 } from "node:path";
11104
+ import { join as join30 } from "node:path";
11092
11105
  function parseProactiveConfig(raw) {
11093
11106
  const obj = raw && typeof raw === "object" ? raw : {};
11094
11107
  const modelRef = typeof obj.model === "string" ? obj.model.trim() : "";
@@ -11115,7 +11128,7 @@ function parseProactiveConfig(raw) {
11115
11128
  };
11116
11129
  }
11117
11130
  function proactiveDbPath(workspace) {
11118
- return join29(workspace, ".proactive", "proactive.db");
11131
+ return join30(workspace, ".proactive", "proactive.db");
11119
11132
  }
11120
11133
  var init_config3 = __esm({
11121
11134
  "src/memory/proactive/config.ts"() {
@@ -11459,8 +11472,8 @@ var init_graph_store = __esm({
11459
11472
 
11460
11473
  // src/memory/proactive/persistence.ts
11461
11474
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
11462
- import { mkdirSync as mkdirSync11 } from "node:fs";
11463
- import { dirname as dirname8 } from "node:path";
11475
+ import { mkdirSync as mkdirSync12 } from "node:fs";
11476
+ import { dirname as dirname9 } from "node:path";
11464
11477
  function rowToAction(r) {
11465
11478
  return {
11466
11479
  id: r.id,
@@ -11561,7 +11574,7 @@ CREATE INDEX IF NOT EXISTS idx_proactive_decisions_created ON proactive_decision
11561
11574
  Persistence = class {
11562
11575
  db;
11563
11576
  constructor(dbPath) {
11564
- mkdirSync11(dirname8(dbPath), { recursive: true });
11577
+ mkdirSync12(dirname9(dbPath), { recursive: true });
11565
11578
  this.db = new DatabaseSync3(dbPath);
11566
11579
  this.db.exec("PRAGMA journal_mode=WAL");
11567
11580
  this.db.exec(SCHEMA2);
@@ -12308,8 +12321,8 @@ var init_agent_tools = __esm({
12308
12321
  });
12309
12322
 
12310
12323
  // src/memory/proactive/prompts.ts
12311
- import { readFileSync as readFileSync21 } from "node:fs";
12312
- import { join as join30 } from "node:path";
12324
+ import { readFileSync as readFileSync22 } from "node:fs";
12325
+ import { join as join31 } from "node:path";
12313
12326
  function buildSectionRegistry(D) {
12314
12327
  const SECTION_CORE_ROLE = `You are a cognitive graph update agent for a proactive memory system that maintains a dynamic knowledge graph representing ${D.domain_description}.
12315
12328
 
@@ -12921,9 +12934,9 @@ Return your response as JSON.`;
12921
12934
  }
12922
12935
  function loadPersona(workspace) {
12923
12936
  if (!workspace) return "";
12924
- const file2 = join30(workspace, "prompts", "proactive-persona.md");
12937
+ const file2 = join31(workspace, "prompts", "proactive-persona.md");
12925
12938
  try {
12926
- const text = readFileSync21(file2, "utf8").trim();
12939
+ const text = readFileSync22(file2, "utf8").trim();
12927
12940
  if (text) console.log(`[proactive] persona loaded from ${file2} (${text.length} chars)`);
12928
12941
  return text;
12929
12942
  } catch {
@@ -12932,9 +12945,9 @@ function loadPersona(workspace) {
12932
12945
  }
12933
12946
  function loadDomain(workspace) {
12934
12947
  if (!workspace) return DEFAULT_DOMAIN;
12935
- const file2 = join30(workspace, "prompts", "proactive-domain.json");
12948
+ const file2 = join31(workspace, "prompts", "proactive-domain.json");
12936
12949
  try {
12937
- const raw = JSON.parse(readFileSync21(file2, "utf8"));
12950
+ const raw = JSON.parse(readFileSync22(file2, "utf8"));
12938
12951
  if (raw && typeof raw === "object") {
12939
12952
  const allowed = new Set(Object.keys(DEFAULT_DOMAIN));
12940
12953
  const clean = {};
@@ -13442,7 +13455,7 @@ var init_helpers = __esm({
13442
13455
  });
13443
13456
 
13444
13457
  // src/calendar/commands.ts
13445
- import { existsSync as existsSync17, statSync as statSync4 } from "node:fs";
13458
+ import { existsSync as existsSync18, statSync as statSync4 } from "node:fs";
13446
13459
  import { isAbsolute as isAbsolute4, resolve as resolve6 } from "node:path";
13447
13460
  function fmtEnd(start, durationMin) {
13448
13461
  const [hh, mm] = start.split(":").map(Number);
@@ -13611,7 +13624,7 @@ function addTask(db2, args2) {
13611
13624
  }
13612
13625
  try {
13613
13626
  const absPath = isAbsolute4(docPath) ? docPath : resolve6(process.cwd(), docPath);
13614
- if (!existsSync17(absPath)) {
13627
+ if (!existsSync18(absPath)) {
13615
13628
  return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728
13616
13629
  \u8DEF\u5F84: ${docPath}
13617
13630
  \u89E3\u6790\u540E: ${absPath}
@@ -14044,8 +14057,8 @@ var init_recall_score = __esm({
14044
14057
  });
14045
14058
 
14046
14059
  // src/memory/proactive/opportunity.ts
14047
- import { readdirSync as readdirSync3, readFileSync as readFileSync22, existsSync as existsSync18 } from "node:fs";
14048
- import { join as join31 } from "node:path";
14060
+ import { readdirSync as readdirSync3, readFileSync as readFileSync23, existsSync as existsSync19 } from "node:fs";
14061
+ import { join as join32 } from "node:path";
14049
14062
  function normalizeOpportunity(raw) {
14050
14063
  if (!raw || typeof raw !== "object") return null;
14051
14064
  const o = raw;
@@ -14130,8 +14143,8 @@ function parseForesightEntries(everosRoot, now, userId) {
14130
14143
  const today3 = todayKey(now);
14131
14144
  let files;
14132
14145
  if (userId) {
14133
- const ownDir = join31(everosRoot, userId, "default_project", "users", userId, ".foresights");
14134
- files = existsSync18(ownDir) ? listForesightMds(ownDir) : findForesightFiles(everosRoot);
14146
+ const ownDir = join32(everosRoot, userId, "default_project", "users", userId, ".foresights");
14147
+ files = existsSync19(ownDir) ? listForesightMds(ownDir) : findForesightFiles(everosRoot);
14135
14148
  } else {
14136
14149
  files = findForesightFiles(everosRoot);
14137
14150
  }
@@ -14140,7 +14153,7 @@ function parseForesightEntries(everosRoot, now, userId) {
14140
14153
  for (const file2 of files) {
14141
14154
  let content;
14142
14155
  try {
14143
- content = readFileSync22(file2, "utf8");
14156
+ content = readFileSync23(file2, "utf8");
14144
14157
  } catch {
14145
14158
  continue;
14146
14159
  }
@@ -14180,7 +14193,7 @@ function matchForesightForEvent(entries2, message, maxHits = 2) {
14180
14193
  }
14181
14194
  function listForesightMds(dir) {
14182
14195
  try {
14183
- return readdirSync3(dir).filter((f) => /^foresight-\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => join31(dir, f)).sort();
14196
+ return readdirSync3(dir).filter((f) => /^foresight-\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => join32(dir, f)).sort();
14184
14197
  } catch {
14185
14198
  return [];
14186
14199
  }
@@ -14196,7 +14209,7 @@ function findForesightFiles(everosRoot) {
14196
14209
  return;
14197
14210
  }
14198
14211
  for (const e of entries2) {
14199
- const p = join31(dir, e.name);
14212
+ const p = join32(dir, e.name);
14200
14213
  if (e.isDirectory()) {
14201
14214
  if (e.name === ".foresights") {
14202
14215
  files.push(...listForesightMds(p));
@@ -15322,7 +15335,7 @@ var init_intent = __esm({
15322
15335
  });
15323
15336
 
15324
15337
  // src/memory/proactive/sweep.ts
15325
- import { readFileSync as readFileSync23 } from "node:fs";
15338
+ import { readFileSync as readFileSync24 } from "node:fs";
15326
15339
  function sharesTerm(a, b) {
15327
15340
  const x = normalizeTitle(a);
15328
15341
  const y = normalizeTitle(b);
@@ -15542,7 +15555,7 @@ ${JSON.stringify(payload, null, 2)}
15542
15555
  const file2 = this.deps.promptFile;
15543
15556
  if (!file2) return DEFAULT_PROMPT;
15544
15557
  try {
15545
- const text = readFileSync23(file2, "utf8").trim();
15558
+ const text = readFileSync24(file2, "utf8").trim();
15546
15559
  return text || DEFAULT_PROMPT;
15547
15560
  } catch {
15548
15561
  return DEFAULT_PROMPT;
@@ -15553,14 +15566,14 @@ ${JSON.stringify(payload, null, 2)}
15553
15566
  });
15554
15567
 
15555
15568
  // src/memory/proactive/proactive-tools.ts
15556
- import { existsSync as existsSync19 } from "node:fs";
15569
+ import { existsSync as existsSync20 } from "node:fs";
15557
15570
  function setProactiveWorkspace(workspace) {
15558
15571
  toolWorkspace = workspace;
15559
15572
  }
15560
15573
  function withStore(fn) {
15561
15574
  if (!toolWorkspace) return null;
15562
15575
  const p = proactiveDbPath(toolWorkspace);
15563
- if (!existsSync19(p)) return null;
15576
+ if (!existsSync20(p)) return null;
15564
15577
  const store = new Persistence(p);
15565
15578
  try {
15566
15579
  return fn(store);
@@ -15813,8 +15826,8 @@ __export(plugin_exports, {
15813
15826
  ProactivePlugin: () => ProactivePlugin,
15814
15827
  feedMem7Cell: () => feedMem7Cell
15815
15828
  });
15816
- import { join as join32 } from "node:path";
15817
- import { existsSync as existsSync20, readFileSync as readFileSync24, appendFileSync as appendFileSync3 } from "node:fs";
15829
+ import { join as join33 } from "node:path";
15830
+ import { existsSync as existsSync21, readFileSync as readFileSync25, appendFileSync as appendFileSync3 } from "node:fs";
15818
15831
  function isFiller(text) {
15819
15832
  const t = text.trim();
15820
15833
  if (t.length >= 5) return false;
@@ -15839,7 +15852,7 @@ function buildPlanningContext(calDb, workspace) {
15839
15852
  }
15840
15853
  }
15841
15854
  try {
15842
- const state2 = readFileSync24(join32(workspace, "SESSION-STATE.md"), "utf8");
15855
+ const state2 = readFileSync25(join33(workspace, "SESSION-STATE.md"), "utf8");
15843
15856
  const active = extractActiveState(state2);
15844
15857
  if (active) {
15845
15858
  lines.push("\n[SESSION-STATE active work]");
@@ -16036,8 +16049,8 @@ var init_plugin = __esm({
16036
16049
  });
16037
16050
  this.actionAgent = new ActionAgent(this.provider, this.config.modelId, persona);
16038
16051
  this.ingestWorkspace = workspace;
16039
- const calDbPath = join32(workspace, ".calendar", "calendar.db");
16040
- this.calDb = existsSync20(calDbPath) ? openDb(workspace) : null;
16052
+ const calDbPath = join33(workspace, ".calendar", "calendar.db");
16053
+ this.calDb = existsSync21(calDbPath) ? openDb(workspace) : null;
16041
16054
  registerCallbackHook("PostToolUse", {
16042
16055
  type: "callback",
16043
16056
  id: "proactive-completion-evidence",
@@ -16076,7 +16089,7 @@ ${String(input.tool_output ?? "")}`
16076
16089
  const pluginCalDb = this.calDb;
16077
16090
  this.sweep = new Sweep({
16078
16091
  persist: this.persist,
16079
- promptFile: join32(workspace, "prompts", "proactive.md"),
16092
+ promptFile: join33(workspace, "prompts", "proactive.md"),
16080
16093
  // 三个都走 getter **每轮现读** —— 热加载规则(config 改了立刻生效)+
16081
16094
  // calendar 会变,都不能在 start() 时快照。
16082
16095
  get minLeadDays() {
@@ -16094,7 +16107,7 @@ ${String(input.tool_output ?? "")}`
16094
16107
  },
16095
16108
  // 闸掉的必须留痕:她要能"扫一眼标题,真有冤案我喊"。
16096
16109
  onGated: (items) => {
16097
- const gatedPath = join32(workspace, ".proactive", "gated.jsonl");
16110
+ const gatedPath = join33(workspace, ".proactive", "gated.jsonl");
16098
16111
  try {
16099
16112
  appendFileSync3(
16100
16113
  gatedPath,
@@ -16170,7 +16183,7 @@ ${String(input.tool_output ?? "")}`
16170
16183
  const nowDate = /* @__PURE__ */ new Date();
16171
16184
  const stateDir = String(liveConfig.get("stateDir") ?? "");
16172
16185
  if (stateDir) {
16173
- const all = loadForesightEntries(join32(stateDir, "mem7"), nowDate);
16186
+ const all = loadForesightEntries(join33(stateDir, "mem7"), nowDate);
16174
16187
  const events = all.filter((e) => e.kind !== "profile");
16175
16188
  const mem7Entries = capForesightEntries(events, todayKey(nowDate));
16176
16189
  if (all.length > 0) {
@@ -16312,7 +16325,7 @@ ${String(input.tool_output ?? "")}`
16312
16325
  if (!stateDir) this.warnOnce("stateDir", "[proactive] stateDir \u4E3A\u7A7A \u2192 mem7 \u53EC\u56DE\u6574\u6BB5\u8DF3\u8FC7\uFF08\u914D\u7F6E/\u521D\u59CB\u5316\u5F02\u5E38\uFF1F\uFF09");
16313
16326
  if (senderScoped) console.log(`[proactive] sender-scoped recall owners=[${(scopedOwners ?? []).join(",")}]`);
16314
16327
  if (stateDir && scopeReady) {
16315
- const mem7Entries = loadForesightEntries(join32(stateDir, "mem7"), now, void 0, scopedOwners);
16328
+ const mem7Entries = loadForesightEntries(join33(stateDir, "mem7"), now, void 0, scopedOwners);
16316
16329
  const bigram = matchForesightForEvent(mem7Entries, prompt);
16317
16330
  for (const h of bigram) hitSet.add(`[mem7] ${h.replace(/^- /, "")}`);
16318
16331
  if (bigram.length === 0) {
@@ -16436,17 +16449,17 @@ ${String(input.tool_output ?? "")}`
16436
16449
  });
16437
16450
 
16438
16451
  // src/memory/sessionMemory/sessionMemoryUtils.ts
16439
- import { join as join33 } from "node:path";
16440
- import { mkdirSync as mkdirSync12, readFileSync as readFileSync25 } from "node:fs";
16452
+ import { join as join34 } from "node:path";
16453
+ import { mkdirSync as mkdirSync13, readFileSync as readFileSync26 } from "node:fs";
16441
16454
  function setSessionMemoryStateDir(dir) {
16442
16455
  _stateDir2 = dir;
16443
- mkdirSync12(dir, { recursive: true });
16456
+ mkdirSync13(dir, { recursive: true });
16444
16457
  }
16445
16458
  function getSessionMemoryDir() {
16446
16459
  return _stateDir2;
16447
16460
  }
16448
16461
  function getSessionMemoryPath() {
16449
- return join33(_stateDir2, "session-notes.md");
16462
+ return join34(_stateDir2, "session-notes.md");
16450
16463
  }
16451
16464
  function markExtractionStarted() {
16452
16465
  extractionStartedAt = Date.now();
@@ -16494,7 +16507,7 @@ var init_sessionMemoryUtils = __esm({
16494
16507
 
16495
16508
  // src/memory/sessionMemory/prompts.ts
16496
16509
  import { readFile as readFile4 } from "node:fs/promises";
16497
- import { join as join34 } from "node:path";
16510
+ import { join as join35 } from "node:path";
16498
16511
  function roughTokenCountEstimation4(text) {
16499
16512
  return Math.ceil(text.length / 4);
16500
16513
  }
@@ -16539,7 +16552,7 @@ REMEMBER: Use the Edit tool in parallel and stop. Do not continue after the edit
16539
16552
  }
16540
16553
  async function loadSessionMemoryTemplate() {
16541
16554
  const configHome = process.env.CLAUDE_CONFIG_HOME || process.env.HOME || "";
16542
- const templatePath = join34(configHome, ".claude", "session-memory", "config", "template.md");
16555
+ const templatePath = join35(configHome, ".claude", "session-memory", "config", "template.md");
16543
16556
  try {
16544
16557
  return await readFile4(templatePath, { encoding: "utf-8" });
16545
16558
  } catch {
@@ -16548,7 +16561,7 @@ async function loadSessionMemoryTemplate() {
16548
16561
  }
16549
16562
  async function loadSessionMemoryPrompt() {
16550
16563
  const configHome = process.env.CLAUDE_CONFIG_HOME || process.env.HOME || "";
16551
- const promptPath = join34(configHome, ".claude", "session-memory", "config", "prompt.md");
16564
+ const promptPath = join35(configHome, ".claude", "session-memory", "config", "prompt.md");
16552
16565
  try {
16553
16566
  return await readFile4(promptPath, { encoding: "utf-8" });
16554
16567
  } catch {
@@ -16712,7 +16725,7 @@ __export(sessionMemory_exports, {
16712
16725
  resetLastMemoryMessageUuid: () => resetLastMemoryMessageUuid,
16713
16726
  shouldExtractMemory: () => shouldExtractMemory
16714
16727
  });
16715
- import { readFileSync as readFileSync26, mkdirSync as mkdirSync13 } from "node:fs";
16728
+ import { readFileSync as readFileSync27, mkdirSync as mkdirSync14 } from "node:fs";
16716
16729
  import { writeFile as writeFile3 } from "node:fs/promises";
16717
16730
  function initSessionMemory(deps) {
16718
16731
  _deps = deps;
@@ -16771,11 +16784,11 @@ function shouldExtractMemory(estimatedTokens, messages) {
16771
16784
  }
16772
16785
  async function setupSessionMemoryFile() {
16773
16786
  const memoryDir = getSessionMemoryDir();
16774
- mkdirSync13(memoryDir, { recursive: true });
16787
+ mkdirSync14(memoryDir, { recursive: true });
16775
16788
  const memoryPath = getSessionMemoryPath();
16776
16789
  let currentMemory;
16777
16790
  try {
16778
- currentMemory = readFileSync26(memoryPath, { encoding: "utf-8" });
16791
+ currentMemory = readFileSync27(memoryPath, { encoding: "utf-8" });
16779
16792
  } catch {
16780
16793
  const template = await loadSessionMemoryTemplate();
16781
16794
  await writeFile3(memoryPath, template, { encoding: "utf-8" });
@@ -16852,7 +16865,7 @@ ${messages.filter((m) => m.role === "user" || m.role === "assistant").slice(-20)
16852
16865
  }
16853
16866
  function getSessionMemoryForCompaction() {
16854
16867
  try {
16855
- const content = readFileSync26(getSessionMemoryPath(), { encoding: "utf-8" }).trim();
16868
+ const content = readFileSync27(getSessionMemoryPath(), { encoding: "utf-8" }).trim();
16856
16869
  if (!content) return null;
16857
16870
  const { truncatedContent, wasTruncated } = truncateSessionMemoryForCompact(content);
16858
16871
  if (wasTruncated) {
@@ -16885,9 +16898,9 @@ var init_sessionMemory = __esm({
16885
16898
 
16886
16899
  // src/memory/autoDream/consolidationLock.ts
16887
16900
  import { mkdir as mkdir3, readFile as readFile5, stat as stat3, unlink, utimes, writeFile as writeFile4 } from "node:fs/promises";
16888
- import { join as join35 } from "node:path";
16901
+ import { join as join36 } from "node:path";
16889
16902
  function lockPath(memoryDir) {
16890
- return join35(memoryDir, LOCK_FILE);
16903
+ return join36(memoryDir, LOCK_FILE);
16891
16904
  }
16892
16905
  async function readLastConsolidatedAt(memoryDir) {
16893
16906
  try {
@@ -16955,7 +16968,7 @@ async function listSessionsTouchedSince(sessionsDir, sinceMs) {
16955
16968
  const results = [];
16956
16969
  for (const f of jsonlFiles) {
16957
16970
  try {
16958
- const s = await stat3(join35(sessionsDir, f));
16971
+ const s = await stat3(join36(sessionsDir, f));
16959
16972
  if (s.mtimeMs > sinceMs) {
16960
16973
  results.push(f.replace(/\.jsonl$/, ""));
16961
16974
  }
@@ -18491,18 +18504,18 @@ var init_tasks2 = __esm({
18491
18504
  });
18492
18505
 
18493
18506
  // src/version.ts
18494
- import { readFileSync as readFileSync32 } from "node:fs";
18495
- import { dirname as dirname10, join as join43 } from "node:path";
18496
- import { fileURLToPath as fileURLToPath6 } from "node:url";
18507
+ import { readFileSync as readFileSync33 } from "node:fs";
18508
+ import { dirname as dirname11, join as join44 } from "node:path";
18509
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
18497
18510
  function candidates() {
18498
- if (_pkgDirOverride !== null) return [join43(_pkgDirOverride, "package.json")];
18499
- const here = dirname10(fileURLToPath6(import.meta.url));
18500
- return [join43(here, "..", "package.json"), join43(here, "..", "..", "package.json")];
18511
+ if (_pkgDirOverride !== null) return [join44(_pkgDirOverride, "package.json")];
18512
+ const here = dirname11(fileURLToPath7(import.meta.url));
18513
+ return [join44(here, "..", "package.json"), join44(here, "..", "..", "package.json")];
18501
18514
  }
18502
18515
  function readFromDisk() {
18503
18516
  for (const p of candidates()) {
18504
18517
  try {
18505
- return JSON.parse(readFileSync32(p, "utf-8")).version || "unknown";
18518
+ return JSON.parse(readFileSync33(p, "utf-8")).version || "unknown";
18506
18519
  } catch {
18507
18520
  }
18508
18521
  }
@@ -18651,8 +18664,8 @@ var reply_blocklist_exports = {};
18651
18664
  __export(reply_blocklist_exports, {
18652
18665
  isUserBlocked: () => isUserBlocked
18653
18666
  });
18654
- import { readFileSync as readFileSync33, writeFileSync as writeFileSync11, existsSync as existsSync24 } from "node:fs";
18655
- import { join as join44 } from "node:path";
18667
+ import { readFileSync as readFileSync34, writeFileSync as writeFileSync12, existsSync as existsSync25 } from "node:fs";
18668
+ import { join as join45 } from "node:path";
18656
18669
  function ensureLoaded(workspace, configIds) {
18657
18670
  if (loaded) return;
18658
18671
  if (configIds?.length) {
@@ -18660,10 +18673,10 @@ function ensureLoaded(workspace, configIds) {
18660
18673
  if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
18661
18674
  }
18662
18675
  }
18663
- const path61 = join44(workspace, ".reply-blocklist.json");
18676
+ const path61 = join45(workspace, ".reply-blocklist.json");
18664
18677
  try {
18665
- if (existsSync24(path61)) {
18666
- const raw = readFileSync33(path61, "utf-8");
18678
+ if (existsSync25(path61)) {
18679
+ const raw = readFileSync34(path61, "utf-8");
18667
18680
  const parsed = JSON.parse(raw);
18668
18681
  if (parsed.blockedUserIds) {
18669
18682
  for (const id of parsed.blockedUserIds) {
@@ -18679,9 +18692,9 @@ function ensureLoaded(workspace, configIds) {
18679
18692
  loaded = true;
18680
18693
  }
18681
18694
  function save(workspace) {
18682
- const path61 = join44(workspace, ".reply-blocklist.json");
18695
+ const path61 = join45(workspace, ".reply-blocklist.json");
18683
18696
  try {
18684
- writeFileSync11(path61, JSON.stringify(state, null, 2), "utf-8");
18697
+ writeFileSync12(path61, JSON.stringify(state, null, 2), "utf-8");
18685
18698
  } catch (err) {
18686
18699
  console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
18687
18700
  }
@@ -24042,6 +24055,7 @@ function startConfigWatcher(config2, deps, provider) {
24042
24055
  }
24043
24056
  });
24044
24057
  };
24058
+ consumeSelfWrite();
24045
24059
  startWatch();
24046
24060
  console.log(`[config-watch] watching ${configPath2}`);
24047
24061
  try {
@@ -24156,17 +24170,81 @@ import * as path16 from "node:path";
24156
24170
  import fs11 from "node:fs";
24157
24171
  import path11 from "node:path";
24158
24172
  import { execSync as execSync2 } from "node:child_process";
24159
- function acquireEngineLock(stateDir) {
24160
- const lockFile = path11.join(stateDir, ".engine.pid");
24161
- const myPid = process.pid;
24173
+ function enginePidFile(stateDir) {
24174
+ return path11.join(stateDir, ".engine.pid");
24175
+ }
24176
+ function isEngineImage(text) {
24177
+ return /node|engine7|electron/i.test(text);
24178
+ }
24179
+ function isPidAlive(pid) {
24180
+ try {
24181
+ process.kill(pid, 0);
24182
+ return true;
24183
+ } catch {
24184
+ return false;
24185
+ }
24186
+ }
24187
+ function probeImage(pid) {
24162
24188
  try {
24163
- const oldPid = parseInt(fs11.readFileSync(lockFile, "utf-8").trim(), 10);
24164
- if (oldPid && oldPid !== myPid && isNodeEngineAlive(oldPid)) {
24165
- console.log(`[pid-lock] Stale engine PID ${oldPid} still alive (node), killing tree...`);
24166
- killTree(oldPid);
24189
+ if (process.platform === "win32") {
24190
+ return execSync2(`tasklist /FI "PID eq ${pid}" /NH /FO CSV`, {
24191
+ encoding: "utf-8",
24192
+ timeout: 3e3,
24193
+ stdio: ["ignore", "pipe", "ignore"]
24194
+ });
24195
+ }
24196
+ if (process.platform === "darwin") {
24197
+ return execSync2(`ps -p ${pid} -o comm=`, {
24198
+ encoding: "utf-8",
24199
+ timeout: 3e3,
24200
+ stdio: ["ignore", "pipe", "ignore"]
24201
+ });
24167
24202
  }
24203
+ return fs11.readFileSync(`/proc/${pid}/comm`, "utf-8");
24204
+ } catch {
24205
+ return null;
24206
+ }
24207
+ }
24208
+ function probeEngineImage(pid) {
24209
+ return isEngineImage(probeImage(pid) ?? "");
24210
+ }
24211
+ function isCliWrapperImage(text) {
24212
+ return /node/i.test(text);
24213
+ }
24214
+ function probeIsCliWrapper(pid) {
24215
+ return isCliWrapperImage(probeImage(pid) ?? "");
24216
+ }
24217
+ function readOwnEnginePidText(stateDir) {
24218
+ try {
24219
+ return fs11.readFileSync(enginePidFile(stateDir), "utf-8");
24168
24220
  } catch (err) {
24169
24221
  if (err?.code !== "ENOENT") console.warn(`[pid-lock] read lock failed: ${err.message}`);
24222
+ return null;
24223
+ }
24224
+ }
24225
+ function pickOwnEnginePid(probe) {
24226
+ const pid = parseInt((probe.pidFileContent ?? "").trim(), 10);
24227
+ if (!Number.isInteger(pid) || pid <= 0) return null;
24228
+ if (pid === probe.myPid) return null;
24229
+ if (!probe.isAlive(pid)) return null;
24230
+ if (!probe.isEngineImage(pid)) return null;
24231
+ return pid;
24232
+ }
24233
+ function ownEnginePid(stateDir, myPid = process.pid) {
24234
+ return pickOwnEnginePid({
24235
+ pidFileContent: readOwnEnginePidText(stateDir),
24236
+ myPid,
24237
+ isAlive: isPidAlive,
24238
+ isEngineImage: probeEngineImage
24239
+ });
24240
+ }
24241
+ function acquireEngineLock(stateDir) {
24242
+ const lockFile = enginePidFile(stateDir);
24243
+ const myPid = process.pid;
24244
+ const stale = ownEnginePid(stateDir, myPid);
24245
+ if (stale !== null) {
24246
+ console.log(`[pid-lock] Stale engine PID ${stale} still alive (engine), killing tree...`);
24247
+ killTree(stale);
24170
24248
  }
24171
24249
  try {
24172
24250
  fs11.mkdirSync(stateDir, { recursive: true });
@@ -24192,54 +24270,42 @@ function acquireEngineLock(stateDir) {
24192
24270
  process.exit(0);
24193
24271
  });
24194
24272
  }
24195
- function isNodeEngineAlive(pid) {
24196
- try {
24197
- process.kill(pid, 0);
24198
- } catch {
24199
- return false;
24200
- }
24201
- try {
24202
- if (process.platform === "win32") {
24203
- const out = execSync2(`tasklist /FI "PID eq ${pid}" /NH /FO CSV`, {
24204
- encoding: "utf-8",
24205
- timeout: 3e3,
24206
- stdio: ["ignore", "pipe", "ignore"]
24207
- });
24208
- return /node\.exe/i.test(out);
24209
- } else if (process.platform === "darwin") {
24210
- const out = execSync2(`ps -p ${pid} -o comm=`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] });
24211
- return /node/.test(out);
24212
- }
24213
- return /node/.test(fs11.readFileSync(`/proc/${pid}/cmdline`, "utf-8"));
24214
- } catch {
24215
- return false;
24216
- }
24273
+ function pickParentPid(procStatus, psOutput) {
24274
+ const fromProc = Number(/PPid:\s*(\d+)/.exec(procStatus ?? "")?.[1] ?? NaN);
24275
+ if (Number.isInteger(fromProc) && fromProc > 0) return fromProc;
24276
+ const fromPs = Number((psOutput ?? "").trim());
24277
+ return Number.isInteger(fromPs) && fromPs > 0 ? fromPs : 0;
24217
24278
  }
24218
24279
  function killTree(pid) {
24219
24280
  try {
24220
24281
  if (process.platform === "win32") {
24221
24282
  execSync2(`taskkill /PID ${pid} /T /F`, { stdio: "ignore", timeout: 8e3 });
24222
24283
  try {
24223
- const parentPid = execSync2(`wmic process where ProcessId=${pid} get ParentProcessId /value`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).match(/ParentProcessId=(\d+)/)?.[1];
24224
- if (parentPid && parseInt(parentPid) !== process.ppid) {
24284
+ const parentPid = parseInt(execSync2(`wmic process where ProcessId=${pid} get ParentProcessId /value`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).match(/ParentProcessId=(\d+)/)?.[1] ?? "0", 10);
24285
+ if (parentPid && parentPid !== process.ppid && probeIsCliWrapper(parentPid)) {
24225
24286
  execSync2(`taskkill /PID ${parentPid} /F`, { stdio: "ignore", timeout: 3e3 });
24226
24287
  }
24227
24288
  } catch {
24228
24289
  }
24229
24290
  } else {
24230
24291
  process.kill(pid, "SIGKILL");
24292
+ let parentPid = 0;
24231
24293
  try {
24232
- const ppid = parseInt(fs11.readFileSync(`/proc/${pid}/status`, "utf-8").match(/PPid:\s+(\d+)/)?.[1] || "0", 10);
24233
- const macPpid = parseInt(execSync2(`ps -p ${pid} -o ppid=`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).trim(), 10);
24234
- const parentPid = ppid || macPpid;
24235
- if (parentPid && parentPid > 1) {
24236
- try {
24237
- process.kill(parentPid, "SIGKILL");
24238
- } catch {
24239
- }
24240
- }
24294
+ parentPid = pickParentPid(fs11.readFileSync(`/proc/${pid}/status`, "utf-8"), null);
24241
24295
  } catch {
24242
24296
  }
24297
+ if (!parentPid) {
24298
+ try {
24299
+ parentPid = pickParentPid(null, execSync2(`ps -p ${pid} -o ppid=`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }));
24300
+ } catch {
24301
+ }
24302
+ }
24303
+ if (parentPid > 1 && parentPid !== process.ppid && probeIsCliWrapper(parentPid)) {
24304
+ try {
24305
+ process.kill(parentPid, "SIGKILL");
24306
+ } catch {
24307
+ }
24308
+ }
24243
24309
  }
24244
24310
  } catch (err) {
24245
24311
  console.warn(`[pid-lock] kill ${pid} failed: ${err.message}`);
@@ -25757,6 +25823,18 @@ var FIELDS = [
25757
25823
 
25758
25824
  // src/cli-init-config.ts
25759
25825
  var FREE_TIER_RELAY_URL = "https://www.twinsun.top:8866";
25826
+ var FREE_TIER_PROVIDER_ID = "7yi";
25827
+ var DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
25828
+ function freeTierVoiceConfig(existing) {
25829
+ const mv = existing && typeof existing === "object" ? existing : {};
25830
+ return {
25831
+ ...mv,
25832
+ provider: "relay",
25833
+ relayProviderId: FREE_TIER_PROVIDER_ID,
25834
+ relayModel: "engine7-tts",
25835
+ voice: mv.voice || DEFAULT_FREE_VOICE
25836
+ };
25837
+ }
25760
25838
  var VISION_CAPABLE = {
25761
25839
  // 0917:原先标 true,但同一个文件里 qwen3.8-max 的 input 是 ['text'],安装器目录
25762
25840
  // 也明确标 vision=false(只有 Flash 叫"多模态")。矛盾直接导致**默认 CLI 装机路径**
@@ -25991,6 +26069,104 @@ function applyFreeTierVideoFixup(io) {
25991
26069
  return changed;
25992
26070
  }
25993
26071
 
26072
+ // src/provision-free.ts
26073
+ import { randomBytes as randomBytes2, randomUUID as randomUUID5 } from "node:crypto";
26074
+ import { chmodSync as chmodSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
26075
+ import { dirname as dirname3, join as join14 } from "node:path";
26076
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
26077
+ var __filename = fileURLToPath2(import.meta.url);
26078
+ var IDENTITY_FILE = "install-identity.json";
26079
+ function readContactEmailOf(parsed) {
26080
+ return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
26081
+ }
26082
+ function loadOrCreateInstallIdentity(stateDir) {
26083
+ const file2 = join14(stateDir, IDENTITY_FILE);
26084
+ if (existsSync10(file2)) {
26085
+ let parsed;
26086
+ try {
26087
+ parsed = JSON.parse(readFileSync9(file2, "utf8"));
26088
+ } catch (e) {
26089
+ throw new Error(
26090
+ `${IDENTITY_FILE} \u5B58\u5728\u4F46\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e.message}\uFF09\u2014\u2014\u5220\u6389\u5B83\u91CD\u8DD1\u4F1A\u9886\u4E00\u628A\u65B0\u4EE4\u724C\uFF0C\u65E7\u7684\u90A3\u628A\u53D6\u4E0D\u56DE\u6765`
26091
+ );
26092
+ }
26093
+ if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
26094
+ throw new Error(`${IDENTITY_FILE} \u7F3A installId / installSecret \u5B57\u6BB5`);
26095
+ }
26096
+ const email = readContactEmailOf(parsed);
26097
+ return {
26098
+ installId: parsed.installId,
26099
+ installSecret: parsed.installSecret,
26100
+ ...email ? { contactEmail: email } : {}
26101
+ };
26102
+ }
26103
+ const identity = {
26104
+ // 服务端校验 installId 长度为 8..36、只允许字母数字和连字符;uuid 正好符合
26105
+ installId: randomUUID5(),
26106
+ // 服务端校验 installSecret 为 32..64 位十六进制
26107
+ installSecret: randomBytes2(32).toString("hex")
26108
+ };
26109
+ mkdirSync7(stateDir, { recursive: true });
26110
+ writeFileSync4(file2, JSON.stringify(identity, null, 2) + "\n", { mode: 384 });
26111
+ try {
26112
+ chmodSync2(file2, 384);
26113
+ } catch {
26114
+ }
26115
+ return identity;
26116
+ }
26117
+ function readInstallIdentityDetailed(stateDir) {
26118
+ const file2 = join14(stateDir, IDENTITY_FILE);
26119
+ if (!existsSync10(file2)) return { ok: false, reason: "missing" };
26120
+ let text;
26121
+ try {
26122
+ text = readFileSync9(file2, "utf8");
26123
+ } catch (e) {
26124
+ return { ok: false, reason: "corrupt", detail: `\u5B58\u5728\u4F46\u8BFB\u4E0D\u4E86\uFF08${e?.message ?? e}\uFF09` };
26125
+ }
26126
+ let parsed;
26127
+ try {
26128
+ parsed = JSON.parse(text);
26129
+ } catch (e) {
26130
+ return { ok: false, reason: "corrupt", detail: `\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e?.message ?? e}\uFF09` };
26131
+ }
26132
+ if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
26133
+ return { ok: false, reason: "corrupt", detail: "\u7F3A installId / installSecret \u5B57\u6BB5" };
26134
+ }
26135
+ const email = readContactEmailOf(parsed);
26136
+ return {
26137
+ ok: true,
26138
+ identity: {
26139
+ installId: parsed.installId,
26140
+ installSecret: parsed.installSecret,
26141
+ ...email ? { contactEmail: email } : {}
26142
+ }
26143
+ };
26144
+ }
26145
+
26146
+ // src/free-tier-apply.ts
26147
+ function isFreeTierConfig(cfg) {
26148
+ const hasProvider = !!cfg?.models?.providers?.[FREE_TIER_PROVIDER_ID];
26149
+ const primary = String(cfg?.agents?.defaults?.model?.primary || "");
26150
+ return hasProvider && primary.startsWith(`${FREE_TIER_PROVIDER_ID}/`);
26151
+ }
26152
+
26153
+ // src/startup/free-tier-voice-fixup.ts
26154
+ function needsFreeTierVoiceFixup(cfg) {
26155
+ if (!isFreeTierConfig(cfg)) return false;
26156
+ return cfg?.tools?.my_voice === void 0;
26157
+ }
26158
+ async function applyFreeTierVoiceFixup(io) {
26159
+ const cfg = io.all();
26160
+ if (!needsFreeTierVoiceFixup(cfg)) return false;
26161
+ const persisted = await io.set("tools.my_voice", freeTierVoiceConfig());
26162
+ if (persisted === false) {
26163
+ console.error("[startup] \u514D\u8D39\u6863\u8865\u9F50 tools.my_voice **\u672A\u843D\u76D8**\uFF08\u672C\u6B21\u8FD0\u884C\u5185\u5B58\u91CC\u5DF2\u751F\u6548\uFF0C\u914D\u7F6E\u6587\u4EF6\u4ECD\u662F\u65E7\u7684\u2014\u2014\u6258\u76D8/\u4E0B\u6B21\u542F\u52A8\u770B\u5230\u7684\u8FD8\u662F edge-tts\uFF09\u3002\u4E0A\u9762 [liveConfig] \u90A3\u884C\u662F\u539F\u56E0\u3002");
26164
+ return true;
26165
+ }
26166
+ console.log("[startup] \u514D\u8D39\u6863\u8865\u9F50 tools.my_voice \u2192 7yi\uFF08\u5347\u7EA7\u524D\u88C5\u7684\u673A\u5668\u8FD9\u5757\u4ECE\u672A\u88AB\u5199\u8FC7\uFF0C\u8BED\u97F3\u6761\u6B64\u524D\u843D\u5230 edge-tts\uFF1B\u7528\u6237\u81EA\u5DF1\u914D\u8FC7\u7684\u4E0D\u52A8\uFF09");
26167
+ return true;
26168
+ }
26169
+
25994
26170
  // src/startup/hooks-boot.ts
25995
26171
  init_live();
25996
26172
  import * as fs23 from "node:fs";
@@ -27044,7 +27220,7 @@ ${manifest}`
27044
27220
  // src/memory/memdir/findRelevantMemoriesVector.ts
27045
27221
  init_well_formed();
27046
27222
  import { statSync as statSync3 } from "node:fs";
27047
- import { join as join19, resolve as resolve5, sep as sep4 } from "node:path";
27223
+ import { join as join20, resolve as resolve5, sep as sep4 } from "node:path";
27048
27224
  import { createRequire as createRequire2 } from "node:module";
27049
27225
  var require2 = createRequire2(import.meta.url);
27050
27226
  var DEFAULT_TOP_K = 3;
@@ -27197,7 +27373,7 @@ async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /*
27197
27373
  }
27198
27374
  const scored = [];
27199
27375
  for (const row of rows) {
27200
- const absPath = join19(memoryDir, row.file_path.replace(/\//g, sep4));
27376
+ const absPath = join20(memoryDir, row.file_path.replace(/\//g, sep4));
27201
27377
  if (alreadySurfaced.has(absPath) || alreadySurfaced.has(row.file_path)) continue;
27202
27378
  const emb = new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4);
27203
27379
  const score = cosineSim(qVec, emb);
@@ -27410,27 +27586,27 @@ ${ep.episode || ep.summary}`,
27410
27586
 
27411
27587
  // src/handle-query.ts
27412
27588
  init_paths();
27413
- import { readFileSync as readFileSync27, existsSync as existsSync21, statSync as statSync5 } from "node:fs";
27414
- import { join as join36, resolve as resolve7 } from "node:path";
27589
+ import { readFileSync as readFileSync28, existsSync as existsSync22, statSync as statSync5 } from "node:fs";
27590
+ import { join as join37, resolve as resolve7 } from "node:path";
27415
27591
  import * as path21 from "node:path";
27416
27592
 
27417
27593
  // src/light-mode.ts
27418
27594
  init_live();
27419
- import { readFileSync as readFileSync13 } from "node:fs";
27595
+ import { readFileSync as readFileSync14 } from "node:fs";
27420
27596
 
27421
27597
  // src/config/persona-files.ts
27422
- import { existsSync as existsSync12 } from "node:fs";
27423
- import { join as join20 } from "node:path";
27598
+ import { existsSync as existsSync13 } from "node:fs";
27599
+ import { join as join21 } from "node:path";
27424
27600
  var LEGACY_RELATIVE = {
27425
27601
  "my-inner-voice.md": "prompts/my-inner-voice.md"
27426
27602
  };
27427
27603
  function resolvePersonaFile(workspace, persona, name) {
27428
27604
  if (persona) {
27429
- const scoped = join20(workspace, "personas", persona, name);
27430
- if (existsSync12(scoped)) return scoped;
27605
+ const scoped = join21(workspace, "personas", persona, name);
27606
+ if (existsSync13(scoped)) return scoped;
27431
27607
  }
27432
- const legacy = join20(workspace, LEGACY_RELATIVE[name] ?? name);
27433
- return existsSync12(legacy) ? legacy : null;
27608
+ const legacy = join21(workspace, LEGACY_RELATIVE[name] ?? name);
27609
+ return existsSync13(legacy) ? legacy : null;
27434
27610
  }
27435
27611
 
27436
27612
  // src/light-mode.ts
@@ -27471,7 +27647,7 @@ function buildLightStablePrompt(workspace, mode, opts) {
27471
27647
  const filePath = resolvePersonaFile(workspace, persona, f);
27472
27648
  if (!filePath) continue;
27473
27649
  try {
27474
- parts.push(readFileSync13(filePath, "utf-8").trim());
27650
+ parts.push(readFileSync14(filePath, "utf-8").trim());
27475
27651
  } catch {
27476
27652
  }
27477
27653
  }
@@ -27555,8 +27731,8 @@ function voiceFastView(history, opts = VOICE_FAST_DEFAULTS) {
27555
27731
 
27556
27732
  // src/sender-context.ts
27557
27733
  init_clock();
27558
- import { readFileSync as readFileSync14, existsSync as existsSync14 } from "node:fs";
27559
- import { join as join21 } from "node:path";
27734
+ import { readFileSync as readFileSync15, existsSync as existsSync15 } from "node:fs";
27735
+ import { join as join22 } from "node:path";
27560
27736
  var contactMap = null;
27561
27737
  var externalChanWhitelist = null;
27562
27738
  function loadContactMap(workspace) {
@@ -27564,10 +27740,10 @@ function loadContactMap(workspace) {
27564
27740
  contactMap = /* @__PURE__ */ new Map();
27565
27741
  externalChanWhitelist = /* @__PURE__ */ new Set();
27566
27742
  try {
27567
- const contactsPath = join21(workspace, "prompts", "contacts.md");
27568
- console.log(`[meta] Loading contacts from ${contactsPath}, exists=${existsSync14(contactsPath)}`);
27569
- if (existsSync14(contactsPath)) {
27570
- const text = readFileSync14(contactsPath, "utf-8");
27743
+ const contactsPath = join22(workspace, "prompts", "contacts.md");
27744
+ console.log(`[meta] Loading contacts from ${contactsPath}, exists=${existsSync15(contactsPath)}`);
27745
+ if (existsSync15(contactsPath)) {
27746
+ const text = readFileSync15(contactsPath, "utf-8");
27571
27747
  const lines = text.split("\n");
27572
27748
  for (const line of lines) {
27573
27749
  const m = line.match(/^\|\s*(.+?)\s*\|\s*([a-zA-Z0-9_@.]+)\s*\|/);
@@ -27656,12 +27832,12 @@ function resetSessionStartInjection(sessionId) {
27656
27832
  }
27657
27833
  var externalChanRulesCache = null;
27658
27834
  function loadExternalChanRules(workspace) {
27659
- const path61 = join36(workspace, "prompts", "external-chan-rules.md");
27835
+ const path61 = join37(workspace, "prompts", "external-chan-rules.md");
27660
27836
  if (externalChanRulesCache && externalChanRulesCache.path === path61) return externalChanRulesCache;
27661
27837
  let content = "";
27662
- if (existsSync21(path61)) {
27838
+ if (existsSync22(path61)) {
27663
27839
  try {
27664
- content = readFileSync27(path61, "utf-8").trim();
27840
+ content = readFileSync28(path61, "utf-8").trim();
27665
27841
  } catch (e) {
27666
27842
  console.warn(`[external-chan-rules] Failed to load: ${e}`);
27667
27843
  }
@@ -27832,7 +28008,7 @@ ${text}` : text });
27832
28008
  }
27833
28009
  if (source === "user") {
27834
28010
  try {
27835
- const wm = readFileSync27(join36(workspace, ".work-mode"), "utf-8").trim();
28011
+ const wm = readFileSync28(join37(workspace, ".work-mode"), "utf-8").trim();
27836
28012
  if (wm === "on" && chatMode !== "work") {
27837
28013
  chatMode = "work";
27838
28014
  console.log(`[mode] ${sessionId} /work on \u2192 \u5F3A\u5236 work`);
@@ -28075,7 +28251,7 @@ ${text}` : text });
28075
28251
  for (const memPath of newPaths) {
28076
28252
  try {
28077
28253
  const stat4 = statSync5(memPath);
28078
- const content = readFileSync27(memPath, "utf-8");
28254
+ const content = readFileSync28(memPath, "utf-8");
28079
28255
  const header = memoryHeader(memPath, stat4.mtimeMs);
28080
28256
  restoredMemories.push({ path: memPath, content, mtimeMs: stat4.mtimeMs, header });
28081
28257
  } catch {
@@ -28162,7 +28338,7 @@ ${text}` : text });
28162
28338
  const attachmentMemories = [];
28163
28339
  for (const mem of relevantMemories) {
28164
28340
  try {
28165
- const content = mem.content ?? readFileSync27(mem.path, "utf-8");
28341
+ const content = mem.content ?? readFileSync28(mem.path, "utf-8");
28166
28342
  const header = mem.header ?? memoryHeader(mem.path, mem.mtimeMs);
28167
28343
  attachmentMemories.push({ path: mem.path, content, mtimeMs: mem.mtimeMs, header });
28168
28344
  } catch {
@@ -28482,7 +28658,7 @@ stack: ${err.stack ?? "(none)"}`);
28482
28658
  }
28483
28659
  } catch (err) {
28484
28660
  try {
28485
- (await import("node:fs")).appendFileSync(join36(process.env.ENGINE7_STATE_DIR || path21.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
28661
+ (await import("node:fs")).appendFileSync(join37(process.env.ENGINE7_STATE_DIR || path21.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
28486
28662
  stack: ${err.stack ?? "(none)"}
28487
28663
  `);
28488
28664
  } catch {
@@ -35088,80 +35264,6 @@ ${inbound.content}` }, ...videoBlocks];
35088
35264
  // src/optional/reporting/reporter.ts
35089
35265
  init_live();
35090
35266
 
35091
- // src/provision-free.ts
35092
- import { randomBytes as randomBytes4, randomUUID as randomUUID6 } from "node:crypto";
35093
- import { chmodSync as chmodSync2, existsSync as existsSync25, mkdirSync as mkdirSync16, readFileSync as readFileSync35, writeFileSync as writeFileSync13 } from "node:fs";
35094
- import { dirname as dirname12, join as join47 } from "node:path";
35095
- import { fileURLToPath as fileURLToPath7 } from "node:url";
35096
- var __filename = fileURLToPath7(import.meta.url);
35097
- var IDENTITY_FILE = "install-identity.json";
35098
- function readContactEmailOf(parsed) {
35099
- return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
35100
- }
35101
- function loadOrCreateInstallIdentity(stateDir) {
35102
- const file2 = join47(stateDir, IDENTITY_FILE);
35103
- if (existsSync25(file2)) {
35104
- let parsed;
35105
- try {
35106
- parsed = JSON.parse(readFileSync35(file2, "utf8"));
35107
- } catch (e) {
35108
- throw new Error(
35109
- `${IDENTITY_FILE} \u5B58\u5728\u4F46\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e.message}\uFF09\u2014\u2014\u5220\u6389\u5B83\u91CD\u8DD1\u4F1A\u9886\u4E00\u628A\u65B0\u4EE4\u724C\uFF0C\u65E7\u7684\u90A3\u628A\u53D6\u4E0D\u56DE\u6765`
35110
- );
35111
- }
35112
- if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
35113
- throw new Error(`${IDENTITY_FILE} \u7F3A installId / installSecret \u5B57\u6BB5`);
35114
- }
35115
- const email = readContactEmailOf(parsed);
35116
- return {
35117
- installId: parsed.installId,
35118
- installSecret: parsed.installSecret,
35119
- ...email ? { contactEmail: email } : {}
35120
- };
35121
- }
35122
- const identity = {
35123
- // 服务端校验 installId 长度为 8..36、只允许字母数字和连字符;uuid 正好符合
35124
- installId: randomUUID6(),
35125
- // 服务端校验 installSecret 为 32..64 位十六进制
35126
- installSecret: randomBytes4(32).toString("hex")
35127
- };
35128
- mkdirSync16(stateDir, { recursive: true });
35129
- writeFileSync13(file2, JSON.stringify(identity, null, 2) + "\n", { mode: 384 });
35130
- try {
35131
- chmodSync2(file2, 384);
35132
- } catch {
35133
- }
35134
- return identity;
35135
- }
35136
- function readInstallIdentityDetailed(stateDir) {
35137
- const file2 = join47(stateDir, IDENTITY_FILE);
35138
- if (!existsSync25(file2)) return { ok: false, reason: "missing" };
35139
- let text;
35140
- try {
35141
- text = readFileSync35(file2, "utf8");
35142
- } catch (e) {
35143
- return { ok: false, reason: "corrupt", detail: `\u5B58\u5728\u4F46\u8BFB\u4E0D\u4E86\uFF08${e?.message ?? e}\uFF09` };
35144
- }
35145
- let parsed;
35146
- try {
35147
- parsed = JSON.parse(text);
35148
- } catch (e) {
35149
- return { ok: false, reason: "corrupt", detail: `\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e?.message ?? e}\uFF09` };
35150
- }
35151
- if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
35152
- return { ok: false, reason: "corrupt", detail: "\u7F3A installId / installSecret \u5B57\u6BB5" };
35153
- }
35154
- const email = readContactEmailOf(parsed);
35155
- return {
35156
- ok: true,
35157
- identity: {
35158
- installId: parsed.installId,
35159
- installSecret: parsed.installSecret,
35160
- ...email ? { contactEmail: email } : {}
35161
- }
35162
- };
35163
- }
35164
-
35165
35267
  // src/optional/reporting/state.ts
35166
35268
  import { existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync36, writeFileSync as writeFileSync14 } from "node:fs";
35167
35269
  import { join as join48 } from "node:path";
@@ -36029,6 +36131,21 @@ var FeishuAdapter = class _FeishuAdapter {
36029
36131
  }
36030
36132
  }
36031
36133
  }
36134
+ /**
36135
+ * 检查飞书 API 的**业务返回码**(1001)。
36136
+ *
36137
+ * SDK 只在 **HTTP 非 2xx** 时抛错;业务错误走的是 "HTTP 200 + code≠0" —— 不查码就等于把
36138
+ * "飞书拒了"读成"发出去了"。客户那台 mac 的语音条"日志 Voice sent!、人没收到"卡了一整天
36139
+ * 就是卡在这儿:**引擎从不看码,所以线上到底是发成功了还是被拒了,日志里一个字都没有**。
36140
+ * (1001 实测:同一套参数在我方租户 code:0 全绿,把时长/内容形状/chat_id 通道三项嫌疑逐条排除,
36141
+ * 嫌疑因此全部落到"客户租户返回了什么"上——而那个答案以前根本打印不出来。)
36142
+ */
36143
+ _assertApiOk(res, what) {
36144
+ const code = res?.code;
36145
+ if (typeof code === "number" && code !== 0) {
36146
+ throw new Error(`Feishu ${what} \u88AB\u62D2: code=${code} msg=${res?.msg ?? ""}\uFF08HTTP 2xx \u4E5F\u53EF\u80FD\u662F\u4E1A\u52A1\u9519\u8BEF\u2014\u2014\u8FD9\u6B63\u662F\u300C\u62A5\u6210\u529F\u5374\u6CA1\u5230\u300D\u90A3\u7C7B\uFF09`);
36147
+ }
36148
+ }
36032
36149
  /** 发送媒体附件(图片/文件) */
36033
36150
  async sendFile(target, message, attachment) {
36034
36151
  const fs60 = await import("node:fs");
@@ -36046,25 +36163,25 @@ var FeishuAdapter = class _FeishuAdapter {
36046
36163
  const imageKey = await this._uploadImage(fileBuffer, filename);
36047
36164
  if (message) {
36048
36165
  const postContent = this._buildImagePost(message, imageKey);
36049
- await this.client.im.message.create({
36166
+ this._assertApiOk(await this.client.im.message.create({
36050
36167
  params: { receive_id_type: receiveIdType },
36051
36168
  data: { receive_id: safeTarget, msg_type: "post", content: JSON.stringify(postContent) }
36052
- });
36169
+ }), "\u56FE\u7247\u6D88\u606F\u53D1\u9001");
36053
36170
  } else {
36054
- await this.client.im.message.create({
36171
+ this._assertApiOk(await this.client.im.message.create({
36055
36172
  params: { receive_id_type: receiveIdType },
36056
36173
  data: { receive_id: safeTarget, msg_type: "image", content: JSON.stringify({ image_key: imageKey }) }
36057
- });
36174
+ }), "\u56FE\u7247\u6D88\u606F\u53D1\u9001");
36058
36175
  }
36059
36176
  } else if (mimeType.startsWith("audio/")) {
36060
36177
  const isOpus = filename.endsWith(".opus") || filename.endsWith(".ogg") || mimeType === "audio/opus";
36061
36178
  if (!isOpus) {
36062
36179
  console.warn(`[feishu:sendFile] audio '${filename}' \u4E0D\u662Fopus\uFF0C\u964D\u7EA7\u4E3A\u6587\u4EF6\u6D88\u606F\uFF08\u975E\u8BED\u97F3\u6761\uFF09`);
36063
36180
  const fileKey = await this._uploadFile(fileBuffer, filename);
36064
- await this.client.im.message.create({
36181
+ this._assertApiOk(await this.client.im.message.create({
36065
36182
  params: { receive_id_type: receiveIdType },
36066
36183
  data: { receive_id: safeTarget, msg_type: "file", content: JSON.stringify({ file_key: fileKey }) }
36067
- });
36184
+ }), "\u6587\u4EF6\u6D88\u606F\u53D1\u9001\uFF08\u975E opus \u97F3\u9891\u964D\u7EA7\uFF09");
36068
36185
  } else {
36069
36186
  let durationMs = Math.round(fileBuffer.length / 3);
36070
36187
  try {
@@ -36077,17 +36194,17 @@ var FeishuAdapter = class _FeishuAdapter {
36077
36194
  } catch {
36078
36195
  }
36079
36196
  const audioKey = await this._uploadAudio(fileBuffer, filename.endsWith(".opus") ? filename : filename.replace(/\.[^.]+$/, ".opus"), durationMs);
36080
- await this.client.im.message.create({
36197
+ this._assertApiOk(await this.client.im.message.create({
36081
36198
  params: { receive_id_type: receiveIdType },
36082
36199
  data: { receive_id: safeTarget, msg_type: "audio", content: JSON.stringify({ file_key: audioKey }) }
36083
- });
36200
+ }), "\u8BED\u97F3\u6761\u53D1\u9001");
36084
36201
  }
36085
36202
  } else {
36086
36203
  const fileKey = await this._uploadFile(fileBuffer, filename);
36087
- await this.client.im.message.create({
36204
+ this._assertApiOk(await this.client.im.message.create({
36088
36205
  params: { receive_id_type: receiveIdType },
36089
36206
  data: { receive_id: safeTarget, msg_type: "file", content: JSON.stringify({ file_key: fileKey }) }
36090
- });
36207
+ }), "\u6587\u4EF6\u6D88\u606F\u53D1\u9001");
36091
36208
  }
36092
36209
  if (message && mimeType.startsWith("image/")) {
36093
36210
  } else if (message) {
@@ -41245,7 +41362,7 @@ var TTS_IMPL = {
41245
41362
  if (r.warning) console.warn(`[my-voice] ${r.warning}`);
41246
41363
  if (!r.voice) {
41247
41364
  throw new TtsConfigError(
41248
- "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"
41365
+ "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"
41249
41366
  );
41250
41367
  }
41251
41368
  try {
@@ -41468,7 +41585,7 @@ registry.register({
41468
41585
  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"
41469
41586
  },
41470
41587
  channel: { type: "string", enum: ["weixin", "feishu", "discord"], description: "Target channel. Default: current channel." },
41471
- 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" },
41588
+ 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' },
41472
41589
  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' },
41473
41590
  caption: { type: "string", description: "Optional text to accompany the voice message." }
41474
41591
  },
@@ -41580,7 +41697,8 @@ registry.register({
41580
41697
  }
41581
41698
  return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
41582
41699
  } catch (err) {
41583
- return { content: `Voice send failed: ${err.message}`, isError: true };
41700
+ const toHint = args2.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' : "";
41701
+ return { content: `Voice send failed: ${err.message}${toHint}`, isError: true };
41584
41702
  }
41585
41703
  },
41586
41704
  isConcurrencySafe: () => false,
@@ -44942,6 +45060,7 @@ async function startEngine(config2, opts) {
44942
45060
  applyFreeTierVideoFixup({ all: () => liveConfig.all(), set: (p, v) => {
44943
45061
  void liveConfig.set(p, v);
44944
45062
  } });
45063
+ await applyFreeTierVoiceFixup({ all: () => liveConfig.all(), set: (p, v) => liveConfig.set(p, v) });
44945
45064
  let provider;
44946
45065
  let visionProvider;
44947
45066
  let visionChainLabels;