engine7 7.1.66 → 7.1.68

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.
Files changed (4) hide show
  1. package/dist/cli.mjs +1167 -872
  2. package/dist/engine-startup.mjs +2878 -1301
  3. package/dist/main.mjs +2873 -1296
  4. package/package.json +15 -2
package/dist/cli.mjs CHANGED
@@ -1254,14 +1254,14 @@ var init_live = __esm({
1254
1254
  }
1255
1255
  /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
1256
1256
  async persistToFile(dotPath, val) {
1257
- const fs28 = await import("node:fs");
1257
+ const fs29 = await import("node:fs");
1258
1258
  const cfgPath = this.current?._configFilePath;
1259
- if (!cfgPath || !fs28.existsSync(cfgPath)) {
1259
+ if (!cfgPath || !fs29.existsSync(cfgPath)) {
1260
1260
  console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
1261
1261
  return;
1262
1262
  }
1263
1263
  try {
1264
- const raw = JSON.parse(fs28.readFileSync(cfgPath, "utf-8"));
1264
+ const raw = JSON.parse(fs29.readFileSync(cfgPath, "utf-8"));
1265
1265
  const keys = dotPath.split(".");
1266
1266
  let o = raw;
1267
1267
  for (let i = 0; i < keys.length - 1; i++) {
@@ -1269,7 +1269,7 @@ var init_live = __esm({
1269
1269
  o = o[keys[i]];
1270
1270
  }
1271
1271
  o[keys[keys.length - 1]] = val;
1272
- fs28.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
1272
+ fs29.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
1273
1273
  console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
1274
1274
  markSelfWrite();
1275
1275
  } catch (e) {
@@ -1515,7 +1515,6 @@ function loadConfig(configPath) {
1515
1515
  services: raw.services,
1516
1516
  commands: raw.commands,
1517
1517
  compaction: raw.compaction,
1518
- cognifold: raw.cognifold,
1519
1518
  everos: raw.everos,
1520
1519
  // 保留原始 agents 段,供 liveConfig.get('agents.defaults.*') 读取(如 privateTools 开关)
1521
1520
  agents: raw.agents,
@@ -1684,6 +1683,130 @@ var init_registry = __esm({
1684
1683
  }
1685
1684
  });
1686
1685
 
1686
+ // src/calendar/db.ts
1687
+ import * as path3 from "node:path";
1688
+ import * as fs3 from "node:fs";
1689
+ import { createRequire as createRequire2 } from "node:module";
1690
+ function getSqlite() {
1691
+ if (!_sqlite) _sqlite = createRequire2(import.meta.url)("node:sqlite");
1692
+ return _sqlite;
1693
+ }
1694
+ function openDb(workspace) {
1695
+ const dir = path3.join(workspace, ".calendar");
1696
+ fs3.mkdirSync(dir, { recursive: true });
1697
+ const dbPath = path3.join(dir, "calendar.db");
1698
+ const db2 = new DatabaseSync(dbPath);
1699
+ db2.exec("PRAGMA journal_mode=WAL");
1700
+ db2.exec(`CREATE TABLE IF NOT EXISTS events (
1701
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1702
+ type TEXT NOT NULL,
1703
+ status TEXT NOT NULL DEFAULT 'pending',
1704
+ event TEXT NOT NULL,
1705
+ day TEXT,
1706
+ time TEXT,
1707
+ date_str TEXT,
1708
+ created_at TEXT NOT NULL,
1709
+ done_at TEXT,
1710
+ archived_at TEXT
1711
+ )`);
1712
+ migrate(db2);
1713
+ return db2;
1714
+ }
1715
+ function migrate(db2) {
1716
+ const cols = new Set(
1717
+ db2.prepare("PRAGMA table_info(events)").all().map((r) => r.name)
1718
+ );
1719
+ if (!cols.has("remind_before_min")) {
1720
+ db2.exec("ALTER TABLE events ADD COLUMN remind_before_min INTEGER DEFAULT 60");
1721
+ }
1722
+ if (!cols.has("remind_at")) {
1723
+ db2.exec("ALTER TABLE events ADD COLUMN remind_at TEXT");
1724
+ }
1725
+ if (!cols.has("reminded")) {
1726
+ db2.exec("ALTER TABLE events ADD COLUMN reminded INTEGER DEFAULT 0");
1727
+ }
1728
+ if (!cols.has("time_exact")) {
1729
+ db2.exec("ALTER TABLE events ADD COLUMN time_exact TEXT");
1730
+ }
1731
+ if (!cols.has("start_time")) {
1732
+ db2.exec("ALTER TABLE events ADD COLUMN start_time TEXT");
1733
+ }
1734
+ if (!cols.has("duration_min")) {
1735
+ db2.exec("ALTER TABLE events ADD COLUMN duration_min INTEGER");
1736
+ }
1737
+ if (!cols.has("created_channel")) {
1738
+ db2.exec("ALTER TABLE events ADD COLUMN created_channel TEXT");
1739
+ }
1740
+ if (!cols.has("created_channel_target")) {
1741
+ db2.exec("ALTER TABLE events ADD COLUMN created_channel_target TEXT");
1742
+ }
1743
+ if (!cols.has("repeat_type")) {
1744
+ db2.exec("ALTER TABLE events ADD COLUMN repeat_type TEXT DEFAULT 'once'");
1745
+ }
1746
+ if (!cols.has("doc_path")) {
1747
+ db2.exec("ALTER TABLE events ADD COLUMN doc_path TEXT");
1748
+ }
1749
+ }
1750
+ var _sqlite, DatabaseSync, TZ_OFFSET_MS;
1751
+ var init_db = __esm({
1752
+ "src/calendar/db.ts"() {
1753
+ "use strict";
1754
+ _sqlite = null;
1755
+ DatabaseSync = new Proxy(function() {
1756
+ }, {
1757
+ construct(_t, args) {
1758
+ return new (getSqlite()).DatabaseSync(...args);
1759
+ },
1760
+ get(_t, prop) {
1761
+ return getSqlite().DatabaseSync[prop];
1762
+ }
1763
+ });
1764
+ TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
1765
+ }
1766
+ });
1767
+
1768
+ // src/goals/store.ts
1769
+ import fs4 from "node:fs";
1770
+ import path4 from "node:path";
1771
+ function file(stateDir) {
1772
+ return path4.join(stateDir, "goals.json");
1773
+ }
1774
+ function db(stateDir) {
1775
+ const d = openDb(stateDir);
1776
+ d.exec(`CREATE TABLE IF NOT EXISTS goals (id TEXT PRIMARY KEY, objective TEXT NOT NULL, status TEXT NOT NULL, steps_json TEXT NOT NULL, current_step INTEGER NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, blocker TEXT)`);
1777
+ d.exec(`CREATE TABLE IF NOT EXISTS goal_events (event_id TEXT PRIMARY KEY, goal_id TEXT NOT NULL, type TEXT NOT NULL, payload_json TEXT NOT NULL, created_at TEXT NOT NULL)`);
1778
+ return d;
1779
+ }
1780
+ function read(stateDir) {
1781
+ try {
1782
+ const v = JSON.parse(fs4.readFileSync(file(stateDir), "utf8"));
1783
+ return Array.isArray(v) ? v : [];
1784
+ } catch {
1785
+ return [];
1786
+ }
1787
+ }
1788
+ function rowToGoal(r) {
1789
+ return { id: r.id, objective: r.objective, status: r.status, steps: JSON.parse(r.steps_json), currentStep: r.current_step, createdAt: r.created_at, updatedAt: r.updated_at, ...r.blocker ? { blocker: r.blocker } : {} };
1790
+ }
1791
+ function migrateLegacy(stateDir, d) {
1792
+ const count = Number(d.prepare("SELECT COUNT(*) AS n FROM goals").get()?.n ?? 0);
1793
+ if (count > 0) return;
1794
+ for (const g of read(stateDir)) d.prepare("INSERT OR IGNORE INTO goals VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(g.id, g.objective, g.status, JSON.stringify(g.steps), g.currentStep, g.createdAt, g.updatedAt, g.blocker ?? null);
1795
+ }
1796
+ function listGoals(stateDir) {
1797
+ const d = db(stateDir);
1798
+ migrateLegacy(stateDir, d);
1799
+ const rows = d.prepare("SELECT * FROM goals ORDER BY created_at").all().map(rowToGoal);
1800
+ d.close?.();
1801
+ return rows;
1802
+ }
1803
+ var init_store = __esm({
1804
+ "src/goals/store.ts"() {
1805
+ "use strict";
1806
+ init_db();
1807
+ }
1808
+ });
1809
+
1687
1810
  // src/memory/memdir/paths.ts
1688
1811
  var paths_exports = {};
1689
1812
  __export(paths_exports, {
@@ -1695,26 +1818,26 @@ __export(paths_exports, {
1695
1818
  isAutoMemPath: () => isAutoMemPath,
1696
1819
  setMemoryDirOverride: () => setMemoryDirOverride
1697
1820
  });
1698
- import { join as join3, normalize, sep, isAbsolute, resolve as resolve2 } from "node:path";
1821
+ import { join as join4, normalize, sep, isAbsolute, resolve as resolve2 } from "node:path";
1699
1822
  function setMemoryDirOverride(dir) {
1700
1823
  _overrideMemoryDir = dir;
1701
1824
  }
1702
1825
  function getAutoMemPath(workspace) {
1703
- const dir = _overrideMemoryDir ? isAbsolute(_overrideMemoryDir) ? _overrideMemoryDir : resolve2(workspace, _overrideMemoryDir) : join3(workspace, AUTO_MEM_DIRNAME);
1826
+ const dir = _overrideMemoryDir ? isAbsolute(_overrideMemoryDir) ? _overrideMemoryDir : resolve2(workspace, _overrideMemoryDir) : join4(workspace, AUTO_MEM_DIRNAME);
1704
1827
  const normalized = normalize(dir);
1705
1828
  return (normalized + sep).normalize("NFC");
1706
1829
  }
1707
1830
  function getAutoMemEntrypoint(workspace) {
1708
- return join3(getAutoMemPath(workspace), ENTRYPOINT_NAME);
1831
+ return join4(getAutoMemPath(workspace), ENTRYPOINT_NAME);
1709
1832
  }
1710
1833
  function isAutoMemPath(absolutePath, workspace) {
1711
1834
  const normalizedPath = normalize(absolutePath);
1712
1835
  return normalizedPath.startsWith(getAutoMemPath(workspace));
1713
1836
  }
1714
1837
  async function ensureMemoryDirExists(memoryDir) {
1715
- const fs28 = await import("node:fs");
1838
+ const fs29 = await import("node:fs");
1716
1839
  try {
1717
- await fs28.promises.mkdir(memoryDir, { recursive: true });
1840
+ await fs29.promises.mkdir(memoryDir, { recursive: true });
1718
1841
  } catch (e) {
1719
1842
  const code = e?.code;
1720
1843
  if (code !== "EEXIST") {
@@ -1899,7 +2022,7 @@ __export(memdir_exports, {
1899
2022
  truncateEntrypointContent: () => truncateEntrypointContent
1900
2023
  });
1901
2024
  import { readFileSync as readFileSync3 } from "node:fs";
1902
- import { join as join4 } from "node:path";
2025
+ import { join as join5 } from "node:path";
1903
2026
  function truncateEntrypointContent(raw) {
1904
2027
  const trimmed = raw.trim();
1905
2028
  const contentLines = trimmed.split("\n");
@@ -1992,7 +2115,7 @@ function buildMemoryLines(displayName, memoryDir, extraGuidelines, skipIndex = f
1992
2115
  }
1993
2116
  function buildMemoryPrompt(params) {
1994
2117
  const { displayName, memoryDir, extraGuidelines } = params;
1995
- const entrypoint = join4(memoryDir, ENTRYPOINT_NAME);
2118
+ const entrypoint = join5(memoryDir, ENTRYPOINT_NAME);
1996
2119
  let entrypointContent = "";
1997
2120
  try {
1998
2121
  entrypointContent = readFileSync3(entrypoint, { encoding: "utf-8" });
@@ -2044,13 +2167,13 @@ __export(prompt_exports, {
2044
2167
  buildSystemPrompt: () => buildSystemPrompt,
2045
2168
  buildVolatileRuntimeContext: () => buildVolatileRuntimeContext
2046
2169
  });
2047
- import * as path3 from "node:path";
2048
- import * as fs3 from "node:fs";
2170
+ import * as path5 from "node:path";
2171
+ import * as fs5 from "node:fs";
2049
2172
  import * as os2 from "node:os";
2050
2173
  function readFileIfExists(filePath) {
2051
2174
  try {
2052
- if (fs3.existsSync(filePath)) {
2053
- return fs3.readFileSync(filePath, "utf-8");
2175
+ if (fs5.existsSync(filePath)) {
2176
+ return fs5.readFileSync(filePath, "utf-8");
2054
2177
  }
2055
2178
  } catch {
2056
2179
  }
@@ -2205,8 +2328,8 @@ function getEnvInfoSection(workspace) {
2205
2328
  function loadStaticFiles(workspace, staticFiles) {
2206
2329
  if (!staticFiles || staticFiles.length === 0) return null;
2207
2330
  const parts = [];
2208
- for (const file of staticFiles) {
2209
- const filePath = path3.isAbsolute(file) ? file : path3.join(workspace, file);
2331
+ for (const file2 of staticFiles) {
2332
+ const filePath = path5.isAbsolute(file2) ? file2 : path5.join(workspace, file2);
2210
2333
  const content = readFileIfExists(filePath);
2211
2334
  if (content) parts.push(content);
2212
2335
  }
@@ -2225,7 +2348,7 @@ function loadMemoryInstructions(workspace) {
2225
2348
  }
2226
2349
  }
2227
2350
  function resolveBlockContent(block, ctx) {
2228
- const overridePath = path3.join(ctx.workspace, "prompts", `${block.name}.md`);
2351
+ const overridePath = path5.join(ctx.workspace, "prompts", `${block.name}.md`);
2229
2352
  const override = readFileIfExists(overridePath);
2230
2353
  if (override) return override;
2231
2354
  return block.generate(ctx);
@@ -2274,7 +2397,7 @@ function buildCustomPrompt(workspace, config) {
2274
2397
  continue;
2275
2398
  }
2276
2399
  if (name.endsWith(".md")) {
2277
- const filePath = path3.isAbsolute(name) ? name : path3.join(workspace, name);
2400
+ const filePath = path5.isAbsolute(name) ? name : path5.join(workspace, name);
2278
2401
  const content = readFileIfExists(filePath);
2279
2402
  if (content) {
2280
2403
  parts.push(content);
@@ -2316,6 +2439,18 @@ ${skillsListing}`);
2316
2439
  loaded2.push("session-guidance");
2317
2440
  }
2318
2441
  parts.push(getEnvInfoSection(options.workspace));
2442
+ const activeGoals = listGoals(options.workspace).filter((g) => g.status === "active" || g.status === "waiting" || g.status === "blocked");
2443
+ if (activeGoals.length > 0) {
2444
+ const summary = activeGoals.map((g) => {
2445
+ const step = g.steps[g.currentStep];
2446
+ return `- ${g.id} [${g.status}] ${g.objective}${step ? ` | current: ${step.title}` : ""}${g.blocker ? ` | blocker: ${g.blocker}` : ""}`;
2447
+ }).join("\n");
2448
+ parts.push(`# Active Goals
2449
+ ${summary}
2450
+
2451
+ Continue active goals across turns. Do not claim a goal is complete without updating its state.`);
2452
+ loaded2.push("active-goals");
2453
+ }
2319
2454
  console.log(`[dynamic-prompt] Loaded: ${loaded2.length > 0 ? loaded2.join(", ") : "(none)"}`);
2320
2455
  return parts.join("\n\n");
2321
2456
  }
@@ -2341,6 +2476,7 @@ var init_prompt = __esm({
2341
2476
  "src/prompt.ts"() {
2342
2477
  "use strict";
2343
2478
  init_registry();
2479
+ init_store();
2344
2480
  init_memdir();
2345
2481
  init_paths();
2346
2482
  BASH_TOOL_NAME = "exec";
@@ -2366,7 +2502,7 @@ var init_prompt = __esm({
2366
2502
  { name: "tone-style", description: "\u8BED\u6C14\u98CE\u683C\uFF08\u7B80\u6D01\u3001\u4E0D\u7528emoji\uFF09", generate: (_) => getToneAndStyleSection() },
2367
2503
  { name: "output-efficiency", description: "\u8F93\u51FA\u6548\u7387\uFF08\u76F4\u5954\u4E3B\u9898\uFF09", generate: (_) => getOutputEfficiencySection() },
2368
2504
  // OpenClaw 叠加层
2369
- { name: "soul", description: "SOUL.md \u4EBA\u683C\u8EAB\u4EFD", generate: (ctx) => readFileIfExists(path3.join(ctx.workspace, "SOUL.md")) },
2505
+ { name: "soul", description: "SOUL.md \u4EBA\u683C\u8EAB\u4EFD", generate: (ctx) => readFileIfExists(path5.join(ctx.workspace, "SOUL.md")) },
2370
2506
  { 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) },
2371
2507
  { name: "auto-memory-instructions", description: "auto memory \u5B8C\u6574\u6307\u4EE4\uFF08\u5B58+\u8BFB+recall\u8BF4\u660E\uFF09", generate: (ctx) => loadMemoryInstructions(ctx.workspace) },
2372
2508
  // Boundary(永远在最后)
@@ -4150,7 +4286,10 @@ async function executePreToolUseHooks(toolName, toolInput, ctx, signal) {
4150
4286
  transcript_path: "",
4151
4287
  cwd: ctx.cwd,
4152
4288
  tool_name: toolName,
4153
- tool_input: toolInput
4289
+ tool_input: toolInput,
4290
+ channel: ctx.channel,
4291
+ // 让 callback hook 能判断来源(0905 skill-gate:channel allowlist 依赖此字段)
4292
+ source: ctx.source || ""
4154
4293
  };
4155
4294
  return executeHooks("PreToolUse", hookInput, ctx, signal, toolName);
4156
4295
  }
@@ -4217,7 +4356,9 @@ async function executeUserPromptSubmitHooks(prompt, ctx, signal) {
4217
4356
  prompt,
4218
4357
  sender_id: ctx.senderId || "",
4219
4358
  channel_type: ctx.channelType || "",
4220
- source: ctx.source || ""
4359
+ source: ctx.source || "",
4360
+ channel: ctx.channel
4361
+ // 让 callback hook 能判断来源(0905 skill-gate prompt 注入依赖)
4221
4362
  };
4222
4363
  return executeHooks("UserPromptSubmit", hookInput, ctx, signal);
4223
4364
  }
@@ -4664,8 +4805,8 @@ var init_attachments = __esm({
4664
4805
  });
4665
4806
 
4666
4807
  // src/utils/context-dump.ts
4667
- import * as fs4 from "node:fs";
4668
- import * as path4 from "node:path";
4808
+ import * as fs6 from "node:fs";
4809
+ import * as path6 from "node:path";
4669
4810
  function dumpApiRequest(opts) {
4670
4811
  const lines = [
4671
4812
  "=== API Request Debug\uFF08\u53D1\u7ED9 LLM \u7684\u6700\u7EC8\u8BF7\u6C42\u4F53\uFF0C\u6BCF\u6B21\u8986\u76D6\u5199\uFF09===",
@@ -4698,7 +4839,7 @@ function dumpApiRequest(opts) {
4698
4839
  lines.push(`[${i}] ${m.role}: (empty)`);
4699
4840
  }
4700
4841
  }
4701
- fs4.writeFileSync(path4.join(opts.workspace, ".context-debug.txt"), lines.join("\n") + "\n", "utf-8");
4842
+ fs6.writeFileSync(path6.join(opts.workspace, ".context-debug.txt"), lines.join("\n") + "\n", "utf-8");
4702
4843
  }
4703
4844
  var init_context_dump = __esm({
4704
4845
  "src/utils/context-dump.ts"() {
@@ -5668,6 +5809,23 @@ var init_compact2 = __esm({
5668
5809
  }
5669
5810
  });
5670
5811
 
5812
+ // src/skills/skill-gate.ts
5813
+ function beginSkillGate(sessionId) {
5814
+ if (loadedBySession.size >= MAX_TRACKED_SESSIONS && !loadedBySession.has(sessionId)) {
5815
+ const oldest = loadedBySession.keys().next().value;
5816
+ if (oldest !== void 0) loadedBySession.delete(oldest);
5817
+ }
5818
+ loadedBySession.set(sessionId, /* @__PURE__ */ new Set());
5819
+ }
5820
+ var loadedBySession, MAX_TRACKED_SESSIONS;
5821
+ var init_skill_gate = __esm({
5822
+ "src/skills/skill-gate.ts"() {
5823
+ "use strict";
5824
+ loadedBySession = /* @__PURE__ */ new Map();
5825
+ MAX_TRACKED_SESSIONS = 100;
5826
+ }
5827
+ });
5828
+
5671
5829
  // src/utils/context-analyzer.ts
5672
5830
  var context_analyzer_exports = {};
5673
5831
  __export(context_analyzer_exports, {
@@ -5676,8 +5834,8 @@ __export(context_analyzer_exports, {
5676
5834
  formatContextReport: () => formatContextReport,
5677
5835
  scanMemoryFiles: () => scanMemoryFiles
5678
5836
  });
5679
- import * as fs5 from "node:fs";
5680
- import * as path5 from "node:path";
5837
+ import * as fs7 from "node:fs";
5838
+ import * as path7 from "node:path";
5681
5839
  function estimateMessageTokens2(m) {
5682
5840
  let tokens = 0;
5683
5841
  if (typeof m.content === "string") {
@@ -5787,9 +5945,9 @@ function breakdownMessages(messages) {
5787
5945
  }
5788
5946
  async function scanMemoryFiles(workspace) {
5789
5947
  const files = [];
5790
- const soul = readFileIfExists2(path5.join(workspace, "SOUL.md"));
5948
+ const soul = readFileIfExists2(path7.join(workspace, "SOUL.md"));
5791
5949
  if (soul) files.push({ path: "SOUL.md", tokens: roughTokenCountEstimation(soul), stable: true });
5792
- const agents = readFileIfExists2(path5.join(workspace, "AGENTS.md"));
5950
+ const agents = readFileIfExists2(path7.join(workspace, "AGENTS.md"));
5793
5951
  if (agents) files.push({ path: "AGENTS.md", tokens: roughTokenCountEstimation(agents), stable: true });
5794
5952
  try {
5795
5953
  const { buildMemoryPrompt: buildMemoryPrompt2 } = await Promise.resolve().then(() => (init_memdir(), memdir_exports));
@@ -5805,7 +5963,7 @@ async function scanMemoryFiles(workspace) {
5805
5963
  }
5806
5964
  function readFileIfExists2(filePath) {
5807
5965
  try {
5808
- if (fs5.existsSync(filePath)) return fs5.readFileSync(filePath, "utf-8");
5966
+ if (fs7.existsSync(filePath)) return fs7.readFileSync(filePath, "utf-8");
5809
5967
  } catch {
5810
5968
  }
5811
5969
  return null;
@@ -5932,8 +6090,8 @@ function formatContextReport(report) {
5932
6090
  `;
5933
6091
  output += `|------|--------|
5934
6092
  `;
5935
- for (const file of stableFiles) {
5936
- output += `| ${file.path} | ${formatTokens(file.tokens)} |
6093
+ for (const file2 of stableFiles) {
6094
+ output += `| ${file2.path} | ${formatTokens(file2.tokens)} |
5937
6095
  `;
5938
6096
  }
5939
6097
  output += "\n";
@@ -5947,8 +6105,8 @@ function formatContextReport(report) {
5947
6105
  `;
5948
6106
  output += `|------|--------|
5949
6107
  `;
5950
- for (const file of dynamicFiles) {
5951
- output += `| ${file.path} | ${formatTokens(file.tokens)} |
6108
+ for (const file2 of dynamicFiles) {
6109
+ output += `| ${file2.path} | ${formatTokens(file2.tokens)} |
5952
6110
  `;
5953
6111
  }
5954
6112
  output += "\n";
@@ -6014,6 +6172,7 @@ var init_query = __esm({
6014
6172
  init_deferred();
6015
6173
  init_hooks();
6016
6174
  init_live();
6175
+ init_skill_gate();
6017
6176
  QueryEngine = class _QueryEngine {
6018
6177
  constructor(provider, options) {
6019
6178
  this.provider = provider;
@@ -6140,6 +6299,7 @@ var init_query = __esm({
6140
6299
  let ac = new AbortController();
6141
6300
  this.abortController = ac;
6142
6301
  this.preQueryAbort = null;
6302
+ beginSkillGate(context?.sessionId || "default");
6143
6303
  if (signal) {
6144
6304
  signal.addEventListener("abort", () => ac.abort(), { once: true });
6145
6305
  }
@@ -6456,6 +6616,7 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
6456
6616
  channel: context?.channel || "",
6457
6617
  cwd: context?.workspace || ""
6458
6618
  };
6619
+ const gatedCalls = [];
6459
6620
  for (const tc of toolCalls) {
6460
6621
  const toolName = tc.function?.name || tc.name || "unknown";
6461
6622
  let toolInput = {};
@@ -6470,11 +6631,35 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
6470
6631
  }
6471
6632
  if (preResult.preventContinuation) {
6472
6633
  console.log(`[hook] PreToolUse ${toolName}: blocked - ${preResult.stopReason || "no reason"}`);
6634
+ gatedCalls.push({
6635
+ call: tc,
6636
+ text: preResult.additionalContexts?.join("\n") || preResult.stopReason || `Tool ${toolName} was blocked by a hook.`
6637
+ });
6473
6638
  }
6474
6639
  } catch (e) {
6475
6640
  console.warn(`[hook] PreToolUse ${toolName} error: ${e.message}`);
6476
6641
  }
6477
6642
  }
6643
+ if (gatedCalls.length > 0) {
6644
+ const gatedTexts = new Map(gatedCalls.map((g) => [g.call.id, g.text]));
6645
+ const blockResults = toolCalls.map(
6646
+ (tc) => msg.tool(tc.id, gatedTexts.get(tc.id) || "\u672C\u8F6E\u6709\u5176\u4ED6\u8C03\u7528\u88AB\u95E8\u7981\u62E6\u4E0B\uFF0C\u6574\u6279\u672A\u6267\u884C\uFF1B\u8BF7\u5148\u6309\u63D0\u793A\u52A0\u8F7D Skill \u518D\u91CD\u8BD5\u3002", true)
6647
+ );
6648
+ const gateAssistant = msg.assistant(textContent, toolCalls);
6649
+ if (turnThinking) {
6650
+ gateAssistant.reasoning_content = turnThinking;
6651
+ if (turnThinkingSig) gateAssistant.thinking_signature = turnThinkingSig;
6652
+ }
6653
+ turnThinking = "";
6654
+ turnThinkingSig = "";
6655
+ currentMessages.push(gateAssistant);
6656
+ currentMessages.push(...blockResults);
6657
+ for (const g of gatedCalls) {
6658
+ yield { type: "tool_result", tool: g.call.function?.name, tool_call_id: g.call.id, summary: g.text.slice(0, 200), isError: true };
6659
+ }
6660
+ yield { type: "history", messages: [msg.assistant(textContent, toolCalls), ...blockResults] };
6661
+ continue;
6662
+ }
6478
6663
  const vcPlaceholderOn = context?.channel === "voice-chat" && (liveConfig.get("voiceChat.placeholder.enabled") ?? true);
6479
6664
  const vcTimer = vcPlaceholderOn ? setTimeout(() => {
6480
6665
  _QueryEngine.tryVoicePlaceholder(context).catch(() => {
@@ -6634,8 +6819,8 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
6634
6819
  });
6635
6820
 
6636
6821
  // src/session/writer.ts
6637
- import * as fs6 from "node:fs";
6638
- import * as path6 from "node:path";
6822
+ import * as fs8 from "node:fs";
6823
+ import * as path8 from "node:path";
6639
6824
  import * as crypto2 from "node:crypto";
6640
6825
  var SessionWriter;
6641
6826
  var init_writer = __esm({
@@ -6658,7 +6843,7 @@ var init_writer = __esm({
6658
6843
  this.sessionId = sessionId || crypto2.randomUUID();
6659
6844
  this.engineSessionId = "";
6660
6845
  const filename = `${this.sessionId}.jsonl`;
6661
- this.filePath = path6.join(sessionsDir, filename);
6846
+ this.filePath = path8.join(sessionsDir, filename);
6662
6847
  }
6663
6848
  get id() {
6664
6849
  return this.sessionId;
@@ -6669,9 +6854,9 @@ var init_writer = __esm({
6669
6854
  /** 打开文件写入 header(新文件才写 header) */
6670
6855
  open(cwd, engineSessionId) {
6671
6856
  this.engineSessionId = engineSessionId || "";
6672
- fs6.mkdirSync(path6.dirname(this.filePath), { recursive: true });
6673
- const fileExists = fs6.existsSync(this.filePath) && fs6.statSync(this.filePath).size > 0;
6674
- this.stream = fs6.createWriteStream(this.filePath, { flags: "a" });
6857
+ fs8.mkdirSync(path8.dirname(this.filePath), { recursive: true });
6858
+ const fileExists = fs8.existsSync(this.filePath) && fs8.statSync(this.filePath).size > 0;
6859
+ this.stream = fs8.createWriteStream(this.filePath, { flags: "a" });
6675
6860
  this.stream.on("error", (err) => {
6676
6861
  console.error(`[SessionWriter] write error on ${this.filePath}:`, err.message);
6677
6862
  });
@@ -6871,17 +7056,17 @@ var init_writer = __esm({
6871
7056
  this.stream.end();
6872
7057
  this.stream = null;
6873
7058
  }
6874
- if (!fs6.existsSync(this.filePath)) return null;
6875
- const fileSize = fs6.statSync(this.filePath).size;
7059
+ if (!fs8.existsSync(this.filePath)) return null;
7060
+ const fileSize = fs8.statSync(this.filePath).size;
6876
7061
  if (fileSize === 0) return null;
6877
7062
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
6878
7063
  const archivedPath = `${this.filePath}.${reason}.${ts}`;
6879
- fs6.renameSync(this.filePath, archivedPath);
7064
+ fs8.renameSync(this.filePath, archivedPath);
6880
7065
  const sizeMB = (fileSize / 1024 / 1024).toFixed(1);
6881
- console.log(`[SessionWriter] Archived JSONL: ${path6.basename(this.filePath)} \u2192 ${path6.basename(archivedPath)} (${sizeMB}MB)`);
7066
+ console.log(`[SessionWriter] Archived JSONL: ${path8.basename(this.filePath)} \u2192 ${path8.basename(archivedPath)} (${sizeMB}MB)`);
6882
7067
  const postBoundaryData = this.readPostBoundaryFromArchived(archivedPath);
6883
- const dir = path6.dirname(this.filePath);
6884
- fs6.mkdirSync(dir, { recursive: true });
7068
+ const dir = path8.dirname(this.filePath);
7069
+ fs8.mkdirSync(dir, { recursive: true });
6885
7070
  const header = {
6886
7071
  type: "session",
6887
7072
  version: 3,
@@ -6895,8 +7080,8 @@ var init_writer = __esm({
6895
7080
  if (postBoundaryData.length > 0) {
6896
7081
  initialData += postBoundaryData.toString("utf-8");
6897
7082
  }
6898
- fs6.writeFileSync(this.filePath, initialData, "utf-8");
6899
- this.stream = fs6.createWriteStream(this.filePath, { flags: "a" });
7083
+ fs8.writeFileSync(this.filePath, initialData, "utf-8");
7084
+ this.stream = fs8.createWriteStream(this.filePath, { flags: "a" });
6900
7085
  this.stream.on("error", (err) => {
6901
7086
  console.error(`[SessionWriter] write error on ${this.filePath}:`, err.message);
6902
7087
  });
@@ -6906,10 +7091,10 @@ var init_writer = __esm({
6906
7091
  * 从归档文件中读取最后一个 compact_boundary 之后的内容
6907
7092
  */
6908
7093
  readPostBoundaryFromArchived(archivedPath) {
6909
- const fileSize = fs6.statSync(archivedPath).size;
7094
+ const fileSize = fs8.statSync(archivedPath).size;
6910
7095
  if (fileSize === 0) return Buffer.alloc(0);
6911
7096
  if (fileSize <= 5 * 1024 * 1024) {
6912
- const content = fs6.readFileSync(archivedPath, "utf-8");
7097
+ const content = fs8.readFileSync(archivedPath, "utf-8");
6913
7098
  const lines = content.split("\n");
6914
7099
  let lastBoundaryIdx = -1;
6915
7100
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -6926,11 +7111,11 @@ var init_writer = __esm({
6926
7111
  {
6927
7112
  const probeSize = Math.min(fileSize, 1024 * 1024);
6928
7113
  const probeBuf = Buffer.allocUnsafe(probeSize);
6929
- const probeFd = fs6.openSync(archivedPath, "r");
7114
+ const probeFd = fs8.openSync(archivedPath, "r");
6930
7115
  let hasBoundary = false;
6931
7116
  let probed = 0;
6932
7117
  while (probed < fileSize) {
6933
- const n = fs6.readSync(probeFd, probeBuf, 0, Math.min(probeSize, fileSize - probed), probed);
7118
+ const n = fs8.readSync(probeFd, probeBuf, 0, Math.min(probeSize, fileSize - probed), probed);
6934
7119
  if (n === 0) break;
6935
7120
  if (probeBuf.subarray(0, n).includes(Buffer.from(boundaryMarker))) {
6936
7121
  hasBoundary = true;
@@ -6938,19 +7123,19 @@ var init_writer = __esm({
6938
7123
  }
6939
7124
  probed += n;
6940
7125
  }
6941
- fs6.closeSync(probeFd);
7126
+ fs8.closeSync(probeFd);
6942
7127
  if (!hasBoundary) return Buffer.alloc(0);
6943
7128
  }
6944
7129
  const outBuf = Buffer.allocUnsafe(Math.min(fileSize, 8 * 1024 * 1024));
6945
7130
  let outLen = 0;
6946
7131
  const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
6947
- const fd = fs6.openSync(archivedPath, "r");
7132
+ const fd = fs8.openSync(archivedPath, "r");
6948
7133
  try {
6949
7134
  let filePos = 0;
6950
7135
  let carryBuf;
6951
7136
  let carryLen = 0;
6952
7137
  while (filePos < fileSize) {
6953
- const bytesRead = fs6.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
7138
+ const bytesRead = fs8.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
6954
7139
  if (bytesRead === 0) break;
6955
7140
  filePos += bytesRead;
6956
7141
  let scanBuf;
@@ -6999,7 +7184,7 @@ var init_writer = __esm({
6999
7184
  }
7000
7185
  }
7001
7186
  } finally {
7002
- fs6.closeSync(fd);
7187
+ fs8.closeSync(fd);
7003
7188
  }
7004
7189
  return outBuf.subarray(0, outLen);
7005
7190
  }
@@ -7011,15 +7196,15 @@ var init_writer = __esm({
7011
7196
  */
7012
7197
  readLastId() {
7013
7198
  try {
7014
- const stat4 = fs6.statSync(this.filePath);
7199
+ const stat4 = fs8.statSync(this.filePath);
7015
7200
  if (stat4.size === 0) return null;
7016
7201
  const readSize = Math.min(stat4.size, 4096);
7017
7202
  const buf = Buffer.alloc(readSize);
7018
- const fd = fs6.openSync(this.filePath, "r");
7203
+ const fd = fs8.openSync(this.filePath, "r");
7019
7204
  try {
7020
- fs6.readSync(fd, buf, 0, readSize, stat4.size - readSize);
7205
+ fs8.readSync(fd, buf, 0, readSize, stat4.size - readSize);
7021
7206
  } finally {
7022
- fs6.closeSync(fd);
7207
+ fs8.closeSync(fd);
7023
7208
  }
7024
7209
  const text = buf.toString("utf-8");
7025
7210
  const lines = text.split("\n").filter((l) => l.trim().length > 0);
@@ -7066,11 +7251,11 @@ var init_writer = __esm({
7066
7251
  });
7067
7252
 
7068
7253
  // src/session/reader.ts
7069
- import * as fs7 from "node:fs";
7070
- import * as path7 from "node:path";
7254
+ import * as fs9 from "node:fs";
7255
+ import * as path9 from "node:path";
7071
7256
  import * as readline from "node:readline";
7072
7257
  async function readSessionHeader(filePath) {
7073
- const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
7258
+ const stream = fs9.createReadStream(filePath, { encoding: "utf-8" });
7074
7259
  const rl = readline.createInterface({ input: stream });
7075
7260
  return new Promise((resolve11) => {
7076
7261
  let resolved = false;
@@ -7101,7 +7286,7 @@ async function readSessionHeader(filePath) {
7101
7286
  });
7102
7287
  }
7103
7288
  async function readLargeFilePostBoundary(filePath) {
7104
- const stat4 = fs7.statSync(filePath);
7289
+ const stat4 = fs9.statSync(filePath);
7105
7290
  const fileSize = stat4.size;
7106
7291
  const boundaryMarker = '"compact_boundary"';
7107
7292
  const CHUNK_SIZE = TRANSCRIPT_READ_CHUNK_SIZE;
@@ -7109,13 +7294,13 @@ async function readLargeFilePostBoundary(filePath) {
7109
7294
  let outLen = 0;
7110
7295
  let boundaryStartOffset = 0;
7111
7296
  const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
7112
- const fd = fs7.openSync(filePath, "r");
7297
+ const fd = fs9.openSync(filePath, "r");
7113
7298
  try {
7114
7299
  let filePos = 0;
7115
7300
  let carryBuf;
7116
7301
  let carryLen = 0;
7117
7302
  while (filePos < fileSize) {
7118
- const bytesRead = fs7.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
7303
+ const bytesRead = fs9.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
7119
7304
  if (bytesRead === 0) break;
7120
7305
  filePos += bytesRead;
7121
7306
  let scanBuf;
@@ -7167,7 +7352,7 @@ async function readLargeFilePostBoundary(filePath) {
7167
7352
  }
7168
7353
  }
7169
7354
  } finally {
7170
- fs7.closeSync(fd);
7355
+ fs9.closeSync(fd);
7171
7356
  }
7172
7357
  const postBoundaryText = outBuf.subarray(0, outLen).toString("utf-8");
7173
7358
  return postBoundaryText.split("\n").filter((l) => l.trim().length > 0);
@@ -7291,7 +7476,7 @@ function recoverOrphanedParallelToolResults(allEntries, chain, byUuid, seen) {
7291
7476
  return result2;
7292
7477
  }
7293
7478
  async function readSessionHistory(filePath) {
7294
- const stat4 = fs7.statSync(filePath);
7479
+ const stat4 = fs9.statSync(filePath);
7295
7480
  const fileSize = stat4.size;
7296
7481
  if (fileSize > MAX_TRANSCRIPT_READ_BYTES) {
7297
7482
  console.warn(`[reader] Session file exceeds 50MB limit (${(fileSize / 1024 / 1024).toFixed(1)}MB), using chunked fd read with boundary skip`);
@@ -7318,12 +7503,19 @@ async function readSessionHistory(filePath) {
7318
7503
  let filtered = filterUnresolvedToolUses(sessionMsgs);
7319
7504
  filtered = filterOrphanedThinkingOnly(filtered);
7320
7505
  filtered = filterWhitespaceOnlyAssistant(filtered);
7321
- const sessionStarts = attachmentMsgs.filter((m) => m.attachment.type === "session_start");
7322
- const restAttachments = attachmentMsgs.filter((m) => m.attachment.type !== "session_start");
7506
+ const seenStartTexts = /* @__PURE__ */ new Set();
7507
+ const sessionStarts = attachmentMsgs.filter((m) => {
7508
+ if (m.attachment.type !== "session_start") return false;
7509
+ const key = JSON.stringify(m.attachment);
7510
+ if (seenStartTexts.has(key)) return false;
7511
+ seenStartTexts.add(key);
7512
+ return true;
7513
+ });
7514
+ const restAttachments = attachmentMsgs.filter((m) => m.type === "attachment" && m.attachment.type !== "session_start");
7323
7515
  return [...sessionStarts, ...filtered, ...restAttachments];
7324
7516
  }
7325
7517
  async function readAllLines(filePath) {
7326
- const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
7518
+ const stream = fs9.createReadStream(filePath, { encoding: "utf-8" });
7327
7519
  const rl = readline.createInterface({ input: stream });
7328
7520
  const lines = [];
7329
7521
  return new Promise((resolve11, reject) => {
@@ -7473,12 +7665,12 @@ function extractText2(content) {
7473
7665
  return content.filter((b) => b.type === "text").map((b) => b.text || "").join("") || null;
7474
7666
  }
7475
7667
  function listSessions(sessionsDir) {
7476
- if (!fs7.existsSync(sessionsDir)) return [];
7477
- const files = fs7.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
7478
- file: path7.join(sessionsDir, f),
7668
+ if (!fs9.existsSync(sessionsDir)) return [];
7669
+ const files = fs9.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
7670
+ file: path9.join(sessionsDir, f),
7479
7671
  id: f.replace(/\.jsonl.*$/, ""),
7480
7672
  // strip .jsonl and everything after (archived suffix)
7481
- modified: new Date(fs7.statSync(path7.join(sessionsDir, f)).mtimeMs)
7673
+ modified: new Date(fs9.statSync(path9.join(sessionsDir, f)).mtimeMs)
7482
7674
  })).sort((a, b) => b.modified.getTime() - a.modified.getTime());
7483
7675
  return files;
7484
7676
  }
@@ -7498,8 +7690,8 @@ var session_manager_exports = {};
7498
7690
  __export(session_manager_exports, {
7499
7691
  SessionManager: () => SessionManager
7500
7692
  });
7501
- import * as path8 from "node:path";
7502
- import * as fs8 from "node:fs";
7693
+ import * as path10 from "node:path";
7694
+ import * as fs10 from "node:fs";
7503
7695
  import * as crypto3 from "node:crypto";
7504
7696
  var RESTORE_MAX_CHARS, CHARS_PER_TOKEN, SessionManager;
7505
7697
  var init_session_manager = __esm({
@@ -7531,24 +7723,24 @@ var init_session_manager = __esm({
7531
7723
  constructor(config) {
7532
7724
  this.config = config;
7533
7725
  this.scopeConfig = config.scopeConfig;
7534
- this.sessionsDir = path8.join(config.stateDir, "agents", "main", "sessions");
7535
- this.indexPath = path8.join(this.sessionsDir, "session-index.json");
7536
- this.platformMapPath = path8.join(this.sessionsDir, "platform-map.json");
7537
- fs8.mkdirSync(this.sessionsDir, { recursive: true });
7726
+ this.sessionsDir = path10.join(config.stateDir, "agents", "main", "sessions");
7727
+ this.indexPath = path10.join(this.sessionsDir, "session-index.json");
7728
+ this.platformMapPath = path10.join(this.sessionsDir, "platform-map.json");
7729
+ fs10.mkdirSync(this.sessionsDir, { recursive: true });
7538
7730
  }
7539
7731
  // === 索引操作 ===
7540
7732
  loadIndex() {
7541
7733
  try {
7542
- if (fs8.existsSync(this.indexPath)) {
7543
- const raw = fs8.readFileSync(this.indexPath, "utf-8");
7734
+ if (fs10.existsSync(this.indexPath)) {
7735
+ const raw = fs10.readFileSync(this.indexPath, "utf-8");
7544
7736
  const obj = JSON.parse(raw);
7545
7737
  this.index = new Map(Object.entries(obj));
7546
7738
  let fixed = 0;
7547
7739
  for (const [key, entry] of this.index) {
7548
- if (fs8.existsSync(entry.file)) continue;
7549
- const basename8 = path8.basename(entry.file);
7550
- const localPath = path8.join(this.sessionsDir, basename8);
7551
- if (fs8.existsSync(localPath)) {
7740
+ if (fs10.existsSync(entry.file)) continue;
7741
+ const basename8 = path10.basename(entry.file);
7742
+ const localPath = path10.join(this.sessionsDir, basename8);
7743
+ if (fs10.existsSync(localPath)) {
7552
7744
  entry.file = localPath;
7553
7745
  fixed++;
7554
7746
  }
@@ -7567,7 +7759,7 @@ var init_session_manager = __esm({
7567
7759
  try {
7568
7760
  const obj = {};
7569
7761
  for (const [k, v] of this.index) obj[k] = v;
7570
- fs8.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
7762
+ fs10.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
7571
7763
  } catch (err) {
7572
7764
  console.error(`[session] Failed to save index: ${err.message}`);
7573
7765
  }
@@ -7575,8 +7767,8 @@ var init_session_manager = __esm({
7575
7767
  // === 平台映射 ===
7576
7768
  loadPlatformMap() {
7577
7769
  try {
7578
- if (fs8.existsSync(this.platformMapPath)) {
7579
- const raw = fs8.readFileSync(this.platformMapPath, "utf-8");
7770
+ if (fs10.existsSync(this.platformMapPath)) {
7771
+ const raw = fs10.readFileSync(this.platformMapPath, "utf-8");
7580
7772
  const obj = JSON.parse(raw);
7581
7773
  this.platformMap = new Map(Object.entries(obj));
7582
7774
  console.log(`[session] Platform map loaded: ${this.platformMap.size} entries`);
@@ -7588,7 +7780,7 @@ var init_session_manager = __esm({
7588
7780
  try {
7589
7781
  const obj = {};
7590
7782
  for (const [k, v] of this.platformMap) obj[k] = v;
7591
- fs8.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
7783
+ fs10.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
7592
7784
  } catch (err) {
7593
7785
  console.error(`[session] Failed to save platform map: ${err.message}`);
7594
7786
  }
@@ -7627,17 +7819,17 @@ var init_session_manager = __esm({
7627
7819
  */
7628
7820
  getSessionFilePath(sessionId) {
7629
7821
  const entry = this.index.get(sessionId);
7630
- if (entry && fs8.existsSync(entry.file)) return entry.file;
7631
- const direct = path8.join(this.sessionsDir, `${sessionId}.jsonl`);
7632
- return fs8.existsSync(direct) ? direct : null;
7822
+ if (entry && fs10.existsSync(entry.file)) return entry.file;
7823
+ const direct = path10.join(this.sessionsDir, `${sessionId}.jsonl`);
7824
+ return fs10.existsSync(direct) ? direct : null;
7633
7825
  }
7634
7826
  // === Writer 管理 ===
7635
7827
  getWriter(sessionId) {
7636
7828
  let writer = this.writers.get(sessionId);
7637
7829
  if (!writer) {
7638
7830
  const existing = this.index.get(sessionId);
7639
- if (existing && fs8.existsSync(existing.file)) {
7640
- const existingFileId = path8.basename(existing.file, ".jsonl");
7831
+ if (existing && fs10.existsSync(existing.file)) {
7832
+ const existingFileId = path10.basename(existing.file, ".jsonl");
7641
7833
  writer = new SessionWriter(this.sessionsDir, existingFileId);
7642
7834
  writer.open(this.config.workspace, sessionId);
7643
7835
  } else {
@@ -7649,7 +7841,7 @@ var init_session_manager = __esm({
7649
7841
  this.saveIndex();
7650
7842
  this.writers.set(sessionId, writer);
7651
7843
  this.onWriterCreated?.(writer, sessionId);
7652
- console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path8.basename(writer.path)}`);
7844
+ console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path10.basename(writer.path)}`);
7653
7845
  }
7654
7846
  return writer;
7655
7847
  }
@@ -7668,7 +7860,7 @@ var init_session_manager = __esm({
7668
7860
  if (!writer) return null;
7669
7861
  try {
7670
7862
  this.lastArchiveCheck = Date.now();
7671
- const stat4 = fs8.statSync(writer.path);
7863
+ const stat4 = fs10.statSync(writer.path);
7672
7864
  if (stat4.size < threshold) return null;
7673
7865
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
7674
7866
  const thresholdMB = (threshold / 1024 / 1024).toFixed(1);
@@ -7677,10 +7869,10 @@ var init_session_manager = __esm({
7677
7869
  if (archivedPath) {
7678
7870
  this.index.set(sessionId, { file: writer.path, updatedAt: Date.now() });
7679
7871
  this.saveIndex();
7680
- const newSize = fs8.statSync(writer.path).size;
7872
+ const newSize = fs10.statSync(writer.path).size;
7681
7873
  const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
7682
- console.log(`[session] Archive complete: ${path8.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
7683
- const fileId = path8.basename(writer.path).replace(/\.jsonl$/, "");
7874
+ console.log(`[session] Archive complete: ${path10.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
7875
+ const fileId = path10.basename(writer.path).replace(/\.jsonl$/, "");
7684
7876
  this.purgeOldArchives(fileId, 3);
7685
7877
  return archivedPath;
7686
7878
  }
@@ -7696,15 +7888,15 @@ var init_session_manager = __esm({
7696
7888
  purgeOldArchives(sessionId, keepCount = 3) {
7697
7889
  try {
7698
7890
  const dir = this.sessionsDir;
7699
- if (!fs8.existsSync(dir)) return;
7700
- const allFiles = fs8.readdirSync(dir);
7891
+ if (!fs10.existsSync(dir)) return;
7892
+ const allFiles = fs10.readdirSync(dir);
7701
7893
  const archiveFiles = allFiles.filter((f) => {
7702
7894
  if (!f.startsWith(sessionId)) return false;
7703
7895
  return f.includes(".archived.") || f.includes(".compaction.");
7704
7896
  }).map((f) => ({
7705
7897
  name: f,
7706
- path: path8.join(dir, f),
7707
- mtime: fs8.statSync(path8.join(dir, f)).mtimeMs
7898
+ path: path10.join(dir, f),
7899
+ mtime: fs10.statSync(path10.join(dir, f)).mtimeMs
7708
7900
  })).sort((a, b) => b.mtime - a.mtime);
7709
7901
  console.log(`[session] purgeOldArchives: sessionId=${sessionId.substring(0, 8)}... found=${archiveFiles.length} keep=${keepCount}`);
7710
7902
  if (archiveFiles.length <= keepCount) return;
@@ -7714,7 +7906,7 @@ var init_session_manager = __esm({
7714
7906
  console.log(`[session] Skipping archived (kept for history): ${f.name}`);
7715
7907
  continue;
7716
7908
  }
7717
- fs8.unlinkSync(f.path);
7909
+ fs10.unlinkSync(f.path);
7718
7910
  console.log(`[session] Purged old archive: ${f.name}`);
7719
7911
  }
7720
7912
  if (toDelete.length > 0) {
@@ -7763,29 +7955,29 @@ var init_session_manager = __esm({
7763
7955
  /** 列出 session 的所有文件(当前 + 归档),按修改时间排序 */
7764
7956
  findAllSessionFiles(sessionId) {
7765
7957
  const results = [];
7766
- const mainFile = path8.join(this.sessionsDir, `${sessionId}.jsonl`);
7767
- if (fs8.existsSync(mainFile)) {
7958
+ const mainFile = path10.join(this.sessionsDir, `${sessionId}.jsonl`);
7959
+ if (fs10.existsSync(mainFile)) {
7768
7960
  results.push(mainFile);
7769
7961
  }
7770
- if (fs8.existsSync(this.sessionsDir)) {
7771
- const compactionFiles = fs8.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
7962
+ if (fs10.existsSync(this.sessionsDir)) {
7963
+ const compactionFiles = fs10.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
7772
7964
  name: f,
7773
- path: path8.join(this.sessionsDir, f),
7774
- mtime: fs8.statSync(path8.join(this.sessionsDir, f)).mtimeMs
7965
+ path: path10.join(this.sessionsDir, f),
7966
+ mtime: fs10.statSync(path10.join(this.sessionsDir, f)).mtimeMs
7775
7967
  })).sort((a, b) => b.mtime - a.mtime);
7776
7968
  if (compactionFiles.length > 0) {
7777
7969
  results.push(compactionFiles[0].path);
7778
7970
  }
7779
7971
  }
7780
7972
  results.sort((a, b) => {
7781
- const ta = fs8.statSync(a).mtimeMs;
7782
- const tb = fs8.statSync(b).mtimeMs;
7973
+ const ta = fs10.statSync(a).mtimeMs;
7974
+ const tb = fs10.statSync(b).mtimeMs;
7783
7975
  return ta - tb;
7784
7976
  });
7785
7977
  return results;
7786
7978
  }
7787
7979
  async findSessionFiles(sessionId) {
7788
- if (!fs8.existsSync(this.sessionsDir)) {
7980
+ if (!fs10.existsSync(this.sessionsDir)) {
7789
7981
  console.log(`[session:find] SESSIONS_DIR not found: ${this.sessionsDir}`);
7790
7982
  return [];
7791
7983
  }
@@ -7797,15 +7989,15 @@ var init_session_manager = __esm({
7797
7989
  return mappedFiles;
7798
7990
  }
7799
7991
  const indexedEntry = this.index.get(mappedId);
7800
- if (indexedEntry && fs8.existsSync(indexedEntry.file)) {
7801
- const fileUuid = path8.basename(indexedEntry.file, ".jsonl");
7992
+ if (indexedEntry && fs10.existsSync(indexedEntry.file)) {
7993
+ const fileUuid = path10.basename(indexedEntry.file, ".jsonl");
7802
7994
  return this.findAllSessionFiles(fileUuid);
7803
7995
  }
7804
7996
  }
7805
7997
  const allFiles = this.findAllSessionFiles(sessionId);
7806
7998
  if (allFiles.length > 0) {
7807
7999
  const labels = allFiles.map((f) => {
7808
- const base = path8.basename(f);
8000
+ const base = path10.basename(f);
7809
8001
  return base.endsWith(".jsonl") ? base : `${base} (archived)`;
7810
8002
  });
7811
8003
  console.log(`[session:find] Found ${allFiles.length} file(s) for ${sessionId}: ${labels.join(", ")}`);
@@ -7813,9 +8005,9 @@ var init_session_manager = __esm({
7813
8005
  }
7814
8006
  const indexed = this.index.get(sessionId);
7815
8007
  if (indexed) {
7816
- console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs8.existsSync(indexed.file)})`);
7817
- if (fs8.existsSync(indexed.file)) {
7818
- return this.findAllSessionFiles(path8.basename(indexed.file, ".jsonl"));
8008
+ console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs10.existsSync(indexed.file)})`);
8009
+ if (fs10.existsSync(indexed.file)) {
8010
+ return this.findAllSessionFiles(path10.basename(indexed.file, ".jsonl"));
7819
8011
  }
7820
8012
  } else {
7821
8013
  console.log(`[session:find] Index miss: ${sessionId} (index has ${this.index.size} entries)`);
@@ -7844,8 +8036,8 @@ var init_session_manager = __esm({
7844
8036
  return [];
7845
8037
  }
7846
8038
  files.sort((a, b) => {
7847
- const ta = fs8.statSync(a).mtimeMs;
7848
- const tb = fs8.statSync(b).mtimeMs;
8039
+ const ta = fs10.statSync(a).mtimeMs;
8040
+ const tb = fs10.statSync(b).mtimeMs;
7849
8041
  return ta - tb;
7850
8042
  });
7851
8043
  const latestFile = files[files.length - 1];
@@ -7853,11 +8045,11 @@ var init_session_manager = __esm({
7853
8045
  if (!currentEntry || currentEntry.file !== latestFile) {
7854
8046
  this.index.set(sessionId, { file: latestFile, updatedAt: Date.now() });
7855
8047
  this.saveIndex();
7856
- console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path8.basename(latestFile)}`);
8048
+ console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path10.basename(latestFile)}`);
7857
8049
  }
7858
8050
  const allMessages = [];
7859
- for (const file of files) {
7860
- const sessionMsgs = await readSessionHistory(file);
8051
+ for (const file2 of files) {
8052
+ const sessionMsgs = await readSessionHistory(file2);
7861
8053
  for (const m of sessionMsgs) {
7862
8054
  if (isAttachmentMessage(m)) {
7863
8055
  allMessages.push(m);
@@ -7889,7 +8081,7 @@ var init_session_manager = __esm({
7889
8081
  if (isAttachmentMessage(m) && m.attachment.type === "relevant_memories") {
7890
8082
  for (const mem of m.attachment.memories) {
7891
8083
  rawCount++;
7892
- restoredPaths.add(path8.resolve(mem.path));
8084
+ restoredPaths.add(path10.resolve(mem.path));
7893
8085
  }
7894
8086
  }
7895
8087
  }
@@ -7918,15 +8110,15 @@ var init_session_manager = __esm({
7918
8110
  */
7919
8111
  rotateMainSession() {
7920
8112
  const entry = this.index.get("main");
7921
- if (!entry || !fs8.existsSync(entry.file)) return;
7922
- const oldFileId = path8.basename(entry.file, ".jsonl");
7923
- const stat4 = fs8.statSync(entry.file);
8113
+ if (!entry || !fs10.existsSync(entry.file)) return;
8114
+ const oldFileId = path10.basename(entry.file, ".jsonl");
8115
+ const stat4 = fs10.statSync(entry.file);
7924
8116
  if (stat4.size < 1024) return;
7925
8117
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
7926
8118
  const archivedPath = `${entry.file}.archived.${ts}`;
7927
- fs8.renameSync(entry.file, archivedPath);
8119
+ fs10.renameSync(entry.file, archivedPath);
7928
8120
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
7929
- console.log(`[session] Archived: ${path8.basename(entry.file)} \u2192 ${path8.basename(archivedPath)} (${sizeMB}MB)`);
8121
+ console.log(`[session] Archived: ${path10.basename(entry.file)} \u2192 ${path10.basename(archivedPath)} (${sizeMB}MB)`);
7930
8122
  const newWriter = new SessionWriter(this.sessionsDir);
7931
8123
  newWriter.open(this.config.workspace, "main");
7932
8124
  newWriter.writeModelChange(this.config.providerId, this.config.model);
@@ -7935,7 +8127,7 @@ var init_session_manager = __esm({
7935
8127
  this.index.set("main", { file: newPath, updatedAt: Date.now() });
7936
8128
  this.saveIndex();
7937
8129
  this.purgeOldArchives(oldFileId, 3);
7938
- console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path8.basename(newPath)}`);
8130
+ console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path10.basename(newPath)}`);
7939
8131
  }
7940
8132
  // === 迁移 ===
7941
8133
  /** 迁移旧索引:session-index.json 里有 "discord:xxx" 格式的 key 时,生成 UUID 替换 */
@@ -8000,7 +8192,7 @@ var init_session_manager = __esm({
8000
8192
  });
8001
8193
 
8002
8194
  // src/utils/path.ts
8003
- import * as path9 from "node:path";
8195
+ import * as path11 from "node:path";
8004
8196
  function fixMsysPath(p) {
8005
8197
  let fixed = p.includes("\\") ? p.replace(/\\/g, "/") : p;
8006
8198
  if (process.platform === "win32") {
@@ -8010,15 +8202,15 @@ function fixMsysPath(p) {
8010
8202
  }
8011
8203
  function resolvePath(p, workspace) {
8012
8204
  const fixed = fixMsysPath(p);
8013
- const resolved = path9.isAbsolute(fixed) ? path9.normalize(fixed) : path9.resolve(workspace, fixed);
8014
- const normalized = path9.normalize(resolved);
8015
- const normalizedWorkspace = path9.normalize(workspace);
8205
+ const resolved = path11.isAbsolute(fixed) ? path11.normalize(fixed) : path11.resolve(workspace, fixed);
8206
+ const normalized = path11.normalize(resolved);
8207
+ const normalizedWorkspace = path11.normalize(workspace);
8016
8208
  if (sandboxOff) return normalized;
8017
- if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path9.sep)) {
8209
+ if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path11.sep)) {
8018
8210
  return normalized;
8019
8211
  }
8020
8212
  for (const allowed of extraAllowedPaths) {
8021
- if (normalized === allowed || normalized.startsWith(allowed + path9.sep)) {
8213
+ if (normalized === allowed || normalized.startsWith(allowed + path11.sep)) {
8022
8214
  return normalized;
8023
8215
  }
8024
8216
  }
@@ -8034,15 +8226,15 @@ var init_path = __esm({
8034
8226
  });
8035
8227
 
8036
8228
  // src/tools/read.ts
8037
- import * as fs9 from "node:fs";
8038
- import * as path10 from "node:path";
8229
+ import * as fs11 from "node:fs";
8230
+ import * as path12 from "node:path";
8039
8231
  function isBlockedDevicePath(filePath) {
8040
8232
  if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
8041
8233
  if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
8042
8234
  return false;
8043
8235
  }
8044
8236
  function checkReadLoop(filePath, offset, limit) {
8045
- const stat4 = fs9.statSync(filePath);
8237
+ const stat4 = fs11.statSync(filePath);
8046
8238
  const mtimeMs = stat4.mtimeMs;
8047
8239
  const prev = readHistory.get(filePath);
8048
8240
  if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
@@ -8056,19 +8248,19 @@ function checkReadLoop(filePath, offset, limit) {
8056
8248
  return null;
8057
8249
  }
8058
8250
  function readFileContent(filePath) {
8059
- const fd = fs9.openSync(filePath, "r");
8251
+ const fd = fs11.openSync(filePath, "r");
8060
8252
  const bom = Buffer.alloc(2);
8061
- fs9.readSync(fd, bom, 0, 2, 0);
8062
- fs9.closeSync(fd);
8253
+ fs11.readSync(fd, bom, 0, 2, 0);
8254
+ fs11.closeSync(fd);
8063
8255
  let encoding = "utf8";
8064
8256
  if (bom[0] === 255 && bom[1] === 254) {
8065
8257
  encoding = "utf16le";
8066
8258
  }
8067
- const stat4 = fs9.statSync(filePath);
8259
+ const stat4 = fs11.statSync(filePath);
8068
8260
  if (stat4.size > MAX_FILE_SIZE) {
8069
8261
  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`);
8070
8262
  }
8071
- const raw = fs9.readFileSync(filePath, encoding);
8263
+ const raw = fs11.readFileSync(filePath, encoding);
8072
8264
  const content = raw.toString().replaceAll("\r\n", "\n");
8073
8265
  return { content, encoding };
8074
8266
  }
@@ -8210,11 +8402,11 @@ Usage:
8210
8402
  } catch (e) {
8211
8403
  return { content: e.message, isError: true };
8212
8404
  }
8213
- if (!fs9.existsSync(filePath)) {
8405
+ if (!fs11.existsSync(filePath)) {
8214
8406
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
8215
8407
  }
8216
- const stat4 = fs9.statSync(filePath);
8217
- const baseName = path10.basename(filePath).toUpperCase();
8408
+ const stat4 = fs11.statSync(filePath);
8409
+ const baseName = path12.basename(filePath).toUpperCase();
8218
8410
  if (BLOCKED_BASENAMES.has(baseName)) {
8219
8411
  return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
8220
8412
  }
@@ -8222,11 +8414,11 @@ Usage:
8222
8414
  return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
8223
8415
  }
8224
8416
  if (stat4.isDirectory()) {
8225
- const entries2 = fs9.readdirSync(filePath);
8417
+ const entries2 = fs11.readdirSync(filePath);
8226
8418
  const items = entries2.map((e) => {
8227
- const full = path10.join(filePath, e);
8419
+ const full = path12.join(filePath, e);
8228
8420
  try {
8229
- const s = fs9.statSync(full);
8421
+ const s = fs11.statSync(full);
8230
8422
  return s.isDirectory() ? `${e}/` : e;
8231
8423
  } catch {
8232
8424
  return e;
@@ -8235,7 +8427,7 @@ Usage:
8235
8427
  return { content: `\u76EE\u5F55 (${entries2.length} \u9879):
8236
8428
  ${items.join("\n")}` };
8237
8429
  }
8238
- const ext = path10.extname(filePath).toLowerCase();
8430
+ const ext = path12.extname(filePath).toLowerCase();
8239
8431
  if (BINARY_EXTENSIONS.has(ext)) {
8240
8432
  return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
8241
8433
  }
@@ -8282,22 +8474,22 @@ ${result2}` : result2 };
8282
8474
  });
8283
8475
 
8284
8476
  // src/tools/write.ts
8285
- import * as fs10 from "node:fs";
8286
- import * as path11 from "node:path";
8477
+ import * as fs12 from "node:fs";
8478
+ import * as path13 from "node:path";
8287
8479
  function isBlockedPath(filePath) {
8288
8480
  return BLOCKED_PATTERNS.some((p) => p.test(filePath));
8289
8481
  }
8290
8482
  function atomicWrite(filePath, content) {
8291
8483
  const tmpPath = filePath + ".tmp." + Date.now() + ".write";
8292
- fs10.writeFileSync(tmpPath, content, "utf-8");
8484
+ fs12.writeFileSync(tmpPath, content, "utf-8");
8293
8485
  try {
8294
- fs10.renameSync(tmpPath, filePath);
8486
+ fs12.renameSync(tmpPath, filePath);
8295
8487
  } catch (e) {
8296
8488
  try {
8297
- fs10.unlinkSync(tmpPath);
8489
+ fs12.unlinkSync(tmpPath);
8298
8490
  } catch {
8299
8491
  }
8300
- fs10.writeFileSync(filePath, content, "utf-8");
8492
+ fs12.writeFileSync(filePath, content, "utf-8");
8301
8493
  }
8302
8494
  }
8303
8495
  function simpleDiff(oldContent, newContent) {
@@ -8391,15 +8583,15 @@ Usage:
8391
8583
  }
8392
8584
  const rawContent = args.content;
8393
8585
  const content = rawContent.replaceAll("\r\n", "\n");
8394
- if (fs10.existsSync(filePath) && fs10.statSync(filePath).isDirectory()) {
8586
+ if (fs12.existsSync(filePath) && fs12.statSync(filePath).isDirectory()) {
8395
8587
  return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
8396
8588
  }
8397
8589
  let oldContent = null;
8398
8590
  let isCreate = true;
8399
- if (fs10.existsSync(filePath)) {
8591
+ if (fs12.existsSync(filePath)) {
8400
8592
  isCreate = false;
8401
8593
  try {
8402
- oldContent = fs10.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8594
+ oldContent = fs12.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8403
8595
  } catch {
8404
8596
  isCreate = true;
8405
8597
  }
@@ -8415,10 +8607,10 @@ Usage:
8415
8607
  isError: true
8416
8608
  };
8417
8609
  }
8418
- const currentStat = fs10.statSync(filePath);
8610
+ const currentStat = fs12.statSync(filePath);
8419
8611
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
8420
8612
  if (lastWriteTime > readState.timestamp) {
8421
- const currentContent = fs10.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8613
+ const currentContent = fs12.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8422
8614
  if (currentContent !== oldContent) {
8423
8615
  return {
8424
8616
  content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
@@ -8427,9 +8619,9 @@ Usage:
8427
8619
  }
8428
8620
  }
8429
8621
  }
8430
- const dir = path11.dirname(filePath);
8622
+ const dir = path13.dirname(filePath);
8431
8623
  try {
8432
- fs10.mkdirSync(dir, { recursive: true });
8624
+ fs12.mkdirSync(dir, { recursive: true });
8433
8625
  } catch (e) {
8434
8626
  return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
8435
8627
  }
@@ -8438,11 +8630,11 @@ Usage:
8438
8630
  } catch (e) {
8439
8631
  return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
8440
8632
  }
8441
- readFileState.set(filePath, { timestamp: fs10.statSync(filePath).mtimeMs });
8633
+ readFileState.set(filePath, { timestamp: fs12.statSync(filePath).mtimeMs });
8442
8634
  const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
8443
8635
  const lines = content.split("\n").length;
8444
8636
  const chars = content.length;
8445
- const stat4 = fs10.statSync(filePath);
8637
+ const stat4 = fs12.statSync(filePath);
8446
8638
  let diff = "";
8447
8639
  if (!isCreate && oldContent !== null) {
8448
8640
  diff = `
@@ -8461,8 +8653,8 @@ ${simpleDiff(oldContent, content)}`;
8461
8653
  });
8462
8654
 
8463
8655
  // src/tools/edit.ts
8464
- import * as fs11 from "node:fs";
8465
- import * as path12 from "node:path";
8656
+ import * as fs13 from "node:fs";
8657
+ import * as path14 from "node:path";
8466
8658
  function normalizeQuotes(str) {
8467
8659
  return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
8468
8660
  }
@@ -8615,7 +8807,7 @@ Usage:
8615
8807
  }
8616
8808
  let fileContent = null;
8617
8809
  try {
8618
- const stat4 = fs11.statSync(filePath);
8810
+ const stat4 = fs13.statSync(filePath);
8619
8811
  if (stat4.isDirectory()) {
8620
8812
  return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
8621
8813
  }
@@ -8625,21 +8817,21 @@ Usage:
8625
8817
  } catch (e) {
8626
8818
  if (e.code === "ENOENT") {
8627
8819
  if (oldString === "") {
8628
- const dir = path12.dirname(filePath);
8629
- fs11.mkdirSync(dir, { recursive: true });
8630
- fs11.writeFileSync(filePath, newString, "utf-8");
8631
- readFileState.set(filePath, { timestamp: fs11.statSync(filePath).mtimeMs });
8820
+ const dir = path14.dirname(filePath);
8821
+ fs13.mkdirSync(dir, { recursive: true });
8822
+ fs13.writeFileSync(filePath, newString, "utf-8");
8823
+ readFileState.set(filePath, { timestamp: fs13.statSync(filePath).mtimeMs });
8632
8824
  return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
8633
8825
  }
8634
8826
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
8635
8827
  }
8636
8828
  throw e;
8637
8829
  }
8638
- const rawContent = fs11.readFileSync(filePath, "utf-8");
8830
+ const rawContent = fs13.readFileSync(filePath, "utf-8");
8639
8831
  fileContent = rawContent.replaceAll("\r\n", "\n");
8640
8832
  if (oldString === "" && fileContent.trim() === "") {
8641
- fs11.writeFileSync(filePath, newString, "utf-8");
8642
- readFileState.set(filePath, { timestamp: fs11.statSync(filePath).mtimeMs });
8833
+ fs13.writeFileSync(filePath, newString, "utf-8");
8834
+ readFileState.set(filePath, { timestamp: fs13.statSync(filePath).mtimeMs });
8643
8835
  return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
8644
8836
  }
8645
8837
  const readState = readFileState.get(filePath);
@@ -8649,11 +8841,11 @@ Usage:
8649
8841
  isError: true
8650
8842
  };
8651
8843
  }
8652
- const currentStat = fs11.statSync(filePath);
8844
+ const currentStat = fs13.statSync(filePath);
8653
8845
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
8654
8846
  if (lastWriteTime > readState.timestamp) {
8655
8847
  if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
8656
- if (fileContent !== fs11.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
8848
+ if (fileContent !== fs13.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
8657
8849
  return {
8658
8850
  content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
8659
8851
  isError: true
@@ -8685,8 +8877,8 @@ ${preview}
8685
8877
  const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
8686
8878
  const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
8687
8879
  const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
8688
- fs11.writeFileSync(filePath, newContent, "utf-8");
8689
- readFileState.set(filePath, { timestamp: fs11.statSync(filePath).mtimeMs });
8880
+ fs13.writeFileSync(filePath, newContent, "utf-8");
8881
+ readFileState.set(filePath, { timestamp: fs13.statSync(filePath).mtimeMs });
8690
8882
  const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
8691
8883
  const count = replaceAll ? matchCount : 1;
8692
8884
  const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
@@ -8703,8 +8895,8 @@ ${diffView}`
8703
8895
  });
8704
8896
 
8705
8897
  // src/tools/glob.ts
8706
- import * as fs12 from "node:fs";
8707
- import * as path13 from "node:path";
8898
+ import * as fs14 from "node:fs";
8899
+ import * as path15 from "node:path";
8708
8900
  function globMatch(pattern, filename) {
8709
8901
  const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
8710
8902
  try {
@@ -8724,18 +8916,18 @@ function findFiles(dir, pattern, limit, baseDir) {
8724
8916
  }
8725
8917
  let entries2;
8726
8918
  try {
8727
- entries2 = fs12.readdirSync(currentDir, { withFileTypes: true });
8919
+ entries2 = fs14.readdirSync(currentDir, { withFileTypes: true });
8728
8920
  } catch {
8729
8921
  return;
8730
8922
  }
8731
8923
  for (const entry of entries2) {
8732
8924
  if (truncated) return;
8733
- const fullPath = path13.join(currentDir, entry.name);
8925
+ const fullPath = path15.join(currentDir, entry.name);
8734
8926
  if (entry.isDirectory()) {
8735
8927
  if (VCS_DIRS.has(entry.name)) continue;
8736
8928
  walk(fullPath);
8737
8929
  } else if (entry.isFile()) {
8738
- const relativePath = path13.relative(baseDir, fullPath).replace(/\\/g, "/");
8930
+ const relativePath = path15.relative(baseDir, fullPath).replace(/\\/g, "/");
8739
8931
  const patternsToTry = [pattern];
8740
8932
  if (pattern.startsWith("**/")) {
8741
8933
  patternsToTry.push(pattern.slice(3));
@@ -8745,7 +8937,7 @@ function findFiles(dir, pattern, limit, baseDir) {
8745
8937
  );
8746
8938
  if (matched) {
8747
8939
  try {
8748
- const stat4 = fs12.statSync(fullPath);
8940
+ const stat4 = fs14.statSync(fullPath);
8749
8941
  results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
8750
8942
  } catch {
8751
8943
  }
@@ -8762,7 +8954,7 @@ function findFiles(dir, pattern, limit, baseDir) {
8762
8954
  };
8763
8955
  }
8764
8956
  function toRelativePath(absolutePath, cwd) {
8765
- if (absolutePath.startsWith(cwd + path13.sep)) {
8957
+ if (absolutePath.startsWith(cwd + path15.sep)) {
8766
8958
  return absolutePath.slice(cwd.length + 1);
8767
8959
  }
8768
8960
  return absolutePath;
@@ -8795,10 +8987,10 @@ var init_glob = __esm({
8795
8987
  const searchPath = args.path ? resolvePath(args.path, ctx.workspace) : ctx.workspace;
8796
8988
  const pattern = args.pattern;
8797
8989
  const limit = args.limit || DEFAULT_LIMIT;
8798
- if (!fs12.existsSync(searchPath)) {
8990
+ if (!fs14.existsSync(searchPath)) {
8799
8991
  return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
8800
8992
  }
8801
- if (!fs12.statSync(searchPath).isDirectory()) {
8993
+ if (!fs14.statSync(searchPath).isDirectory()) {
8802
8994
  return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
8803
8995
  }
8804
8996
  const start = Date.now();
@@ -8822,7 +9014,7 @@ ${filenames.join("\n")}${truncatedNote}`
8822
9014
 
8823
9015
  // src/tools/grep.ts
8824
9016
  import { execFile } from "node:child_process";
8825
- import * as path14 from "node:path";
9017
+ import * as path16 from "node:path";
8826
9018
  function ripGrep(args, searchPath, signal) {
8827
9019
  return new Promise((resolve11) => {
8828
9020
  const fullArgs = [...args, searchPath];
@@ -8854,7 +9046,7 @@ function applyHeadLimit(items, limit, offset = 0) {
8854
9046
  };
8855
9047
  }
8856
9048
  function toRelativePath2(absolutePath, cwd) {
8857
- if (absolutePath.startsWith(cwd + path14.sep)) {
9049
+ if (absolutePath.startsWith(cwd + path16.sep)) {
8858
9050
  return absolutePath.slice(cwd.length + 1);
8859
9051
  }
8860
9052
  if (absolutePath.startsWith(cwd)) {
@@ -9024,12 +9216,14 @@ ${filenames.join("\n")}${truncatedNote}`
9024
9216
  // src/tools/task-manager.ts
9025
9217
  var task_manager_exports = {};
9026
9218
  __export(task_manager_exports, {
9219
+ ackPendingNotification: () => ackPendingNotification,
9027
9220
  buildCalendarNotification: () => buildCalendarNotification,
9028
9221
  buildNudgeNotification: () => buildNudgeNotification,
9029
9222
  clearNotificationCallback: () => clearNotificationCallback,
9030
9223
  drainPendingNotifications: () => drainPendingNotifications,
9031
9224
  enqueueNotification: () => enqueueNotification,
9032
9225
  generateTaskId: () => generateTaskId,
9226
+ getPendingNotificationRecords: () => getPendingNotificationRecords,
9033
9227
  getPendingNotifications: () => getPendingNotifications,
9034
9228
  getTask: () => getTask,
9035
9229
  getTaskOutput: () => getTaskOutput,
@@ -9038,14 +9232,16 @@ __export(task_manager_exports, {
9038
9232
  getTaskOutputPath: () => getTaskOutputPath,
9039
9233
  getTaskOutputSize: () => getTaskOutputSize,
9040
9234
  killTask: () => killTask,
9235
+ listLiveTasks: () => listLiveTasks,
9041
9236
  listTasks: () => listTasks,
9237
+ loadPersistedTasks: () => loadPersistedTasks,
9042
9238
  setNotificationCallback: () => setNotificationCallback,
9043
9239
  spawnBackgroundTask: () => spawnBackgroundTask
9044
9240
  });
9045
9241
  import { randomBytes as randomBytes3 } from "node:crypto";
9046
9242
  import { spawn as spawn2 } from "node:child_process";
9047
- import * as fs13 from "node:fs";
9048
- import * as path15 from "node:path";
9243
+ import * as fs15 from "node:fs";
9244
+ import * as path17 from "node:path";
9049
9245
  function generateTaskId(type2 = "local_bash") {
9050
9246
  const prefix = TASK_ID_PREFIXES[type2] ?? "x";
9051
9247
  const bytes = randomBytes3(8);
@@ -9058,60 +9254,182 @@ function generateTaskId(type2 = "local_bash") {
9058
9254
  function getTaskOutputDir() {
9059
9255
  if (_taskOutputDir === void 0) {
9060
9256
  const stateDir = process.env.ENGINE_STATE_DIR || process.cwd();
9061
- _taskOutputDir = path15.join(stateDir, "tasks");
9257
+ _taskOutputDir = path17.join(stateDir, "tasks");
9062
9258
  }
9063
9259
  return _taskOutputDir;
9064
9260
  }
9065
9261
  function getTaskOutputPath(taskId) {
9066
- return path15.join(getTaskOutputDir(), `${taskId}.output`);
9262
+ return path17.join(getTaskOutputDir(), `${taskId}.output`);
9067
9263
  }
9068
9264
  function ensureOutputDir() {
9069
9265
  const dir = getTaskOutputDir();
9070
- if (!fs13.existsSync(dir)) {
9071
- fs13.mkdirSync(dir, { recursive: true });
9266
+ if (!fs15.existsSync(dir)) {
9267
+ fs15.mkdirSync(dir, { recursive: true });
9072
9268
  }
9073
9269
  }
9074
9270
  function initTaskOutput(taskId) {
9075
9271
  ensureOutputDir();
9076
9272
  const outputPath = getTaskOutputPath(taskId);
9077
- fs13.writeFileSync(outputPath, "", "utf-8");
9273
+ fs15.writeFileSync(outputPath, "", "utf-8");
9078
9274
  return outputPath;
9079
9275
  }
9276
+ function persistTask(state2) {
9277
+ try {
9278
+ ensureOutputDir();
9279
+ const p = taskIndexPath();
9280
+ const existing = fs15.existsSync(p) ? JSON.parse(fs15.readFileSync(p, "utf8")) : [];
9281
+ const next = existing.filter((t) => t.id !== state2.id);
9282
+ next.push({ ...state2 });
9283
+ const tmp = `${p}.${process.pid}.tmp`;
9284
+ fs15.writeFileSync(tmp, JSON.stringify(next, null, 2));
9285
+ fs15.renameSync(tmp, p);
9286
+ } catch (err) {
9287
+ console.warn(`[task-manager] persist failed: ${err.message}`);
9288
+ }
9289
+ }
9290
+ function loadPersistedTasks() {
9291
+ try {
9292
+ const v = JSON.parse(fs15.readFileSync(taskIndexPath(), "utf8"));
9293
+ return Array.isArray(v) ? v : [];
9294
+ } catch {
9295
+ return [];
9296
+ }
9297
+ }
9298
+ function loadNotificationQueue() {
9299
+ if (notificationsLoaded) return;
9300
+ notificationsLoaded = true;
9301
+ try {
9302
+ const value = JSON.parse(fs15.readFileSync(notificationQueuePath(), "utf8"));
9303
+ if (Array.isArray(value)) pendingNotifications.push(...value.filter((x) => x && typeof x.notification === "string"));
9304
+ } catch {
9305
+ }
9306
+ }
9307
+ function persistNotificationQueue() {
9308
+ try {
9309
+ ensureOutputDir();
9310
+ const p = notificationQueuePath();
9311
+ const tmp = `${p}.${process.pid}.tmp`;
9312
+ fs15.writeFileSync(tmp, JSON.stringify(pendingNotifications, null, 2), "utf8");
9313
+ fs15.renameSync(tmp, p);
9314
+ } catch (err) {
9315
+ console.warn(`[task-manager] notification persist failed: ${err.message}`);
9316
+ }
9317
+ }
9318
+ function notificationRetryDelayMs(attempt) {
9319
+ return Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** Math.min(attempt, 6));
9320
+ }
9321
+ function notificationDue(item, now = Date.now()) {
9322
+ if (!item.nextAttemptAt) return true;
9323
+ const dueAt = Date.parse(item.nextAttemptAt);
9324
+ return Number.isFinite(dueAt) && dueAt <= now;
9325
+ }
9326
+ function scheduleNotificationRetry() {
9327
+ if (notificationRetryTimer || !notificationCallback || pendingNotifications.length === 0) return;
9328
+ let earliest;
9329
+ for (const item of pendingNotifications) {
9330
+ if (!item.nextAttemptAt) continue;
9331
+ const dueAt = Date.parse(item.nextAttemptAt);
9332
+ if (Number.isFinite(dueAt) && (earliest === void 0 || dueAt < earliest)) earliest = dueAt;
9333
+ }
9334
+ if (earliest === void 0) return;
9335
+ notificationRetryTimer = setTimeout(() => {
9336
+ notificationRetryTimer = void 0;
9337
+ attemptDueNotifications();
9338
+ }, Math.max(0, earliest - Date.now()));
9339
+ notificationRetryTimer.unref?.();
9340
+ }
9341
+ function attemptDueNotifications() {
9342
+ if (!notificationCallback) return;
9343
+ const remaining = [];
9344
+ for (const item of pendingNotifications) {
9345
+ if (!notificationDue(item)) {
9346
+ remaining.push(item);
9347
+ continue;
9348
+ }
9349
+ try {
9350
+ notificationCallback(item.notification, item.route);
9351
+ } catch (err) {
9352
+ const attempt = (item.attempt ?? 0) + 1;
9353
+ remaining.push({ ...item, attempt, nextAttemptAt: new Date(Date.now() + notificationRetryDelayMs(attempt)).toISOString(), lastError: String(err?.message || err) });
9354
+ }
9355
+ }
9356
+ pendingNotifications.length = 0;
9357
+ pendingNotifications.push(...remaining);
9358
+ persistNotificationQueue();
9359
+ scheduleNotificationRetry();
9360
+ }
9080
9361
  function setNotificationCallback(cb) {
9081
9362
  notificationCallback = cb;
9363
+ loadNotificationQueue();
9364
+ if (pendingNotifications.length === 0) return;
9365
+ attemptDueNotifications();
9082
9366
  }
9083
9367
  function clearNotificationCallback() {
9084
9368
  notificationCallback = null;
9369
+ if (notificationRetryTimer) {
9370
+ clearTimeout(notificationRetryTimer);
9371
+ notificationRetryTimer = void 0;
9372
+ }
9085
9373
  }
9086
- function enqueueNotification(notification, route) {
9374
+ function enqueueNotification(notification, route, idempotencyKey) {
9375
+ loadNotificationQueue();
9376
+ if (idempotencyKey && pendingNotifications.some((item) => item.idempotencyKey === idempotencyKey)) return;
9087
9377
  if (notificationCallback) {
9088
- notificationCallback(notification, route);
9089
- console.log(`[task-manager] Notification dispatched via callback (event-driven, session=${route?.sessionId || "none"}, channel=${route?.channel || "none"})`);
9090
- return;
9378
+ try {
9379
+ notificationCallback(notification, route);
9380
+ console.log(`[task-manager] Notification dispatched via callback (event-driven, session=${route?.sessionId || "none"}, channel=${route?.channel || "none"})`);
9381
+ return;
9382
+ } catch (err) {
9383
+ console.warn(`[task-manager] Notification callback failed, persisting for retry: ${err.message}`);
9384
+ pendingNotifications.push({ id: `n-${Date.now()}-${randomBytes3(4).toString("hex")}`, notification, route, createdAt: (/* @__PURE__ */ new Date()).toISOString(), attempt: 1, nextAttemptAt: new Date(Date.now() + notificationRetryDelayMs(1)).toISOString(), lastError: String(err?.message || err), idempotencyKey });
9385
+ persistNotificationQueue();
9386
+ scheduleNotificationRetry();
9387
+ return;
9388
+ }
9091
9389
  }
9092
- pendingNotifications.push(notification);
9390
+ pendingNotifications.push({ id: `n-${Date.now()}-${randomBytes3(4).toString("hex")}`, notification, route, createdAt: (/* @__PURE__ */ new Date()).toISOString(), idempotencyKey });
9391
+ persistNotificationQueue();
9093
9392
  console.log(`[task-manager] Notification queued (${pendingNotifications.length} pending, no callback)`);
9094
9393
  }
9095
9394
  function getPendingNotifications() {
9096
- return [...pendingNotifications];
9395
+ loadNotificationQueue();
9396
+ return pendingNotifications.map((item) => item.notification);
9397
+ }
9398
+ function getPendingNotificationRecords() {
9399
+ loadNotificationQueue();
9400
+ return pendingNotifications.map((item) => ({ ...item, route: item.route ? { ...item.route } : void 0 }));
9401
+ }
9402
+ function ackPendingNotification(id) {
9403
+ loadNotificationQueue();
9404
+ const index = pendingNotifications.findIndex((item) => item.id === id);
9405
+ if (index < 0) return false;
9406
+ pendingNotifications.splice(index, 1);
9407
+ persistNotificationQueue();
9408
+ scheduleNotificationRetry();
9409
+ return true;
9097
9410
  }
9098
9411
  function drainPendingNotifications() {
9099
- const notifications = [...pendingNotifications];
9412
+ loadNotificationQueue();
9413
+ const due = pendingNotifications.filter((item) => notificationDue(item));
9414
+ if (due.length === 0) return [];
9415
+ const kept = pendingNotifications.filter((item) => !notificationDue(item));
9100
9416
  pendingNotifications.length = 0;
9101
- return notifications;
9417
+ pendingNotifications.push(...kept);
9418
+ persistNotificationQueue();
9419
+ return due.map((item) => item.notification);
9102
9420
  }
9103
9421
  function spawnBackgroundTask(opts) {
9104
9422
  const taskId = generateTaskId("local_bash");
9105
9423
  const outputPath = initTaskOutput(taskId);
9106
9424
  const { shell, args: shellArgs } = findShell();
9107
- const outputFd = fs13.openSync(outputPath, "w");
9425
+ const outputFd = fs15.openSync(outputPath, "w");
9108
9426
  const child = spawn2(shell, [...shellArgs, opts.command], {
9109
9427
  cwd: opts.cwd,
9110
9428
  env: opts.env || process.env,
9111
9429
  stdio: ["ignore", outputFd, outputFd]
9112
9430
  });
9113
9431
  try {
9114
- fs13.closeSync(outputFd);
9432
+ fs15.closeSync(outputFd);
9115
9433
  } catch {
9116
9434
  }
9117
9435
  processes.set(taskId, child);
@@ -9129,6 +9447,7 @@ function spawnBackgroundTask(opts) {
9129
9447
  channelTarget: opts.channelTarget
9130
9448
  };
9131
9449
  tasks.set(taskId, taskState);
9450
+ persistTask(taskState);
9132
9451
  let timer;
9133
9452
  if (opts.timeout && opts.timeout > 0) {
9134
9453
  timer = setTimeout(() => {
@@ -9142,12 +9461,12 @@ function spawnBackgroundTask(opts) {
9142
9461
  let killedForSize = false;
9143
9462
  sizeWatchdog = setInterval(() => {
9144
9463
  if (tasks.get(taskId)?.status !== "running") return;
9145
- fs13.stat(outputPath, (err, st) => {
9464
+ fs15.stat(outputPath, (err, st) => {
9146
9465
  if (err || st.size <= MAX_TASK_OUTPUT_BYTES) return;
9147
9466
  killedForSize = true;
9148
9467
  if (sizeWatchdog) clearInterval(sizeWatchdog);
9149
9468
  try {
9150
- fs13.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
9469
+ fs15.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
9151
9470
  } catch {
9152
9471
  }
9153
9472
  killChild(child);
@@ -9165,8 +9484,15 @@ function spawnBackgroundTask(opts) {
9165
9484
  state2.status = status;
9166
9485
  state2.exitCode = exitCode;
9167
9486
  state2.endTime = Date.now();
9487
+ persistTask(state2);
9488
+ try {
9489
+ opts.onComplete?.(state2);
9490
+ } catch (err) {
9491
+ console.error(`[task-manager] completion callback failed: ${err.message}`);
9492
+ }
9168
9493
  if (!state2.notified) {
9169
9494
  state2.notified = true;
9495
+ persistTask(state2);
9170
9496
  const summary = buildSummary(state2);
9171
9497
  const notification = buildTaskNotification(taskId, outputPath, status, summary);
9172
9498
  enqueueNotification(notification, { sessionId: state2.sessionId, channel: state2.channel, channelTarget: state2.channelTarget });
@@ -9221,6 +9547,12 @@ function getTask(taskId) {
9221
9547
  return tasks.get(taskId);
9222
9548
  }
9223
9549
  function listTasks() {
9550
+ const merged = /* @__PURE__ */ new Map();
9551
+ for (const t of loadPersistedTasks()) merged.set(t.id, t);
9552
+ for (const t of tasks.values()) merged.set(t.id, t);
9553
+ return [...merged.values()];
9554
+ }
9555
+ function listLiveTasks() {
9224
9556
  return [...tasks.values()];
9225
9557
  }
9226
9558
  function getTaskOutput(taskId, maxBytes = 8 * 1024 * 1024) {
@@ -9228,16 +9560,16 @@ function getTaskOutput(taskId, maxBytes = 8 * 1024 * 1024) {
9228
9560
  if (!state2) return "";
9229
9561
  try {
9230
9562
  const outputPath = state2.outputFile;
9231
- if (!fs13.existsSync(outputPath)) return "";
9232
- const stat4 = fs13.statSync(outputPath);
9563
+ if (!fs15.existsSync(outputPath)) return "";
9564
+ const stat4 = fs15.statSync(outputPath);
9233
9565
  if (stat4.size <= maxBytes) {
9234
- return fs13.readFileSync(outputPath, "utf-8");
9566
+ return fs15.readFileSync(outputPath, "utf-8");
9235
9567
  }
9236
- const fd = fs13.openSync(outputPath, "r");
9568
+ const fd = fs15.openSync(outputPath, "r");
9237
9569
  const start = stat4.size - maxBytes;
9238
9570
  const buf = Buffer.alloc(maxBytes);
9239
- fs13.readSync(fd, buf, 0, maxBytes, start);
9240
- fs13.closeSync(fd);
9571
+ fs15.readSync(fd, buf, 0, maxBytes, start);
9572
+ fs15.closeSync(fd);
9241
9573
  const content = buf.toString("utf-8");
9242
9574
  const omitted = Math.round((stat4.size - maxBytes) / 1024);
9243
9575
  return `[${omitted}KB of earlier output omitted]
@@ -9251,14 +9583,14 @@ function getTaskOutputDelta(taskId, fromOffset, maxBytes = 8 * 1024 * 1024) {
9251
9583
  if (!state2) return { content: "", newOffset: fromOffset };
9252
9584
  try {
9253
9585
  const outputPath = state2.outputFile;
9254
- if (!fs13.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
9255
- const stat4 = fs13.statSync(outputPath);
9586
+ if (!fs15.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
9587
+ const stat4 = fs15.statSync(outputPath);
9256
9588
  if (fromOffset >= stat4.size) return { content: "", newOffset: stat4.size };
9257
9589
  const readLen = Math.min(maxBytes, stat4.size - fromOffset);
9258
9590
  const buf = Buffer.alloc(readLen);
9259
- const fd = fs13.openSync(outputPath, "r");
9260
- fs13.readSync(fd, buf, 0, readLen, fromOffset);
9261
- fs13.closeSync(fd);
9591
+ const fd = fs15.openSync(outputPath, "r");
9592
+ fs15.readSync(fd, buf, 0, readLen, fromOffset);
9593
+ fs15.closeSync(fd);
9262
9594
  return { content: buf.toString("utf-8"), newOffset: fromOffset + readLen };
9263
9595
  } catch {
9264
9596
  return { content: "", newOffset: fromOffset };
@@ -9268,8 +9600,8 @@ function getTaskOutputSize(taskId) {
9268
9600
  const state2 = tasks.get(taskId);
9269
9601
  if (!state2) return 0;
9270
9602
  try {
9271
- if (!fs13.existsSync(state2.outputFile)) return 0;
9272
- return fs13.statSync(state2.outputFile).size;
9603
+ if (!fs15.existsSync(state2.outputFile)) return 0;
9604
+ return fs15.statSync(state2.outputFile).size;
9273
9605
  } catch {
9274
9606
  return 0;
9275
9607
  }
@@ -9293,7 +9625,7 @@ function killTask(taskId) {
9293
9625
  }
9294
9626
  return true;
9295
9627
  }
9296
- var TASK_ID_PREFIXES, TASK_ID_ALPHABET, MAX_TASK_OUTPUT_BYTES, _taskOutputDir, tasks, processes, pendingNotifications, notificationCallback, TASK_NOTIFICATION_TAG, TASK_ID_TAG, TASK_TYPE_TAG, TOOL_USE_ID_TAG, OUTPUT_FILE_TAG, STATUS_TAG, SUMMARY_TAG, CALENDAR_NOTIFICATION_TAG, CAL_TYPE_TAG, CAL_EVENT_TAG, CAL_EVENTS_TAG, NUDGE_NOTIFICATION_TAG, NUDGE_TYPE_TAG, NUDGE_DESC_TAG;
9628
+ var TASK_ID_PREFIXES, TASK_ID_ALPHABET, MAX_TASK_OUTPUT_BYTES, _taskOutputDir, tasks, processes, taskIndexPath, pendingNotifications, notificationsLoaded, notificationQueuePath, notificationCallback, RETRY_BASE_MS, RETRY_MAX_MS, notificationRetryTimer, TASK_NOTIFICATION_TAG, TASK_ID_TAG, TASK_TYPE_TAG, TOOL_USE_ID_TAG, OUTPUT_FILE_TAG, STATUS_TAG, SUMMARY_TAG, CALENDAR_NOTIFICATION_TAG, CAL_TYPE_TAG, CAL_EVENT_TAG, CAL_EVENTS_TAG, NUDGE_NOTIFICATION_TAG, NUDGE_TYPE_TAG, NUDGE_DESC_TAG;
9297
9629
  var init_task_manager = __esm({
9298
9630
  "src/tools/task-manager.ts"() {
9299
9631
  "use strict";
@@ -9307,8 +9639,13 @@ var init_task_manager = __esm({
9307
9639
  MAX_TASK_OUTPUT_BYTES = 5 * 1024 * 1024 * 1024;
9308
9640
  tasks = /* @__PURE__ */ new Map();
9309
9641
  processes = /* @__PURE__ */ new Map();
9642
+ taskIndexPath = () => path17.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "index.json");
9310
9643
  pendingNotifications = [];
9644
+ notificationsLoaded = false;
9645
+ notificationQueuePath = () => path17.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "notifications.json");
9311
9646
  notificationCallback = null;
9647
+ RETRY_BASE_MS = 1e3;
9648
+ RETRY_MAX_MS = 6e4;
9312
9649
  TASK_NOTIFICATION_TAG = "task-notification";
9313
9650
  TASK_ID_TAG = "task-id";
9314
9651
  TASK_TYPE_TAG = "task-type";
@@ -9547,8 +9884,8 @@ __export(BashTool_exports, {
9547
9884
  killChild: () => killChild
9548
9885
  });
9549
9886
  import { spawn as spawn3, execSync } from "node:child_process";
9550
- import * as fs14 from "node:fs";
9551
- import * as path16 from "node:path";
9887
+ import * as fs16 from "node:fs";
9888
+ import * as path18 from "node:path";
9552
9889
  function isWslBash(p) {
9553
9890
  const normalized = p.replace(/\//g, "\\").toLowerCase();
9554
9891
  return WSL_PATH_MARKERS.some((m) => normalized.includes(m.toLowerCase()));
@@ -9567,7 +9904,7 @@ function findShell() {
9567
9904
  });
9568
9905
  const candidates = result2.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
9569
9906
  const nonWsl = candidates.find((p) => !isWslBash(p));
9570
- if (nonWsl && fs14.existsSync(nonWsl)) {
9907
+ if (nonWsl && fs16.existsSync(nonWsl)) {
9571
9908
  cachedShell = { shell: nonWsl, args: ["-c"] };
9572
9909
  return cachedShell;
9573
9910
  }
@@ -9577,10 +9914,10 @@ function findShell() {
9577
9914
  "C:\\Program Files\\Git\\bin\\bash.exe",
9578
9915
  "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
9579
9916
  "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
9580
- path16.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
9917
+ path18.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
9581
9918
  ];
9582
9919
  for (const p of knownPaths) {
9583
- if (p && fs14.existsSync(p)) {
9920
+ if (p && fs16.existsSync(p)) {
9584
9921
  cachedShell = { shell: p, args: ["-c"] };
9585
9922
  return cachedShell;
9586
9923
  }
@@ -9683,8 +10020,8 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
9683
10020
  }
9684
10021
  const MAX_OUTPUT = 100 * 1024;
9685
10022
  const osMod = await import("node:os");
9686
- const outputFile = path16.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
9687
- const outputHandle = await fs14.promises.open(outputFile, "w");
10023
+ const outputFile = path18.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
10024
+ const outputHandle = await fs16.promises.open(outputFile, "w");
9688
10025
  return new Promise((resolve11) => {
9689
10026
  const { shell, args: shellArgs } = findShell();
9690
10027
  const child = spawn3(shell, [...shellArgs, command], {
@@ -9703,21 +10040,21 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
9703
10040
  let fileOutput = "";
9704
10041
  let truncated = false;
9705
10042
  try {
9706
- const st = await fs14.promises.stat(outputFile);
10043
+ const st = await fs16.promises.stat(outputFile);
9707
10044
  if (st.size > MAX_OUTPUT) {
9708
- const rfd = await fs14.promises.open(outputFile, "r");
10045
+ const rfd = await fs16.promises.open(outputFile, "r");
9709
10046
  const buf = Buffer.alloc(MAX_OUTPUT);
9710
10047
  await rfd.read(buf, 0, MAX_OUTPUT, 0);
9711
10048
  await rfd.close();
9712
10049
  fileOutput = buf.toString("utf-8");
9713
10050
  truncated = true;
9714
10051
  } else {
9715
- fileOutput = await fs14.promises.readFile(outputFile, "utf-8");
10052
+ fileOutput = await fs16.promises.readFile(outputFile, "utf-8");
9716
10053
  }
9717
10054
  } catch {
9718
10055
  }
9719
10056
  try {
9720
- await fs14.promises.unlink(outputFile);
10057
+ await fs16.promises.unlink(outputFile);
9721
10058
  } catch {
9722
10059
  }
9723
10060
  const processedStdout = fileOutput.replace(/^(\s*\n)+/, "").trimEnd();
@@ -10522,23 +10859,23 @@ var init_agentSwarmsEnabled = __esm({
10522
10859
  });
10523
10860
 
10524
10861
  // src/swarm/teamHelpers.ts
10525
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
10862
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
10526
10863
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
10527
- import { join as join15 } from "node:path";
10864
+ import { join as join16 } from "node:path";
10528
10865
  function getTeamsDir() {
10529
- return join15(_stateDir, "teams");
10866
+ return join16(_stateDir, "teams");
10530
10867
  }
10531
10868
  function getTasksDir() {
10532
- return join15(_stateDir, "tasks");
10869
+ return join16(_stateDir, "tasks");
10533
10870
  }
10534
10871
  function sanitizeName(name) {
10535
10872
  return name.replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
10536
10873
  }
10537
10874
  function getTeamDir(teamName) {
10538
- return join15(getTeamsDir(), sanitizeName(teamName));
10875
+ return join16(getTeamsDir(), sanitizeName(teamName));
10539
10876
  }
10540
10877
  function getTeamFilePath(teamName) {
10541
- return join15(getTeamDir(teamName), "config.json");
10878
+ return join16(getTeamDir(teamName), "config.json");
10542
10879
  }
10543
10880
  function readTeamFile(teamName) {
10544
10881
  try {
@@ -10605,7 +10942,7 @@ async function cleanupTeamDirectories(teamName) {
10605
10942
  } catch (error) {
10606
10943
  console.warn(`[teamHelpers] Failed to clean up team directory ${teamDir}: ${error.message}`);
10607
10944
  }
10608
- const tasksDir = join15(getTasksDir(), sanitizedName);
10945
+ const tasksDir = join16(getTasksDir(), sanitizedName);
10609
10946
  try {
10610
10947
  await rm(tasksDir, { recursive: true, force: true });
10611
10948
  console.log(`[teamHelpers] Cleaned up tasks directory: ${tasksDir}`);
@@ -10614,8 +10951,8 @@ async function cleanupTeamDirectories(teamName) {
10614
10951
  }
10615
10952
  }
10616
10953
  function ensureTasksDir(taskListId) {
10617
- const dir = join15(getTasksDir(), taskListId);
10618
- mkdirSync7(dir, { recursive: true });
10954
+ const dir = join16(getTasksDir(), taskListId);
10955
+ mkdirSync8(dir, { recursive: true });
10619
10956
  }
10620
10957
  function setLeaderTeamName(name) {
10621
10958
  _leaderTeamName = name;
@@ -10795,9 +11132,9 @@ The user interacts primarily with the team lead. Your work is coordinated throug
10795
11132
 
10796
11133
  // src/swarm/teammateMailbox.ts
10797
11134
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
10798
- import { join as join16 } from "node:path";
11135
+ import { join as join17 } from "node:path";
10799
11136
  function getTeamsDir2() {
10800
- return join16(process.env.ENGINE_STATE_DIR || ".", "teams");
11137
+ return join17(process.env.ENGINE_STATE_DIR || ".", "teams");
10801
11138
  }
10802
11139
  function sanitizePathComponent(s) {
10803
11140
  return s.replace(/[^a-zA-Z0-9_-]/g, "-");
@@ -10806,12 +11143,12 @@ function getInboxPath(agentName, teamName) {
10806
11143
  const team = teamName || "default";
10807
11144
  const safeTeam = sanitizePathComponent(team);
10808
11145
  const safeAgentName = sanitizePathComponent(agentName);
10809
- return join16(getTeamsDir2(), safeTeam, "inboxes", `${safeAgentName}.json`);
11146
+ return join17(getTeamsDir2(), safeTeam, "inboxes", `${safeAgentName}.json`);
10810
11147
  }
10811
11148
  async function ensureInboxDir(teamName) {
10812
11149
  const team = teamName || "default";
10813
11150
  const safeTeam = sanitizePathComponent(team);
10814
- const inboxDir = join16(getTeamsDir2(), safeTeam, "inboxes");
11151
+ const inboxDir = join17(getTeamsDir2(), safeTeam, "inboxes");
10815
11152
  await mkdir2(inboxDir, { recursive: true });
10816
11153
  }
10817
11154
  async function sleep4(ms) {
@@ -10848,7 +11185,7 @@ async function acquireLock(inboxPath) {
10848
11185
  for (let i = 0; i < LOCK_RETRIES; i++) {
10849
11186
  if (await isLockStale(lockPath2)) {
10850
11187
  try {
10851
- await import("node:fs/promises").then((fs28) => fs28.rm(lockPath2, { force: true }));
11188
+ await import("node:fs/promises").then((fs29) => fs29.rm(lockPath2, { force: true }));
10852
11189
  } catch {
10853
11190
  }
10854
11191
  }
@@ -10856,7 +11193,7 @@ async function acquireLock(inboxPath) {
10856
11193
  await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
10857
11194
  return async () => {
10858
11195
  try {
10859
- await import("node:fs/promises").then((fs28) => fs28.rm(lockPath2, { force: true }));
11196
+ await import("node:fs/promises").then((fs29) => fs29.rm(lockPath2, { force: true }));
10860
11197
  } catch {
10861
11198
  }
10862
11199
  };
@@ -12026,12 +12363,12 @@ Examples:
12026
12363
  });
12027
12364
 
12028
12365
  // src/tools/msg-husband.ts
12029
- import fs15 from "node:fs";
12030
- import path17 from "node:path";
12366
+ import fs17 from "node:fs";
12367
+ import path19 from "node:path";
12031
12368
  function getHusbandFeishuId(workspace) {
12032
- const contactsPath = path17.join(workspace, "prompts", "contacts.md");
12369
+ const contactsPath = path19.join(workspace, "prompts", "contacts.md");
12033
12370
  try {
12034
- const text = fs15.readFileSync(contactsPath, "utf-8");
12371
+ const text = fs17.readFileSync(contactsPath, "utf-8");
12035
12372
  const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
12036
12373
  return m ? m[1] : null;
12037
12374
  } catch {
@@ -12184,8 +12521,8 @@ Examples:
12184
12521
  if (!to && !resolvedChannelId) {
12185
12522
  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 };
12186
12523
  }
12187
- const fs28 = await import("node:fs");
12188
- if (!fs28.existsSync(filePath)) {
12524
+ const fs29 = await import("node:fs");
12525
+ if (!fs29.existsSync(filePath)) {
12189
12526
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
12190
12527
  }
12191
12528
  const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
@@ -12213,7 +12550,7 @@ Examples:
12213
12550
  md: "text/markdown"
12214
12551
  };
12215
12552
  const mimeType = mimeTypeMap[ext] || "application/octet-stream";
12216
- const stat4 = fs28.statSync(filePath);
12553
+ const stat4 = fs29.statSync(filePath);
12217
12554
  const sizeMB = stat4.size / 1024 / 1024;
12218
12555
  if (sizeMB > 25) {
12219
12556
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
@@ -12242,12 +12579,12 @@ Examples:
12242
12579
  });
12243
12580
 
12244
12581
  // src/tools/my-eyes.ts
12245
- import * as fs16 from "node:fs";
12246
- import * as path18 from "node:path";
12582
+ import * as fs18 from "node:fs";
12583
+ import * as path20 from "node:path";
12247
12584
  function resolveLatestImage(specifiedPath, mediaDir) {
12248
- if (specifiedPath && fs16.existsSync(specifiedPath)) return specifiedPath;
12249
- if (!fs16.existsSync(mediaDir)) return null;
12250
- const files = fs16.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp)$/i.test(f)).map((f) => ({ name: f, p: path18.join(mediaDir, f), mtime: fs16.statSync(path18.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
12585
+ if (specifiedPath && fs18.existsSync(specifiedPath)) return specifiedPath;
12586
+ if (!fs18.existsSync(mediaDir)) return null;
12587
+ const files = fs18.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp)$/i.test(f)).map((f) => ({ name: f, p: path20.join(mediaDir, f), mtime: fs18.statSync(path20.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
12251
12588
  return files[0]?.p || null;
12252
12589
  }
12253
12590
  var MIME_MAP;
@@ -12292,15 +12629,15 @@ var init_my_eyes = __esm({
12292
12629
  if (!provider?.streamChat) {
12293
12630
  return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
12294
12631
  }
12295
- const mediaDir = path18.join(ctx.stateDir, "media", "inbound");
12632
+ const mediaDir = path20.join(ctx.stateDir, "media", "inbound");
12296
12633
  const imagePath = resolveLatestImage(args.image_path, mediaDir);
12297
12634
  if (!imagePath) {
12298
12635
  return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
12299
12636
  }
12300
12637
  const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
12301
- const ext = path18.extname(imagePath).toLowerCase();
12638
+ const ext = path20.extname(imagePath).toLowerCase();
12302
12639
  const mime = MIME_MAP[ext] || "jpeg";
12303
- const imgB64 = fs16.readFileSync(imagePath).toString("base64");
12640
+ const imgB64 = fs18.readFileSync(imagePath).toString("base64");
12304
12641
  const userMsg = {
12305
12642
  role: "user",
12306
12643
  content: [
@@ -12335,7 +12672,7 @@ var init_my_eyes = __esm({
12335
12672
  });
12336
12673
 
12337
12674
  // src/tools/opus-encoder.ts
12338
- import * as fs17 from "node:fs";
12675
+ import * as fs19 from "node:fs";
12339
12676
  function oggCrc32(buf) {
12340
12677
  let crc = 0;
12341
12678
  for (let i = 0; i < buf.length; i++) {
@@ -12395,7 +12732,7 @@ async function wavToOggOpusNative(wavPath) {
12395
12732
  const mod = await import("@discordjs/opus");
12396
12733
  const OpusEncoder = mod.OpusEncoder ?? mod.default?.OpusEncoder;
12397
12734
  if (!OpusEncoder) throw new Error("@discordjs/opus export shape unexpected");
12398
- const wav = parseWav(fs17.readFileSync(wavPath));
12735
+ const wav = parseWav(fs19.readFileSync(wavPath));
12399
12736
  if (wav.channels !== 1) throw new Error(`unsupported ${wav.channels}ch (need mono)`);
12400
12737
  if (!NATIVE_RATES.includes(wav.sampleRate)) throw new Error(`unsupported rate ${wav.sampleRate}`);
12401
12738
  if (wav.pcm.length === 0) throw new Error("empty pcm data");
@@ -12431,7 +12768,7 @@ async function wavToOggOpusNative(wavPath) {
12431
12768
  }
12432
12769
  ogg.page(cur, pageGranule, false, true);
12433
12770
  const oggPath = wavPath.replace(/\.wav$/, ".ogg");
12434
- fs17.writeFileSync(oggPath, ogg.finish());
12771
+ fs19.writeFileSync(oggPath, ogg.finish());
12435
12772
  return oggPath;
12436
12773
  }
12437
12774
  var FRAME_MS, PRESKIP_48K, OPUS_RATE, NATIVE_RATES, BITRATE, CRC_TABLE, OggWriter;
@@ -12511,8 +12848,8 @@ var init_voice_chat_tts_daemon = __esm({
12511
12848
  import { execFile as execFile2 } from "node:child_process";
12512
12849
  import { createInterface as createInterface2 } from "node:readline";
12513
12850
  import { promisify } from "node:util";
12514
- import * as fs18 from "node:fs";
12515
- import * as path19 from "node:path";
12851
+ import * as fs20 from "node:fs";
12852
+ import * as path21 from "node:path";
12516
12853
  import * as os3 from "node:os";
12517
12854
  function resolvePython(configuredPath) {
12518
12855
  if (configuredPath) {
@@ -12548,8 +12885,8 @@ async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction
12548
12885
  }
12549
12886
  async function ttsCosyvoiceStream(text, cfg, onChunk) {
12550
12887
  const { apiKey, model, voice, workspaceId, instruction } = cfg;
12551
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12552
- const output = path19.join(VOICE_DIR, `tts_${Date.now()}.wav`);
12888
+ fs20.mkdirSync(VOICE_DIR, { recursive: true });
12889
+ const output = path21.join(VOICE_DIR, `tts_${Date.now()}.wav`);
12553
12890
  const script = `
12554
12891
  import sys, json, base64, threading
12555
12892
  import dashscope
@@ -12634,7 +12971,7 @@ print('EOS')
12634
12971
  header.writeUInt16LE(16, 34);
12635
12972
  header.write("data", 36);
12636
12973
  header.writeUInt32LE(pcm.length, 40);
12637
- fs18.writeFileSync(output, Buffer.concat([header, pcm]));
12974
+ fs20.writeFileSync(output, Buffer.concat([header, pcm]));
12638
12975
  return output;
12639
12976
  }
12640
12977
  async function ttsQwen3Local(text, cfg, onChunk) {
@@ -12686,14 +13023,14 @@ async function ttsQwen3Opus(text, cfg) {
12686
13023
  const ogg = Buffer.from(await res.arrayBuffer());
12687
13024
  if (ogg.length < 20) throw new Error("qwen3-3060 opus: empty output");
12688
13025
  const durationMs = parseInt(res.headers.get("x-duration-ms") || "0", 10);
12689
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12690
- const oggPath = path19.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
12691
- fs18.writeFileSync(oggPath, ogg);
13026
+ fs20.mkdirSync(VOICE_DIR, { recursive: true });
13027
+ const oggPath = path21.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
13028
+ fs20.writeFileSync(oggPath, ogg);
12692
13029
  return { oggPath, durationMs };
12693
13030
  }
12694
13031
  async function ttsGptsovits(text) {
12695
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12696
- const output = path19.join(VOICE_DIR, `tts_${Date.now()}.wav`);
13032
+ fs20.mkdirSync(VOICE_DIR, { recursive: true });
13033
+ const output = path21.join(VOICE_DIR, `tts_${Date.now()}.wav`);
12697
13034
  const params = new URLSearchParams({
12698
13035
  text,
12699
13036
  text_language: "zh",
@@ -12704,12 +13041,12 @@ async function ttsGptsovits(text) {
12704
13041
  const res = await fetch(`${GPTSOVITS_API}/?${params}`);
12705
13042
  if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
12706
13043
  const buf = Buffer.from(await res.arrayBuffer());
12707
- fs18.writeFileSync(output, buf);
13044
+ fs20.writeFileSync(output, buf);
12708
13045
  return output;
12709
13046
  }
12710
13047
  async function ttsEdge(text) {
12711
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12712
- const output = path19.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
13048
+ fs20.mkdirSync(VOICE_DIR, { recursive: true });
13049
+ const output = path21.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
12713
13050
  const script = `
12714
13051
  import asyncio, edge_tts, sys
12715
13052
  async def main():
@@ -12736,11 +13073,11 @@ async function toWav24kWithDuration(audioPath) {
12736
13073
  "pcm_s16le",
12737
13074
  wavPath
12738
13075
  ], { timeout: 3e4 });
12739
- if (!fs18.existsSync(wavPath) || fs18.statSync(wavPath).size < 44) {
13076
+ if (!fs20.existsSync(wavPath) || fs20.statSync(wavPath).size < 44) {
12740
13077
  throw new Error("toWav24k produced empty output");
12741
13078
  }
12742
13079
  try {
12743
- fs18.unlinkSync(audioPath);
13080
+ fs20.unlinkSync(audioPath);
12744
13081
  } catch {
12745
13082
  }
12746
13083
  }
@@ -12771,7 +13108,7 @@ async function compressWav(wavPath) {
12771
13108
  "+faststart",
12772
13109
  m4aPath
12773
13110
  ], { timeout: 3e4 });
12774
- fs18.unlinkSync(wavPath);
13111
+ fs20.unlinkSync(wavPath);
12775
13112
  return m4aPath;
12776
13113
  } catch {
12777
13114
  return wavPath;
@@ -12798,10 +13135,10 @@ async function wavToOggOpus(wavPath) {
12798
13135
  oggPath
12799
13136
  ], { timeout: 3e4 });
12800
13137
  }
12801
- if (!fs18.existsSync(oggPath) || fs18.statSync(oggPath).size < 20) {
13138
+ if (!fs20.existsSync(oggPath) || fs20.statSync(oggPath).size < 20) {
12802
13139
  throw new Error("ogg/opus encode produced empty output");
12803
13140
  }
12804
- fs18.unlinkSync(wavPath);
13141
+ fs20.unlinkSync(wavPath);
12805
13142
  return oggPath;
12806
13143
  }
12807
13144
  async function sendVoiceToMulticaIssue(text, issueId, opts) {
@@ -12818,8 +13155,8 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12818
13155
  const pcmChunks = [];
12819
13156
  await ttsQwen3Local(text, { url: vc.url, voice: vc.voice, lang: vc.lang }, (pcm2) => pcmChunks.push(pcm2));
12820
13157
  const pcm = Buffer.concat(pcmChunks);
12821
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12822
- const wavPath = path19.join(VOICE_DIR, `tts_mc_${Date.now()}.wav`);
13158
+ fs20.mkdirSync(VOICE_DIR, { recursive: true });
13159
+ const wavPath = path21.join(VOICE_DIR, `tts_mc_${Date.now()}.wav`);
12823
13160
  const header = Buffer.alloc(44);
12824
13161
  header.write("RIFF", 0);
12825
13162
  header.writeUInt32LE(36 + pcm.length, 4);
@@ -12834,7 +13171,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12834
13171
  header.writeUInt16LE(16, 34);
12835
13172
  header.write("data", 36);
12836
13173
  header.writeUInt32LE(pcm.length, 40);
12837
- fs18.writeFileSync(wavPath, Buffer.concat([header, pcm]));
13174
+ fs20.writeFileSync(wavPath, Buffer.concat([header, pcm]));
12838
13175
  audioPath = wavPath;
12839
13176
  }
12840
13177
  } else if (actualEngine === "cosyvoice" && vc?.apiKey) {
@@ -12848,7 +13185,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12848
13185
  } catch (e) {
12849
13186
  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 };
12850
13187
  }
12851
- if (!audioPath || !fs18.existsSync(audioPath)) {
13188
+ if (!audioPath || !fs20.existsSync(audioPath)) {
12852
13189
  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 };
12853
13190
  }
12854
13191
  if (audioPath.endsWith(".wav")) {
@@ -12858,21 +13195,21 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12858
13195
  console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
12859
13196
  }
12860
13197
  }
12861
- const ext = path19.extname(audioPath).toLowerCase();
12862
- const sizeKB = fs18.statSync(audioPath).size / 1024;
13198
+ const ext = path21.extname(audioPath).toLowerCase();
13199
+ const sizeKB = fs20.statSync(audioPath).size / 1024;
12863
13200
  const voiceFile = `voice_${Date.now()}${ext}`;
12864
- const cwdCopy = path19.join(process.cwd(), voiceFile);
13201
+ const cwdCopy = path21.join(process.cwd(), voiceFile);
12865
13202
  try {
12866
- fs18.copyFileSync(audioPath, cwdCopy);
13203
+ fs20.copyFileSync(audioPath, cwdCopy);
12867
13204
  } catch (e) {
12868
13205
  try {
12869
- fs18.unlinkSync(audioPath);
13206
+ fs20.unlinkSync(audioPath);
12870
13207
  } catch {
12871
13208
  }
12872
13209
  return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
12873
13210
  }
12874
13211
  try {
12875
- fs18.unlinkSync(audioPath);
13212
+ fs20.unlinkSync(audioPath);
12876
13213
  } catch {
12877
13214
  }
12878
13215
  const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
@@ -12901,13 +13238,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12901
13238
  }
12902
13239
  if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
12903
13240
  try {
12904
- fs18.unlinkSync(cwdCopy);
13241
+ fs20.unlinkSync(cwdCopy);
12905
13242
  } catch {
12906
13243
  }
12907
13244
  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)` };
12908
13245
  } catch (e) {
12909
13246
  try {
12910
- fs18.unlinkSync(cwdCopy);
13247
+ fs20.unlinkSync(cwdCopy);
12911
13248
  } catch {
12912
13249
  }
12913
13250
  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 };
@@ -12922,7 +13259,7 @@ var init_my_voice = __esm({
12922
13259
  init_opus_encoder();
12923
13260
  init_voice_chat_tts_daemon();
12924
13261
  execFileAsync = promisify(execFile2);
12925
- VOICE_DIR = path19.join(os3.tmpdir(), "engine-voice");
13262
+ VOICE_DIR = path21.join(os3.tmpdir(), "engine-voice");
12926
13263
  _pyCache = null;
12927
13264
  GPTSOVITS_API = "http://127.0.0.1:9880";
12928
13265
  GPTSOVITS_REF_WAV = "/home/chong/voice/ref/shanshan_ref_v2.wav";
@@ -13021,8 +13358,8 @@ var init_my_voice = __esm({
13021
13358
  const pcmChunks = [];
13022
13359
  await ttsQwen3Local(text, { url: vc.url, voice: vc.voice, lang: vc.lang }, (pcm2) => pcmChunks.push(pcm2));
13023
13360
  const pcm = Buffer.concat(pcmChunks);
13024
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
13025
- const wavPath = path19.join(VOICE_DIR, `tts_${Date.now()}.wav`);
13361
+ fs20.mkdirSync(VOICE_DIR, { recursive: true });
13362
+ const wavPath = path21.join(VOICE_DIR, `tts_${Date.now()}.wav`);
13026
13363
  const header = Buffer.alloc(44);
13027
13364
  header.write("RIFF", 0);
13028
13365
  header.writeUInt32LE(36 + pcm.length, 4);
@@ -13037,7 +13374,7 @@ var init_my_voice = __esm({
13037
13374
  header.writeUInt16LE(16, 34);
13038
13375
  header.write("data", 36);
13039
13376
  header.writeUInt32LE(pcm.length, 40);
13040
- fs18.writeFileSync(wavPath, Buffer.concat([header, pcm]));
13377
+ fs20.writeFileSync(wavPath, Buffer.concat([header, pcm]));
13041
13378
  audioPath = wavPath;
13042
13379
  }
13043
13380
  } catch (e) {
@@ -13068,10 +13405,10 @@ var init_my_voice = __esm({
13068
13405
  audioPath = await compressWav(audioPath);
13069
13406
  }
13070
13407
  }
13071
- const ext = path19.extname(audioPath).toLowerCase();
13408
+ const ext = path21.extname(audioPath).toLowerCase();
13072
13409
  const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
13073
13410
  const mimeType = mimeMap[ext] || "audio/mpeg";
13074
- const sizeKB = fs18.statSync(audioPath).size / 1024;
13411
+ const sizeKB = fs20.statSync(audioPath).size / 1024;
13075
13412
  try {
13076
13413
  await mgr.sendFile(resolvedChannel, target, caption, {
13077
13414
  path: audioPath,
@@ -13080,7 +13417,7 @@ var init_my_voice = __esm({
13080
13417
  ...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
13081
13418
  });
13082
13419
  try {
13083
- fs18.unlinkSync(audioPath);
13420
+ fs20.unlinkSync(audioPath);
13084
13421
  } catch {
13085
13422
  }
13086
13423
  return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
@@ -13097,8 +13434,8 @@ var init_my_voice = __esm({
13097
13434
  });
13098
13435
 
13099
13436
  // src/tools/my-selfie.ts
13100
- import * as fs19 from "node:fs";
13101
- import * as path20 from "node:path";
13437
+ import * as fs21 from "node:fs";
13438
+ import * as path22 from "node:path";
13102
13439
  function getProxyDispatcher2() {
13103
13440
  const cfg = liveConfig.all();
13104
13441
  const proxy = cfg.providers?.xai?.proxy;
@@ -13414,12 +13751,12 @@ var init_my_selfie = __esm({
13414
13751
  const REFERENCES = getReferences(ctx);
13415
13752
  const refName = args.reference || "default";
13416
13753
  const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
13417
- const refPath = path20.join(ctx.workspace, refEntry.p);
13418
- if (provider !== "autodl" && !fs19.existsSync(refPath)) {
13754
+ const refPath = path22.join(ctx.workspace, refEntry.p);
13755
+ if (provider !== "autodl" && !fs21.existsSync(refPath)) {
13419
13756
  return { content: `Error: reference image not found at ${refPath}`, isError: true };
13420
13757
  }
13421
13758
  const resolution = args.resolution || DEFAULT_RESOLUTION;
13422
- const refB64 = fs19.existsSync(refPath) ? fs19.readFileSync(refPath).toString("base64") : "";
13759
+ const refB64 = fs21.existsSync(refPath) ? fs21.readFileSync(refPath).toString("base64") : "";
13423
13760
  let imageBuffer;
13424
13761
  try {
13425
13762
  if (provider === "autodl") {
@@ -13434,11 +13771,11 @@ var init_my_selfie = __esm({
13434
13771
  } catch (err) {
13435
13772
  return { content: `Selfie generation failed: ${err.message}`, isError: true };
13436
13773
  }
13437
- const imagesDir = path20.join(ctx.workspace, "images");
13438
- if (!fs19.existsSync(imagesDir)) fs19.mkdirSync(imagesDir, { recursive: true });
13774
+ const imagesDir = path22.join(ctx.workspace, "images");
13775
+ if (!fs21.existsSync(imagesDir)) fs21.mkdirSync(imagesDir, { recursive: true });
13439
13776
  const filename = `selfie_${Date.now()}.jpg`;
13440
- const outputPath = path20.join(imagesDir, filename);
13441
- fs19.writeFileSync(outputPath, imageBuffer);
13777
+ const outputPath = path22.join(imagesDir, filename);
13778
+ fs21.writeFileSync(outputPath, imageBuffer);
13442
13779
  const mgr = ctx.channelManager;
13443
13780
  if (mgr) {
13444
13781
  const resolvedChannel = ctx.channel || "feishu";
@@ -13449,11 +13786,11 @@ var init_my_selfie = __esm({
13449
13786
  mimeType: "image/jpeg"
13450
13787
  });
13451
13788
  } catch (err) {
13452
- return { content: `Selfie generated but send failed: ${err.message}. Image: ${path20.resolve(outputPath)}`, isError: false };
13789
+ return { content: `Selfie generated but send failed: ${err.message}. Image: ${path22.resolve(outputPath)}`, isError: false };
13453
13790
  }
13454
13791
  return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
13455
13792
  }
13456
- return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path20.resolve(outputPath)}` };
13793
+ return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path22.resolve(outputPath)}` };
13457
13794
  },
13458
13795
  isConcurrencySafe: () => false,
13459
13796
  interruptBehavior: () => "block",
@@ -13548,88 +13885,6 @@ var init_body_move = __esm({
13548
13885
  }
13549
13886
  });
13550
13887
 
13551
- // src/calendar/db.ts
13552
- import * as path21 from "node:path";
13553
- import * as fs20 from "node:fs";
13554
- import { createRequire as createRequire2 } from "node:module";
13555
- function getSqlite() {
13556
- if (!_sqlite) _sqlite = createRequire2(import.meta.url)("node:sqlite");
13557
- return _sqlite;
13558
- }
13559
- function openDb(workspace) {
13560
- const dir = path21.join(workspace, ".calendar");
13561
- fs20.mkdirSync(dir, { recursive: true });
13562
- const dbPath = path21.join(dir, "calendar.db");
13563
- const db = new DatabaseSync(dbPath);
13564
- db.exec("PRAGMA journal_mode=WAL");
13565
- db.exec(`CREATE TABLE IF NOT EXISTS events (
13566
- id INTEGER PRIMARY KEY AUTOINCREMENT,
13567
- type TEXT NOT NULL,
13568
- status TEXT NOT NULL DEFAULT 'pending',
13569
- event TEXT NOT NULL,
13570
- day TEXT,
13571
- time TEXT,
13572
- date_str TEXT,
13573
- created_at TEXT NOT NULL,
13574
- done_at TEXT,
13575
- archived_at TEXT
13576
- )`);
13577
- migrate(db);
13578
- return db;
13579
- }
13580
- function migrate(db) {
13581
- const cols = new Set(
13582
- db.prepare("PRAGMA table_info(events)").all().map((r) => r.name)
13583
- );
13584
- if (!cols.has("remind_before_min")) {
13585
- db.exec("ALTER TABLE events ADD COLUMN remind_before_min INTEGER DEFAULT 60");
13586
- }
13587
- if (!cols.has("remind_at")) {
13588
- db.exec("ALTER TABLE events ADD COLUMN remind_at TEXT");
13589
- }
13590
- if (!cols.has("reminded")) {
13591
- db.exec("ALTER TABLE events ADD COLUMN reminded INTEGER DEFAULT 0");
13592
- }
13593
- if (!cols.has("time_exact")) {
13594
- db.exec("ALTER TABLE events ADD COLUMN time_exact TEXT");
13595
- }
13596
- if (!cols.has("start_time")) {
13597
- db.exec("ALTER TABLE events ADD COLUMN start_time TEXT");
13598
- }
13599
- if (!cols.has("duration_min")) {
13600
- db.exec("ALTER TABLE events ADD COLUMN duration_min INTEGER");
13601
- }
13602
- if (!cols.has("created_channel")) {
13603
- db.exec("ALTER TABLE events ADD COLUMN created_channel TEXT");
13604
- }
13605
- if (!cols.has("created_channel_target")) {
13606
- db.exec("ALTER TABLE events ADD COLUMN created_channel_target TEXT");
13607
- }
13608
- if (!cols.has("repeat_type")) {
13609
- db.exec("ALTER TABLE events ADD COLUMN repeat_type TEXT DEFAULT 'once'");
13610
- }
13611
- if (!cols.has("doc_path")) {
13612
- db.exec("ALTER TABLE events ADD COLUMN doc_path TEXT");
13613
- }
13614
- }
13615
- var _sqlite, DatabaseSync, TZ_OFFSET_MS;
13616
- var init_db = __esm({
13617
- "src/calendar/db.ts"() {
13618
- "use strict";
13619
- _sqlite = null;
13620
- DatabaseSync = new Proxy(function() {
13621
- }, {
13622
- construct(_t, args) {
13623
- return new (getSqlite()).DatabaseSync(...args);
13624
- },
13625
- get(_t, prop) {
13626
- return getSqlite().DatabaseSync[prop];
13627
- }
13628
- });
13629
- TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
13630
- }
13631
- });
13632
-
13633
13888
  // src/calendar/helpers.ts
13634
13889
  function nowIso() {
13635
13890
  return new Date(Date.now() + TZ_OFFSET_MS2 - (/* @__PURE__ */ new Date()).getTimezoneOffset() * 6e4).toISOString().replace("Z", "+08:00");
@@ -13855,14 +14110,14 @@ function fmtEnd(start, durationMin) {
13855
14110
  const total = hh * 60 + mm + durationMin;
13856
14111
  return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, "0")}`;
13857
14112
  }
13858
- function addWeekly(db, args) {
14113
+ function addWeekly(db2, args) {
13859
14114
  const { day, event } = args;
13860
14115
  if (!WEEKDAYS2.includes(day)) return `\u9519\u8BEF: \u661F\u671F\u5FC5\u987B\u662F ${WEEKDAYS2.join("/")}`;
13861
14116
  if (!args.time) return `\u9519\u8BEF: \u5468\u671F\u65E5\u7A0B\u5FC5\u987B\u586B start_time\uFF08\u5982 time='14:00'\uFF09`;
13862
14117
  if (!args.duration) return `\u9519\u8BEF: \u5468\u671F\u65E5\u7A0B\u5FC5\u987B\u586B duration\uFF08\u5982 duration='1h'\uFF09`;
13863
14118
  const durationMin = parseDuration(args.duration);
13864
14119
  if (!durationMin) return `\u9519\u8BEF: duration \u683C\u5F0F\u4E0D\u5BF9\uFF08\u5982 '30m' / '1h'\uFF09`;
13865
- const conflictRows = db.prepare(
14120
+ const conflictRows = db2.prepare(
13866
14121
  "SELECT * FROM events WHERE status='pending' AND type='weekly' AND day=?"
13867
14122
  ).all(day);
13868
14123
  const conflict = checkScheduleConflict(conflictRows, args.time, durationMin);
@@ -13877,16 +14132,16 @@ function addWeekly(db, args) {
13877
14132
  else remindMin = parseInt(v) || 60;
13878
14133
  }
13879
14134
  const remindAt = computeWeeklyRemindAt(day, args.time, remindMin);
13880
- const r = db.prepare(
14135
+ const r = db2.prepare(
13881
14136
  `INSERT INTO events (type,status,event,day,time,start_time,duration_min,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target)
13882
14137
  VALUES ('weekly','pending',?,?,?,?,?,?,?,?,?,?,?)`
13883
14138
  ).run(event, day, args.time, args.time, durationMin, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
13884
14139
  return `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0: [\u6BCF\u5468] ${day} ${args.time} (${durationMin}min) ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
13885
14140
  }
13886
- function addDaily(db, args) {
14141
+ function addDaily(db2, args) {
13887
14142
  const { time, event, repeatType } = args;
13888
14143
  if (!time) return `\u9519\u8BEF: \u6BCF\u65E5\u4EFB\u52A1\u5FC5\u987B\u586B time\uFF08\u5982 time='23:00'\uFF09`;
13889
- const dailyRows = db.prepare(
14144
+ const dailyRows = db2.prepare(
13890
14145
  "SELECT * FROM events WHERE status='pending' AND type='daily'"
13891
14146
  ).all();
13892
14147
  const [hh, mm] = time.split(":").map(Number);
@@ -13908,21 +14163,21 @@ function addDaily(db, args) {
13908
14163
  }
13909
14164
  const remindAt = repeatType === "daily" ? computeDailyRemindAt(time, remindMin) : computeWeekdaysRemindAt(time, remindMin);
13910
14165
  if (!remindAt) return `\u9519\u8BEF: \u65E0\u6CD5\u8BA1\u7B97 remind_at`;
13911
- const r = db.prepare(
14166
+ const r = db2.prepare(
13912
14167
  `INSERT INTO events (type,status,event,time,start_time,repeat_type,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target)
13913
14168
  VALUES ('daily','pending',?,?,?,?,?,?,?,?,?,?)`
13914
14169
  ).run(event, time, time, repeatType, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
13915
14170
  const label = repeatType === "daily" ? "\u6BCF\u5929" : "\u5DE5\u4F5C\u65E5";
13916
14171
  return `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0: [${label}] ${time} ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
13917
14172
  }
13918
- function addDate(db, args) {
14173
+ function addDate(db2, args) {
13919
14174
  const { dateStr, event } = args;
13920
14175
  if (!args.time) return `\u9519\u8BEF: \u4E00\u6B21\u6027\u65E5\u7A0B\u5FC5\u987B\u586B start_time\uFF08\u5982 time='14:00'\uFF09`;
13921
14176
  if (!args.duration) return `\u9519\u8BEF: \u4E00\u6B21\u6027\u65E5\u7A0B\u5FC5\u987B\u586B duration\uFF08\u5982 duration='1h'\uFF09`;
13922
14177
  const durationMin = parseDuration(args.duration);
13923
14178
  if (!durationMin) return `\u9519\u8BEF: duration \u683C\u5F0F\u4E0D\u5BF9\uFF08\u5982 '30m' / '1h'\uFF09`;
13924
14179
  const todayWeekday = getTodayWeekday();
13925
- const dateRows = db.prepare(
14180
+ const dateRows = db2.prepare(
13926
14181
  "SELECT * FROM events WHERE status='pending' AND type='date' AND date_str=?"
13927
14182
  ).all(dateStr);
13928
14183
  const parsed = parseDateRange(dateStr);
@@ -13932,7 +14187,7 @@ function addDate(db, args) {
13932
14187
  const year = now.getUTCFullYear();
13933
14188
  const d = new Date(Date.UTC(year, parsed.month - 1, parsed.dStart));
13934
14189
  const weekday = WEEKDAYS2[d.getUTCDay() === 0 ? 6 : d.getUTCDay() - 1];
13935
- weeklyRows = db.prepare(
14190
+ weeklyRows = db2.prepare(
13936
14191
  "SELECT * FROM events WHERE status='pending' AND type='weekly' AND day=?"
13937
14192
  ).all(weekday);
13938
14193
  }
@@ -13949,13 +14204,13 @@ function addDate(db, args) {
13949
14204
  else remindMin = parseInt(v) || 60;
13950
14205
  }
13951
14206
  const remindAt = computeRemindAt(dateStr, args.time, remindMin);
13952
- const r = db.prepare(
14207
+ const r = db2.prepare(
13953
14208
  `INSERT INTO events (type,status,event,date_str,time,start_time,duration_min,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target)
13954
14209
  VALUES ('date','pending',?,?,?,?,?,?,?,?,?,?,?)`
13955
14210
  ).run(event, dateStr, args.time, args.time, durationMin, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
13956
14211
  return `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0: [${dateStr} ${args.time} (${durationMin}min)] ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
13957
14212
  }
13958
- function addBatch(db, args) {
14213
+ function addBatch(db2, args) {
13959
14214
  if (!args.time) return `\u9519\u8BEF: \u6279\u91CF\u6DFB\u52A0\u5FC5\u987B\u586B time\uFF08\u5982 time='14:00'\uFF09`;
13960
14215
  if (!args.duration) return `\u9519\u8BEF: \u6279\u91CF\u6DFB\u52A0\u5FC5\u987B\u586B duration\uFF08\u5982 duration='1h'\uFF09`;
13961
14216
  const durationMin = parseDuration(args.duration);
@@ -13972,7 +14227,7 @@ function addBatch(db, args) {
13972
14227
  const ok = [];
13973
14228
  const skipped = [];
13974
14229
  for (const dateStr of dates) {
13975
- const dateRows = db.prepare(
14230
+ const dateRows = db2.prepare(
13976
14231
  "SELECT * FROM events WHERE status='pending' AND type='date' AND date_str=?"
13977
14232
  ).all(dateStr);
13978
14233
  const parsed = parseDateRange(dateStr);
@@ -13982,7 +14237,7 @@ function addBatch(db, args) {
13982
14237
  const year = now.getUTCFullYear();
13983
14238
  const d = new Date(Date.UTC(year, parsed.month - 1, parsed.dStart));
13984
14239
  const weekday = WEEKDAYS2[d.getUTCDay() === 0 ? 6 : d.getUTCDay() - 1];
13985
- weeklyRows = db.prepare(
14240
+ weeklyRows = db2.prepare(
13986
14241
  "SELECT * FROM events WHERE status='pending' AND type='weekly' AND day=?"
13987
14242
  ).all(weekday);
13988
14243
  }
@@ -13993,7 +14248,7 @@ function addBatch(db, args) {
13993
14248
  continue;
13994
14249
  }
13995
14250
  const remindAt = computeRemindAt(dateStr, args.time, remindMin);
13996
- const r = db.prepare(
14251
+ const r = db2.prepare(
13997
14252
  `INSERT INTO events (type,status,event,date_str,time,start_time,duration_min,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target)
13998
14253
  VALUES ('date','pending',?,?,?,?,?,?,?,?,?,?,?)`
13999
14254
  ).run(args.event, dateStr, args.time, args.time, durationMin, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
@@ -14010,7 +14265,7 @@ ${skipped.map((s) => ` ${s}`).join("\n")}`;
14010
14265
  }
14011
14266
  return result2;
14012
14267
  }
14013
- function addTask(db, args) {
14268
+ function addTask(db2, args) {
14014
14269
  const { dateStr, timeExact, event, docPath } = args;
14015
14270
  if (!docPath || !docPath.trim()) {
14016
14271
  return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Aadd-task \u5FC5\u987B\u4F20 doc_path\u3002
@@ -14041,12 +14296,12 @@ function addTask(db, args) {
14041
14296
  else if (v.endsWith("h")) remindMin = parseInt(v.slice(0, -1)) * 60;
14042
14297
  else remindMin = parseInt(v) || 60;
14043
14298
  }
14044
- const taskRows = db.prepare(
14299
+ const taskRows = db2.prepare(
14045
14300
  "SELECT * FROM events WHERE status='pending' AND type='task' AND date_str=?"
14046
14301
  ).all(dateStr);
14047
14302
  const prox = checkTaskProximity(taskRows, timeExact);
14048
14303
  const remindAt = computeRemindAt(dateStr, timeExact, remindMin);
14049
- const r = db.prepare(
14304
+ const r = db2.prepare(
14050
14305
  `INSERT INTO events (type,status,event,date_str,time_exact,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target,doc_path)
14051
14306
  VALUES ('task','pending',?,?,?,?,?,?,?,?,?,?)`
14052
14307
  ).run(event, dateStr, timeExact, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null, docPath);
@@ -14058,9 +14313,9 @@ function addTask(db, args) {
14058
14313
  }
14059
14314
  return msg2;
14060
14315
  }
14061
- function reschedule(db, args) {
14316
+ function reschedule(db2, args) {
14062
14317
  const { id, dateStr, timeExact } = args;
14063
- const row = db.prepare("SELECT * FROM events WHERE id=?").get(id);
14318
+ const row = db2.prepare("SELECT * FROM events WHERE id=?").get(id);
14064
14319
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14065
14320
  if (row.type !== "task") return `#${id} \u4E0D\u662F task \u7C7B\u578B\uFF08${row.type}\uFF09\uFF0Creschedule \u4EC5\u652F\u6301 task`;
14066
14321
  let remindMin = row.remind_before_min || 60;
@@ -14071,12 +14326,12 @@ function reschedule(db, args) {
14071
14326
  else remindMin = parseInt(v) || remindMin;
14072
14327
  }
14073
14328
  const remindAt = computeRemindAt(dateStr, timeExact, remindMin);
14074
- db.prepare("UPDATE events SET date_str=?, time_exact=?, remind_before_min=?, remind_at=?, reminded=0 WHERE id=?").run(dateStr, timeExact, remindMin, remindAt, id);
14329
+ db2.prepare("UPDATE events SET date_str=?, time_exact=?, remind_before_min=?, remind_at=?, reminded=0 WHERE id=?").run(dateStr, timeExact, remindMin, remindAt, id);
14075
14330
  return `#${id} \u5DF2\u6539\u671F: [${dateStr} ${timeExact}] ${row.event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
14076
14331
  }
14077
- function list(db, opts = {}) {
14332
+ function list(db2, opts = {}) {
14078
14333
  if (opts.all) {
14079
- const rows = db.prepare("SELECT * FROM events WHERE status NOT IN ('archived', 'deleted') ORDER BY type, id").all();
14334
+ const rows = db2.prepare("SELECT * FROM events WHERE status NOT IN ('archived', 'deleted') ORDER BY type, id").all();
14080
14335
  const out2 = ["## \u6BCF\u5468\u56FA\u5B9A"];
14081
14336
  for (const r of rows) if (r.type === "weekly") out2.push(fmtRow(r));
14082
14337
  out2.push("\n## \u6BCF\u65E5\u56FA\u5B9A");
@@ -14090,17 +14345,17 @@ function list(db, opts = {}) {
14090
14345
  const out = [`\u5F53\u524D\u65F6\u95F4: ${fmtNow()}`];
14091
14346
  const todayWeekday = getTodayWeekday();
14092
14347
  const events = [];
14093
- for (const r of db.prepare("SELECT * FROM events WHERE type='weekly' AND status='pending' AND day=?").all(todayWeekday)) {
14348
+ for (const r of db2.prepare("SELECT * FROM events WHERE type='weekly' AND status='pending' AND day=?").all(todayWeekday)) {
14094
14349
  events.push(` #${r.id} ${r.time || ""} ${r.event}`);
14095
14350
  }
14096
- for (const r of db.prepare("SELECT * FROM events WHERE type='daily' AND status='pending'").all()) {
14351
+ for (const r of db2.prepare("SELECT * FROM events WHERE type='daily' AND status='pending'").all()) {
14097
14352
  if (r.repeat_type === "weekdays") {
14098
14353
  const idx = new Date(Date.now() + 8 * 60 * 60 * 1e3).getUTCDay();
14099
14354
  if (idx === 0 || idx === 6) continue;
14100
14355
  }
14101
14356
  events.push(` #${r.id} ${r.time || ""} ${r.event}`);
14102
14357
  }
14103
- for (const r of db.prepare("SELECT * FROM events WHERE type='date' AND status='pending'").all()) {
14358
+ for (const r of db2.prepare("SELECT * FROM events WHERE type='date' AND status='pending'").all()) {
14104
14359
  const p = parseDateRange(r.date_str);
14105
14360
  if (p && isToday(p.month, p.dStart, p.dEnd)) {
14106
14361
  events.push(` #${r.id} ${r.event}`);
@@ -14114,14 +14369,14 @@ function list(db, opts = {}) {
14114
14369
  }
14115
14370
  return out.join("\n");
14116
14371
  }
14117
- function pending(db) {
14372
+ function pending(db2) {
14118
14373
  const out = [`\u5F53\u524D\u65F6\u95F4: ${fmtNow()}`];
14119
14374
  const todayWeekday = getTodayWeekday();
14120
14375
  const events = [];
14121
- for (const r of db.prepare("SELECT * FROM events WHERE type='weekly' AND status='pending' AND day=?").all(todayWeekday)) {
14376
+ for (const r of db2.prepare("SELECT * FROM events WHERE type='weekly' AND status='pending' AND day=?").all(todayWeekday)) {
14122
14377
  events.push(` #${r.id} [\u6BCF\u5468] ${r.time || ""} ${r.event}`);
14123
14378
  }
14124
- for (const r of db.prepare("SELECT * FROM events WHERE type='daily' AND status='pending'").all()) {
14379
+ for (const r of db2.prepare("SELECT * FROM events WHERE type='daily' AND status='pending'").all()) {
14125
14380
  if (r.repeat_type === "weekdays") {
14126
14381
  const idx = new Date(Date.now() + 8 * 60 * 60 * 1e3).getUTCDay();
14127
14382
  if (idx === 0 || idx === 6) continue;
@@ -14129,7 +14384,7 @@ function pending(db) {
14129
14384
  const label = r.repeat_type === "weekdays" ? "[\u5DE5\u4F5C\u65E5]" : "[\u6BCF\u5929]";
14130
14385
  events.push(` #${r.id} ${label} ${r.time || ""} ${r.event}`);
14131
14386
  }
14132
- for (const r of db.prepare("SELECT * FROM events WHERE type='date' AND status='pending'").all()) {
14387
+ for (const r of db2.prepare("SELECT * FROM events WHERE type='date' AND status='pending'").all()) {
14133
14388
  const p = parseDateRange(r.date_str);
14134
14389
  if (!p) continue;
14135
14390
  if (isToday(p.month, p.dStart, p.dEnd)) {
@@ -14148,31 +14403,31 @@ function pending(db) {
14148
14403
  }
14149
14404
  return out.join("\n");
14150
14405
  }
14151
- function done(db, id) {
14152
- const row = db.prepare("SELECT * FROM events WHERE id=? AND status=?").get(id, "pending");
14406
+ function done(db2, id) {
14407
+ const row = db2.prepare("SELECT * FROM events WHERE id=? AND status=?").get(id, "pending");
14153
14408
  if (!row) return `\u672A\u627E\u5230 pending \u4E8B\u4EF6 #${id}`;
14154
14409
  if (row.type === "daily" || row.type === "weekly") {
14155
14410
  return `\u274C ${row.type === "daily" ? "\u6BCF\u65E5/\u5DE5\u4F5C\u65E5" : "\u6BCF\u5468"}\u7C7B\u578B\u4E0D\u652F\u6301 done\uFF08\u4F1A\u505C\u6B62\u5FAA\u73AF\uFF09\u3002\u4E0D\u9700\u8981\u4E86\u8BF7\u7528 delete ${id}`;
14156
14411
  }
14157
- db.prepare("UPDATE events SET status=?, done_at=?, reminded=1 WHERE id=?").run("done", nowIso(), id);
14412
+ db2.prepare("UPDATE events SET status=?, done_at=?, reminded=1 WHERE id=?").run("done", nowIso(), id);
14158
14413
  return `#${id} \u5DF2\u6807\u8BB0\u5B8C\u6210: ${row.event}`;
14159
14414
  }
14160
- function linkDoc(db, id, docPath) {
14161
- const row = db.prepare("SELECT * FROM events WHERE id=?").get(id);
14415
+ function linkDoc(db2, id, docPath) {
14416
+ const row = db2.prepare("SELECT * FROM events WHERE id=?").get(id);
14162
14417
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14163
- db.prepare("UPDATE events SET doc_path=? WHERE id=?").run(docPath, id);
14418
+ db2.prepare("UPDATE events SET doc_path=? WHERE id=?").run(docPath, id);
14164
14419
  return `#${id} \u5DF2\u5173\u8054\u6587\u6863: ${docPath}`;
14165
14420
  }
14166
- function findDoc(db, id) {
14167
- const row = db.prepare("SELECT * FROM events WHERE id=?").get(id);
14421
+ function findDoc(db2, id) {
14422
+ const row = db2.prepare("SELECT * FROM events WHERE id=?").get(id);
14168
14423
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14169
14424
  const parts = [`#${id} ${row.event}`];
14170
14425
  if (row.doc_path) parts.push(`\u{1F4C4} doc_path: ${row.doc_path}`);
14171
14426
  else parts.push(`\u{1F4C4} doc_path: (\u672A\u5173\u8054)`);
14172
14427
  return parts.join("\n");
14173
14428
  }
14174
- function search(db, keyword) {
14175
- const rows = db.prepare("SELECT * FROM events WHERE event LIKE ? ORDER BY id").all(`%${keyword}%`);
14429
+ function search(db2, keyword) {
14430
+ const rows = db2.prepare("SELECT * FROM events WHERE event LIKE ? ORDER BY id").all(`%${keyword}%`);
14176
14431
  if (rows.length > 0) {
14177
14432
  const out = [`\u67E5\u8BE2 '${keyword}' (${rows.length} \u6761):`];
14178
14433
  rows.forEach((r) => out.push(fmtRow(r)));
@@ -14180,29 +14435,29 @@ function search(db, keyword) {
14180
14435
  }
14181
14436
  return `\u67E5\u8BE2 '${keyword}' \u65E0\u7ED3\u679C`;
14182
14437
  }
14183
- function archive(db, id) {
14184
- const row = db.prepare("SELECT * FROM events WHERE id=? AND status!=?").get(id, "archived");
14438
+ function archive(db2, id) {
14439
+ const row = db2.prepare("SELECT * FROM events WHERE id=? AND status!=?").get(id, "archived");
14185
14440
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14186
- db.prepare("UPDATE events SET status=?, archived_at=?, reminded=1 WHERE id=?").run("archived", nowIso(), id);
14441
+ db2.prepare("UPDATE events SET status=?, archived_at=?, reminded=1 WHERE id=?").run("archived", nowIso(), id);
14187
14442
  return `#${id} \u5DF2\u5F52\u6863: ${row.event}`;
14188
14443
  }
14189
- function cleanup(db) {
14190
- const rows = db.prepare("SELECT * FROM events WHERE type='date' AND status='done'").all();
14444
+ function cleanup(db2) {
14445
+ const rows = db2.prepare("SELECT * FROM events WHERE type='date' AND status='done'").all();
14191
14446
  let archived = 0;
14192
14447
  for (const r of rows) {
14193
14448
  const p = parseDateRange(r.date_str);
14194
14449
  if (p && isOverdue(p.month, p.dStart, p.dEnd)) {
14195
- db.prepare("UPDATE events SET status=?, archived_at=? WHERE id=?").run("archived", nowIso(), r.id);
14450
+ db2.prepare("UPDATE events SET status=?, archived_at=? WHERE id=?").run("archived", nowIso(), r.id);
14196
14451
  archived++;
14197
14452
  }
14198
14453
  }
14199
14454
  return archived > 0 ? `\u5DF2\u81EA\u52A8\u5F52\u6863 ${archived} \u6761\u8FC7\u671F\u5B8C\u6210\u65E5\u7A0B` : "\u65E0\u8FC7\u671F\u5B8C\u6210\u65E5\u7A0B\u9700\u8981\u5F52\u6863";
14200
14455
  }
14201
- function stats(db) {
14202
- const total = db.prepare("SELECT COUNT(*) as c FROM events").get().c;
14203
- const pending2 = db.prepare("SELECT COUNT(*) as c FROM events WHERE status='pending'").get().c;
14204
- const done2 = db.prepare("SELECT COUNT(*) as c FROM events WHERE status='done'").get().c;
14205
- const archived = db.prepare("SELECT COUNT(*) as c FROM events WHERE status='archived'").get().c;
14456
+ function stats(db2) {
14457
+ const total = db2.prepare("SELECT COUNT(*) as c FROM events").get().c;
14458
+ const pending2 = db2.prepare("SELECT COUNT(*) as c FROM events WHERE status='pending'").get().c;
14459
+ const done2 = db2.prepare("SELECT COUNT(*) as c FROM events WHERE status='done'").get().c;
14460
+ const archived = db2.prepare("SELECT COUNT(*) as c FROM events WHERE status='archived'").get().c;
14206
14461
  return `\u65E5\u5386\u7EDF\u8BA1: \u603B\u8BA1 ${total} | pending ${pending2} | done ${done2} | archived ${archived}`;
14207
14462
  }
14208
14463
  var WEEKDAYS2;
@@ -14248,7 +14503,7 @@ var init_calendar = __esm({
14248
14503
  const action = args.action;
14249
14504
  if (!action) return { content: "Error: action is required", isError: true };
14250
14505
  try {
14251
- const db = openDb(ctx.workspace);
14506
+ const db2 = openDb(ctx.workspace);
14252
14507
  let result2;
14253
14508
  let isAddTask = false;
14254
14509
  if (action === "add") {
@@ -14258,22 +14513,22 @@ var init_calendar = __esm({
14258
14513
  const repeat = args.repeat || (args.weekly ? "weekly" : "once");
14259
14514
  if (repeat === "daily" || repeat === "weekdays") {
14260
14515
  if (!args.time) return { content: "Error: add daily/weekdays needs time (e.g. 23:00)", isError: true };
14261
- result2 = addDaily(db, { time: args.time, event, repeatType: repeat, remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14516
+ result2 = addDaily(db2, { time: args.time, event, repeatType: repeat, remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14262
14517
  } else if (repeat === "weekly") {
14263
14518
  const day = args.day;
14264
14519
  if (!day) return { content: "Error: add weekly needs day", isError: true };
14265
- result2 = addWeekly(db, { day, event, time: args.time, duration: args.duration, remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14520
+ result2 = addWeekly(db2, { day, event, time: args.time, duration: args.duration, remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14266
14521
  } else {
14267
14522
  const date = args.date?.trim();
14268
14523
  if (!date) return { content: "Error: add once needs date (e.g. 5/26)", isError: true };
14269
- result2 = addDate(db, { dateStr: date, event, time: args.time, duration: args.duration, remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14524
+ result2 = addDate(db2, { dateStr: date, event, time: args.time, duration: args.duration, remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14270
14525
  }
14271
14526
  } else if (action === "add-batch") {
14272
14527
  const event = args.event?.trim();
14273
14528
  const datesInput = args.dates?.trim();
14274
14529
  if (!event) return { content: "Error: add-batch needs event", isError: true };
14275
14530
  if (!datesInput) return { content: 'Error: add-batch needs dates (e.g. "7/2,7/4,7/6-7/10")', isError: true };
14276
- result2 = addBatch(db, { datesInput, event, time: args.time, duration: args.duration, remind: args.remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14531
+ result2 = addBatch(db2, { datesInput, event, time: args.time, duration: args.duration, remind: args.remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
14277
14532
  } else if (action === "add-task") {
14278
14533
  isAddTask = true;
14279
14534
  const event = args.event?.trim();
@@ -14284,47 +14539,47 @@ var init_calendar = __esm({
14284
14539
  if (!date) return { content: "Error: add-task needs date (e.g. 7/5)", isError: true };
14285
14540
  if (!timeExact || !timeExact.includes(":")) return { content: "Error: add-task needs time_exact (HH:MM, e.g. 14:00)", isError: true };
14286
14541
  if (!docPath) return { content: "\u274C \u521B\u5EFA\u5931\u8D25\uFF1Aadd-task \u5FC5\u987B\u4F20 doc_path\u3002\n\u6CA1\u6709\u6587\u6863\u652F\u6491\u7684 task \u4E0D\u662F\u5408\u683C\u7684 task\u3002\n\u8BF7\u5148\u5728 docs/todo/ \u4E0B\u521B\u5EFA\u6587\u6863\uFF08\u547D\u540D\uFF1AYYYY-MM-DD_\u4E3B\u9898.md \u6216 \u4EFB\u52A1\u540D.md\uFF09\uFF0C\u7136\u540E\u4F20 doc_path \u53C2\u6570\u3002", isError: true };
14287
- result2 = addTask(db, { dateStr: date, timeExact, event, remind: args.remind, channel: ctx.channel, channelTarget: ctx.channelTarget, docPath });
14542
+ result2 = addTask(db2, { dateStr: date, timeExact, event, remind: args.remind, channel: ctx.channel, channelTarget: ctx.channelTarget, docPath });
14288
14543
  } else if (action === "reschedule") {
14289
14544
  if (args.id == null) return { content: "Error: reschedule needs id", isError: true };
14290
14545
  const date = args.date?.trim();
14291
14546
  const timeExact = args.time_exact?.trim();
14292
14547
  if (!date) return { content: "Error: reschedule needs date (e.g. 7/10)", isError: true };
14293
14548
  if (!timeExact || !timeExact.includes(":")) return { content: "Error: reschedule needs time_exact (HH:MM)", isError: true };
14294
- result2 = reschedule(db, { id: args.id, dateStr: date, timeExact, remind: args.remind });
14549
+ result2 = reschedule(db2, { id: args.id, dateStr: date, timeExact, remind: args.remind });
14295
14550
  } else if (action === "link-doc") {
14296
14551
  if (args.id == null) return { content: "Error: link-doc needs id", isError: true };
14297
14552
  const docPath = args.doc_path?.trim();
14298
14553
  if (!docPath) return { content: "Error: link-doc needs doc_path", isError: true };
14299
- result2 = linkDoc(db, args.id, docPath);
14554
+ result2 = linkDoc(db2, args.id, docPath);
14300
14555
  } else if (action === "find-doc") {
14301
14556
  if (args.id == null) return { content: "Error: find-doc needs id", isError: true };
14302
- result2 = findDoc(db, args.id);
14557
+ result2 = findDoc(db2, args.id);
14303
14558
  } else if (action === "list") {
14304
- result2 = list(db, { all: !!args.all });
14559
+ result2 = list(db2, { all: !!args.all });
14305
14560
  } else if (action === "done") {
14306
14561
  if (args.id == null) return { content: "Error: done needs id", isError: true };
14307
- result2 = done(db, args.id);
14562
+ result2 = done(db2, args.id);
14308
14563
  } else if (action === "pending") {
14309
- result2 = pending(db);
14564
+ result2 = pending(db2);
14310
14565
  } else if (action === "search") {
14311
14566
  const kw = args.event?.trim();
14312
14567
  if (!kw) return { content: "Error: search needs keyword (event field)", isError: true };
14313
- result2 = search(db, kw);
14568
+ result2 = search(db2, kw);
14314
14569
  } else if (action === "archive") {
14315
14570
  if (args.id == null) return { content: "Error: archive needs id", isError: true };
14316
- result2 = archive(db, args.id);
14571
+ result2 = archive(db2, args.id);
14317
14572
  } else if (action === "delete") {
14318
14573
  if (args.id == null) return { content: "Error: delete needs id", isError: true };
14319
- result2 = archive(db, args.id);
14574
+ result2 = archive(db2, args.id);
14320
14575
  } else if (action === "cleanup") {
14321
- result2 = cleanup(db);
14576
+ result2 = cleanup(db2);
14322
14577
  } else if (action === "stats") {
14323
- result2 = stats(db);
14578
+ result2 = stats(db2);
14324
14579
  } else {
14325
14580
  return { content: `Error: unknown action '${action}'`, isError: true };
14326
14581
  }
14327
- db.close();
14582
+ db2.close();
14328
14583
  const isFailed = result2.startsWith("\u274C") || result2.includes("Error") || result2.includes("\u7528\u6CD5");
14329
14584
  if (isAddTask && !isFailed) {
14330
14585
  const { enqueueNotification: enqueueNotification2, buildCalendarNotification: buildCalendarNotification2 } = await Promise.resolve().then(() => (init_task_manager(), task_manager_exports));
@@ -14568,24 +14823,24 @@ var init_constants5 = __esm({
14568
14823
  });
14569
14824
 
14570
14825
  // src/tools/TodoWriteTool/TodoWriteTool.ts
14571
- import fs21 from "node:fs";
14572
- import path22 from "node:path";
14826
+ import fs22 from "node:fs";
14827
+ import path23 from "node:path";
14573
14828
  function todoFilePath(sessionId) {
14574
- return path22.join(todosDir, `${sessionId}.json`);
14829
+ return path23.join(todosDir, `${sessionId}.json`);
14575
14830
  }
14576
14831
  function loadTodos(sessionId) {
14577
14832
  if (!todosDir) return [];
14578
14833
  try {
14579
14834
  const filePath = todoFilePath(sessionId);
14580
- if (!fs21.existsSync(filePath)) return [];
14581
- return JSON.parse(fs21.readFileSync(filePath, "utf-8"));
14835
+ if (!fs22.existsSync(filePath)) return [];
14836
+ return JSON.parse(fs22.readFileSync(filePath, "utf-8"));
14582
14837
  } catch {
14583
14838
  return [];
14584
14839
  }
14585
14840
  }
14586
14841
  function saveTodos(sessionId, todos) {
14587
14842
  if (!todosDir) return;
14588
- fs21.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
14843
+ fs22.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
14589
14844
  }
14590
14845
  var todosDir;
14591
14846
  var init_TodoWriteTool = __esm({
@@ -14842,15 +15097,15 @@ var init_constants7 = __esm({
14842
15097
  });
14843
15098
 
14844
15099
  // src/utils/plans.ts
14845
- import * as fs22 from "node:fs";
14846
- import * as path23 from "node:path";
15100
+ import * as fs23 from "node:fs";
15101
+ import * as path24 from "node:path";
14847
15102
  import * as crypto4 from "node:crypto";
14848
15103
  function generateSlug() {
14849
15104
  return crypto4.randomBytes(4).toString("hex");
14850
15105
  }
14851
15106
  function getPlansDirectory(stateDir) {
14852
- const plansDir = path23.join(stateDir, "plans");
14853
- fs22.mkdirSync(plansDir, { recursive: true });
15107
+ const plansDir = path24.join(stateDir, "plans");
15108
+ fs23.mkdirSync(plansDir, { recursive: true });
14854
15109
  return plansDir;
14855
15110
  }
14856
15111
  function getPlanSlug(sessionId, stateDir) {
@@ -14859,8 +15114,8 @@ function getPlanSlug(sessionId, stateDir) {
14859
15114
  const plansDir = getPlansDirectory(stateDir);
14860
15115
  for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
14861
15116
  slug = generateSlug();
14862
- const filePath = path23.join(plansDir, `${slug}.md`);
14863
- if (!fs22.existsSync(filePath)) {
15117
+ const filePath = path24.join(plansDir, `${slug}.md`);
15118
+ if (!fs23.existsSync(filePath)) {
14864
15119
  break;
14865
15120
  }
14866
15121
  }
@@ -14871,21 +15126,21 @@ function getPlanSlug(sessionId, stateDir) {
14871
15126
  function getPlanFilePath(sessionId, stateDir, agentId) {
14872
15127
  const slug = getPlanSlug(sessionId, stateDir);
14873
15128
  if (!agentId) {
14874
- return path23.join(getPlansDirectory(stateDir), `${slug}.md`);
15129
+ return path24.join(getPlansDirectory(stateDir), `${slug}.md`);
14875
15130
  }
14876
- return path23.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
15131
+ return path24.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
14877
15132
  }
14878
15133
  function getPlan(sessionId, stateDir, agentId) {
14879
15134
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
14880
15135
  try {
14881
- return fs22.readFileSync(filePath, "utf-8");
15136
+ return fs23.readFileSync(filePath, "utf-8");
14882
15137
  } catch {
14883
15138
  return null;
14884
15139
  }
14885
15140
  }
14886
15141
  function writePlan(sessionId, stateDir, content, agentId) {
14887
15142
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
14888
- fs22.writeFileSync(filePath, content, "utf-8");
15143
+ fs23.writeFileSync(filePath, content, "utf-8");
14889
15144
  return filePath;
14890
15145
  }
14891
15146
  var MAX_SLUG_RETRIES, planSlugCache;
@@ -15033,28 +15288,28 @@ var init_constants8 = __esm({
15033
15288
  });
15034
15289
 
15035
15290
  // src/utils/tasks.ts
15036
- import * as fs23 from "node:fs";
15037
- import * as path24 from "node:path";
15291
+ import * as fs24 from "node:fs";
15292
+ import * as path25 from "node:path";
15038
15293
  function sanitizePathComponent2(input) {
15039
15294
  return input.replace(/[^a-zA-Z0-9_-]/g, "-");
15040
15295
  }
15041
15296
  function getTasksDir2(stateDir, listId) {
15042
- return path24.join(stateDir, "tasks", sanitizePathComponent2(listId));
15297
+ return path25.join(stateDir, "tasks", sanitizePathComponent2(listId));
15043
15298
  }
15044
15299
  function getTaskPath(stateDir, listId, taskId) {
15045
- return path24.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
15300
+ return path25.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
15046
15301
  }
15047
15302
  function ensureTasksDir2(stateDir, listId) {
15048
15303
  const dir = getTasksDir2(stateDir, listId);
15049
- fs23.mkdirSync(dir, { recursive: true });
15304
+ fs24.mkdirSync(dir, { recursive: true });
15050
15305
  return dir;
15051
15306
  }
15052
15307
  function getHighWaterMarkPath(stateDir, listId) {
15053
- return path24.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
15308
+ return path25.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
15054
15309
  }
15055
15310
  function readHighWaterMark(stateDir, listId) {
15056
15311
  try {
15057
- const content = fs23.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
15312
+ const content = fs24.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
15058
15313
  const value = parseInt(content, 10);
15059
15314
  return isNaN(value) ? 0 : value;
15060
15315
  } catch {
@@ -15062,20 +15317,20 @@ function readHighWaterMark(stateDir, listId) {
15062
15317
  }
15063
15318
  }
15064
15319
  function writeHighWaterMark(stateDir, listId, value) {
15065
- fs23.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
15320
+ fs24.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
15066
15321
  }
15067
15322
  function findHighestTaskIdFromFiles(stateDir, listId) {
15068
15323
  const dir = getTasksDir2(stateDir, listId);
15069
15324
  let files;
15070
15325
  try {
15071
- files = fs23.readdirSync(dir);
15326
+ files = fs24.readdirSync(dir);
15072
15327
  } catch {
15073
15328
  return 0;
15074
15329
  }
15075
15330
  let highest = 0;
15076
- for (const file of files) {
15077
- if (!file.endsWith(".json")) continue;
15078
- const taskId = parseInt(file.replace(".json", ""), 10);
15331
+ for (const file2 of files) {
15332
+ if (!file2.endsWith(".json")) continue;
15333
+ const taskId = parseInt(file2.replace(".json", ""), 10);
15079
15334
  if (!isNaN(taskId) && taskId > highest) {
15080
15335
  highest = taskId;
15081
15336
  }
@@ -15094,14 +15349,14 @@ function createTask(stateDir, listId, taskData) {
15094
15349
  const id = String(highestId + 1);
15095
15350
  const task = { id, ...taskData };
15096
15351
  const filePath = getTaskPath(stateDir, listId, id);
15097
- fs23.writeFileSync(filePath, JSON.stringify(task, null, 2));
15352
+ fs24.writeFileSync(filePath, JSON.stringify(task, null, 2));
15098
15353
  return id;
15099
15354
  });
15100
15355
  }
15101
15356
  function getTask2(stateDir, listId, taskId) {
15102
15357
  const filePath = getTaskPath(stateDir, listId, taskId);
15103
15358
  try {
15104
- const content = fs23.readFileSync(filePath, "utf-8");
15359
+ const content = fs24.readFileSync(filePath, "utf-8");
15105
15360
  return JSON.parse(content);
15106
15361
  } catch {
15107
15362
  return null;
@@ -15111,7 +15366,7 @@ function listTasks2(stateDir, listId) {
15111
15366
  const dir = getTasksDir2(stateDir, listId);
15112
15367
  let files;
15113
15368
  try {
15114
- files = fs23.readdirSync(dir);
15369
+ files = fs24.readdirSync(dir);
15115
15370
  } catch {
15116
15371
  return [];
15117
15372
  }
@@ -15123,7 +15378,7 @@ function updateTask(stateDir, listId, taskId, updates) {
15123
15378
  if (!existing) return null;
15124
15379
  const updated = { ...existing, ...updates, id: taskId };
15125
15380
  const filePath = getTaskPath(stateDir, listId, taskId);
15126
- fs23.writeFileSync(filePath, JSON.stringify(updated, null, 2));
15381
+ fs24.writeFileSync(filePath, JSON.stringify(updated, null, 2));
15127
15382
  return updated;
15128
15383
  }
15129
15384
  function deleteTask(stateDir, listId, taskId) {
@@ -15137,7 +15392,7 @@ function deleteTask(stateDir, listId, taskId) {
15137
15392
  }
15138
15393
  }
15139
15394
  try {
15140
- fs23.unlinkSync(filePath);
15395
+ fs24.unlinkSync(filePath);
15141
15396
  } catch {
15142
15397
  return false;
15143
15398
  }
@@ -16570,10 +16825,10 @@ function ensureLoaded(workspace, configIds) {
16570
16825
  if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
16571
16826
  }
16572
16827
  }
16573
- const path30 = join23(workspace, ".reply-blocklist.json");
16828
+ const path31 = join23(workspace, ".reply-blocklist.json");
16574
16829
  try {
16575
- if (existsSync18(path30)) {
16576
- const raw = readFileSync18(path30, "utf-8");
16830
+ if (existsSync18(path31)) {
16831
+ const raw = readFileSync18(path31, "utf-8");
16577
16832
  const parsed = JSON.parse(raw);
16578
16833
  if (parsed.blockedUserIds) {
16579
16834
  for (const id of parsed.blockedUserIds) {
@@ -16589,9 +16844,9 @@ function ensureLoaded(workspace, configIds) {
16589
16844
  loaded = true;
16590
16845
  }
16591
16846
  function save(workspace) {
16592
- const path30 = join23(workspace, ".reply-blocklist.json");
16847
+ const path31 = join23(workspace, ".reply-blocklist.json");
16593
16848
  try {
16594
- writeFileSync14(path30, JSON.stringify(state, null, 2), "utf-8");
16849
+ writeFileSync14(path31, JSON.stringify(state, null, 2), "utf-8");
16595
16850
  } catch (err) {
16596
16851
  console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
16597
16852
  }
@@ -17108,9 +17363,9 @@ function cosineSim(a, b) {
17108
17363
  }
17109
17364
  function readDbEmbeddings(dbPath) {
17110
17365
  const { DatabaseSync: DatabaseSync2 } = require3("node:sqlite");
17111
- const db = new DatabaseSync2(dbPath, { readOnly: true });
17366
+ const db2 = new DatabaseSync2(dbPath, { readOnly: true });
17112
17367
  try {
17113
- const stmt = db.prepare(`
17368
+ const stmt = db2.prepare(`
17114
17369
  SELECT file_path, name, description, mtime, embedding
17115
17370
  FROM files
17116
17371
  WHERE embedding IS NOT NULL AND deprecated_by IS NULL
@@ -17127,7 +17382,7 @@ function readDbEmbeddings(dbPath) {
17127
17382
  }
17128
17383
  return rows;
17129
17384
  } finally {
17130
- db.close();
17385
+ db2.close();
17131
17386
  }
17132
17387
  }
17133
17388
  async function llmRerank(query, candidates, topK, ollamaChatUrl, model) {
@@ -17504,6 +17759,69 @@ var init_light_mode = __esm({
17504
17759
  }
17505
17760
  });
17506
17761
 
17762
+ // src/compact/voiceFastView.ts
17763
+ function blocksText(content) {
17764
+ if (typeof content === "string") return content;
17765
+ if (Array.isArray(content)) return content.filter((b) => b && b.type === "text").map((b) => b.text || "").join(" ");
17766
+ return "";
17767
+ }
17768
+ function splitTurns(history) {
17769
+ const turns = [];
17770
+ let cur = [];
17771
+ for (const m of history) {
17772
+ if (m.role === "user" && cur.length > 0) {
17773
+ turns.push(cur);
17774
+ cur = [m];
17775
+ } else cur.push(m);
17776
+ }
17777
+ if (cur.length > 0) turns.push(cur);
17778
+ return turns;
17779
+ }
17780
+ function voiceFastView(history, opts = VOICE_FAST_DEFAULTS) {
17781
+ const { keepTurns, toolCap, argCap } = opts;
17782
+ const turns = splitTurns(history);
17783
+ const oldTurns = turns.slice(0, Math.max(0, turns.length - keepTurns));
17784
+ const keepTurnsArr = turns.slice(Math.max(0, turns.length - keepTurns));
17785
+ const folded = oldTurns.map(
17786
+ (turn) => turn.map((m) => {
17787
+ if (m.role === "toolResult") {
17788
+ const text = blocksText(m.content);
17789
+ if (text.length > toolCap) {
17790
+ const compressed = smartCompressToolResult(text, void 0, toolCap);
17791
+ return { ...m, content: [{ type: "text", text: compressed }] };
17792
+ }
17793
+ return m;
17794
+ }
17795
+ if (m.role === "assistant" && Array.isArray(m.content)) {
17796
+ const newContent = m.content.map((b) => {
17797
+ if (b && b.type === "toolCall" && b.arguments) {
17798
+ const argStr = typeof b.arguments === "string" ? b.arguments : JSON.stringify(b.arguments);
17799
+ if (argStr.length > argCap) {
17800
+ return { ...b, arguments: argStr.slice(0, argCap) + "\u2026[voice-fold]" };
17801
+ }
17802
+ }
17803
+ return b;
17804
+ });
17805
+ return { ...m, content: newContent };
17806
+ }
17807
+ return m;
17808
+ })
17809
+ );
17810
+ const out = [...folded.flat(), ...keepTurnsArr.flat()];
17811
+ const before = JSON.stringify(history).length;
17812
+ const saved = before - JSON.stringify(out).length;
17813
+ console.log(`[voice-fast] ${history.length} \u2192 ${out.length} \u6761 (keepTurns=${keepTurns}, toolCap=${toolCap}, argCap=${argCap}, -${(saved * 100 / Math.max(1, before)).toFixed(0)}%)`);
17814
+ return out;
17815
+ }
17816
+ var VOICE_FAST_DEFAULTS;
17817
+ var init_voiceFastView = __esm({
17818
+ "src/compact/voiceFastView.ts"() {
17819
+ "use strict";
17820
+ init_ruleCompact();
17821
+ VOICE_FAST_DEFAULTS = { keepTurns: 5, toolCap: 500, argCap: 100 };
17822
+ }
17823
+ });
17824
+
17507
17825
  // src/sender-context.ts
17508
17826
  import { readFileSync as readFileSync21, existsSync as existsSync20 } from "node:fs";
17509
17827
  import { join as join28 } from "node:path";
@@ -17671,8 +17989,8 @@ var extractMemories_exports = {};
17671
17989
  __export(extractMemories_exports, {
17672
17990
  createMemoryExtractor: () => createMemoryExtractor
17673
17991
  });
17674
- import * as fs24 from "fs";
17675
- import * as path25 from "path";
17992
+ import * as fs25 from "fs";
17993
+ import * as path26 from "path";
17676
17994
  function isModelVisibleMessage(message) {
17677
17995
  return message.role === "user" || message.role === "assistant";
17678
17996
  }
@@ -17695,13 +18013,13 @@ function getMemoryTools() {
17695
18013
  return allDefs.filter((d) => MEMORY_TOOL_NAMES.includes(d.function.name));
17696
18014
  }
17697
18015
  function getStatePath(workspace) {
17698
- return path25.join(workspace, STATE_FILE);
18016
+ return path26.join(workspace, STATE_FILE);
17699
18017
  }
17700
18018
  function loadPersistedState(workspace) {
17701
18019
  try {
17702
18020
  const p = getStatePath(workspace);
17703
- if (fs24.existsSync(p)) {
17704
- const data = JSON.parse(fs24.readFileSync(p, "utf-8"));
18021
+ if (fs25.existsSync(p)) {
18022
+ const data = JSON.parse(fs25.readFileSync(p, "utf-8"));
17705
18023
  for (const [sid, ts] of Object.entries(data.lastTs ?? {})) {
17706
18024
  lastTsMap.set(sid, ts);
17707
18025
  }
@@ -17721,7 +18039,7 @@ function persistState(workspace) {
17721
18039
  for (const [sid, ts] of lastTsMap.entries()) lastTs[sid] = ts;
17722
18040
  for (const [sid, ts] of lastExtractTimeMap.entries()) timestamps[sid] = ts;
17723
18041
  const data = JSON.stringify({ lastTs, timestamps }, null, 2);
17724
- fs24.writeFileSync(getStatePath(workspace), data, "utf-8");
18042
+ fs25.writeFileSync(getStatePath(workspace), data, "utf-8");
17725
18043
  } catch (e) {
17726
18044
  console.warn(`[memory] failed to persist extract state: ${e?.message ?? e}`);
17727
18045
  }
@@ -17762,11 +18080,11 @@ function createMemoryExtractor(workspace, enabled) {
17762
18080
  const existingMemories = formatMemoryManifest(
17763
18081
  await scanMemoryFiles2(memoryDir, new AbortController().signal)
17764
18082
  );
17765
- const extractOverridePath = path25.join(workspace, "prompts", "extract.md");
18083
+ const extractOverridePath = path26.join(workspace, "prompts", "extract.md");
17766
18084
  let systemPrompt;
17767
18085
  try {
17768
- if (fs24.existsSync(extractOverridePath)) {
17769
- systemPrompt = fs24.readFileSync(extractOverridePath, { encoding: "utf-8" });
18086
+ if (fs25.existsSync(extractOverridePath)) {
18087
+ systemPrompt = fs25.readFileSync(extractOverridePath, { encoding: "utf-8" });
17770
18088
  if (existingMemories.length > 0) {
17771
18089
  systemPrompt += `
17772
18090
 
@@ -17867,8 +18185,8 @@ var ingest_exports = {};
17867
18185
  __export(ingest_exports, {
17868
18186
  pushConversation: () => pushConversation
17869
18187
  });
17870
- import fs25 from "node:fs";
17871
- import path26 from "node:path";
18188
+ import fs26 from "node:fs";
18189
+ import path27 from "node:path";
17872
18190
  function parseMeta(text) {
17873
18191
  const m = text.match(/^\[meta:\s*(.+?)\s*\((.+?)\)\s*@(\S+)\s*[^\]]*\]/);
17874
18192
  if (!m) return null;
@@ -17901,9 +18219,9 @@ async function readConfig() {
17901
18219
  }
17902
18220
  function loadPushTs(workspace, sessionId) {
17903
18221
  try {
17904
- const p = path26.join(workspace, PUSH_STATE_FILE);
17905
- if (fs25.existsSync(p)) {
17906
- const data = JSON.parse(fs25.readFileSync(p, "utf-8"));
18222
+ const p = path27.join(workspace, PUSH_STATE_FILE);
18223
+ if (fs26.existsSync(p)) {
18224
+ const data = JSON.parse(fs26.readFileSync(p, "utf-8"));
17907
18225
  return typeof data[sessionId] === "number" ? data[sessionId] : 0;
17908
18226
  }
17909
18227
  } catch (e) {
@@ -17913,14 +18231,14 @@ function loadPushTs(workspace, sessionId) {
17913
18231
  }
17914
18232
  function savePushTs(workspace, sessionId, ts) {
17915
18233
  try {
17916
- const p = path26.join(workspace, PUSH_STATE_FILE);
18234
+ const p = path27.join(workspace, PUSH_STATE_FILE);
17917
18235
  let data = {};
17918
18236
  try {
17919
- if (fs25.existsSync(p)) data = JSON.parse(fs25.readFileSync(p, "utf-8"));
18237
+ if (fs26.existsSync(p)) data = JSON.parse(fs26.readFileSync(p, "utf-8"));
17920
18238
  } catch {
17921
18239
  }
17922
18240
  data[sessionId] = ts;
17923
- fs25.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
18241
+ fs26.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
17924
18242
  } catch (e) {
17925
18243
  console.warn(`[everos-ingest] save pushTs failed: ${e?.message ?? e}`);
17926
18244
  }
@@ -18569,11 +18887,11 @@ async function readLastConsolidatedAt(memoryDir) {
18569
18887
  }
18570
18888
  }
18571
18889
  async function tryAcquireConsolidationLock(memoryDir) {
18572
- const path30 = lockPath(memoryDir);
18890
+ const path31 = lockPath(memoryDir);
18573
18891
  let mtimeMs;
18574
18892
  let holderPid;
18575
18893
  try {
18576
- const [s, raw] = await Promise.all([stat3(path30), readFile5(path30, "utf8")]);
18894
+ const [s, raw] = await Promise.all([stat3(path31), readFile5(path31, "utf8")]);
18577
18895
  mtimeMs = s.mtimeMs;
18578
18896
  const parsed = parseInt(raw.trim(), 10);
18579
18897
  holderPid = Number.isFinite(parsed) ? parsed : void 0;
@@ -18586,10 +18904,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
18586
18904
  }
18587
18905
  }
18588
18906
  await mkdir3(memoryDir, { recursive: true });
18589
- await writeFile4(path30, String(process.pid));
18907
+ await writeFile4(path31, String(process.pid));
18590
18908
  let verify;
18591
18909
  try {
18592
- verify = await readFile5(path30, "utf8");
18910
+ verify = await readFile5(path31, "utf8");
18593
18911
  } catch {
18594
18912
  return null;
18595
18913
  }
@@ -18597,15 +18915,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
18597
18915
  return mtimeMs ?? 0;
18598
18916
  }
18599
18917
  async function rollbackConsolidationLock(memoryDir, priorMtime) {
18600
- const path30 = lockPath(memoryDir);
18918
+ const path31 = lockPath(memoryDir);
18601
18919
  try {
18602
18920
  if (priorMtime === 0) {
18603
- await unlink(path30);
18921
+ await unlink(path31);
18604
18922
  return;
18605
18923
  }
18606
- await writeFile4(path30, "");
18924
+ await writeFile4(path31, "");
18607
18925
  const t = priorMtime / 1e3;
18608
- await utimes(path30, t, t);
18926
+ await utimes(path31, t, t);
18609
18927
  } catch (e) {
18610
18928
  console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
18611
18929
  }
@@ -18888,34 +19206,30 @@ var handle_query_exports = {};
18888
19206
  __export(handle_query_exports, {
18889
19207
  handleQuery: () => handleQuery,
18890
19208
  resetSessionStartInjection: () => resetSessionStartInjection,
18891
- resetWorkModeInjection: () => resetWorkModeInjection,
18892
19209
  resolveSystemPrompt: () => resolveSystemPrompt
18893
19210
  });
18894
19211
  import { readFileSync as readFileSync25, existsSync as existsSync22 } from "node:fs";
18895
19212
  import { join as join33, resolve as resolve8 } from "node:path";
18896
- import * as path27 from "node:path";
19213
+ import * as path28 from "node:path";
18897
19214
  function resolveSystemPrompt(v) {
18898
19215
  return typeof v === "function" ? v() : v || "";
18899
19216
  }
18900
19217
  function resetSessionStartInjection(sessionId) {
18901
19218
  sessionStartDone.delete(sessionId);
18902
19219
  }
18903
- function resetWorkModeInjection(sessionId) {
18904
- workModeInjected.delete(sessionId);
18905
- }
18906
19220
  function loadExternalChanRules(workspace) {
18907
- const path30 = join33(workspace, "prompts", "external-chan-rules.md");
18908
- if (externalChanRulesCache && externalChanRulesCache.path === path30) return externalChanRulesCache;
19221
+ const path31 = join33(workspace, "prompts", "external-chan-rules.md");
19222
+ if (externalChanRulesCache && externalChanRulesCache.path === path31) return externalChanRulesCache;
18909
19223
  let content = "";
18910
- if (existsSync22(path30)) {
19224
+ if (existsSync22(path31)) {
18911
19225
  try {
18912
- content = readFileSync25(path30, "utf-8").trim();
19226
+ content = readFileSync25(path31, "utf-8").trim();
18913
19227
  } catch (e) {
18914
19228
  console.warn(`[external-chan-rules] Failed to load: ${e}`);
18915
19229
  }
18916
19230
  }
18917
- externalChanRulesCache = { path: path30, content };
18918
- console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path30}`);
19231
+ externalChanRulesCache = { path: path31, content };
19232
+ console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path31}`);
18919
19233
  return externalChanRulesCache;
18920
19234
  }
18921
19235
  function getExternalChanRulesBlock(inboundMeta, workspace) {
@@ -19123,7 +19437,13 @@ ${text}` : text });
19123
19437
  const isLight = isLightMode(chatMode, channelName) && chatMode !== "emotion";
19124
19438
  const lightN = resolveLightN(channelName);
19125
19439
  const lightHistory = buildLightHistory(history, { isLight, lightN, channelName, chatMode, recallFull: emotionStripped });
19126
- const messages = [...lightHistory, msg.user(userMsgContent)];
19440
+ const voiceFastOn = channelName === "voice-chat" && chatMode === "work";
19441
+ const finalHistory = voiceFastOn ? voiceFastView(lightHistory, {
19442
+ keepTurns: liveConfig.get("voiceChat.voiceFast.keepTurns") ?? 5,
19443
+ toolCap: liveConfig.get("voiceChat.voiceFast.toolCap") ?? 500,
19444
+ argCap: liveConfig.get("voiceChat.voiceFast.argCap") ?? 100
19445
+ }) : lightHistory;
19446
+ const messages = [...finalHistory, msg.user(userMsgContent)];
19127
19447
  if (deps.mcpManager && !deps.mcpManager.isMcpDeltaSent(sessionId)) {
19128
19448
  const delta = deps.mcpManager.getMcpDelta();
19129
19449
  if (delta && delta.addedBlocks.length > 0) {
@@ -19177,30 +19497,6 @@ ${text}` : text });
19177
19497
  }
19178
19498
  }
19179
19499
  }
19180
- if (chatMode === "emotion") {
19181
- if (workModeInjected.has(sessionId)) workModeInjected.delete(sessionId);
19182
- } else if (!workModeInjected.has(sessionId)) {
19183
- workModeInjected.add(sessionId);
19184
- try {
19185
- const sr = await executeSessionStartHooks(channelName === "cli" ? "cli" : "channel", {
19186
- sessionId,
19187
- workspace,
19188
- cwd: workspace,
19189
- channel: channelName === "cli" ? "console" : channelName,
19190
- senderId: inboundMeta?.from || "",
19191
- channelType: inboundMeta?.channelType || "",
19192
- source
19193
- });
19194
- if (sr.additionalContexts && sr.additionalContexts.length > 0) {
19195
- const att = createAttachmentMessage({ type: "session_start", text: sr.additionalContexts.join("\n\n") });
19196
- history.push(att);
19197
- messages.push(att);
19198
- console.log(`[hooks] work-mode injection: ${sr.additionalContexts.length} additionalContext(s) at END of messages (session ${sessionId}, cache-safe, persisted)`);
19199
- }
19200
- } catch (err) {
19201
- console.warn(`[hooks] work-mode injection error: ${err.message}`);
19202
- }
19203
- }
19204
19500
  const pendingNotifications2 = drainPendingNotifications();
19205
19501
  if (pendingNotifications2.length > 0) {
19206
19502
  messages.push(createAttachmentMessage({
@@ -19221,7 +19517,7 @@ ${text}` : text });
19221
19517
  }));
19222
19518
  console.log(`[handle-query] Injected ${teammateMsgs.length} teammate message(s): ${teammateMsgs.map((m) => `[from=${m.from}] ${(m.text || "").slice(0, 80).replace(/\n/g, " ")}`).join(" | ")}`);
19223
19519
  }
19224
- if (channelName !== "heartbeat" && channelName !== "cron" && channelName !== "inner-voice" && channelName !== "cognifold") {
19520
+ if (channelName !== "heartbeat" && channelName !== "cron" && channelName !== "inner-voice" && channelName !== "proactive") {
19225
19521
  sessions.touch(sessionId);
19226
19522
  }
19227
19523
  const toolContext = {
@@ -19665,7 +19961,7 @@ stack: ${err.stack ?? "(none)"}`);
19665
19961
  }
19666
19962
  } catch (err) {
19667
19963
  try {
19668
- (await import("node:fs")).appendFileSync(join33(process.env.ENGINE7_STATE_DIR || path27.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
19964
+ (await import("node:fs")).appendFileSync(join33(process.env.ENGINE7_STATE_DIR || path28.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
19669
19965
  stack: ${err.stack ?? "(none)"}
19670
19966
  `);
19671
19967
  } catch {
@@ -19683,7 +19979,7 @@ function roughTokenCount(messages) {
19683
19979
  }
19684
19980
  return total;
19685
19981
  }
19686
- var sessionStartDone, workModeInjected, externalChanRulesCache;
19982
+ var sessionStartDone, externalChanRulesCache;
19687
19983
  var init_handle_query = __esm({
19688
19984
  "src/handle-query.ts"() {
19689
19985
  "use strict";
@@ -19703,9 +19999,9 @@ var init_handle_query = __esm({
19703
19999
  init_findRelevantMemoriesEveros();
19704
20000
  init_paths();
19705
20001
  init_light_mode();
20002
+ init_voiceFastView();
19706
20003
  init_sender_context();
19707
20004
  sessionStartDone = /* @__PURE__ */ new Set();
19708
- workModeInjected = /* @__PURE__ */ new Set();
19709
20005
  externalChanRulesCache = null;
19710
20006
  }
19711
20007
  });
@@ -20211,20 +20507,20 @@ __export(cli_travel_exports, {
20211
20507
  loadTravelConfig: () => loadTravelConfig,
20212
20508
  saveTravelConfig: () => saveTravelConfig
20213
20509
  });
20214
- import * as path28 from "node:path";
20215
- import * as fs26 from "node:fs";
20510
+ import * as path29 from "node:path";
20511
+ import * as fs27 from "node:fs";
20216
20512
  import * as os4 from "node:os";
20217
20513
  import { execSync as execSync2 } from "node:child_process";
20218
20514
  function loadTravelConfig() {
20219
20515
  try {
20220
- if (!fs26.existsSync(CONFIG_PATH)) return null;
20221
- return JSON.parse(fs26.readFileSync(CONFIG_PATH, "utf-8"));
20516
+ if (!fs27.existsSync(CONFIG_PATH)) return null;
20517
+ return JSON.parse(fs27.readFileSync(CONFIG_PATH, "utf-8"));
20222
20518
  } catch {
20223
20519
  return null;
20224
20520
  }
20225
20521
  }
20226
20522
  function saveTravelConfig(cfg) {
20227
- fs26.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
20523
+ fs27.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
20228
20524
  }
20229
20525
  function sanitizeContent(content, dirs) {
20230
20526
  let result2 = content;
@@ -20249,7 +20545,7 @@ function restoreContent(content, dirs) {
20249
20545
  return result2;
20250
20546
  }
20251
20547
  function isTextFile(filePath) {
20252
- const ext = path28.extname(filePath).toLowerCase();
20548
+ const ext = path29.extname(filePath).toLowerCase();
20253
20549
  return TEXT_EXTENSIONS.has(ext);
20254
20550
  }
20255
20551
  function shouldExclude(name) {
@@ -20264,14 +20560,14 @@ function shouldExclude(name) {
20264
20560
  }
20265
20561
  function collectFiles(rootDir, includeSet, optionalSet) {
20266
20562
  const files = [];
20267
- const entries2 = fs26.readdirSync(rootDir, { withFileTypes: true });
20563
+ const entries2 = fs27.readdirSync(rootDir, { withFileTypes: true });
20268
20564
  for (const entry of entries2) {
20269
20565
  if (shouldExclude(entry.name)) continue;
20270
- const fullPath = path28.join(rootDir, entry.name);
20271
- const realPath = fs26.realpathSync(fullPath);
20566
+ const fullPath = path29.join(rootDir, entry.name);
20567
+ const realPath = fs27.realpathSync(fullPath);
20272
20568
  if (realPath !== fullPath) {
20273
20569
  try {
20274
- const lstat = fs26.lstatSync(fullPath);
20570
+ const lstat = fs27.lstatSync(fullPath);
20275
20571
  if (lstat.isSymbolicLink()) {
20276
20572
  continue;
20277
20573
  }
@@ -20292,12 +20588,12 @@ function collectFiles(rootDir, includeSet, optionalSet) {
20292
20588
  function collectAllFiles(dir) {
20293
20589
  const files = [];
20294
20590
  try {
20295
- const entries2 = fs26.readdirSync(dir, { withFileTypes: true });
20591
+ const entries2 = fs27.readdirSync(dir, { withFileTypes: true });
20296
20592
  for (const entry of entries2) {
20297
20593
  if (shouldExclude(entry.name)) continue;
20298
- const fullPath = path28.join(dir, entry.name);
20594
+ const fullPath = path29.join(dir, entry.name);
20299
20595
  try {
20300
- if (fs26.lstatSync(fullPath).isSymbolicLink()) continue;
20596
+ if (fs27.lstatSync(fullPath).isSymbolicLink()) continue;
20301
20597
  } catch {
20302
20598
  }
20303
20599
  if (entry.isDirectory()) {
@@ -20312,16 +20608,16 @@ function collectAllFiles(dir) {
20312
20608
  }
20313
20609
  function readMainEngineUuid(agentsDir) {
20314
20610
  try {
20315
- const platformMapPath = path28.join(agentsDir, "main", "sessions", "platform-map.json");
20316
- const indexMapPath = path28.join(agentsDir, "main", "sessions", "session-index.json");
20317
- if (!fs26.existsSync(platformMapPath) || !fs26.existsSync(indexMapPath)) return null;
20318
- const platformMap = JSON.parse(fs26.readFileSync(platformMapPath, "utf-8"));
20611
+ const platformMapPath = path29.join(agentsDir, "main", "sessions", "platform-map.json");
20612
+ const indexMapPath = path29.join(agentsDir, "main", "sessions", "session-index.json");
20613
+ if (!fs27.existsSync(platformMapPath) || !fs27.existsSync(indexMapPath)) return null;
20614
+ const platformMap = JSON.parse(fs27.readFileSync(platformMapPath, "utf-8"));
20319
20615
  const mainPlatformId = platformMap["scope:main"] || platformMap["main"];
20320
20616
  if (!mainPlatformId) return null;
20321
- const indexMap = JSON.parse(fs26.readFileSync(indexMapPath, "utf-8"));
20617
+ const indexMap = JSON.parse(fs27.readFileSync(indexMapPath, "utf-8"));
20322
20618
  const entry = indexMap[mainPlatformId];
20323
20619
  if (!entry || !entry.file) return null;
20324
- const basename8 = path28.basename(entry.file).replace(/\.jsonl$/, "");
20620
+ const basename8 = path29.basename(entry.file).replace(/\.jsonl$/, "");
20325
20621
  return basename8;
20326
20622
  } catch {
20327
20623
  return null;
@@ -20329,13 +20625,13 @@ function readMainEngineUuid(agentsDir) {
20329
20625
  }
20330
20626
  function collectRecentSessions(agentsDir, _days = 7) {
20331
20627
  const files = [];
20332
- if (!fs26.existsSync(agentsDir)) return files;
20628
+ if (!fs27.existsSync(agentsDir)) return files;
20333
20629
  const sessionGroups = /* @__PURE__ */ new Map();
20334
20630
  function scanSessionsDir(dir) {
20335
20631
  try {
20336
- const entries2 = fs26.readdirSync(dir, { withFileTypes: true });
20632
+ const entries2 = fs27.readdirSync(dir, { withFileTypes: true });
20337
20633
  for (const entry of entries2) {
20338
- const fullPath = path28.join(dir, entry.name);
20634
+ const fullPath = path29.join(dir, entry.name);
20339
20635
  if (entry.isDirectory()) {
20340
20636
  scanSessionsDir(fullPath);
20341
20637
  continue;
@@ -20359,7 +20655,7 @@ function collectRecentSessions(agentsDir, _days = 7) {
20359
20655
  if (entry.name.endsWith(".jsonl")) {
20360
20656
  group.jsonl = fullPath;
20361
20657
  } else {
20362
- const stat4 = fs26.statSync(fullPath);
20658
+ const stat4 = fs27.statSync(fullPath);
20363
20659
  group.archived.push({ file: fullPath, mtime: stat4.mtimeMs });
20364
20660
  }
20365
20661
  }
@@ -20378,37 +20674,37 @@ function collectRecentSessions(agentsDir, _days = 7) {
20378
20674
  }
20379
20675
  async function doExport(opts) {
20380
20676
  const { agentName, stateDir, note, dryRun: dryRun2 } = opts;
20381
- const workspace = (opts.workspace || path28.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
20382
- const engineHome = path28.join(os4.homedir(), ".engine7").replace(/[/\\]+$/, "");
20677
+ const workspace = (opts.workspace || path29.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
20678
+ const engineHome = path29.join(os4.homedir(), ".engine7").replace(/[/\\]+$/, "");
20383
20679
  console.log(`\u{1F4E6} engine7 export`);
20384
20680
  console.log(` agent: ${agentName}`);
20385
20681
  console.log(` state: ${stateDir}`);
20386
20682
  console.log(` workspace: ${workspace}`);
20387
- if (!fs26.existsSync(workspace)) {
20683
+ if (!fs27.existsSync(workspace)) {
20388
20684
  console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
20389
20685
  process.exit(1);
20390
20686
  }
20391
20687
  const dirs = { workspace, stateDir, engineHome };
20392
20688
  const wsFiles = collectFiles(workspace, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL);
20393
- const sessionFiles = collectRecentSessions(path28.join(stateDir, "agents"), 7);
20394
- const configsDir = path28.join(stateDir, "configs");
20689
+ const sessionFiles = collectRecentSessions(path29.join(stateDir, "agents"), 7);
20690
+ const configsDir = path29.join(stateDir, "configs");
20395
20691
  const configFiles = [];
20396
- if (fs26.existsSync(configsDir)) {
20692
+ if (fs27.existsSync(configsDir)) {
20397
20693
  for (const f of collectAllFiles(configsDir)) {
20398
- if (shouldExclude(path28.basename(f))) continue;
20694
+ if (shouldExclude(path29.basename(f))) continue;
20399
20695
  configFiles.push(f);
20400
20696
  }
20401
20697
  }
20402
20698
  const EVEROS_SKIP = /* @__PURE__ */ new Set([".tmp", ".lock", "import.log", "import_progress.json"]);
20403
- const everosDir = path28.join(stateDir, ".everos");
20699
+ const everosDir = path29.join(stateDir, ".everos");
20404
20700
  const everosFiles = [];
20405
- if (fs26.existsSync(everosDir)) {
20701
+ if (fs27.existsSync(everosDir)) {
20406
20702
  for (const f of collectAllFiles(everosDir)) {
20407
- if (EVEROS_SKIP.has(path28.basename(f))) continue;
20703
+ if (EVEROS_SKIP.has(path29.basename(f))) continue;
20408
20704
  everosFiles.push(f);
20409
20705
  }
20410
- const walFile = path28.join(everosDir, ".index", "sqlite", "system.db-wal");
20411
- if (fs26.existsSync(walFile) && fs26.statSync(walFile).size > 0) {
20706
+ const walFile = path29.join(everosDir, ".index", "sqlite", "system.db-wal");
20707
+ if (fs27.existsSync(walFile) && fs27.statSync(walFile).size > 0) {
20412
20708
  console.warn(`\u26A0\uFE0F .everos/system.db-wal \u975E\u7A7A\u2014\u2014everos \u670D\u52A1\u53EF\u80FD\u6B63\u5728\u5199\u5165\uFF0C\u5FEB\u7167\u53EF\u80FD\u4E0D\u4E00\u81F4`);
20413
20709
  console.warn(` \u5EFA\u8BAE: \u5148\u505C everos \u670D\u52A1\u518D export\uFF0C\u6216 import \u540E\u91CD\u5EFA\u7D22\u5F15`);
20414
20710
  }
@@ -20416,16 +20712,16 @@ async function doExport(opts) {
20416
20712
  console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
20417
20713
  console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
20418
20714
  console.log(` configs: ${configFiles.length}`);
20419
- console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs26.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
20715
+ console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs27.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
20420
20716
  if (dryRun2) {
20421
20717
  console.log(`
20422
20718
  [DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
20423
- wsFiles.slice(0, 20).forEach((f) => console.log(` ${path28.relative(workspace, f)}`));
20719
+ wsFiles.slice(0, 20).forEach((f) => console.log(` ${path29.relative(workspace, f)}`));
20424
20720
  if (wsFiles.length > 20) console.log(` ... \u8FD8\u6709 ${wsFiles.length - 20} \u4E2A\u6587\u4EF6`);
20425
20721
  if (everosFiles.length > 0) {
20426
20722
  console.log(`
20427
20723
  [DRY RUN] everos (${everosFiles.length} \u6587\u4EF6):`);
20428
- everosFiles.slice(0, 10).forEach((f) => console.log(` ${path28.relative(stateDir, f)}`));
20724
+ everosFiles.slice(0, 10).forEach((f) => console.log(` ${path29.relative(stateDir, f)}`));
20429
20725
  if (everosFiles.length > 10) console.log(` ... \u8FD8\u6709 ${everosFiles.length - 10} \u4E2A\u6587\u4EF6`);
20430
20726
  }
20431
20727
  console.log(`
@@ -20434,46 +20730,46 @@ async function doExport(opts) {
20434
20730
  }
20435
20731
  const now = /* @__PURE__ */ new Date();
20436
20732
  const version = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
20437
- const tmpDir = path28.join(os4.tmpdir(), `engine7-export-${agentName}-${version}`);
20438
- fs26.mkdirSync(tmpDir, { recursive: true });
20439
- const stagingDir = path28.join(tmpDir, agentName);
20440
- fs26.mkdirSync(stagingDir, { recursive: true });
20733
+ const tmpDir = path29.join(os4.tmpdir(), `engine7-export-${agentName}-${version}`);
20734
+ fs27.mkdirSync(tmpDir, { recursive: true });
20735
+ const stagingDir = path29.join(tmpDir, agentName);
20736
+ fs27.mkdirSync(stagingDir, { recursive: true });
20441
20737
  let fileCount = 0;
20442
20738
  let totalSize = 0;
20443
20739
  let copyFail = 0;
20444
20740
  const copyOne = (srcFile, relRoot, destRoot) => {
20445
- const relPath = path28.relative(relRoot, srcFile);
20446
- const destFile = path28.join(destRoot, relPath);
20447
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20741
+ const relPath = path29.relative(relRoot, srcFile);
20742
+ const destFile = path29.join(destRoot, relPath);
20743
+ fs27.mkdirSync(path29.dirname(destFile), { recursive: true });
20448
20744
  try {
20449
20745
  if (isTextFile(srcFile)) {
20450
- const content = fs26.readFileSync(srcFile, "utf-8");
20451
- fs26.writeFileSync(destFile, sanitizeContent(content, dirs));
20746
+ const content = fs27.readFileSync(srcFile, "utf-8");
20747
+ fs27.writeFileSync(destFile, sanitizeContent(content, dirs));
20452
20748
  } else {
20453
- fs26.copyFileSync(srcFile, destFile);
20749
+ fs27.copyFileSync(srcFile, destFile);
20454
20750
  }
20455
20751
  fileCount++;
20456
- totalSize += fs26.statSync(srcFile).size;
20752
+ totalSize += fs27.statSync(srcFile).size;
20457
20753
  } catch (e) {
20458
20754
  copyFail++;
20459
20755
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
20460
20756
  }
20461
20757
  };
20462
- for (const srcFile of wsFiles) copyOne(srcFile, workspace, path28.join(stagingDir, "workspace"));
20758
+ for (const srcFile of wsFiles) copyOne(srcFile, workspace, path29.join(stagingDir, "workspace"));
20463
20759
  for (const srcFile of sessionFiles) {
20464
- const relPath = path28.relative(stateDir, srcFile);
20465
- const destFile = path28.join(stagingDir, relPath);
20466
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20760
+ const relPath = path29.relative(stateDir, srcFile);
20761
+ const destFile = path29.join(stagingDir, relPath);
20762
+ fs27.mkdirSync(path29.dirname(destFile), { recursive: true });
20467
20763
  try {
20468
- let content = fs26.readFileSync(srcFile, "utf-8");
20764
+ let content = fs27.readFileSync(srcFile, "utf-8");
20469
20765
  content = sanitizeContent(content, dirs);
20470
- const baseName = path28.basename(srcFile);
20766
+ const baseName = path29.basename(srcFile);
20471
20767
  if (baseName === "session-index.json" || baseName === "platform-map.json") {
20472
20768
  content = content.split("\\\\").join("/");
20473
20769
  }
20474
- fs26.writeFileSync(destFile, content);
20770
+ fs27.writeFileSync(destFile, content);
20475
20771
  fileCount++;
20476
- totalSize += fs26.statSync(srcFile).size;
20772
+ totalSize += fs27.statSync(srcFile).size;
20477
20773
  } catch (e) {
20478
20774
  copyFail++;
20479
20775
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
@@ -20495,13 +20791,13 @@ async function doExport(opts) {
20495
20791
  totalSize,
20496
20792
  note
20497
20793
  };
20498
- fs26.writeFileSync(path28.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
20499
- const archiveFile = path28.join(tmpDir, `${agentName}-${version}.tar.gz`);
20794
+ fs27.writeFileSync(path29.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
20795
+ const archiveFile = path29.join(tmpDir, `${agentName}-${version}.tar.gz`);
20500
20796
  console.log(`
20501
20797
  \u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
20502
20798
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
20503
20799
  execSync2(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
20504
- const archiveSize = fs26.statSync(archiveFile).size;
20800
+ const archiveSize = fs27.statSync(archiveFile).size;
20505
20801
  console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6${copyFail ? `, \u5931\u8D25 ${copyFail}` : ""})`);
20506
20802
  const cfg = loadTravelConfig();
20507
20803
  if (!cfg || !cfg.githubToken) {
@@ -20524,8 +20820,8 @@ async function doImport(opts) {
20524
20820
  console.error(` \u914D\u7F6E: \u7F16\u8F91 ${CONFIG_PATH}`);
20525
20821
  process.exit(1);
20526
20822
  }
20527
- const tmpDir = path28.join(os4.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
20528
- fs26.mkdirSync(tmpDir, { recursive: true });
20823
+ const tmpDir = path29.join(os4.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
20824
+ fs27.mkdirSync(tmpDir, { recursive: true });
20529
20825
  const archiveFile = await downloadFromGitHub(cfg, agentName, version, tmpDir);
20530
20826
  console.log(`\u2705 \u4E0B\u8F7D\u5B8C\u6210: ${archiveFile}`);
20531
20827
  if (dryRun2) {
@@ -20536,99 +20832,99 @@ async function doImport(opts) {
20536
20832
  console.log(`\u{1F4C2} \u89E3\u5305\u4E2D...`);
20537
20833
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
20538
20834
  execSync2(`"${tarExe}" -xzf "${archiveFile}" -C "${tmpDir}"`, { stdio: "pipe" });
20539
- const stagingDir = path28.join(tmpDir, agentName);
20540
- const manifestPath = path28.join(stagingDir, "manifest.json");
20541
- if (!fs26.existsSync(manifestPath)) {
20835
+ const stagingDir = path29.join(tmpDir, agentName);
20836
+ const manifestPath = path29.join(stagingDir, "manifest.json");
20837
+ if (!fs27.existsSync(manifestPath)) {
20542
20838
  console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
20543
20839
  process.exit(1);
20544
20840
  }
20545
- const manifest = JSON.parse(fs26.readFileSync(manifestPath, "utf-8"));
20546
- const workspace = path28.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
20547
- const engineHome = path28.join(os4.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
20841
+ const manifest = JSON.parse(fs27.readFileSync(manifestPath, "utf-8"));
20842
+ const workspace = path29.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
20843
+ const engineHome = path29.join(os4.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
20548
20844
  const dirs = { workspace, stateDir: stateDir.replace(/\\/g, "/").replace(/[/\\]+$/, ""), engineHome };
20549
20845
  console.log(` \u7248\u672C: ${manifest.version}`);
20550
20846
  console.log(` \u521B\u5EFA: ${manifest.createdAt}`);
20551
20847
  console.log(` \u6587\u4EF6\u6570: ${manifest.fileCount}`);
20552
- const wsStaging = path28.join(stagingDir, "workspace");
20848
+ const wsStaging = path29.join(stagingDir, "workspace");
20553
20849
  let restoredCount = 0;
20554
20850
  let skipCount = 0;
20555
- if (fs26.existsSync(wsStaging)) {
20851
+ if (fs27.existsSync(wsStaging)) {
20556
20852
  const allFiles = collectAllFiles(wsStaging);
20557
20853
  for (const srcFile of allFiles) {
20558
- const relPath = path28.relative(wsStaging, srcFile);
20559
- const destFile = path28.join(workspace, relPath);
20560
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20854
+ const relPath = path29.relative(wsStaging, srcFile);
20855
+ const destFile = path29.join(workspace, relPath);
20856
+ fs27.mkdirSync(path29.dirname(destFile), { recursive: true });
20561
20857
  try {
20562
20858
  if (isTextFile(srcFile)) {
20563
- const content = fs26.readFileSync(srcFile, "utf-8");
20564
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20859
+ const content = fs27.readFileSync(srcFile, "utf-8");
20860
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20565
20861
  } else {
20566
- fs26.copyFileSync(srcFile, destFile);
20862
+ fs27.copyFileSync(srcFile, destFile);
20567
20863
  }
20568
20864
  restoredCount++;
20569
20865
  } catch (e) {
20570
20866
  skipCount++;
20571
- console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path28.relative(wsStaging, srcFile)} (${e.code || e.message})`);
20867
+ console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path29.relative(wsStaging, srcFile)} (${e.code || e.message})`);
20572
20868
  }
20573
20869
  }
20574
20870
  }
20575
- const agentsStaging = path28.join(stagingDir, "agents");
20576
- if (fs26.existsSync(agentsStaging)) {
20871
+ const agentsStaging = path29.join(stagingDir, "agents");
20872
+ if (fs27.existsSync(agentsStaging)) {
20577
20873
  const sessionFiles = collectAllFiles(agentsStaging);
20578
20874
  for (const srcFile of sessionFiles) {
20579
- const relPath = path28.relative(stagingDir, srcFile);
20580
- const destFile = path28.join(stateDir, relPath);
20581
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20582
- const content = fs26.readFileSync(srcFile, "utf-8");
20583
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20875
+ const relPath = path29.relative(stagingDir, srcFile);
20876
+ const destFile = path29.join(stateDir, relPath);
20877
+ fs27.mkdirSync(path29.dirname(destFile), { recursive: true });
20878
+ const content = fs27.readFileSync(srcFile, "utf-8");
20879
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20584
20880
  restoredCount++;
20585
20881
  }
20586
20882
  }
20587
- const configsStaging = path28.join(stagingDir, "configs");
20588
- if (fs26.existsSync(configsStaging)) {
20883
+ const configsStaging = path29.join(stagingDir, "configs");
20884
+ if (fs27.existsSync(configsStaging)) {
20589
20885
  const cfgFiles = collectAllFiles(configsStaging);
20590
20886
  for (const srcFile of cfgFiles) {
20591
- const relPath = path28.relative(stagingDir, srcFile);
20592
- const destFile = path28.join(stateDir, relPath);
20593
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20887
+ const relPath = path29.relative(stagingDir, srcFile);
20888
+ const destFile = path29.join(stateDir, relPath);
20889
+ fs27.mkdirSync(path29.dirname(destFile), { recursive: true });
20594
20890
  if (isTextFile(srcFile)) {
20595
- const content = fs26.readFileSync(srcFile, "utf-8");
20596
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20891
+ const content = fs27.readFileSync(srcFile, "utf-8");
20892
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20597
20893
  } else {
20598
- fs26.copyFileSync(srcFile, destFile);
20894
+ fs27.copyFileSync(srcFile, destFile);
20599
20895
  }
20600
20896
  restoredCount++;
20601
20897
  }
20602
20898
  }
20603
- const everosStaging = path28.join(stagingDir, ".everos");
20604
- if (fs26.existsSync(everosStaging)) {
20899
+ const everosStaging = path29.join(stagingDir, ".everos");
20900
+ if (fs27.existsSync(everosStaging)) {
20605
20901
  const everosFiles = collectAllFiles(everosStaging);
20606
20902
  for (const srcFile of everosFiles) {
20607
- const relPath = path28.relative(stagingDir, srcFile);
20608
- const destFile = path28.join(stateDir, relPath);
20609
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20903
+ const relPath = path29.relative(stagingDir, srcFile);
20904
+ const destFile = path29.join(stateDir, relPath);
20905
+ fs27.mkdirSync(path29.dirname(destFile), { recursive: true });
20610
20906
  try {
20611
20907
  if (isTextFile(srcFile)) {
20612
- const content = fs26.readFileSync(srcFile, "utf-8");
20613
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20908
+ const content = fs27.readFileSync(srcFile, "utf-8");
20909
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20614
20910
  } else {
20615
- fs26.copyFileSync(srcFile, destFile);
20911
+ fs27.copyFileSync(srcFile, destFile);
20616
20912
  }
20617
20913
  restoredCount++;
20618
20914
  } catch (e) {
20619
20915
  skipCount++;
20620
- console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path28.relative(everosStaging, srcFile)} (${e.code || e.message})`);
20916
+ console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path29.relative(everosStaging, srcFile)} (${e.code || e.message})`);
20621
20917
  }
20622
20918
  }
20623
20919
  console.log(` everos: ${everosFiles.length} \u6587\u4EF6\u5DF2\u6062\u590D`);
20624
20920
  }
20625
20921
  console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}${skipCount ? ` (\u8DF3\u8FC7 ${skipCount})` : ""}`);
20626
20922
  const platformConfigName = process.platform === "darwin" ? "xiaoke-mac.json" : "xiaoke-win.json";
20627
- const restoredConfigPath = path28.join(stateDir, "configs", platformConfigName);
20628
- const configToUse = fs26.existsSync(restoredConfigPath) ? restoredConfigPath : path28.join(stateDir, "configs", "xiaoke.json");
20923
+ const restoredConfigPath = path29.join(stateDir, "configs", platformConfigName);
20924
+ const configToUse = fs27.existsSync(restoredConfigPath) ? restoredConfigPath : path29.join(stateDir, "configs", "xiaoke.json");
20629
20925
  console.log(`
20630
20926
  \u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config "${configToUse}"`);
20631
- fs26.rmSync(tmpDir, { recursive: true, force: true });
20927
+ fs27.rmSync(tmpDir, { recursive: true, force: true });
20632
20928
  }
20633
20929
  async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
20634
20930
  const repo = `${cfg.githubOwner}/${cfg.repoName}`;
@@ -20658,8 +20954,8 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
20658
20954
  }
20659
20955
  const release2 = await createRes.json();
20660
20956
  const uploadUrl = release2.upload_url.replace("{?name,label}", "");
20661
- const fileBuffer = fs26.readFileSync(archiveFile);
20662
- const fileName = path28.basename(archiveFile);
20957
+ const fileBuffer = fs27.readFileSync(archiveFile);
20958
+ const fileName = path29.basename(archiveFile);
20663
20959
  const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
20664
20960
  method: "POST",
20665
20961
  headers: {
@@ -20682,7 +20978,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
20682
20978
  throw e;
20683
20979
  }
20684
20980
  try {
20685
- fs26.rmSync(path28.dirname(archiveFile), { recursive: true, force: true });
20981
+ fs27.rmSync(path29.dirname(archiveFile), { recursive: true, force: true });
20686
20982
  } catch {
20687
20983
  }
20688
20984
  }
@@ -20714,8 +21010,8 @@ async function downloadFromGitHub(cfg, agentName, version, destDir) {
20714
21010
  throw new Error(`\u4E0B\u8F7D asset \u5931\u8D25: ${downloadRes.status}`);
20715
21011
  }
20716
21012
  const buffer = Buffer.from(await downloadRes.arrayBuffer());
20717
- const archiveFile = path28.join(destDir, asset.name);
20718
- fs26.writeFileSync(archiveFile, buffer);
21013
+ const archiveFile = path29.join(destDir, asset.name);
21014
+ fs27.writeFileSync(archiveFile, buffer);
20719
21015
  return archiveFile;
20720
21016
  }
20721
21017
  async function getLatestReleaseTag(cfg, agentName) {
@@ -20740,7 +21036,7 @@ var CONFIG_PATH, PATH_PLACEHOLDERS, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL, WORKS
20740
21036
  var init_cli_travel = __esm({
20741
21037
  "src/cli-travel.ts"() {
20742
21038
  "use strict";
20743
- CONFIG_PATH = path28.join(os4.homedir(), ".engine7-travel.json");
21039
+ CONFIG_PATH = path29.join(os4.homedir(), ".engine7-travel.json");
20744
21040
  PATH_PLACEHOLDERS = [
20745
21041
  { placeholder: "{{WORKSPACE}}", getOriginal: (d) => d.workspace },
20746
21042
  { placeholder: "{{ENGINE_HOME}}", getOriginal: (d) => d.engineHome },
@@ -20816,8 +21112,8 @@ var init_cli_travel = __esm({
20816
21112
  init_feishu_quick_register();
20817
21113
  init_wechat();
20818
21114
  init_qr_render();
20819
- import * as path29 from "node:path";
20820
- import * as fs27 from "node:fs";
21115
+ import * as path30 from "node:path";
21116
+ import * as fs28 from "node:fs";
20821
21117
  import * as readline3 from "node:readline";
20822
21118
  import { fileURLToPath } from "node:url";
20823
21119
  var origEmitWarning = process.emitWarning.bind(process);
@@ -20828,7 +21124,7 @@ process.emitWarning = (warning, ...rest) => {
20828
21124
  return origEmitWarning(warning, ...rest);
20829
21125
  };
20830
21126
  var __filename = fileURLToPath(import.meta.url);
20831
- var __dirname = path29.dirname(__filename);
21127
+ var __dirname = path30.dirname(__filename);
20832
21128
  var SCHEMA_VERSION = 1;
20833
21129
  function parseArgs() {
20834
21130
  const args = process.argv.slice(2);
@@ -20853,10 +21149,10 @@ function parseArgs() {
20853
21149
  }
20854
21150
  }
20855
21151
  if (!stateDir) {
20856
- stateDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21152
+ stateDir = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
20857
21153
  console.log(` \u4F7F\u7528\u9ED8\u8BA4\u76EE\u5F55: ${stateDir}`);
20858
21154
  }
20859
- stateDir = path29.resolve(stateDir);
21155
+ stateDir = path30.resolve(stateDir);
20860
21156
  return { stateDir, quick, dryRun: dryRun2, force };
20861
21157
  }
20862
21158
  function printHelp() {
@@ -20957,10 +21253,10 @@ function getDefaultValues(stateDir) {
20957
21253
  };
20958
21254
  }
20959
21255
  function loadExistingValues(stateDir) {
20960
- const configPath = path29.join(stateDir, "configs", "main7.json");
21256
+ const configPath = path30.join(stateDir, "configs", "main7.json");
20961
21257
  try {
20962
- if (!fs27.existsSync(configPath)) return {};
20963
- const j = JSON.parse(fs27.readFileSync(configPath, "utf8"));
21258
+ if (!fs28.existsSync(configPath)) return {};
21259
+ const j = JSON.parse(fs28.readFileSync(configPath, "utf8"));
20964
21260
  const out = {};
20965
21261
  if (j.agents?.defaults?.name) out.agentName = j.agents.defaults.name;
20966
21262
  const providers = j.models?.providers || {};
@@ -21015,15 +21311,15 @@ function loadExistingValues(stateDir) {
21015
21311
  }
21016
21312
  function readSecretsValue(stateDir, envName) {
21017
21313
  try {
21018
- const secretsDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
21019
- const cfgBase = path29.basename(stateDir) === ".engine7" ? "main7" : path29.basename(stateDir);
21314
+ const secretsDir = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
21315
+ const cfgBase = path30.basename(stateDir) === ".engine7" ? "main7" : path30.basename(stateDir);
21020
21316
  const candidates = [
21021
- path29.join(secretsDir, `${cfgBase}.env`),
21022
- path29.join(stateDir, "configs", `.env.${cfgBase}`)
21317
+ path30.join(secretsDir, `${cfgBase}.env`),
21318
+ path30.join(stateDir, "configs", `.env.${cfgBase}`)
21023
21319
  ];
21024
21320
  for (const p of candidates) {
21025
- if (fs27.existsSync(p)) {
21026
- for (const line of fs27.readFileSync(p, "utf8").split("\n")) {
21321
+ if (fs28.existsSync(p)) {
21322
+ for (const line of fs28.readFileSync(p, "utf8").split("\n")) {
21027
21323
  const eq = line.indexOf("=");
21028
21324
  if (eq > 0 && line.slice(0, eq).trim() === envName) {
21029
21325
  return line.slice(eq + 1).trim();
@@ -21249,7 +21545,7 @@ async function configureWechat(rl, v) {
21249
21545
  }
21250
21546
  }
21251
21547
  function generateConfig(v) {
21252
- const workspace = path29.join(v.stateDir, "workspace").replace(/\\/g, "/");
21548
+ const workspace = path30.join(v.stateDir, "workspace").replace(/\\/g, "/");
21253
21549
  const config = {
21254
21550
  schemaVersion: SCHEMA_VERSION,
21255
21551
  stateDir: v.stateDir.replace(/\\/g, "/"),
@@ -21399,45 +21695,45 @@ function generateConfig(v) {
21399
21695
  }
21400
21696
  function buildDirTree(v) {
21401
21697
  const d = v.stateDir;
21402
- const w = path29.join(d, "workspace");
21698
+ const w = path30.join(d, "workspace");
21403
21699
  const now = (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false });
21404
21700
  return [
21405
21701
  // 目录
21406
- { path: path29.join(d, "configs"), type: "dir" },
21407
- { path: path29.join(d, "state", "agents", "main", "sessions"), type: "dir" },
21408
- { path: path29.join(w, "prompts"), type: "dir" },
21409
- { path: path29.join(w, "memory", "daily"), type: "dir" },
21410
- { path: path29.join(w, "docs", "research"), type: "dir" },
21411
- { path: path29.join(w, "docs", "todo"), type: "dir" },
21412
- { path: path29.join(w, "docs", "decisions"), type: "dir" },
21413
- { path: path29.join(w, "docs", "knowledge"), type: "dir" },
21414
- { path: path29.join(w, "docs", "sop"), type: "dir" },
21415
- { path: path29.join(d, "logs"), type: "dir" },
21416
- { path: path29.join(d, "media", "inbound"), type: "dir" },
21702
+ { path: path30.join(d, "configs"), type: "dir" },
21703
+ { path: path30.join(d, "state", "agents", "main", "sessions"), type: "dir" },
21704
+ { path: path30.join(w, "prompts"), type: "dir" },
21705
+ { path: path30.join(w, "memory", "daily"), type: "dir" },
21706
+ { path: path30.join(w, "docs", "research"), type: "dir" },
21707
+ { path: path30.join(w, "docs", "todo"), type: "dir" },
21708
+ { path: path30.join(w, "docs", "decisions"), type: "dir" },
21709
+ { path: path30.join(w, "docs", "knowledge"), type: "dir" },
21710
+ { path: path30.join(w, "docs", "sop"), type: "dir" },
21711
+ { path: path30.join(d, "logs"), type: "dir" },
21712
+ { path: path30.join(d, "media", "inbound"), type: "dir" },
21417
21713
  // workspace 文件
21418
21714
  {
21419
- path: path29.join(w, "SESSION-STATE.md"),
21715
+ path: path30.join(w, "SESSION-STATE.md"),
21420
21716
  type: "file",
21421
21717
  content: readTemplate("workspace/SESSION-STATE.md").replace("{{CURRENT_TIME}}", now)
21422
21718
  },
21423
- { path: path29.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
21719
+ { path: path30.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
21424
21720
  {
21425
- path: path29.join(w, "SOUL.md"),
21721
+ path: path30.join(w, "SOUL.md"),
21426
21722
  type: "file",
21427
21723
  content: readTemplate("workspace/SOUL.md").replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
21428
21724
  },
21429
- { path: path29.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
21725
+ { path: path30.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
21430
21726
  {
21431
- path: path29.join(w, "prompts", "contacts.md"),
21727
+ path: path30.join(w, "prompts", "contacts.md"),
21432
21728
  type: "file",
21433
21729
  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")
21434
21730
  },
21435
- { path: path29.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
21436
- { path: path29.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" },
21437
- { path: path29.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" },
21731
+ { path: path30.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
21732
+ { path: path30.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" },
21733
+ { path: path30.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" },
21438
21734
  // package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
21439
21735
  {
21440
- path: path29.join(d, "package.json"),
21736
+ path: path30.join(d, "package.json"),
21441
21737
  type: "file",
21442
21738
  content: JSON.stringify({
21443
21739
  name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
@@ -21448,7 +21744,7 @@ function buildDirTree(v) {
21448
21744
  },
21449
21745
  // 启动脚本(根据 OS 生成)
21450
21746
  ...process.platform === "win32" ? [{
21451
- path: path29.join(d, "start.cmd"),
21747
+ path: path30.join(d, "start.cmd"),
21452
21748
  type: "file",
21453
21749
  content: `@echo off
21454
21750
  rem Engine 7 startup script
@@ -21480,7 +21776,7 @@ if %ERRORLEVEL% NEQ 0 (
21480
21776
  )
21481
21777
  `
21482
21778
  }] : [{
21483
- path: path29.join(d, "start.sh"),
21779
+ path: path30.join(d, "start.sh"),
21484
21780
  type: "file",
21485
21781
  content: `#!/bin/bash
21486
21782
  # Engine 7 startup script
@@ -21513,13 +21809,13 @@ node "$ENGINE7_BIN" --engine-config configs/main7.json
21513
21809
  }
21514
21810
  function readTemplate(relativePath) {
21515
21811
  const candidates = [
21516
- path29.join(__dirname, "..", "templates", relativePath),
21517
- path29.join(__dirname, "..", "..", "templates", relativePath),
21518
- path29.join(process.cwd(), "templates", relativePath)
21812
+ path30.join(__dirname, "..", "templates", relativePath),
21813
+ path30.join(__dirname, "..", "..", "templates", relativePath),
21814
+ path30.join(process.cwd(), "templates", relativePath)
21519
21815
  ];
21520
21816
  for (const p of candidates) {
21521
- if (fs27.existsSync(p)) {
21522
- return fs27.readFileSync(p, "utf-8");
21817
+ if (fs28.existsSync(p)) {
21818
+ return fs28.readFileSync(p, "utf-8");
21523
21819
  }
21524
21820
  }
21525
21821
  throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
@@ -21534,11 +21830,11 @@ function dryRun(entries2) {
21534
21830
  function execute(entries2) {
21535
21831
  for (const e of entries2) {
21536
21832
  if (e.type === "dir") {
21537
- fs27.mkdirSync(e.path, { recursive: true });
21833
+ fs28.mkdirSync(e.path, { recursive: true });
21538
21834
  console.log(` \u{1F4C1} ${e.path}`);
21539
21835
  } else {
21540
- fs27.mkdirSync(path29.dirname(e.path), { recursive: true });
21541
- fs27.writeFileSync(e.path, e.content || "", "utf-8");
21836
+ fs28.mkdirSync(path30.dirname(e.path), { recursive: true });
21837
+ fs28.writeFileSync(e.path, e.content || "", "utf-8");
21542
21838
  console.log(` \u{1F4C4} ${e.path}`);
21543
21839
  }
21544
21840
  }
@@ -21572,8 +21868,8 @@ async function main() {
21572
21868
  if (subcommand === "--version" || subcommand === "-v") {
21573
21869
  let ver = "unknown";
21574
21870
  try {
21575
- const pkgPath = path29.join(path29.dirname(__filename), "..", "package.json");
21576
- ver = JSON.parse(fs27.readFileSync(pkgPath, "utf8")).version || "unknown";
21871
+ const pkgPath = path30.join(path30.dirname(__filename), "..", "package.json");
21872
+ ver = JSON.parse(fs28.readFileSync(pkgPath, "utf8")).version || "unknown";
21577
21873
  } catch {
21578
21874
  }
21579
21875
  console.log(`engine7 ${ver}`);
@@ -21591,18 +21887,18 @@ async function main() {
21591
21887
  else if (args[i] === "--config" && args[i + 1]) configName = args[++i].trim();
21592
21888
  }
21593
21889
  if (!stateDir) {
21594
- const cwd = path29.resolve(process.cwd());
21595
- if (fs27.existsSync(path29.join(cwd, "configs"))) {
21890
+ const cwd = path30.resolve(process.cwd());
21891
+ if (fs28.existsSync(path30.join(cwd, "configs"))) {
21596
21892
  stateDir = cwd;
21597
21893
  } else {
21598
- const pointer = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
21599
- if (fs27.existsSync(pointer)) {
21894
+ const pointer = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
21895
+ if (fs28.existsSync(pointer)) {
21600
21896
  try {
21601
- stateDir = JSON.parse(fs27.readFileSync(pointer, "utf8")).stateDir || "";
21897
+ stateDir = JSON.parse(fs28.readFileSync(pointer, "utf8")).stateDir || "";
21602
21898
  } catch {
21603
21899
  }
21604
21900
  }
21605
- if (!stateDir) stateDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21901
+ if (!stateDir) stateDir = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21606
21902
  }
21607
21903
  }
21608
21904
  if (!target && !isLegacyAddchannel) {
@@ -21622,12 +21918,12 @@ async function main() {
21622
21918
  process.exit(0);
21623
21919
  }
21624
21920
  if (channel === "channels") {
21625
- const configsDir = path29.join(stateDir, "configs");
21626
- if (fs27.existsSync(configsDir)) {
21627
- const files = fs27.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
21921
+ const configsDir = path30.join(stateDir, "configs");
21922
+ if (fs28.existsSync(configsDir)) {
21923
+ const files = fs28.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
21628
21924
  for (const f of files) {
21629
21925
  try {
21630
- const j = JSON.parse(fs27.readFileSync(path29.join(configsDir, f), "utf8"));
21926
+ const j = JSON.parse(fs28.readFileSync(path30.join(configsDir, f), "utf8"));
21631
21927
  if (!j.channels) continue;
21632
21928
  console.log(`
21633
21929
  \u{1F4C4} ${f}:`);
@@ -21673,14 +21969,14 @@ async function main() {
21673
21969
  console.error("\u274C \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25");
21674
21970
  process.exit(1);
21675
21971
  }
21676
- const configsDir2 = path29.join(stateDir, "configs");
21677
- let configFile2 = configName ? path29.join(configsDir2, configName) : "";
21678
- if (!configFile2 || !fs27.existsSync(configFile2)) {
21679
- if (fs27.existsSync(configsDir2)) {
21680
- for (const f of fs27.readdirSync(configsDir2).filter((f2) => f2.endsWith(".json"))) {
21681
- const full = path29.join(configsDir2, f);
21972
+ const configsDir2 = path30.join(stateDir, "configs");
21973
+ let configFile2 = configName ? path30.join(configsDir2, configName) : "";
21974
+ if (!configFile2 || !fs28.existsSync(configFile2)) {
21975
+ if (fs28.existsSync(configsDir2)) {
21976
+ for (const f of fs28.readdirSync(configsDir2).filter((f2) => f2.endsWith(".json"))) {
21977
+ const full = path30.join(configsDir2, f);
21682
21978
  try {
21683
- if (JSON.parse(fs27.readFileSync(full, "utf8")).channels) {
21979
+ if (JSON.parse(fs28.readFileSync(full, "utf8")).channels) {
21684
21980
  configFile2 = full;
21685
21981
  break;
21686
21982
  }
@@ -21689,11 +21985,11 @@ async function main() {
21689
21985
  }
21690
21986
  }
21691
21987
  }
21692
- if (configFile2 && fs27.existsSync(configFile2)) {
21693
- const j = JSON.parse(fs27.readFileSync(configFile2, "utf8"));
21988
+ if (configFile2 && fs28.existsSync(configFile2)) {
21989
+ const j = JSON.parse(fs28.readFileSync(configFile2, "utf8"));
21694
21990
  j.channels = j.channels || {};
21695
21991
  j.channels.feishu = { enabled: true, appId: result2.appId, appSecret: result2.appSecret, connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" };
21696
- fs27.writeFileSync(configFile2, JSON.stringify(j, null, 2), "utf8");
21992
+ fs28.writeFileSync(configFile2, JSON.stringify(j, null, 2), "utf8");
21697
21993
  console.log("\u2705 \u98DE\u4E66\u901A\u9053\u5DF2\u5199\u5165: " + configFile2);
21698
21994
  console.log("\u91CD\u542F\u751F\u6548: engine7 restart");
21699
21995
  } else {
@@ -21711,16 +22007,16 @@ async function main() {
21711
22007
  console.error("\u274C \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25\uFF0C\u672A\u4FEE\u6539\u4EFB\u4F55\u914D\u7F6E");
21712
22008
  process.exit(1);
21713
22009
  }
21714
- const configsDir = path29.join(stateDir, "configs");
22010
+ const configsDir = path30.join(stateDir, "configs");
21715
22011
  let configFile = "";
21716
22012
  if (configName) {
21717
- configFile = path29.join(configsDir, configName);
21718
- } else if (fs27.existsSync(configsDir)) {
21719
- const candidates = fs27.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
22013
+ configFile = path30.join(configsDir, configName);
22014
+ } else if (fs28.existsSync(configsDir)) {
22015
+ const candidates = fs28.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
21720
22016
  for (const f of candidates) {
21721
- const full = path29.join(configsDir, f);
22017
+ const full = path30.join(configsDir, f);
21722
22018
  try {
21723
- const j2 = JSON.parse(fs27.readFileSync(full, "utf8"));
22019
+ const j2 = JSON.parse(fs28.readFileSync(full, "utf8"));
21724
22020
  if (j2.channels) {
21725
22021
  configFile = full;
21726
22022
  break;
@@ -21728,14 +22024,14 @@ async function main() {
21728
22024
  } catch {
21729
22025
  }
21730
22026
  }
21731
- if (!configFile && candidates.length) configFile = path29.join(configsDir, candidates[0]);
22027
+ if (!configFile && candidates.length) configFile = path30.join(configsDir, candidates[0]);
21732
22028
  }
21733
- if (!configFile || !fs27.existsSync(configFile)) {
22029
+ if (!configFile || !fs28.existsSync(configFile)) {
21734
22030
  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");
21735
22031
  console.log(JSON.stringify({ wechat: { enabled: true, token: cred.token, accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } } }, null, 2));
21736
22032
  process.exit(0);
21737
22033
  }
21738
- const j = JSON.parse(fs27.readFileSync(configFile, "utf8"));
22034
+ const j = JSON.parse(fs28.readFileSync(configFile, "utf8"));
21739
22035
  j.channels = j.channels || {};
21740
22036
  j.channels.wechat = {
21741
22037
  enabled: true,
@@ -21744,7 +22040,7 @@ async function main() {
21744
22040
  dmPolicy: "pairing",
21745
22041
  group: { policy: "disabled" }
21746
22042
  };
21747
- fs27.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
22043
+ fs28.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
21748
22044
  console.log(`
21749
22045
  \u2705 \u5FAE\u4FE1\u901A\u9053\u5DF2\u5199\u5165: ${configFile}`);
21750
22046
  console.log(` accountId: ${cred.accountId}`);
@@ -21772,8 +22068,8 @@ async function main() {
21772
22068
  else if (args[i] === "--note" && args[i + 1]) note = args[++i];
21773
22069
  else if (args[i] === "--dry-run") dryRun2 = true;
21774
22070
  }
21775
- if (!exportStateDir) exportStateDir = path29.resolve(process.cwd());
21776
- if (!agentName) agentName = path29.basename(exportStateDir);
22071
+ if (!exportStateDir) exportStateDir = path30.resolve(process.cwd());
22072
+ if (!agentName) agentName = path30.basename(exportStateDir);
21777
22073
  await doExport2({ agentName, stateDir: exportStateDir, note, dryRun: dryRun2 });
21778
22074
  process.exit(0);
21779
22075
  }
@@ -21793,7 +22089,7 @@ async function main() {
21793
22089
  console.error("\u274C import \u9700\u8981 --state-dir <path>");
21794
22090
  process.exit(1);
21795
22091
  }
21796
- if (!agentName) agentName = path29.basename(importStateDir);
22092
+ if (!agentName) agentName = path30.basename(importStateDir);
21797
22093
  await doImport2({ agentName, stateDir: importStateDir, version, dryRun: dryRun2 });
21798
22094
  process.exit(0);
21799
22095
  }
@@ -21818,18 +22114,18 @@ engine7 start \u2014 \u542F\u52A8 Engine
21818
22114
  }
21819
22115
  }
21820
22116
  if (!configPath2) {
21821
- const defaultCfg = path29.join("configs", "main7.json");
21822
- const homeCfg = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
21823
- if (fs27.existsSync(defaultCfg)) {
22117
+ const defaultCfg = path30.join("configs", "main7.json");
22118
+ const homeCfg = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
22119
+ if (fs28.existsSync(defaultCfg)) {
21824
22120
  configPath2 = defaultCfg;
21825
- } else if (fs27.existsSync(homeCfg)) {
22121
+ } else if (fs28.existsSync(homeCfg)) {
21826
22122
  configPath2 = homeCfg;
21827
22123
  console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
21828
22124
  } else {
21829
22125
  const ptr = readHomePointer();
21830
22126
  if (ptr?.stateDir) {
21831
- const ptrCfg = path29.join(ptr.stateDir, "configs", "main7.json");
21832
- if (fs27.existsSync(ptrCfg)) {
22127
+ const ptrCfg = path30.join(ptr.stateDir, "configs", "main7.json");
22128
+ if (fs28.existsSync(ptrCfg)) {
21833
22129
  configPath2 = ptrCfg;
21834
22130
  console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
21835
22131
  }
@@ -21844,19 +22140,19 @@ engine7 start \u2014 \u542F\u52A8 Engine
21844
22140
  }
21845
22141
  const { execSync: execSync3, spawn: spawn5 } = await import("node:child_process");
21846
22142
  let enginePath;
21847
- const localPath = path29.join("node_modules", "engine7", "dist", "main.mjs");
21848
- if (fs27.existsSync(localPath)) {
22143
+ const localPath = path30.join("node_modules", "engine7", "dist", "main.mjs");
22144
+ if (fs28.existsSync(localPath)) {
21849
22145
  enginePath = localPath;
21850
22146
  } else {
21851
- const cliPath = path29.resolve(process.argv[1]);
21852
- const distDir = path29.dirname(cliPath);
21853
- const candidate = path29.join(distDir, "main.mjs");
21854
- if (fs27.existsSync(candidate)) {
22147
+ const cliPath = path30.resolve(process.argv[1]);
22148
+ const distDir = path30.dirname(cliPath);
22149
+ const candidate = path30.join(distDir, "main.mjs");
22150
+ if (fs28.existsSync(candidate)) {
21855
22151
  enginePath = candidate;
21856
22152
  } else {
21857
22153
  try {
21858
22154
  const globalRoot = execSync3("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
21859
- enginePath = path29.join(globalRoot, "engine7", "dist", "main.mjs");
22155
+ enginePath = path30.join(globalRoot, "engine7", "dist", "main.mjs");
21860
22156
  } catch {
21861
22157
  console.error("\u274C \u627E\u4E0D\u5230 engine7 main.mjs");
21862
22158
  process.exit(1);
@@ -21866,7 +22162,7 @@ engine7 start \u2014 \u542F\u52A8 Engine
21866
22162
  console.log(label);
21867
22163
  console.log(` config: ${configPath2}`);
21868
22164
  console.log(` engine: ${enginePath}`);
21869
- const configName = path29.basename(configPath2);
22165
+ const configName = path30.basename(configPath2);
21870
22166
  const myPid = process.pid;
21871
22167
  try {
21872
22168
  if (process.platform === "win32") {
@@ -21884,16 +22180,16 @@ engine7 start \u2014 \u542F\u52A8 Engine
21884
22180
  }
21885
22181
  console.log("");
21886
22182
  const envForChild = { ...process.env };
21887
- const secretsDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
21888
- const cfgBase = path29.basename(configPath2, ".json");
22183
+ const secretsDir = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
22184
+ const cfgBase = path30.basename(configPath2, ".json");
21889
22185
  const secretCandidates = [
21890
- path29.join(secretsDir, `${cfgBase}.env`),
21891
- path29.join(path29.dirname(configPath2), `.env.${cfgBase}`),
21892
- path29.join(path29.dirname(configPath2), ".env")
22186
+ path30.join(secretsDir, `${cfgBase}.env`),
22187
+ path30.join(path30.dirname(configPath2), `.env.${cfgBase}`),
22188
+ path30.join(path30.dirname(configPath2), ".env")
21893
22189
  ];
21894
22190
  for (const secretPath of secretCandidates) {
21895
- if (fs27.existsSync(secretPath)) {
21896
- const content = fs27.readFileSync(secretPath, "utf-8");
22191
+ if (fs28.existsSync(secretPath)) {
22192
+ const content = fs28.readFileSync(secretPath, "utf-8");
21897
22193
  for (const line of content.split("\n")) {
21898
22194
  const trimmed = line.trim();
21899
22195
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -21968,14 +22264,14 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
21968
22264
  console.error(`\u274C \u672A\u77E5\u6A21\u5F0F: ${mode}\uFF08\u53EF\u9009: archive / drop-last / strip-images\uFF09`);
21969
22265
  process.exit(1);
21970
22266
  }
21971
- const configRaw = JSON.parse(fs27.readFileSync(configPath2, "utf-8"));
22267
+ const configRaw = JSON.parse(fs28.readFileSync(configPath2, "utf-8"));
21972
22268
  const stateDir = configRaw.stateDir;
21973
22269
  if (!stateDir) {
21974
22270
  console.error("\u274C config \u91CC\u6CA1\u6709 stateDir");
21975
22271
  process.exit(1);
21976
22272
  }
21977
- const sessionsDir = path29.join(stateDir, "agents", "main", "sessions");
21978
- if (!fs27.existsSync(sessionsDir)) {
22273
+ const sessionsDir = path30.join(stateDir, "agents", "main", "sessions");
22274
+ if (!fs28.existsSync(sessionsDir)) {
21979
22275
  console.error(`\u274C sessions \u76EE\u5F55\u4E0D\u5B58\u5728: ${sessionsDir}`);
21980
22276
  process.exit(1);
21981
22277
  }
@@ -21983,37 +22279,37 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
21983
22279
  console.log(` config: ${configPath2}`);
21984
22280
  console.log(` mode: ${mode}`);
21985
22281
  if (mode === "drop-last") console.log(` n: ${dropN}`);
21986
- const platformMapPath = path29.join(sessionsDir, "platform-map.json");
21987
- const indexPath = path29.join(sessionsDir, "session-index.json");
22282
+ const platformMapPath = path30.join(sessionsDir, "platform-map.json");
22283
+ const indexPath = path30.join(sessionsDir, "session-index.json");
21988
22284
  let sessionFileUUID = null;
21989
- if (fs27.existsSync(indexPath)) {
21990
- const index = JSON.parse(fs27.readFileSync(indexPath, "utf-8"));
22285
+ if (fs28.existsSync(indexPath)) {
22286
+ const index = JSON.parse(fs28.readFileSync(indexPath, "utf-8"));
21991
22287
  const entries2 = Object.values(index);
21992
22288
  if (entries2.length > 0) {
21993
22289
  const fileVal = entries2[0].file || "";
21994
- sessionFileUUID = path29.isAbsolute(fileVal) ? path29.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
22290
+ sessionFileUUID = path30.isAbsolute(fileVal) ? path30.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
21995
22291
  }
21996
22292
  }
21997
22293
  if (!sessionFileUUID) {
21998
- const jsonlFiles = fs27.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs27.statSync(path29.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
22294
+ const jsonlFiles = fs28.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs28.statSync(path30.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
21999
22295
  if (jsonlFiles.length === 0) {
22000
22296
  console.error("\u274C \u627E\u4E0D\u5230\u6D3B\u8DC3\u7684 session JSONL \u6587\u4EF6");
22001
22297
  process.exit(1);
22002
22298
  }
22003
22299
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
22004
22300
  }
22005
- let jsonlPath = path29.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22006
- if (!fs27.existsSync(jsonlPath)) {
22007
- const jsonlFiles = fs27.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs27.statSync(path29.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
22301
+ let jsonlPath = path30.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22302
+ if (!fs28.existsSync(jsonlPath)) {
22303
+ const jsonlFiles = fs28.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs28.statSync(path30.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
22008
22304
  if (jsonlFiles.length === 0) {
22009
22305
  console.error(`\u274C JSONL \u6587\u4EF6\u4E0D\u5B58\u5728: ${jsonlPath}`);
22010
22306
  process.exit(1);
22011
22307
  }
22012
22308
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
22013
- jsonlPath = path29.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22309
+ jsonlPath = path30.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22014
22310
  }
22015
22311
  console.log(` file: ${jsonlPath}`);
22016
- const configName = path29.basename(configPath2);
22312
+ const configName = path30.basename(configPath2);
22017
22313
  if (autoRestart) {
22018
22314
  try {
22019
22315
  const myPid = process.pid;
@@ -22029,10 +22325,10 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
22029
22325
  }
22030
22326
  }
22031
22327
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
22032
- const { readFileSync: readFileSync29, writeFileSync: writeFileSync20, renameSync: renameSync4 } = fs27;
22328
+ const { readFileSync: readFileSync29, writeFileSync: writeFileSync20, renameSync: renameSync5 } = fs28;
22033
22329
  if (mode === "archive") {
22034
22330
  const archiveName = `${sessionFileUUID}.jsonl.archived.${timestamp}`;
22035
- renameSync4(jsonlPath, path29.join(sessionsDir, archiveName));
22331
+ renameSync5(jsonlPath, path30.join(sessionsDir, archiveName));
22036
22332
  console.log(`
22037
22333
  \u2705 \u5F52\u6863\u5B8C\u6210: ${archiveName}`);
22038
22334
  console.log(` \u91CD\u542F\u540E\u5C06\u4ECE\u7A7A\u767D\u4F1A\u8BDD\u5F00\u59CB`);
@@ -22107,12 +22403,12 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
22107
22403
  \u2705 \u6458\u9664 ${stripped} \u884C\u56FE\u7247\u76F8\u5173\u5185\u5BB9`);
22108
22404
  }
22109
22405
  if (autoRestart) {
22110
- const realCliPath = fs27.realpathSync(process.argv[1]);
22111
- const cliDir = path29.dirname(realCliPath);
22112
- const pkgRoot = path29.resolve(cliDir, "..");
22113
- let enginePath = path29.join(pkgRoot, "dist", "main.mjs");
22114
- if (!fs27.existsSync(enginePath)) {
22115
- enginePath = path29.join(cliDir, "main.mjs");
22406
+ const realCliPath = fs28.realpathSync(process.argv[1]);
22407
+ const cliDir = path30.dirname(realCliPath);
22408
+ const pkgRoot = path30.resolve(cliDir, "..");
22409
+ let enginePath = path30.join(pkgRoot, "dist", "main.mjs");
22410
+ if (!fs28.existsSync(enginePath)) {
22411
+ enginePath = path30.join(cliDir, "main.mjs");
22116
22412
  }
22117
22413
  console.log(`
22118
22414
  \u{1F680} \u62C9\u8D77 engine...`);
@@ -22155,18 +22451,18 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
22155
22451
  else if (args[i] === "--cwd" && args[i + 1]) cwd = args[++i];
22156
22452
  }
22157
22453
  if (!configPath2) {
22158
- const defaultCfg = path29.join(cwd, "configs", "main7.json");
22159
- const homeCfg = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
22160
- if (fs27.existsSync(defaultCfg)) {
22454
+ const defaultCfg = path30.join(cwd, "configs", "main7.json");
22455
+ const homeCfg = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
22456
+ if (fs28.existsSync(defaultCfg)) {
22161
22457
  configPath2 = defaultCfg;
22162
- } else if (fs27.existsSync(homeCfg)) {
22458
+ } else if (fs28.existsSync(homeCfg)) {
22163
22459
  configPath2 = homeCfg;
22164
- cwd = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
22460
+ cwd = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
22165
22461
  } else {
22166
22462
  const ptr = readHomePointer();
22167
22463
  if (ptr?.stateDir) {
22168
- const ptrCfg = path29.join(ptr.stateDir, "configs", "main7.json");
22169
- if (fs27.existsSync(ptrCfg)) {
22464
+ const ptrCfg = path30.join(ptr.stateDir, "configs", "main7.json");
22465
+ if (fs28.existsSync(ptrCfg)) {
22170
22466
  configPath2 = ptrCfg;
22171
22467
  cwd = ptr.stateDir;
22172
22468
  }
@@ -22185,14 +22481,14 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
22185
22481
  if (process.platform === "win32") {
22186
22482
  const taskName = "Engine7";
22187
22483
  const nodeExe = process.execPath;
22188
- const cliMjs = path29.resolve(engine7Bin);
22189
- const absConfig = path29.resolve(configPath2);
22190
- const wrapperPath = path29.join(cwd, "engine7-start.cmd");
22484
+ const cliMjs = path30.resolve(engine7Bin);
22485
+ const absConfig = path30.resolve(configPath2);
22486
+ const wrapperPath = path30.join(cwd, "engine7-start.cmd");
22191
22487
  const wrapperContent = `@echo off\r
22192
22488
  cd /d "${cwd}"\r
22193
22489
  "${nodeExe}" "${cliMjs}" start --config "${absConfig}"\r
22194
22490
  `;
22195
- fs27.writeFileSync(wrapperPath, wrapperContent);
22491
+ fs28.writeFileSync(wrapperPath, wrapperContent);
22196
22492
  try {
22197
22493
  execSync3(`schtasks /create /tn "${taskName}" /tr "${wrapperPath}" /sc onlogon /rl highest /f`, { stdio: "inherit", shell: true });
22198
22494
  console.log(`\u2705 Windows \u8BA1\u5212\u4EFB\u52A1 "${taskName}" \u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
@@ -22203,11 +22499,11 @@ cd /d "${cwd}"\r
22203
22499
  }
22204
22500
  } else if (process.platform === "darwin") {
22205
22501
  const label = "com.engine7.agent";
22206
- const plistDir = path29.join(process.env.HOME, "Library", "LaunchAgents");
22207
- fs27.mkdirSync(plistDir, { recursive: true });
22208
- const plistPath = path29.join(plistDir, `${label}.plist`);
22209
- const localCli = path29.join("node_modules", "engine7", "dist", "cli.mjs");
22210
- const cliMjs = fs27.existsSync(localCli) ? path29.resolve(localCli) : path29.join(path29.dirname(path29.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
22502
+ const plistDir = path30.join(process.env.HOME, "Library", "LaunchAgents");
22503
+ fs28.mkdirSync(plistDir, { recursive: true });
22504
+ const plistPath = path30.join(plistDir, `${label}.plist`);
22505
+ const localCli = path30.join("node_modules", "engine7", "dist", "cli.mjs");
22506
+ const cliMjs = fs28.existsSync(localCli) ? path30.resolve(localCli) : path30.join(path30.dirname(path30.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
22211
22507
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
22212
22508
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
22213
22509
  <plist version="1.0">
@@ -22219,14 +22515,14 @@ cd /d "${cwd}"\r
22219
22515
  <string>${cliMjs}</string>
22220
22516
  <string>start</string>
22221
22517
  <string>--config</string>
22222
- <string>${path29.resolve(configPath2)}</string>
22518
+ <string>${path30.resolve(configPath2)}</string>
22223
22519
  </array>
22224
22520
  <key>WorkingDirectory</key><string>${cwd}</string>
22225
22521
  <key>RunAtLoad</key><true/>
22226
22522
  <key>KeepAlive</key><true/>
22227
22523
  </dict>
22228
22524
  </plist>`;
22229
- fs27.writeFileSync(plistPath, plist);
22525
+ fs28.writeFileSync(plistPath, plist);
22230
22526
  try {
22231
22527
  execSync3(`launchctl load "${plistPath}"`, { stdio: "inherit" });
22232
22528
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
@@ -22237,9 +22533,9 @@ cd /d "${cwd}"\r
22237
22533
  }
22238
22534
  } else {
22239
22535
  const svcName = "engine7";
22240
- const svcDir = path29.join(process.env.HOME, ".config", "systemd", "user");
22241
- fs27.mkdirSync(svcDir, { recursive: true });
22242
- const svcPath = path29.join(svcDir, `${svcName}.service`);
22536
+ const svcDir = path30.join(process.env.HOME, ".config", "systemd", "user");
22537
+ fs28.mkdirSync(svcDir, { recursive: true });
22538
+ const svcPath = path30.join(svcDir, `${svcName}.service`);
22243
22539
  const svc = `[Unit]
22244
22540
  Description=Engine 7 Agent
22245
22541
  After=network.target
@@ -22247,13 +22543,13 @@ After=network.target
22247
22543
  [Service]
22248
22544
  Type=simple
22249
22545
  WorkingDirectory=${cwd}
22250
- ExecStart=${process.execPath} ${engine7Bin} start --config ${path29.resolve(configPath2)}
22546
+ ExecStart=${process.execPath} ${engine7Bin} start --config ${path30.resolve(configPath2)}
22251
22547
  Restart=on-failure
22252
22548
  RestartSec=10
22253
22549
 
22254
22550
  [Install]
22255
22551
  WantedBy=default.target`;
22256
- fs27.writeFileSync(svcPath, svc);
22552
+ fs28.writeFileSync(svcPath, svc);
22257
22553
  try {
22258
22554
  execSync3(`systemctl --user daemon-reload`, { stdio: "inherit" });
22259
22555
  execSync3(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
@@ -22274,13 +22570,13 @@ WantedBy=default.target`;
22274
22570
  process.exit(1);
22275
22571
  }
22276
22572
  } else if (process.platform === "darwin") {
22277
- const plistPath = path29.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
22573
+ const plistPath = path30.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
22278
22574
  try {
22279
22575
  execSync3(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
22280
22576
  } catch {
22281
22577
  }
22282
22578
  try {
22283
- fs27.unlinkSync(plistPath);
22579
+ fs28.unlinkSync(plistPath);
22284
22580
  } catch {
22285
22581
  }
22286
22582
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
@@ -22289,9 +22585,9 @@ WantedBy=default.target`;
22289
22585
  execSync3(`systemctl --user disable engine7`, { stdio: "inherit" });
22290
22586
  } catch {
22291
22587
  }
22292
- const svcPath = path29.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
22588
+ const svcPath = path30.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
22293
22589
  try {
22294
- fs27.unlinkSync(svcPath);
22590
+ fs28.unlinkSync(svcPath);
22295
22591
  } catch {
22296
22592
  }
22297
22593
  try {
@@ -22308,8 +22604,8 @@ WantedBy=default.target`;
22308
22604
  console.log("\u274C \u672A\u5B89\u88C5");
22309
22605
  }
22310
22606
  } else if (process.platform === "darwin") {
22311
- const plistPath = path29.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
22312
- if (fs27.existsSync(plistPath)) {
22607
+ const plistPath = path30.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
22608
+ if (fs28.existsSync(plistPath)) {
22313
22609
  console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
22314
22610
  } else {
22315
22611
  console.log("\u274C \u672A\u5B89\u88C5");
@@ -22332,16 +22628,16 @@ WantedBy=default.target`;
22332
22628
  console.log(`
22333
22629
  \u{1F680} engine7 init`);
22334
22630
  console.log(` state-dir: ${opts.stateDir}`);
22335
- if (fs27.existsSync(opts.stateDir) && !opts.dryRun) {
22336
- const files = fs27.readdirSync(opts.stateDir);
22631
+ if (fs28.existsSync(opts.stateDir) && !opts.dryRun) {
22632
+ const files = fs28.readdirSync(opts.stateDir);
22337
22633
  if (files.length > 0) {
22338
22634
  if (opts.force) {
22339
22635
  console.log(`
22340
22636
  \u26A0\uFE0F --force: \u6E05\u7A7A\u5DF2\u6709\u76EE\u5F55 ${opts.stateDir}`);
22341
- fs27.rmSync(opts.stateDir, { recursive: true, force: true });
22637
+ fs28.rmSync(opts.stateDir, { recursive: true, force: true });
22342
22638
  } else {
22343
- const existingConfig = path29.join(opts.stateDir, "configs", "main7.json");
22344
- if (fs27.existsSync(existingConfig)) {
22639
+ const existingConfig = path30.join(opts.stateDir, "configs", "main7.json");
22640
+ if (fs28.existsSync(existingConfig)) {
22345
22641
  console.log(`
22346
22642
  \u267B\uFE0F \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E: ${existingConfig}`);
22347
22643
  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`);
@@ -22365,7 +22661,7 @@ WantedBy=default.target`;
22365
22661
  rl.close();
22366
22662
  }
22367
22663
  const config = generateConfig(values);
22368
- const configPath = path29.join(opts.stateDir, "configs", "main7.json");
22664
+ const configPath = path30.join(opts.stateDir, "configs", "main7.json");
22369
22665
  const tree = buildDirTree(values);
22370
22666
  tree.push({
22371
22667
  path: configPath,
@@ -22376,9 +22672,9 @@ WantedBy=default.target`;
22376
22672
  dryRun(tree);
22377
22673
  const skillsSrc = findTemplateDir("skills");
22378
22674
  if (skillsSrc) {
22379
- const skills = fs27.readdirSync(skillsSrc);
22675
+ const skills = fs28.readdirSync(skillsSrc);
22380
22676
  for (const s of skills) {
22381
- console.log(` \u{1F4C1} ${path29.join(opts.stateDir, "workspace", "skills", s)}`);
22677
+ console.log(` \u{1F4C1} ${path30.join(opts.stateDir, "workspace", "skills", s)}`);
22382
22678
  }
22383
22679
  }
22384
22680
  } else {
@@ -22386,16 +22682,16 @@ WantedBy=default.target`;
22386
22682
  execute(tree);
22387
22683
  if (values.primaryApiKey && values.primaryApiKey.trim()) {
22388
22684
  const envName = values.primaryProvider.toUpperCase().replace(/[^A-Z0-9_]/g, "_") + "_API_KEY";
22389
- const secretsDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
22390
- if (!fs27.existsSync(secretsDir)) fs27.mkdirSync(secretsDir, { recursive: true });
22391
- const envFile = path29.join(secretsDir, "main7.env");
22685
+ const secretsDir = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
22686
+ if (!fs28.existsSync(secretsDir)) fs28.mkdirSync(secretsDir, { recursive: true });
22687
+ const envFile = path30.join(secretsDir, "main7.env");
22392
22688
  let envContent = "";
22393
- if (fs27.existsSync(envFile)) envContent = fs27.readFileSync(envFile, "utf8");
22689
+ if (fs28.existsSync(envFile)) envContent = fs28.readFileSync(envFile, "utf8");
22394
22690
  const lines = envContent.split("\n").filter((l) => l && !l.startsWith(envName + "="));
22395
22691
  lines.push(envName + "=" + values.primaryApiKey.trim());
22396
- fs27.writeFileSync(envFile, lines.join("\n") + "\n", "utf8");
22692
+ fs28.writeFileSync(envFile, lines.join("\n") + "\n", "utf8");
22397
22693
  try {
22398
- fs27.chmodSync(envFile, 384);
22694
+ fs28.chmodSync(envFile, 384);
22399
22695
  } catch {
22400
22696
  }
22401
22697
  console.log("\u{1F511} API key \u5DF2\u5B58\u5165: " + envFile);
@@ -22403,55 +22699,55 @@ WantedBy=default.target`;
22403
22699
  }
22404
22700
  const skillsSrc = findTemplateDir("skills");
22405
22701
  if (skillsSrc) {
22406
- const skillsDest = path29.join(opts.stateDir, "workspace", "skills");
22407
- fs27.mkdirSync(skillsDest, { recursive: true });
22408
- const skills = fs27.readdirSync(skillsSrc);
22702
+ const skillsDest = path30.join(opts.stateDir, "workspace", "skills");
22703
+ fs28.mkdirSync(skillsDest, { recursive: true });
22704
+ const skills = fs28.readdirSync(skillsSrc);
22409
22705
  for (const s of skills) {
22410
- copyDirRecursive(path29.join(skillsSrc, s), path29.join(skillsDest, s));
22706
+ copyDirRecursive(path30.join(skillsSrc, s), path30.join(skillsDest, s));
22411
22707
  console.log(` \u{1F4E6} skill: ${s}`);
22412
22708
  }
22413
22709
  }
22414
22710
  console.log(`
22415
22711
  \u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
22416
22712
  `);
22417
- const homePointer = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
22713
+ const homePointer = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
22418
22714
  const pointerData = { stateDir: opts.stateDir };
22419
- fs27.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
22715
+ fs28.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
22420
22716
  console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
22421
22717
  console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
22422
22718
  console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
22423
22719
  console.log(` 2. \u542F\u52A8 Engine: engine7 start\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
22424
22720
  console.log(` 3. \u5F00\u673A\u81EA\u542F: engine7 service install\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
22425
- console.log(` 4. \u67E5\u770B workspace: ${path29.join(opts.stateDir, "workspace")}`);
22721
+ console.log(` 4. \u67E5\u770B workspace: ${path30.join(opts.stateDir, "workspace")}`);
22426
22722
  }
22427
22723
  }
22428
22724
  function copyDirRecursive(src, dest) {
22429
- fs27.mkdirSync(dest, { recursive: true });
22430
- for (const entry of fs27.readdirSync(src, { withFileTypes: true })) {
22431
- const srcPath = path29.join(src, entry.name);
22432
- const destPath = path29.join(dest, entry.name);
22725
+ fs28.mkdirSync(dest, { recursive: true });
22726
+ for (const entry of fs28.readdirSync(src, { withFileTypes: true })) {
22727
+ const srcPath = path30.join(src, entry.name);
22728
+ const destPath = path30.join(dest, entry.name);
22433
22729
  if (entry.isDirectory()) {
22434
22730
  copyDirRecursive(srcPath, destPath);
22435
22731
  } else {
22436
- fs27.copyFileSync(srcPath, destPath);
22732
+ fs28.copyFileSync(srcPath, destPath);
22437
22733
  }
22438
22734
  }
22439
22735
  }
22440
22736
  function findTemplateDir(name) {
22441
22737
  const candidates = [
22442
- path29.join(__dirname, "..", "templates", name),
22443
- path29.join(__dirname, "..", "..", "templates", name),
22444
- path29.join(process.cwd(), "templates", name)
22738
+ path30.join(__dirname, "..", "templates", name),
22739
+ path30.join(__dirname, "..", "..", "templates", name),
22740
+ path30.join(process.cwd(), "templates", name)
22445
22741
  ];
22446
22742
  for (const p of candidates) {
22447
- if (fs27.existsSync(p)) return p;
22743
+ if (fs28.existsSync(p)) return p;
22448
22744
  }
22449
22745
  return null;
22450
22746
  }
22451
22747
  function readHomePointer() {
22452
- const ptrPath = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
22748
+ const ptrPath = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
22453
22749
  try {
22454
- return JSON.parse(fs27.readFileSync(ptrPath, "utf-8"));
22750
+ return JSON.parse(fs28.readFileSync(ptrPath, "utf-8"));
22455
22751
  } catch {
22456
22752
  return null;
22457
22753
  }
@@ -22462,4 +22758,3 @@ main().catch((err) => {
22462
22758
  console.error(err.stack);
22463
22759
  process.exit(1);
22464
22760
  });
22465
- //# sourceMappingURL=cli.mjs.map