engine7 7.1.67 → 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 +1158 -870
  2. package/dist/engine-startup.mjs +2869 -1299
  3. package/dist/main.mjs +2864 -1294
  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`);
@@ -7330,7 +7515,7 @@ async function readSessionHistory(filePath) {
7330
7515
  return [...sessionStarts, ...filtered, ...restAttachments];
7331
7516
  }
7332
7517
  async function readAllLines(filePath) {
7333
- const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
7518
+ const stream = fs9.createReadStream(filePath, { encoding: "utf-8" });
7334
7519
  const rl = readline.createInterface({ input: stream });
7335
7520
  const lines = [];
7336
7521
  return new Promise((resolve11, reject) => {
@@ -7480,12 +7665,12 @@ function extractText2(content) {
7480
7665
  return content.filter((b) => b.type === "text").map((b) => b.text || "").join("") || null;
7481
7666
  }
7482
7667
  function listSessions(sessionsDir) {
7483
- if (!fs7.existsSync(sessionsDir)) return [];
7484
- const files = fs7.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
7485
- 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),
7486
7671
  id: f.replace(/\.jsonl.*$/, ""),
7487
7672
  // strip .jsonl and everything after (archived suffix)
7488
- modified: new Date(fs7.statSync(path7.join(sessionsDir, f)).mtimeMs)
7673
+ modified: new Date(fs9.statSync(path9.join(sessionsDir, f)).mtimeMs)
7489
7674
  })).sort((a, b) => b.modified.getTime() - a.modified.getTime());
7490
7675
  return files;
7491
7676
  }
@@ -7505,8 +7690,8 @@ var session_manager_exports = {};
7505
7690
  __export(session_manager_exports, {
7506
7691
  SessionManager: () => SessionManager
7507
7692
  });
7508
- import * as path8 from "node:path";
7509
- import * as fs8 from "node:fs";
7693
+ import * as path10 from "node:path";
7694
+ import * as fs10 from "node:fs";
7510
7695
  import * as crypto3 from "node:crypto";
7511
7696
  var RESTORE_MAX_CHARS, CHARS_PER_TOKEN, SessionManager;
7512
7697
  var init_session_manager = __esm({
@@ -7538,24 +7723,24 @@ var init_session_manager = __esm({
7538
7723
  constructor(config) {
7539
7724
  this.config = config;
7540
7725
  this.scopeConfig = config.scopeConfig;
7541
- this.sessionsDir = path8.join(config.stateDir, "agents", "main", "sessions");
7542
- this.indexPath = path8.join(this.sessionsDir, "session-index.json");
7543
- this.platformMapPath = path8.join(this.sessionsDir, "platform-map.json");
7544
- 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 });
7545
7730
  }
7546
7731
  // === 索引操作 ===
7547
7732
  loadIndex() {
7548
7733
  try {
7549
- if (fs8.existsSync(this.indexPath)) {
7550
- const raw = fs8.readFileSync(this.indexPath, "utf-8");
7734
+ if (fs10.existsSync(this.indexPath)) {
7735
+ const raw = fs10.readFileSync(this.indexPath, "utf-8");
7551
7736
  const obj = JSON.parse(raw);
7552
7737
  this.index = new Map(Object.entries(obj));
7553
7738
  let fixed = 0;
7554
7739
  for (const [key, entry] of this.index) {
7555
- if (fs8.existsSync(entry.file)) continue;
7556
- const basename8 = path8.basename(entry.file);
7557
- const localPath = path8.join(this.sessionsDir, basename8);
7558
- 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)) {
7559
7744
  entry.file = localPath;
7560
7745
  fixed++;
7561
7746
  }
@@ -7574,7 +7759,7 @@ var init_session_manager = __esm({
7574
7759
  try {
7575
7760
  const obj = {};
7576
7761
  for (const [k, v] of this.index) obj[k] = v;
7577
- fs8.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
7762
+ fs10.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
7578
7763
  } catch (err) {
7579
7764
  console.error(`[session] Failed to save index: ${err.message}`);
7580
7765
  }
@@ -7582,8 +7767,8 @@ var init_session_manager = __esm({
7582
7767
  // === 平台映射 ===
7583
7768
  loadPlatformMap() {
7584
7769
  try {
7585
- if (fs8.existsSync(this.platformMapPath)) {
7586
- const raw = fs8.readFileSync(this.platformMapPath, "utf-8");
7770
+ if (fs10.existsSync(this.platformMapPath)) {
7771
+ const raw = fs10.readFileSync(this.platformMapPath, "utf-8");
7587
7772
  const obj = JSON.parse(raw);
7588
7773
  this.platformMap = new Map(Object.entries(obj));
7589
7774
  console.log(`[session] Platform map loaded: ${this.platformMap.size} entries`);
@@ -7595,7 +7780,7 @@ var init_session_manager = __esm({
7595
7780
  try {
7596
7781
  const obj = {};
7597
7782
  for (const [k, v] of this.platformMap) obj[k] = v;
7598
- fs8.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
7783
+ fs10.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
7599
7784
  } catch (err) {
7600
7785
  console.error(`[session] Failed to save platform map: ${err.message}`);
7601
7786
  }
@@ -7634,17 +7819,17 @@ var init_session_manager = __esm({
7634
7819
  */
7635
7820
  getSessionFilePath(sessionId) {
7636
7821
  const entry = this.index.get(sessionId);
7637
- if (entry && fs8.existsSync(entry.file)) return entry.file;
7638
- const direct = path8.join(this.sessionsDir, `${sessionId}.jsonl`);
7639
- 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;
7640
7825
  }
7641
7826
  // === Writer 管理 ===
7642
7827
  getWriter(sessionId) {
7643
7828
  let writer = this.writers.get(sessionId);
7644
7829
  if (!writer) {
7645
7830
  const existing = this.index.get(sessionId);
7646
- if (existing && fs8.existsSync(existing.file)) {
7647
- const existingFileId = path8.basename(existing.file, ".jsonl");
7831
+ if (existing && fs10.existsSync(existing.file)) {
7832
+ const existingFileId = path10.basename(existing.file, ".jsonl");
7648
7833
  writer = new SessionWriter(this.sessionsDir, existingFileId);
7649
7834
  writer.open(this.config.workspace, sessionId);
7650
7835
  } else {
@@ -7656,7 +7841,7 @@ var init_session_manager = __esm({
7656
7841
  this.saveIndex();
7657
7842
  this.writers.set(sessionId, writer);
7658
7843
  this.onWriterCreated?.(writer, sessionId);
7659
- 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)}`);
7660
7845
  }
7661
7846
  return writer;
7662
7847
  }
@@ -7675,7 +7860,7 @@ var init_session_manager = __esm({
7675
7860
  if (!writer) return null;
7676
7861
  try {
7677
7862
  this.lastArchiveCheck = Date.now();
7678
- const stat4 = fs8.statSync(writer.path);
7863
+ const stat4 = fs10.statSync(writer.path);
7679
7864
  if (stat4.size < threshold) return null;
7680
7865
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
7681
7866
  const thresholdMB = (threshold / 1024 / 1024).toFixed(1);
@@ -7684,10 +7869,10 @@ var init_session_manager = __esm({
7684
7869
  if (archivedPath) {
7685
7870
  this.index.set(sessionId, { file: writer.path, updatedAt: Date.now() });
7686
7871
  this.saveIndex();
7687
- const newSize = fs8.statSync(writer.path).size;
7872
+ const newSize = fs10.statSync(writer.path).size;
7688
7873
  const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
7689
- console.log(`[session] Archive complete: ${path8.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
7690
- 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$/, "");
7691
7876
  this.purgeOldArchives(fileId, 3);
7692
7877
  return archivedPath;
7693
7878
  }
@@ -7703,15 +7888,15 @@ var init_session_manager = __esm({
7703
7888
  purgeOldArchives(sessionId, keepCount = 3) {
7704
7889
  try {
7705
7890
  const dir = this.sessionsDir;
7706
- if (!fs8.existsSync(dir)) return;
7707
- const allFiles = fs8.readdirSync(dir);
7891
+ if (!fs10.existsSync(dir)) return;
7892
+ const allFiles = fs10.readdirSync(dir);
7708
7893
  const archiveFiles = allFiles.filter((f) => {
7709
7894
  if (!f.startsWith(sessionId)) return false;
7710
7895
  return f.includes(".archived.") || f.includes(".compaction.");
7711
7896
  }).map((f) => ({
7712
7897
  name: f,
7713
- path: path8.join(dir, f),
7714
- mtime: fs8.statSync(path8.join(dir, f)).mtimeMs
7898
+ path: path10.join(dir, f),
7899
+ mtime: fs10.statSync(path10.join(dir, f)).mtimeMs
7715
7900
  })).sort((a, b) => b.mtime - a.mtime);
7716
7901
  console.log(`[session] purgeOldArchives: sessionId=${sessionId.substring(0, 8)}... found=${archiveFiles.length} keep=${keepCount}`);
7717
7902
  if (archiveFiles.length <= keepCount) return;
@@ -7721,7 +7906,7 @@ var init_session_manager = __esm({
7721
7906
  console.log(`[session] Skipping archived (kept for history): ${f.name}`);
7722
7907
  continue;
7723
7908
  }
7724
- fs8.unlinkSync(f.path);
7909
+ fs10.unlinkSync(f.path);
7725
7910
  console.log(`[session] Purged old archive: ${f.name}`);
7726
7911
  }
7727
7912
  if (toDelete.length > 0) {
@@ -7770,29 +7955,29 @@ var init_session_manager = __esm({
7770
7955
  /** 列出 session 的所有文件(当前 + 归档),按修改时间排序 */
7771
7956
  findAllSessionFiles(sessionId) {
7772
7957
  const results = [];
7773
- const mainFile = path8.join(this.sessionsDir, `${sessionId}.jsonl`);
7774
- if (fs8.existsSync(mainFile)) {
7958
+ const mainFile = path10.join(this.sessionsDir, `${sessionId}.jsonl`);
7959
+ if (fs10.existsSync(mainFile)) {
7775
7960
  results.push(mainFile);
7776
7961
  }
7777
- if (fs8.existsSync(this.sessionsDir)) {
7778
- 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) => ({
7779
7964
  name: f,
7780
- path: path8.join(this.sessionsDir, f),
7781
- 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
7782
7967
  })).sort((a, b) => b.mtime - a.mtime);
7783
7968
  if (compactionFiles.length > 0) {
7784
7969
  results.push(compactionFiles[0].path);
7785
7970
  }
7786
7971
  }
7787
7972
  results.sort((a, b) => {
7788
- const ta = fs8.statSync(a).mtimeMs;
7789
- const tb = fs8.statSync(b).mtimeMs;
7973
+ const ta = fs10.statSync(a).mtimeMs;
7974
+ const tb = fs10.statSync(b).mtimeMs;
7790
7975
  return ta - tb;
7791
7976
  });
7792
7977
  return results;
7793
7978
  }
7794
7979
  async findSessionFiles(sessionId) {
7795
- if (!fs8.existsSync(this.sessionsDir)) {
7980
+ if (!fs10.existsSync(this.sessionsDir)) {
7796
7981
  console.log(`[session:find] SESSIONS_DIR not found: ${this.sessionsDir}`);
7797
7982
  return [];
7798
7983
  }
@@ -7804,15 +7989,15 @@ var init_session_manager = __esm({
7804
7989
  return mappedFiles;
7805
7990
  }
7806
7991
  const indexedEntry = this.index.get(mappedId);
7807
- if (indexedEntry && fs8.existsSync(indexedEntry.file)) {
7808
- const fileUuid = path8.basename(indexedEntry.file, ".jsonl");
7992
+ if (indexedEntry && fs10.existsSync(indexedEntry.file)) {
7993
+ const fileUuid = path10.basename(indexedEntry.file, ".jsonl");
7809
7994
  return this.findAllSessionFiles(fileUuid);
7810
7995
  }
7811
7996
  }
7812
7997
  const allFiles = this.findAllSessionFiles(sessionId);
7813
7998
  if (allFiles.length > 0) {
7814
7999
  const labels = allFiles.map((f) => {
7815
- const base = path8.basename(f);
8000
+ const base = path10.basename(f);
7816
8001
  return base.endsWith(".jsonl") ? base : `${base} (archived)`;
7817
8002
  });
7818
8003
  console.log(`[session:find] Found ${allFiles.length} file(s) for ${sessionId}: ${labels.join(", ")}`);
@@ -7820,9 +8005,9 @@ var init_session_manager = __esm({
7820
8005
  }
7821
8006
  const indexed = this.index.get(sessionId);
7822
8007
  if (indexed) {
7823
- console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs8.existsSync(indexed.file)})`);
7824
- if (fs8.existsSync(indexed.file)) {
7825
- 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"));
7826
8011
  }
7827
8012
  } else {
7828
8013
  console.log(`[session:find] Index miss: ${sessionId} (index has ${this.index.size} entries)`);
@@ -7851,8 +8036,8 @@ var init_session_manager = __esm({
7851
8036
  return [];
7852
8037
  }
7853
8038
  files.sort((a, b) => {
7854
- const ta = fs8.statSync(a).mtimeMs;
7855
- const tb = fs8.statSync(b).mtimeMs;
8039
+ const ta = fs10.statSync(a).mtimeMs;
8040
+ const tb = fs10.statSync(b).mtimeMs;
7856
8041
  return ta - tb;
7857
8042
  });
7858
8043
  const latestFile = files[files.length - 1];
@@ -7860,11 +8045,11 @@ var init_session_manager = __esm({
7860
8045
  if (!currentEntry || currentEntry.file !== latestFile) {
7861
8046
  this.index.set(sessionId, { file: latestFile, updatedAt: Date.now() });
7862
8047
  this.saveIndex();
7863
- console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path8.basename(latestFile)}`);
8048
+ console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path10.basename(latestFile)}`);
7864
8049
  }
7865
8050
  const allMessages = [];
7866
- for (const file of files) {
7867
- const sessionMsgs = await readSessionHistory(file);
8051
+ for (const file2 of files) {
8052
+ const sessionMsgs = await readSessionHistory(file2);
7868
8053
  for (const m of sessionMsgs) {
7869
8054
  if (isAttachmentMessage(m)) {
7870
8055
  allMessages.push(m);
@@ -7896,7 +8081,7 @@ var init_session_manager = __esm({
7896
8081
  if (isAttachmentMessage(m) && m.attachment.type === "relevant_memories") {
7897
8082
  for (const mem of m.attachment.memories) {
7898
8083
  rawCount++;
7899
- restoredPaths.add(path8.resolve(mem.path));
8084
+ restoredPaths.add(path10.resolve(mem.path));
7900
8085
  }
7901
8086
  }
7902
8087
  }
@@ -7925,15 +8110,15 @@ var init_session_manager = __esm({
7925
8110
  */
7926
8111
  rotateMainSession() {
7927
8112
  const entry = this.index.get("main");
7928
- if (!entry || !fs8.existsSync(entry.file)) return;
7929
- const oldFileId = path8.basename(entry.file, ".jsonl");
7930
- 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);
7931
8116
  if (stat4.size < 1024) return;
7932
8117
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
7933
8118
  const archivedPath = `${entry.file}.archived.${ts}`;
7934
- fs8.renameSync(entry.file, archivedPath);
8119
+ fs10.renameSync(entry.file, archivedPath);
7935
8120
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
7936
- 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)`);
7937
8122
  const newWriter = new SessionWriter(this.sessionsDir);
7938
8123
  newWriter.open(this.config.workspace, "main");
7939
8124
  newWriter.writeModelChange(this.config.providerId, this.config.model);
@@ -7942,7 +8127,7 @@ var init_session_manager = __esm({
7942
8127
  this.index.set("main", { file: newPath, updatedAt: Date.now() });
7943
8128
  this.saveIndex();
7944
8129
  this.purgeOldArchives(oldFileId, 3);
7945
- console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path8.basename(newPath)}`);
8130
+ console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path10.basename(newPath)}`);
7946
8131
  }
7947
8132
  // === 迁移 ===
7948
8133
  /** 迁移旧索引:session-index.json 里有 "discord:xxx" 格式的 key 时,生成 UUID 替换 */
@@ -8007,7 +8192,7 @@ var init_session_manager = __esm({
8007
8192
  });
8008
8193
 
8009
8194
  // src/utils/path.ts
8010
- import * as path9 from "node:path";
8195
+ import * as path11 from "node:path";
8011
8196
  function fixMsysPath(p) {
8012
8197
  let fixed = p.includes("\\") ? p.replace(/\\/g, "/") : p;
8013
8198
  if (process.platform === "win32") {
@@ -8017,15 +8202,15 @@ function fixMsysPath(p) {
8017
8202
  }
8018
8203
  function resolvePath(p, workspace) {
8019
8204
  const fixed = fixMsysPath(p);
8020
- const resolved = path9.isAbsolute(fixed) ? path9.normalize(fixed) : path9.resolve(workspace, fixed);
8021
- const normalized = path9.normalize(resolved);
8022
- 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);
8023
8208
  if (sandboxOff) return normalized;
8024
- if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path9.sep)) {
8209
+ if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path11.sep)) {
8025
8210
  return normalized;
8026
8211
  }
8027
8212
  for (const allowed of extraAllowedPaths) {
8028
- if (normalized === allowed || normalized.startsWith(allowed + path9.sep)) {
8213
+ if (normalized === allowed || normalized.startsWith(allowed + path11.sep)) {
8029
8214
  return normalized;
8030
8215
  }
8031
8216
  }
@@ -8041,15 +8226,15 @@ var init_path = __esm({
8041
8226
  });
8042
8227
 
8043
8228
  // src/tools/read.ts
8044
- import * as fs9 from "node:fs";
8045
- import * as path10 from "node:path";
8229
+ import * as fs11 from "node:fs";
8230
+ import * as path12 from "node:path";
8046
8231
  function isBlockedDevicePath(filePath) {
8047
8232
  if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
8048
8233
  if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
8049
8234
  return false;
8050
8235
  }
8051
8236
  function checkReadLoop(filePath, offset, limit) {
8052
- const stat4 = fs9.statSync(filePath);
8237
+ const stat4 = fs11.statSync(filePath);
8053
8238
  const mtimeMs = stat4.mtimeMs;
8054
8239
  const prev = readHistory.get(filePath);
8055
8240
  if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
@@ -8063,19 +8248,19 @@ function checkReadLoop(filePath, offset, limit) {
8063
8248
  return null;
8064
8249
  }
8065
8250
  function readFileContent(filePath) {
8066
- const fd = fs9.openSync(filePath, "r");
8251
+ const fd = fs11.openSync(filePath, "r");
8067
8252
  const bom = Buffer.alloc(2);
8068
- fs9.readSync(fd, bom, 0, 2, 0);
8069
- fs9.closeSync(fd);
8253
+ fs11.readSync(fd, bom, 0, 2, 0);
8254
+ fs11.closeSync(fd);
8070
8255
  let encoding = "utf8";
8071
8256
  if (bom[0] === 255 && bom[1] === 254) {
8072
8257
  encoding = "utf16le";
8073
8258
  }
8074
- const stat4 = fs9.statSync(filePath);
8259
+ const stat4 = fs11.statSync(filePath);
8075
8260
  if (stat4.size > MAX_FILE_SIZE) {
8076
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`);
8077
8262
  }
8078
- const raw = fs9.readFileSync(filePath, encoding);
8263
+ const raw = fs11.readFileSync(filePath, encoding);
8079
8264
  const content = raw.toString().replaceAll("\r\n", "\n");
8080
8265
  return { content, encoding };
8081
8266
  }
@@ -8217,11 +8402,11 @@ Usage:
8217
8402
  } catch (e) {
8218
8403
  return { content: e.message, isError: true };
8219
8404
  }
8220
- if (!fs9.existsSync(filePath)) {
8405
+ if (!fs11.existsSync(filePath)) {
8221
8406
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
8222
8407
  }
8223
- const stat4 = fs9.statSync(filePath);
8224
- const baseName = path10.basename(filePath).toUpperCase();
8408
+ const stat4 = fs11.statSync(filePath);
8409
+ const baseName = path12.basename(filePath).toUpperCase();
8225
8410
  if (BLOCKED_BASENAMES.has(baseName)) {
8226
8411
  return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
8227
8412
  }
@@ -8229,11 +8414,11 @@ Usage:
8229
8414
  return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
8230
8415
  }
8231
8416
  if (stat4.isDirectory()) {
8232
- const entries2 = fs9.readdirSync(filePath);
8417
+ const entries2 = fs11.readdirSync(filePath);
8233
8418
  const items = entries2.map((e) => {
8234
- const full = path10.join(filePath, e);
8419
+ const full = path12.join(filePath, e);
8235
8420
  try {
8236
- const s = fs9.statSync(full);
8421
+ const s = fs11.statSync(full);
8237
8422
  return s.isDirectory() ? `${e}/` : e;
8238
8423
  } catch {
8239
8424
  return e;
@@ -8242,7 +8427,7 @@ Usage:
8242
8427
  return { content: `\u76EE\u5F55 (${entries2.length} \u9879):
8243
8428
  ${items.join("\n")}` };
8244
8429
  }
8245
- const ext = path10.extname(filePath).toLowerCase();
8430
+ const ext = path12.extname(filePath).toLowerCase();
8246
8431
  if (BINARY_EXTENSIONS.has(ext)) {
8247
8432
  return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
8248
8433
  }
@@ -8289,22 +8474,22 @@ ${result2}` : result2 };
8289
8474
  });
8290
8475
 
8291
8476
  // src/tools/write.ts
8292
- import * as fs10 from "node:fs";
8293
- import * as path11 from "node:path";
8477
+ import * as fs12 from "node:fs";
8478
+ import * as path13 from "node:path";
8294
8479
  function isBlockedPath(filePath) {
8295
8480
  return BLOCKED_PATTERNS.some((p) => p.test(filePath));
8296
8481
  }
8297
8482
  function atomicWrite(filePath, content) {
8298
8483
  const tmpPath = filePath + ".tmp." + Date.now() + ".write";
8299
- fs10.writeFileSync(tmpPath, content, "utf-8");
8484
+ fs12.writeFileSync(tmpPath, content, "utf-8");
8300
8485
  try {
8301
- fs10.renameSync(tmpPath, filePath);
8486
+ fs12.renameSync(tmpPath, filePath);
8302
8487
  } catch (e) {
8303
8488
  try {
8304
- fs10.unlinkSync(tmpPath);
8489
+ fs12.unlinkSync(tmpPath);
8305
8490
  } catch {
8306
8491
  }
8307
- fs10.writeFileSync(filePath, content, "utf-8");
8492
+ fs12.writeFileSync(filePath, content, "utf-8");
8308
8493
  }
8309
8494
  }
8310
8495
  function simpleDiff(oldContent, newContent) {
@@ -8398,15 +8583,15 @@ Usage:
8398
8583
  }
8399
8584
  const rawContent = args.content;
8400
8585
  const content = rawContent.replaceAll("\r\n", "\n");
8401
- if (fs10.existsSync(filePath) && fs10.statSync(filePath).isDirectory()) {
8586
+ if (fs12.existsSync(filePath) && fs12.statSync(filePath).isDirectory()) {
8402
8587
  return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
8403
8588
  }
8404
8589
  let oldContent = null;
8405
8590
  let isCreate = true;
8406
- if (fs10.existsSync(filePath)) {
8591
+ if (fs12.existsSync(filePath)) {
8407
8592
  isCreate = false;
8408
8593
  try {
8409
- oldContent = fs10.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8594
+ oldContent = fs12.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8410
8595
  } catch {
8411
8596
  isCreate = true;
8412
8597
  }
@@ -8422,10 +8607,10 @@ Usage:
8422
8607
  isError: true
8423
8608
  };
8424
8609
  }
8425
- const currentStat = fs10.statSync(filePath);
8610
+ const currentStat = fs12.statSync(filePath);
8426
8611
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
8427
8612
  if (lastWriteTime > readState.timestamp) {
8428
- const currentContent = fs10.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8613
+ const currentContent = fs12.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
8429
8614
  if (currentContent !== oldContent) {
8430
8615
  return {
8431
8616
  content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
@@ -8434,9 +8619,9 @@ Usage:
8434
8619
  }
8435
8620
  }
8436
8621
  }
8437
- const dir = path11.dirname(filePath);
8622
+ const dir = path13.dirname(filePath);
8438
8623
  try {
8439
- fs10.mkdirSync(dir, { recursive: true });
8624
+ fs12.mkdirSync(dir, { recursive: true });
8440
8625
  } catch (e) {
8441
8626
  return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
8442
8627
  }
@@ -8445,11 +8630,11 @@ Usage:
8445
8630
  } catch (e) {
8446
8631
  return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
8447
8632
  }
8448
- readFileState.set(filePath, { timestamp: fs10.statSync(filePath).mtimeMs });
8633
+ readFileState.set(filePath, { timestamp: fs12.statSync(filePath).mtimeMs });
8449
8634
  const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
8450
8635
  const lines = content.split("\n").length;
8451
8636
  const chars = content.length;
8452
- const stat4 = fs10.statSync(filePath);
8637
+ const stat4 = fs12.statSync(filePath);
8453
8638
  let diff = "";
8454
8639
  if (!isCreate && oldContent !== null) {
8455
8640
  diff = `
@@ -8468,8 +8653,8 @@ ${simpleDiff(oldContent, content)}`;
8468
8653
  });
8469
8654
 
8470
8655
  // src/tools/edit.ts
8471
- import * as fs11 from "node:fs";
8472
- import * as path12 from "node:path";
8656
+ import * as fs13 from "node:fs";
8657
+ import * as path14 from "node:path";
8473
8658
  function normalizeQuotes(str) {
8474
8659
  return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
8475
8660
  }
@@ -8622,7 +8807,7 @@ Usage:
8622
8807
  }
8623
8808
  let fileContent = null;
8624
8809
  try {
8625
- const stat4 = fs11.statSync(filePath);
8810
+ const stat4 = fs13.statSync(filePath);
8626
8811
  if (stat4.isDirectory()) {
8627
8812
  return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
8628
8813
  }
@@ -8632,21 +8817,21 @@ Usage:
8632
8817
  } catch (e) {
8633
8818
  if (e.code === "ENOENT") {
8634
8819
  if (oldString === "") {
8635
- const dir = path12.dirname(filePath);
8636
- fs11.mkdirSync(dir, { recursive: true });
8637
- fs11.writeFileSync(filePath, newString, "utf-8");
8638
- 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 });
8639
8824
  return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
8640
8825
  }
8641
8826
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
8642
8827
  }
8643
8828
  throw e;
8644
8829
  }
8645
- const rawContent = fs11.readFileSync(filePath, "utf-8");
8830
+ const rawContent = fs13.readFileSync(filePath, "utf-8");
8646
8831
  fileContent = rawContent.replaceAll("\r\n", "\n");
8647
8832
  if (oldString === "" && fileContent.trim() === "") {
8648
- fs11.writeFileSync(filePath, newString, "utf-8");
8649
- readFileState.set(filePath, { timestamp: fs11.statSync(filePath).mtimeMs });
8833
+ fs13.writeFileSync(filePath, newString, "utf-8");
8834
+ readFileState.set(filePath, { timestamp: fs13.statSync(filePath).mtimeMs });
8650
8835
  return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
8651
8836
  }
8652
8837
  const readState = readFileState.get(filePath);
@@ -8656,11 +8841,11 @@ Usage:
8656
8841
  isError: true
8657
8842
  };
8658
8843
  }
8659
- const currentStat = fs11.statSync(filePath);
8844
+ const currentStat = fs13.statSync(filePath);
8660
8845
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
8661
8846
  if (lastWriteTime > readState.timestamp) {
8662
8847
  if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
8663
- if (fileContent !== fs11.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
8848
+ if (fileContent !== fs13.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
8664
8849
  return {
8665
8850
  content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
8666
8851
  isError: true
@@ -8692,8 +8877,8 @@ ${preview}
8692
8877
  const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
8693
8878
  const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
8694
8879
  const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
8695
- fs11.writeFileSync(filePath, newContent, "utf-8");
8696
- readFileState.set(filePath, { timestamp: fs11.statSync(filePath).mtimeMs });
8880
+ fs13.writeFileSync(filePath, newContent, "utf-8");
8881
+ readFileState.set(filePath, { timestamp: fs13.statSync(filePath).mtimeMs });
8697
8882
  const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
8698
8883
  const count = replaceAll ? matchCount : 1;
8699
8884
  const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
@@ -8710,8 +8895,8 @@ ${diffView}`
8710
8895
  });
8711
8896
 
8712
8897
  // src/tools/glob.ts
8713
- import * as fs12 from "node:fs";
8714
- import * as path13 from "node:path";
8898
+ import * as fs14 from "node:fs";
8899
+ import * as path15 from "node:path";
8715
8900
  function globMatch(pattern, filename) {
8716
8901
  const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
8717
8902
  try {
@@ -8731,18 +8916,18 @@ function findFiles(dir, pattern, limit, baseDir) {
8731
8916
  }
8732
8917
  let entries2;
8733
8918
  try {
8734
- entries2 = fs12.readdirSync(currentDir, { withFileTypes: true });
8919
+ entries2 = fs14.readdirSync(currentDir, { withFileTypes: true });
8735
8920
  } catch {
8736
8921
  return;
8737
8922
  }
8738
8923
  for (const entry of entries2) {
8739
8924
  if (truncated) return;
8740
- const fullPath = path13.join(currentDir, entry.name);
8925
+ const fullPath = path15.join(currentDir, entry.name);
8741
8926
  if (entry.isDirectory()) {
8742
8927
  if (VCS_DIRS.has(entry.name)) continue;
8743
8928
  walk(fullPath);
8744
8929
  } else if (entry.isFile()) {
8745
- const relativePath = path13.relative(baseDir, fullPath).replace(/\\/g, "/");
8930
+ const relativePath = path15.relative(baseDir, fullPath).replace(/\\/g, "/");
8746
8931
  const patternsToTry = [pattern];
8747
8932
  if (pattern.startsWith("**/")) {
8748
8933
  patternsToTry.push(pattern.slice(3));
@@ -8752,7 +8937,7 @@ function findFiles(dir, pattern, limit, baseDir) {
8752
8937
  );
8753
8938
  if (matched) {
8754
8939
  try {
8755
- const stat4 = fs12.statSync(fullPath);
8940
+ const stat4 = fs14.statSync(fullPath);
8756
8941
  results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
8757
8942
  } catch {
8758
8943
  }
@@ -8769,7 +8954,7 @@ function findFiles(dir, pattern, limit, baseDir) {
8769
8954
  };
8770
8955
  }
8771
8956
  function toRelativePath(absolutePath, cwd) {
8772
- if (absolutePath.startsWith(cwd + path13.sep)) {
8957
+ if (absolutePath.startsWith(cwd + path15.sep)) {
8773
8958
  return absolutePath.slice(cwd.length + 1);
8774
8959
  }
8775
8960
  return absolutePath;
@@ -8802,10 +8987,10 @@ var init_glob = __esm({
8802
8987
  const searchPath = args.path ? resolvePath(args.path, ctx.workspace) : ctx.workspace;
8803
8988
  const pattern = args.pattern;
8804
8989
  const limit = args.limit || DEFAULT_LIMIT;
8805
- if (!fs12.existsSync(searchPath)) {
8990
+ if (!fs14.existsSync(searchPath)) {
8806
8991
  return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
8807
8992
  }
8808
- if (!fs12.statSync(searchPath).isDirectory()) {
8993
+ if (!fs14.statSync(searchPath).isDirectory()) {
8809
8994
  return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
8810
8995
  }
8811
8996
  const start = Date.now();
@@ -8829,7 +9014,7 @@ ${filenames.join("\n")}${truncatedNote}`
8829
9014
 
8830
9015
  // src/tools/grep.ts
8831
9016
  import { execFile } from "node:child_process";
8832
- import * as path14 from "node:path";
9017
+ import * as path16 from "node:path";
8833
9018
  function ripGrep(args, searchPath, signal) {
8834
9019
  return new Promise((resolve11) => {
8835
9020
  const fullArgs = [...args, searchPath];
@@ -8861,7 +9046,7 @@ function applyHeadLimit(items, limit, offset = 0) {
8861
9046
  };
8862
9047
  }
8863
9048
  function toRelativePath2(absolutePath, cwd) {
8864
- if (absolutePath.startsWith(cwd + path14.sep)) {
9049
+ if (absolutePath.startsWith(cwd + path16.sep)) {
8865
9050
  return absolutePath.slice(cwd.length + 1);
8866
9051
  }
8867
9052
  if (absolutePath.startsWith(cwd)) {
@@ -9031,12 +9216,14 @@ ${filenames.join("\n")}${truncatedNote}`
9031
9216
  // src/tools/task-manager.ts
9032
9217
  var task_manager_exports = {};
9033
9218
  __export(task_manager_exports, {
9219
+ ackPendingNotification: () => ackPendingNotification,
9034
9220
  buildCalendarNotification: () => buildCalendarNotification,
9035
9221
  buildNudgeNotification: () => buildNudgeNotification,
9036
9222
  clearNotificationCallback: () => clearNotificationCallback,
9037
9223
  drainPendingNotifications: () => drainPendingNotifications,
9038
9224
  enqueueNotification: () => enqueueNotification,
9039
9225
  generateTaskId: () => generateTaskId,
9226
+ getPendingNotificationRecords: () => getPendingNotificationRecords,
9040
9227
  getPendingNotifications: () => getPendingNotifications,
9041
9228
  getTask: () => getTask,
9042
9229
  getTaskOutput: () => getTaskOutput,
@@ -9045,14 +9232,16 @@ __export(task_manager_exports, {
9045
9232
  getTaskOutputPath: () => getTaskOutputPath,
9046
9233
  getTaskOutputSize: () => getTaskOutputSize,
9047
9234
  killTask: () => killTask,
9235
+ listLiveTasks: () => listLiveTasks,
9048
9236
  listTasks: () => listTasks,
9237
+ loadPersistedTasks: () => loadPersistedTasks,
9049
9238
  setNotificationCallback: () => setNotificationCallback,
9050
9239
  spawnBackgroundTask: () => spawnBackgroundTask
9051
9240
  });
9052
9241
  import { randomBytes as randomBytes3 } from "node:crypto";
9053
9242
  import { spawn as spawn2 } from "node:child_process";
9054
- import * as fs13 from "node:fs";
9055
- import * as path15 from "node:path";
9243
+ import * as fs15 from "node:fs";
9244
+ import * as path17 from "node:path";
9056
9245
  function generateTaskId(type2 = "local_bash") {
9057
9246
  const prefix = TASK_ID_PREFIXES[type2] ?? "x";
9058
9247
  const bytes = randomBytes3(8);
@@ -9065,60 +9254,182 @@ function generateTaskId(type2 = "local_bash") {
9065
9254
  function getTaskOutputDir() {
9066
9255
  if (_taskOutputDir === void 0) {
9067
9256
  const stateDir = process.env.ENGINE_STATE_DIR || process.cwd();
9068
- _taskOutputDir = path15.join(stateDir, "tasks");
9257
+ _taskOutputDir = path17.join(stateDir, "tasks");
9069
9258
  }
9070
9259
  return _taskOutputDir;
9071
9260
  }
9072
9261
  function getTaskOutputPath(taskId) {
9073
- return path15.join(getTaskOutputDir(), `${taskId}.output`);
9262
+ return path17.join(getTaskOutputDir(), `${taskId}.output`);
9074
9263
  }
9075
9264
  function ensureOutputDir() {
9076
9265
  const dir = getTaskOutputDir();
9077
- if (!fs13.existsSync(dir)) {
9078
- fs13.mkdirSync(dir, { recursive: true });
9266
+ if (!fs15.existsSync(dir)) {
9267
+ fs15.mkdirSync(dir, { recursive: true });
9079
9268
  }
9080
9269
  }
9081
9270
  function initTaskOutput(taskId) {
9082
9271
  ensureOutputDir();
9083
9272
  const outputPath = getTaskOutputPath(taskId);
9084
- fs13.writeFileSync(outputPath, "", "utf-8");
9273
+ fs15.writeFileSync(outputPath, "", "utf-8");
9085
9274
  return outputPath;
9086
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
+ }
9087
9361
  function setNotificationCallback(cb) {
9088
9362
  notificationCallback = cb;
9363
+ loadNotificationQueue();
9364
+ if (pendingNotifications.length === 0) return;
9365
+ attemptDueNotifications();
9089
9366
  }
9090
9367
  function clearNotificationCallback() {
9091
9368
  notificationCallback = null;
9369
+ if (notificationRetryTimer) {
9370
+ clearTimeout(notificationRetryTimer);
9371
+ notificationRetryTimer = void 0;
9372
+ }
9092
9373
  }
9093
- function enqueueNotification(notification, route) {
9374
+ function enqueueNotification(notification, route, idempotencyKey) {
9375
+ loadNotificationQueue();
9376
+ if (idempotencyKey && pendingNotifications.some((item) => item.idempotencyKey === idempotencyKey)) return;
9094
9377
  if (notificationCallback) {
9095
- notificationCallback(notification, route);
9096
- console.log(`[task-manager] Notification dispatched via callback (event-driven, session=${route?.sessionId || "none"}, channel=${route?.channel || "none"})`);
9097
- 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
+ }
9098
9389
  }
9099
- pendingNotifications.push(notification);
9390
+ pendingNotifications.push({ id: `n-${Date.now()}-${randomBytes3(4).toString("hex")}`, notification, route, createdAt: (/* @__PURE__ */ new Date()).toISOString(), idempotencyKey });
9391
+ persistNotificationQueue();
9100
9392
  console.log(`[task-manager] Notification queued (${pendingNotifications.length} pending, no callback)`);
9101
9393
  }
9102
9394
  function getPendingNotifications() {
9103
- 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;
9104
9410
  }
9105
9411
  function drainPendingNotifications() {
9106
- 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));
9107
9416
  pendingNotifications.length = 0;
9108
- return notifications;
9417
+ pendingNotifications.push(...kept);
9418
+ persistNotificationQueue();
9419
+ return due.map((item) => item.notification);
9109
9420
  }
9110
9421
  function spawnBackgroundTask(opts) {
9111
9422
  const taskId = generateTaskId("local_bash");
9112
9423
  const outputPath = initTaskOutput(taskId);
9113
9424
  const { shell, args: shellArgs } = findShell();
9114
- const outputFd = fs13.openSync(outputPath, "w");
9425
+ const outputFd = fs15.openSync(outputPath, "w");
9115
9426
  const child = spawn2(shell, [...shellArgs, opts.command], {
9116
9427
  cwd: opts.cwd,
9117
9428
  env: opts.env || process.env,
9118
9429
  stdio: ["ignore", outputFd, outputFd]
9119
9430
  });
9120
9431
  try {
9121
- fs13.closeSync(outputFd);
9432
+ fs15.closeSync(outputFd);
9122
9433
  } catch {
9123
9434
  }
9124
9435
  processes.set(taskId, child);
@@ -9136,6 +9447,7 @@ function spawnBackgroundTask(opts) {
9136
9447
  channelTarget: opts.channelTarget
9137
9448
  };
9138
9449
  tasks.set(taskId, taskState);
9450
+ persistTask(taskState);
9139
9451
  let timer;
9140
9452
  if (opts.timeout && opts.timeout > 0) {
9141
9453
  timer = setTimeout(() => {
@@ -9149,12 +9461,12 @@ function spawnBackgroundTask(opts) {
9149
9461
  let killedForSize = false;
9150
9462
  sizeWatchdog = setInterval(() => {
9151
9463
  if (tasks.get(taskId)?.status !== "running") return;
9152
- fs13.stat(outputPath, (err, st) => {
9464
+ fs15.stat(outputPath, (err, st) => {
9153
9465
  if (err || st.size <= MAX_TASK_OUTPUT_BYTES) return;
9154
9466
  killedForSize = true;
9155
9467
  if (sizeWatchdog) clearInterval(sizeWatchdog);
9156
9468
  try {
9157
- fs13.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
9469
+ fs15.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
9158
9470
  } catch {
9159
9471
  }
9160
9472
  killChild(child);
@@ -9172,8 +9484,15 @@ function spawnBackgroundTask(opts) {
9172
9484
  state2.status = status;
9173
9485
  state2.exitCode = exitCode;
9174
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
+ }
9175
9493
  if (!state2.notified) {
9176
9494
  state2.notified = true;
9495
+ persistTask(state2);
9177
9496
  const summary = buildSummary(state2);
9178
9497
  const notification = buildTaskNotification(taskId, outputPath, status, summary);
9179
9498
  enqueueNotification(notification, { sessionId: state2.sessionId, channel: state2.channel, channelTarget: state2.channelTarget });
@@ -9228,6 +9547,12 @@ function getTask(taskId) {
9228
9547
  return tasks.get(taskId);
9229
9548
  }
9230
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() {
9231
9556
  return [...tasks.values()];
9232
9557
  }
9233
9558
  function getTaskOutput(taskId, maxBytes = 8 * 1024 * 1024) {
@@ -9235,16 +9560,16 @@ function getTaskOutput(taskId, maxBytes = 8 * 1024 * 1024) {
9235
9560
  if (!state2) return "";
9236
9561
  try {
9237
9562
  const outputPath = state2.outputFile;
9238
- if (!fs13.existsSync(outputPath)) return "";
9239
- const stat4 = fs13.statSync(outputPath);
9563
+ if (!fs15.existsSync(outputPath)) return "";
9564
+ const stat4 = fs15.statSync(outputPath);
9240
9565
  if (stat4.size <= maxBytes) {
9241
- return fs13.readFileSync(outputPath, "utf-8");
9566
+ return fs15.readFileSync(outputPath, "utf-8");
9242
9567
  }
9243
- const fd = fs13.openSync(outputPath, "r");
9568
+ const fd = fs15.openSync(outputPath, "r");
9244
9569
  const start = stat4.size - maxBytes;
9245
9570
  const buf = Buffer.alloc(maxBytes);
9246
- fs13.readSync(fd, buf, 0, maxBytes, start);
9247
- fs13.closeSync(fd);
9571
+ fs15.readSync(fd, buf, 0, maxBytes, start);
9572
+ fs15.closeSync(fd);
9248
9573
  const content = buf.toString("utf-8");
9249
9574
  const omitted = Math.round((stat4.size - maxBytes) / 1024);
9250
9575
  return `[${omitted}KB of earlier output omitted]
@@ -9258,14 +9583,14 @@ function getTaskOutputDelta(taskId, fromOffset, maxBytes = 8 * 1024 * 1024) {
9258
9583
  if (!state2) return { content: "", newOffset: fromOffset };
9259
9584
  try {
9260
9585
  const outputPath = state2.outputFile;
9261
- if (!fs13.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
9262
- const stat4 = fs13.statSync(outputPath);
9586
+ if (!fs15.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
9587
+ const stat4 = fs15.statSync(outputPath);
9263
9588
  if (fromOffset >= stat4.size) return { content: "", newOffset: stat4.size };
9264
9589
  const readLen = Math.min(maxBytes, stat4.size - fromOffset);
9265
9590
  const buf = Buffer.alloc(readLen);
9266
- const fd = fs13.openSync(outputPath, "r");
9267
- fs13.readSync(fd, buf, 0, readLen, fromOffset);
9268
- fs13.closeSync(fd);
9591
+ const fd = fs15.openSync(outputPath, "r");
9592
+ fs15.readSync(fd, buf, 0, readLen, fromOffset);
9593
+ fs15.closeSync(fd);
9269
9594
  return { content: buf.toString("utf-8"), newOffset: fromOffset + readLen };
9270
9595
  } catch {
9271
9596
  return { content: "", newOffset: fromOffset };
@@ -9275,8 +9600,8 @@ function getTaskOutputSize(taskId) {
9275
9600
  const state2 = tasks.get(taskId);
9276
9601
  if (!state2) return 0;
9277
9602
  try {
9278
- if (!fs13.existsSync(state2.outputFile)) return 0;
9279
- return fs13.statSync(state2.outputFile).size;
9603
+ if (!fs15.existsSync(state2.outputFile)) return 0;
9604
+ return fs15.statSync(state2.outputFile).size;
9280
9605
  } catch {
9281
9606
  return 0;
9282
9607
  }
@@ -9300,7 +9625,7 @@ function killTask(taskId) {
9300
9625
  }
9301
9626
  return true;
9302
9627
  }
9303
- 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;
9304
9629
  var init_task_manager = __esm({
9305
9630
  "src/tools/task-manager.ts"() {
9306
9631
  "use strict";
@@ -9314,8 +9639,13 @@ var init_task_manager = __esm({
9314
9639
  MAX_TASK_OUTPUT_BYTES = 5 * 1024 * 1024 * 1024;
9315
9640
  tasks = /* @__PURE__ */ new Map();
9316
9641
  processes = /* @__PURE__ */ new Map();
9642
+ taskIndexPath = () => path17.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "index.json");
9317
9643
  pendingNotifications = [];
9644
+ notificationsLoaded = false;
9645
+ notificationQueuePath = () => path17.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "notifications.json");
9318
9646
  notificationCallback = null;
9647
+ RETRY_BASE_MS = 1e3;
9648
+ RETRY_MAX_MS = 6e4;
9319
9649
  TASK_NOTIFICATION_TAG = "task-notification";
9320
9650
  TASK_ID_TAG = "task-id";
9321
9651
  TASK_TYPE_TAG = "task-type";
@@ -9554,8 +9884,8 @@ __export(BashTool_exports, {
9554
9884
  killChild: () => killChild
9555
9885
  });
9556
9886
  import { spawn as spawn3, execSync } from "node:child_process";
9557
- import * as fs14 from "node:fs";
9558
- import * as path16 from "node:path";
9887
+ import * as fs16 from "node:fs";
9888
+ import * as path18 from "node:path";
9559
9889
  function isWslBash(p) {
9560
9890
  const normalized = p.replace(/\//g, "\\").toLowerCase();
9561
9891
  return WSL_PATH_MARKERS.some((m) => normalized.includes(m.toLowerCase()));
@@ -9574,7 +9904,7 @@ function findShell() {
9574
9904
  });
9575
9905
  const candidates = result2.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
9576
9906
  const nonWsl = candidates.find((p) => !isWslBash(p));
9577
- if (nonWsl && fs14.existsSync(nonWsl)) {
9907
+ if (nonWsl && fs16.existsSync(nonWsl)) {
9578
9908
  cachedShell = { shell: nonWsl, args: ["-c"] };
9579
9909
  return cachedShell;
9580
9910
  }
@@ -9584,10 +9914,10 @@ function findShell() {
9584
9914
  "C:\\Program Files\\Git\\bin\\bash.exe",
9585
9915
  "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
9586
9916
  "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
9587
- path16.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
9917
+ path18.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
9588
9918
  ];
9589
9919
  for (const p of knownPaths) {
9590
- if (p && fs14.existsSync(p)) {
9920
+ if (p && fs16.existsSync(p)) {
9591
9921
  cachedShell = { shell: p, args: ["-c"] };
9592
9922
  return cachedShell;
9593
9923
  }
@@ -9690,8 +10020,8 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
9690
10020
  }
9691
10021
  const MAX_OUTPUT = 100 * 1024;
9692
10022
  const osMod = await import("node:os");
9693
- const outputFile = path16.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
9694
- 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");
9695
10025
  return new Promise((resolve11) => {
9696
10026
  const { shell, args: shellArgs } = findShell();
9697
10027
  const child = spawn3(shell, [...shellArgs, command], {
@@ -9710,21 +10040,21 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
9710
10040
  let fileOutput = "";
9711
10041
  let truncated = false;
9712
10042
  try {
9713
- const st = await fs14.promises.stat(outputFile);
10043
+ const st = await fs16.promises.stat(outputFile);
9714
10044
  if (st.size > MAX_OUTPUT) {
9715
- const rfd = await fs14.promises.open(outputFile, "r");
10045
+ const rfd = await fs16.promises.open(outputFile, "r");
9716
10046
  const buf = Buffer.alloc(MAX_OUTPUT);
9717
10047
  await rfd.read(buf, 0, MAX_OUTPUT, 0);
9718
10048
  await rfd.close();
9719
10049
  fileOutput = buf.toString("utf-8");
9720
10050
  truncated = true;
9721
10051
  } else {
9722
- fileOutput = await fs14.promises.readFile(outputFile, "utf-8");
10052
+ fileOutput = await fs16.promises.readFile(outputFile, "utf-8");
9723
10053
  }
9724
10054
  } catch {
9725
10055
  }
9726
10056
  try {
9727
- await fs14.promises.unlink(outputFile);
10057
+ await fs16.promises.unlink(outputFile);
9728
10058
  } catch {
9729
10059
  }
9730
10060
  const processedStdout = fileOutput.replace(/^(\s*\n)+/, "").trimEnd();
@@ -10529,23 +10859,23 @@ var init_agentSwarmsEnabled = __esm({
10529
10859
  });
10530
10860
 
10531
10861
  // src/swarm/teamHelpers.ts
10532
- 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";
10533
10863
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
10534
- import { join as join15 } from "node:path";
10864
+ import { join as join16 } from "node:path";
10535
10865
  function getTeamsDir() {
10536
- return join15(_stateDir, "teams");
10866
+ return join16(_stateDir, "teams");
10537
10867
  }
10538
10868
  function getTasksDir() {
10539
- return join15(_stateDir, "tasks");
10869
+ return join16(_stateDir, "tasks");
10540
10870
  }
10541
10871
  function sanitizeName(name) {
10542
10872
  return name.replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
10543
10873
  }
10544
10874
  function getTeamDir(teamName) {
10545
- return join15(getTeamsDir(), sanitizeName(teamName));
10875
+ return join16(getTeamsDir(), sanitizeName(teamName));
10546
10876
  }
10547
10877
  function getTeamFilePath(teamName) {
10548
- return join15(getTeamDir(teamName), "config.json");
10878
+ return join16(getTeamDir(teamName), "config.json");
10549
10879
  }
10550
10880
  function readTeamFile(teamName) {
10551
10881
  try {
@@ -10612,7 +10942,7 @@ async function cleanupTeamDirectories(teamName) {
10612
10942
  } catch (error) {
10613
10943
  console.warn(`[teamHelpers] Failed to clean up team directory ${teamDir}: ${error.message}`);
10614
10944
  }
10615
- const tasksDir = join15(getTasksDir(), sanitizedName);
10945
+ const tasksDir = join16(getTasksDir(), sanitizedName);
10616
10946
  try {
10617
10947
  await rm(tasksDir, { recursive: true, force: true });
10618
10948
  console.log(`[teamHelpers] Cleaned up tasks directory: ${tasksDir}`);
@@ -10621,8 +10951,8 @@ async function cleanupTeamDirectories(teamName) {
10621
10951
  }
10622
10952
  }
10623
10953
  function ensureTasksDir(taskListId) {
10624
- const dir = join15(getTasksDir(), taskListId);
10625
- mkdirSync7(dir, { recursive: true });
10954
+ const dir = join16(getTasksDir(), taskListId);
10955
+ mkdirSync8(dir, { recursive: true });
10626
10956
  }
10627
10957
  function setLeaderTeamName(name) {
10628
10958
  _leaderTeamName = name;
@@ -10802,9 +11132,9 @@ The user interacts primarily with the team lead. Your work is coordinated throug
10802
11132
 
10803
11133
  // src/swarm/teammateMailbox.ts
10804
11134
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
10805
- import { join as join16 } from "node:path";
11135
+ import { join as join17 } from "node:path";
10806
11136
  function getTeamsDir2() {
10807
- return join16(process.env.ENGINE_STATE_DIR || ".", "teams");
11137
+ return join17(process.env.ENGINE_STATE_DIR || ".", "teams");
10808
11138
  }
10809
11139
  function sanitizePathComponent(s) {
10810
11140
  return s.replace(/[^a-zA-Z0-9_-]/g, "-");
@@ -10813,12 +11143,12 @@ function getInboxPath(agentName, teamName) {
10813
11143
  const team = teamName || "default";
10814
11144
  const safeTeam = sanitizePathComponent(team);
10815
11145
  const safeAgentName = sanitizePathComponent(agentName);
10816
- return join16(getTeamsDir2(), safeTeam, "inboxes", `${safeAgentName}.json`);
11146
+ return join17(getTeamsDir2(), safeTeam, "inboxes", `${safeAgentName}.json`);
10817
11147
  }
10818
11148
  async function ensureInboxDir(teamName) {
10819
11149
  const team = teamName || "default";
10820
11150
  const safeTeam = sanitizePathComponent(team);
10821
- const inboxDir = join16(getTeamsDir2(), safeTeam, "inboxes");
11151
+ const inboxDir = join17(getTeamsDir2(), safeTeam, "inboxes");
10822
11152
  await mkdir2(inboxDir, { recursive: true });
10823
11153
  }
10824
11154
  async function sleep4(ms) {
@@ -10855,7 +11185,7 @@ async function acquireLock(inboxPath) {
10855
11185
  for (let i = 0; i < LOCK_RETRIES; i++) {
10856
11186
  if (await isLockStale(lockPath2)) {
10857
11187
  try {
10858
- 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 }));
10859
11189
  } catch {
10860
11190
  }
10861
11191
  }
@@ -10863,7 +11193,7 @@ async function acquireLock(inboxPath) {
10863
11193
  await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
10864
11194
  return async () => {
10865
11195
  try {
10866
- 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 }));
10867
11197
  } catch {
10868
11198
  }
10869
11199
  };
@@ -12033,12 +12363,12 @@ Examples:
12033
12363
  });
12034
12364
 
12035
12365
  // src/tools/msg-husband.ts
12036
- import fs15 from "node:fs";
12037
- import path17 from "node:path";
12366
+ import fs17 from "node:fs";
12367
+ import path19 from "node:path";
12038
12368
  function getHusbandFeishuId(workspace) {
12039
- const contactsPath = path17.join(workspace, "prompts", "contacts.md");
12369
+ const contactsPath = path19.join(workspace, "prompts", "contacts.md");
12040
12370
  try {
12041
- const text = fs15.readFileSync(contactsPath, "utf-8");
12371
+ const text = fs17.readFileSync(contactsPath, "utf-8");
12042
12372
  const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
12043
12373
  return m ? m[1] : null;
12044
12374
  } catch {
@@ -12191,8 +12521,8 @@ Examples:
12191
12521
  if (!to && !resolvedChannelId) {
12192
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 };
12193
12523
  }
12194
- const fs28 = await import("node:fs");
12195
- if (!fs28.existsSync(filePath)) {
12524
+ const fs29 = await import("node:fs");
12525
+ if (!fs29.existsSync(filePath)) {
12196
12526
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
12197
12527
  }
12198
12528
  const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
@@ -12220,7 +12550,7 @@ Examples:
12220
12550
  md: "text/markdown"
12221
12551
  };
12222
12552
  const mimeType = mimeTypeMap[ext] || "application/octet-stream";
12223
- const stat4 = fs28.statSync(filePath);
12553
+ const stat4 = fs29.statSync(filePath);
12224
12554
  const sizeMB = stat4.size / 1024 / 1024;
12225
12555
  if (sizeMB > 25) {
12226
12556
  return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
@@ -12249,12 +12579,12 @@ Examples:
12249
12579
  });
12250
12580
 
12251
12581
  // src/tools/my-eyes.ts
12252
- import * as fs16 from "node:fs";
12253
- import * as path18 from "node:path";
12582
+ import * as fs18 from "node:fs";
12583
+ import * as path20 from "node:path";
12254
12584
  function resolveLatestImage(specifiedPath, mediaDir) {
12255
- if (specifiedPath && fs16.existsSync(specifiedPath)) return specifiedPath;
12256
- if (!fs16.existsSync(mediaDir)) return null;
12257
- 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);
12258
12588
  return files[0]?.p || null;
12259
12589
  }
12260
12590
  var MIME_MAP;
@@ -12299,15 +12629,15 @@ var init_my_eyes = __esm({
12299
12629
  if (!provider?.streamChat) {
12300
12630
  return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
12301
12631
  }
12302
- const mediaDir = path18.join(ctx.stateDir, "media", "inbound");
12632
+ const mediaDir = path20.join(ctx.stateDir, "media", "inbound");
12303
12633
  const imagePath = resolveLatestImage(args.image_path, mediaDir);
12304
12634
  if (!imagePath) {
12305
12635
  return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
12306
12636
  }
12307
12637
  const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
12308
- const ext = path18.extname(imagePath).toLowerCase();
12638
+ const ext = path20.extname(imagePath).toLowerCase();
12309
12639
  const mime = MIME_MAP[ext] || "jpeg";
12310
- const imgB64 = fs16.readFileSync(imagePath).toString("base64");
12640
+ const imgB64 = fs18.readFileSync(imagePath).toString("base64");
12311
12641
  const userMsg = {
12312
12642
  role: "user",
12313
12643
  content: [
@@ -12342,7 +12672,7 @@ var init_my_eyes = __esm({
12342
12672
  });
12343
12673
 
12344
12674
  // src/tools/opus-encoder.ts
12345
- import * as fs17 from "node:fs";
12675
+ import * as fs19 from "node:fs";
12346
12676
  function oggCrc32(buf) {
12347
12677
  let crc = 0;
12348
12678
  for (let i = 0; i < buf.length; i++) {
@@ -12402,7 +12732,7 @@ async function wavToOggOpusNative(wavPath) {
12402
12732
  const mod = await import("@discordjs/opus");
12403
12733
  const OpusEncoder = mod.OpusEncoder ?? mod.default?.OpusEncoder;
12404
12734
  if (!OpusEncoder) throw new Error("@discordjs/opus export shape unexpected");
12405
- const wav = parseWav(fs17.readFileSync(wavPath));
12735
+ const wav = parseWav(fs19.readFileSync(wavPath));
12406
12736
  if (wav.channels !== 1) throw new Error(`unsupported ${wav.channels}ch (need mono)`);
12407
12737
  if (!NATIVE_RATES.includes(wav.sampleRate)) throw new Error(`unsupported rate ${wav.sampleRate}`);
12408
12738
  if (wav.pcm.length === 0) throw new Error("empty pcm data");
@@ -12438,7 +12768,7 @@ async function wavToOggOpusNative(wavPath) {
12438
12768
  }
12439
12769
  ogg.page(cur, pageGranule, false, true);
12440
12770
  const oggPath = wavPath.replace(/\.wav$/, ".ogg");
12441
- fs17.writeFileSync(oggPath, ogg.finish());
12771
+ fs19.writeFileSync(oggPath, ogg.finish());
12442
12772
  return oggPath;
12443
12773
  }
12444
12774
  var FRAME_MS, PRESKIP_48K, OPUS_RATE, NATIVE_RATES, BITRATE, CRC_TABLE, OggWriter;
@@ -12518,8 +12848,8 @@ var init_voice_chat_tts_daemon = __esm({
12518
12848
  import { execFile as execFile2 } from "node:child_process";
12519
12849
  import { createInterface as createInterface2 } from "node:readline";
12520
12850
  import { promisify } from "node:util";
12521
- import * as fs18 from "node:fs";
12522
- import * as path19 from "node:path";
12851
+ import * as fs20 from "node:fs";
12852
+ import * as path21 from "node:path";
12523
12853
  import * as os3 from "node:os";
12524
12854
  function resolvePython(configuredPath) {
12525
12855
  if (configuredPath) {
@@ -12555,8 +12885,8 @@ async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction
12555
12885
  }
12556
12886
  async function ttsCosyvoiceStream(text, cfg, onChunk) {
12557
12887
  const { apiKey, model, voice, workspaceId, instruction } = cfg;
12558
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12559
- 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`);
12560
12890
  const script = `
12561
12891
  import sys, json, base64, threading
12562
12892
  import dashscope
@@ -12641,7 +12971,7 @@ print('EOS')
12641
12971
  header.writeUInt16LE(16, 34);
12642
12972
  header.write("data", 36);
12643
12973
  header.writeUInt32LE(pcm.length, 40);
12644
- fs18.writeFileSync(output, Buffer.concat([header, pcm]));
12974
+ fs20.writeFileSync(output, Buffer.concat([header, pcm]));
12645
12975
  return output;
12646
12976
  }
12647
12977
  async function ttsQwen3Local(text, cfg, onChunk) {
@@ -12693,14 +13023,14 @@ async function ttsQwen3Opus(text, cfg) {
12693
13023
  const ogg = Buffer.from(await res.arrayBuffer());
12694
13024
  if (ogg.length < 20) throw new Error("qwen3-3060 opus: empty output");
12695
13025
  const durationMs = parseInt(res.headers.get("x-duration-ms") || "0", 10);
12696
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12697
- const oggPath = path19.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
12698
- 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);
12699
13029
  return { oggPath, durationMs };
12700
13030
  }
12701
13031
  async function ttsGptsovits(text) {
12702
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12703
- 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`);
12704
13034
  const params = new URLSearchParams({
12705
13035
  text,
12706
13036
  text_language: "zh",
@@ -12711,12 +13041,12 @@ async function ttsGptsovits(text) {
12711
13041
  const res = await fetch(`${GPTSOVITS_API}/?${params}`);
12712
13042
  if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
12713
13043
  const buf = Buffer.from(await res.arrayBuffer());
12714
- fs18.writeFileSync(output, buf);
13044
+ fs20.writeFileSync(output, buf);
12715
13045
  return output;
12716
13046
  }
12717
13047
  async function ttsEdge(text) {
12718
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12719
- 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`);
12720
13050
  const script = `
12721
13051
  import asyncio, edge_tts, sys
12722
13052
  async def main():
@@ -12743,11 +13073,11 @@ async function toWav24kWithDuration(audioPath) {
12743
13073
  "pcm_s16le",
12744
13074
  wavPath
12745
13075
  ], { timeout: 3e4 });
12746
- if (!fs18.existsSync(wavPath) || fs18.statSync(wavPath).size < 44) {
13076
+ if (!fs20.existsSync(wavPath) || fs20.statSync(wavPath).size < 44) {
12747
13077
  throw new Error("toWav24k produced empty output");
12748
13078
  }
12749
13079
  try {
12750
- fs18.unlinkSync(audioPath);
13080
+ fs20.unlinkSync(audioPath);
12751
13081
  } catch {
12752
13082
  }
12753
13083
  }
@@ -12778,7 +13108,7 @@ async function compressWav(wavPath) {
12778
13108
  "+faststart",
12779
13109
  m4aPath
12780
13110
  ], { timeout: 3e4 });
12781
- fs18.unlinkSync(wavPath);
13111
+ fs20.unlinkSync(wavPath);
12782
13112
  return m4aPath;
12783
13113
  } catch {
12784
13114
  return wavPath;
@@ -12805,10 +13135,10 @@ async function wavToOggOpus(wavPath) {
12805
13135
  oggPath
12806
13136
  ], { timeout: 3e4 });
12807
13137
  }
12808
- if (!fs18.existsSync(oggPath) || fs18.statSync(oggPath).size < 20) {
13138
+ if (!fs20.existsSync(oggPath) || fs20.statSync(oggPath).size < 20) {
12809
13139
  throw new Error("ogg/opus encode produced empty output");
12810
13140
  }
12811
- fs18.unlinkSync(wavPath);
13141
+ fs20.unlinkSync(wavPath);
12812
13142
  return oggPath;
12813
13143
  }
12814
13144
  async function sendVoiceToMulticaIssue(text, issueId, opts) {
@@ -12825,8 +13155,8 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12825
13155
  const pcmChunks = [];
12826
13156
  await ttsQwen3Local(text, { url: vc.url, voice: vc.voice, lang: vc.lang }, (pcm2) => pcmChunks.push(pcm2));
12827
13157
  const pcm = Buffer.concat(pcmChunks);
12828
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
12829
- 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`);
12830
13160
  const header = Buffer.alloc(44);
12831
13161
  header.write("RIFF", 0);
12832
13162
  header.writeUInt32LE(36 + pcm.length, 4);
@@ -12841,7 +13171,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12841
13171
  header.writeUInt16LE(16, 34);
12842
13172
  header.write("data", 36);
12843
13173
  header.writeUInt32LE(pcm.length, 40);
12844
- fs18.writeFileSync(wavPath, Buffer.concat([header, pcm]));
13174
+ fs20.writeFileSync(wavPath, Buffer.concat([header, pcm]));
12845
13175
  audioPath = wavPath;
12846
13176
  }
12847
13177
  } else if (actualEngine === "cosyvoice" && vc?.apiKey) {
@@ -12855,7 +13185,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12855
13185
  } catch (e) {
12856
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 };
12857
13187
  }
12858
- if (!audioPath || !fs18.existsSync(audioPath)) {
13188
+ if (!audioPath || !fs20.existsSync(audioPath)) {
12859
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 };
12860
13190
  }
12861
13191
  if (audioPath.endsWith(".wav")) {
@@ -12865,21 +13195,21 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12865
13195
  console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
12866
13196
  }
12867
13197
  }
12868
- const ext = path19.extname(audioPath).toLowerCase();
12869
- const sizeKB = fs18.statSync(audioPath).size / 1024;
13198
+ const ext = path21.extname(audioPath).toLowerCase();
13199
+ const sizeKB = fs20.statSync(audioPath).size / 1024;
12870
13200
  const voiceFile = `voice_${Date.now()}${ext}`;
12871
- const cwdCopy = path19.join(process.cwd(), voiceFile);
13201
+ const cwdCopy = path21.join(process.cwd(), voiceFile);
12872
13202
  try {
12873
- fs18.copyFileSync(audioPath, cwdCopy);
13203
+ fs20.copyFileSync(audioPath, cwdCopy);
12874
13204
  } catch (e) {
12875
13205
  try {
12876
- fs18.unlinkSync(audioPath);
13206
+ fs20.unlinkSync(audioPath);
12877
13207
  } catch {
12878
13208
  }
12879
13209
  return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
12880
13210
  }
12881
13211
  try {
12882
- fs18.unlinkSync(audioPath);
13212
+ fs20.unlinkSync(audioPath);
12883
13213
  } catch {
12884
13214
  }
12885
13215
  const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
@@ -12908,13 +13238,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12908
13238
  }
12909
13239
  if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
12910
13240
  try {
12911
- fs18.unlinkSync(cwdCopy);
13241
+ fs20.unlinkSync(cwdCopy);
12912
13242
  } catch {
12913
13243
  }
12914
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)` };
12915
13245
  } catch (e) {
12916
13246
  try {
12917
- fs18.unlinkSync(cwdCopy);
13247
+ fs20.unlinkSync(cwdCopy);
12918
13248
  } catch {
12919
13249
  }
12920
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 };
@@ -12929,7 +13259,7 @@ var init_my_voice = __esm({
12929
13259
  init_opus_encoder();
12930
13260
  init_voice_chat_tts_daemon();
12931
13261
  execFileAsync = promisify(execFile2);
12932
- VOICE_DIR = path19.join(os3.tmpdir(), "engine-voice");
13262
+ VOICE_DIR = path21.join(os3.tmpdir(), "engine-voice");
12933
13263
  _pyCache = null;
12934
13264
  GPTSOVITS_API = "http://127.0.0.1:9880";
12935
13265
  GPTSOVITS_REF_WAV = "/home/chong/voice/ref/shanshan_ref_v2.wav";
@@ -13028,8 +13358,8 @@ var init_my_voice = __esm({
13028
13358
  const pcmChunks = [];
13029
13359
  await ttsQwen3Local(text, { url: vc.url, voice: vc.voice, lang: vc.lang }, (pcm2) => pcmChunks.push(pcm2));
13030
13360
  const pcm = Buffer.concat(pcmChunks);
13031
- fs18.mkdirSync(VOICE_DIR, { recursive: true });
13032
- 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`);
13033
13363
  const header = Buffer.alloc(44);
13034
13364
  header.write("RIFF", 0);
13035
13365
  header.writeUInt32LE(36 + pcm.length, 4);
@@ -13044,7 +13374,7 @@ var init_my_voice = __esm({
13044
13374
  header.writeUInt16LE(16, 34);
13045
13375
  header.write("data", 36);
13046
13376
  header.writeUInt32LE(pcm.length, 40);
13047
- fs18.writeFileSync(wavPath, Buffer.concat([header, pcm]));
13377
+ fs20.writeFileSync(wavPath, Buffer.concat([header, pcm]));
13048
13378
  audioPath = wavPath;
13049
13379
  }
13050
13380
  } catch (e) {
@@ -13075,10 +13405,10 @@ var init_my_voice = __esm({
13075
13405
  audioPath = await compressWav(audioPath);
13076
13406
  }
13077
13407
  }
13078
- const ext = path19.extname(audioPath).toLowerCase();
13408
+ const ext = path21.extname(audioPath).toLowerCase();
13079
13409
  const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
13080
13410
  const mimeType = mimeMap[ext] || "audio/mpeg";
13081
- const sizeKB = fs18.statSync(audioPath).size / 1024;
13411
+ const sizeKB = fs20.statSync(audioPath).size / 1024;
13082
13412
  try {
13083
13413
  await mgr.sendFile(resolvedChannel, target, caption, {
13084
13414
  path: audioPath,
@@ -13087,7 +13417,7 @@ var init_my_voice = __esm({
13087
13417
  ...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
13088
13418
  });
13089
13419
  try {
13090
- fs18.unlinkSync(audioPath);
13420
+ fs20.unlinkSync(audioPath);
13091
13421
  } catch {
13092
13422
  }
13093
13423
  return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
@@ -13104,8 +13434,8 @@ var init_my_voice = __esm({
13104
13434
  });
13105
13435
 
13106
13436
  // src/tools/my-selfie.ts
13107
- import * as fs19 from "node:fs";
13108
- import * as path20 from "node:path";
13437
+ import * as fs21 from "node:fs";
13438
+ import * as path22 from "node:path";
13109
13439
  function getProxyDispatcher2() {
13110
13440
  const cfg = liveConfig.all();
13111
13441
  const proxy = cfg.providers?.xai?.proxy;
@@ -13421,12 +13751,12 @@ var init_my_selfie = __esm({
13421
13751
  const REFERENCES = getReferences(ctx);
13422
13752
  const refName = args.reference || "default";
13423
13753
  const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
13424
- const refPath = path20.join(ctx.workspace, refEntry.p);
13425
- if (provider !== "autodl" && !fs19.existsSync(refPath)) {
13754
+ const refPath = path22.join(ctx.workspace, refEntry.p);
13755
+ if (provider !== "autodl" && !fs21.existsSync(refPath)) {
13426
13756
  return { content: `Error: reference image not found at ${refPath}`, isError: true };
13427
13757
  }
13428
13758
  const resolution = args.resolution || DEFAULT_RESOLUTION;
13429
- const refB64 = fs19.existsSync(refPath) ? fs19.readFileSync(refPath).toString("base64") : "";
13759
+ const refB64 = fs21.existsSync(refPath) ? fs21.readFileSync(refPath).toString("base64") : "";
13430
13760
  let imageBuffer;
13431
13761
  try {
13432
13762
  if (provider === "autodl") {
@@ -13441,11 +13771,11 @@ var init_my_selfie = __esm({
13441
13771
  } catch (err) {
13442
13772
  return { content: `Selfie generation failed: ${err.message}`, isError: true };
13443
13773
  }
13444
- const imagesDir = path20.join(ctx.workspace, "images");
13445
- 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 });
13446
13776
  const filename = `selfie_${Date.now()}.jpg`;
13447
- const outputPath = path20.join(imagesDir, filename);
13448
- fs19.writeFileSync(outputPath, imageBuffer);
13777
+ const outputPath = path22.join(imagesDir, filename);
13778
+ fs21.writeFileSync(outputPath, imageBuffer);
13449
13779
  const mgr = ctx.channelManager;
13450
13780
  if (mgr) {
13451
13781
  const resolvedChannel = ctx.channel || "feishu";
@@ -13456,11 +13786,11 @@ var init_my_selfie = __esm({
13456
13786
  mimeType: "image/jpeg"
13457
13787
  });
13458
13788
  } catch (err) {
13459
- 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 };
13460
13790
  }
13461
13791
  return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
13462
13792
  }
13463
- 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)}` };
13464
13794
  },
13465
13795
  isConcurrencySafe: () => false,
13466
13796
  interruptBehavior: () => "block",
@@ -13555,88 +13885,6 @@ var init_body_move = __esm({
13555
13885
  }
13556
13886
  });
13557
13887
 
13558
- // src/calendar/db.ts
13559
- import * as path21 from "node:path";
13560
- import * as fs20 from "node:fs";
13561
- import { createRequire as createRequire2 } from "node:module";
13562
- function getSqlite() {
13563
- if (!_sqlite) _sqlite = createRequire2(import.meta.url)("node:sqlite");
13564
- return _sqlite;
13565
- }
13566
- function openDb(workspace) {
13567
- const dir = path21.join(workspace, ".calendar");
13568
- fs20.mkdirSync(dir, { recursive: true });
13569
- const dbPath = path21.join(dir, "calendar.db");
13570
- const db = new DatabaseSync(dbPath);
13571
- db.exec("PRAGMA journal_mode=WAL");
13572
- db.exec(`CREATE TABLE IF NOT EXISTS events (
13573
- id INTEGER PRIMARY KEY AUTOINCREMENT,
13574
- type TEXT NOT NULL,
13575
- status TEXT NOT NULL DEFAULT 'pending',
13576
- event TEXT NOT NULL,
13577
- day TEXT,
13578
- time TEXT,
13579
- date_str TEXT,
13580
- created_at TEXT NOT NULL,
13581
- done_at TEXT,
13582
- archived_at TEXT
13583
- )`);
13584
- migrate(db);
13585
- return db;
13586
- }
13587
- function migrate(db) {
13588
- const cols = new Set(
13589
- db.prepare("PRAGMA table_info(events)").all().map((r) => r.name)
13590
- );
13591
- if (!cols.has("remind_before_min")) {
13592
- db.exec("ALTER TABLE events ADD COLUMN remind_before_min INTEGER DEFAULT 60");
13593
- }
13594
- if (!cols.has("remind_at")) {
13595
- db.exec("ALTER TABLE events ADD COLUMN remind_at TEXT");
13596
- }
13597
- if (!cols.has("reminded")) {
13598
- db.exec("ALTER TABLE events ADD COLUMN reminded INTEGER DEFAULT 0");
13599
- }
13600
- if (!cols.has("time_exact")) {
13601
- db.exec("ALTER TABLE events ADD COLUMN time_exact TEXT");
13602
- }
13603
- if (!cols.has("start_time")) {
13604
- db.exec("ALTER TABLE events ADD COLUMN start_time TEXT");
13605
- }
13606
- if (!cols.has("duration_min")) {
13607
- db.exec("ALTER TABLE events ADD COLUMN duration_min INTEGER");
13608
- }
13609
- if (!cols.has("created_channel")) {
13610
- db.exec("ALTER TABLE events ADD COLUMN created_channel TEXT");
13611
- }
13612
- if (!cols.has("created_channel_target")) {
13613
- db.exec("ALTER TABLE events ADD COLUMN created_channel_target TEXT");
13614
- }
13615
- if (!cols.has("repeat_type")) {
13616
- db.exec("ALTER TABLE events ADD COLUMN repeat_type TEXT DEFAULT 'once'");
13617
- }
13618
- if (!cols.has("doc_path")) {
13619
- db.exec("ALTER TABLE events ADD COLUMN doc_path TEXT");
13620
- }
13621
- }
13622
- var _sqlite, DatabaseSync, TZ_OFFSET_MS;
13623
- var init_db = __esm({
13624
- "src/calendar/db.ts"() {
13625
- "use strict";
13626
- _sqlite = null;
13627
- DatabaseSync = new Proxy(function() {
13628
- }, {
13629
- construct(_t, args) {
13630
- return new (getSqlite()).DatabaseSync(...args);
13631
- },
13632
- get(_t, prop) {
13633
- return getSqlite().DatabaseSync[prop];
13634
- }
13635
- });
13636
- TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
13637
- }
13638
- });
13639
-
13640
13888
  // src/calendar/helpers.ts
13641
13889
  function nowIso() {
13642
13890
  return new Date(Date.now() + TZ_OFFSET_MS2 - (/* @__PURE__ */ new Date()).getTimezoneOffset() * 6e4).toISOString().replace("Z", "+08:00");
@@ -13862,14 +14110,14 @@ function fmtEnd(start, durationMin) {
13862
14110
  const total = hh * 60 + mm + durationMin;
13863
14111
  return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, "0")}`;
13864
14112
  }
13865
- function addWeekly(db, args) {
14113
+ function addWeekly(db2, args) {
13866
14114
  const { day, event } = args;
13867
14115
  if (!WEEKDAYS2.includes(day)) return `\u9519\u8BEF: \u661F\u671F\u5FC5\u987B\u662F ${WEEKDAYS2.join("/")}`;
13868
14116
  if (!args.time) return `\u9519\u8BEF: \u5468\u671F\u65E5\u7A0B\u5FC5\u987B\u586B start_time\uFF08\u5982 time='14:00'\uFF09`;
13869
14117
  if (!args.duration) return `\u9519\u8BEF: \u5468\u671F\u65E5\u7A0B\u5FC5\u987B\u586B duration\uFF08\u5982 duration='1h'\uFF09`;
13870
14118
  const durationMin = parseDuration(args.duration);
13871
14119
  if (!durationMin) return `\u9519\u8BEF: duration \u683C\u5F0F\u4E0D\u5BF9\uFF08\u5982 '30m' / '1h'\uFF09`;
13872
- const conflictRows = db.prepare(
14120
+ const conflictRows = db2.prepare(
13873
14121
  "SELECT * FROM events WHERE status='pending' AND type='weekly' AND day=?"
13874
14122
  ).all(day);
13875
14123
  const conflict = checkScheduleConflict(conflictRows, args.time, durationMin);
@@ -13884,16 +14132,16 @@ function addWeekly(db, args) {
13884
14132
  else remindMin = parseInt(v) || 60;
13885
14133
  }
13886
14134
  const remindAt = computeWeeklyRemindAt(day, args.time, remindMin);
13887
- const r = db.prepare(
14135
+ const r = db2.prepare(
13888
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)
13889
14137
  VALUES ('weekly','pending',?,?,?,?,?,?,?,?,?,?,?)`
13890
14138
  ).run(event, day, args.time, args.time, durationMin, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
13891
14139
  return `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0: [\u6BCF\u5468] ${day} ${args.time} (${durationMin}min) ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
13892
14140
  }
13893
- function addDaily(db, args) {
14141
+ function addDaily(db2, args) {
13894
14142
  const { time, event, repeatType } = args;
13895
14143
  if (!time) return `\u9519\u8BEF: \u6BCF\u65E5\u4EFB\u52A1\u5FC5\u987B\u586B time\uFF08\u5982 time='23:00'\uFF09`;
13896
- const dailyRows = db.prepare(
14144
+ const dailyRows = db2.prepare(
13897
14145
  "SELECT * FROM events WHERE status='pending' AND type='daily'"
13898
14146
  ).all();
13899
14147
  const [hh, mm] = time.split(":").map(Number);
@@ -13915,21 +14163,21 @@ function addDaily(db, args) {
13915
14163
  }
13916
14164
  const remindAt = repeatType === "daily" ? computeDailyRemindAt(time, remindMin) : computeWeekdaysRemindAt(time, remindMin);
13917
14165
  if (!remindAt) return `\u9519\u8BEF: \u65E0\u6CD5\u8BA1\u7B97 remind_at`;
13918
- const r = db.prepare(
14166
+ const r = db2.prepare(
13919
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)
13920
14168
  VALUES ('daily','pending',?,?,?,?,?,?,?,?,?,?)`
13921
14169
  ).run(event, time, time, repeatType, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
13922
14170
  const label = repeatType === "daily" ? "\u6BCF\u5929" : "\u5DE5\u4F5C\u65E5";
13923
14171
  return `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0: [${label}] ${time} ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
13924
14172
  }
13925
- function addDate(db, args) {
14173
+ function addDate(db2, args) {
13926
14174
  const { dateStr, event } = args;
13927
14175
  if (!args.time) return `\u9519\u8BEF: \u4E00\u6B21\u6027\u65E5\u7A0B\u5FC5\u987B\u586B start_time\uFF08\u5982 time='14:00'\uFF09`;
13928
14176
  if (!args.duration) return `\u9519\u8BEF: \u4E00\u6B21\u6027\u65E5\u7A0B\u5FC5\u987B\u586B duration\uFF08\u5982 duration='1h'\uFF09`;
13929
14177
  const durationMin = parseDuration(args.duration);
13930
14178
  if (!durationMin) return `\u9519\u8BEF: duration \u683C\u5F0F\u4E0D\u5BF9\uFF08\u5982 '30m' / '1h'\uFF09`;
13931
14179
  const todayWeekday = getTodayWeekday();
13932
- const dateRows = db.prepare(
14180
+ const dateRows = db2.prepare(
13933
14181
  "SELECT * FROM events WHERE status='pending' AND type='date' AND date_str=?"
13934
14182
  ).all(dateStr);
13935
14183
  const parsed = parseDateRange(dateStr);
@@ -13939,7 +14187,7 @@ function addDate(db, args) {
13939
14187
  const year = now.getUTCFullYear();
13940
14188
  const d = new Date(Date.UTC(year, parsed.month - 1, parsed.dStart));
13941
14189
  const weekday = WEEKDAYS2[d.getUTCDay() === 0 ? 6 : d.getUTCDay() - 1];
13942
- weeklyRows = db.prepare(
14190
+ weeklyRows = db2.prepare(
13943
14191
  "SELECT * FROM events WHERE status='pending' AND type='weekly' AND day=?"
13944
14192
  ).all(weekday);
13945
14193
  }
@@ -13956,13 +14204,13 @@ function addDate(db, args) {
13956
14204
  else remindMin = parseInt(v) || 60;
13957
14205
  }
13958
14206
  const remindAt = computeRemindAt(dateStr, args.time, remindMin);
13959
- const r = db.prepare(
14207
+ const r = db2.prepare(
13960
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)
13961
14209
  VALUES ('date','pending',?,?,?,?,?,?,?,?,?,?,?)`
13962
14210
  ).run(event, dateStr, args.time, args.time, durationMin, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
13963
14211
  return `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0: [${dateStr} ${args.time} (${durationMin}min)] ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
13964
14212
  }
13965
- function addBatch(db, args) {
14213
+ function addBatch(db2, args) {
13966
14214
  if (!args.time) return `\u9519\u8BEF: \u6279\u91CF\u6DFB\u52A0\u5FC5\u987B\u586B time\uFF08\u5982 time='14:00'\uFF09`;
13967
14215
  if (!args.duration) return `\u9519\u8BEF: \u6279\u91CF\u6DFB\u52A0\u5FC5\u987B\u586B duration\uFF08\u5982 duration='1h'\uFF09`;
13968
14216
  const durationMin = parseDuration(args.duration);
@@ -13979,7 +14227,7 @@ function addBatch(db, args) {
13979
14227
  const ok = [];
13980
14228
  const skipped = [];
13981
14229
  for (const dateStr of dates) {
13982
- const dateRows = db.prepare(
14230
+ const dateRows = db2.prepare(
13983
14231
  "SELECT * FROM events WHERE status='pending' AND type='date' AND date_str=?"
13984
14232
  ).all(dateStr);
13985
14233
  const parsed = parseDateRange(dateStr);
@@ -13989,7 +14237,7 @@ function addBatch(db, args) {
13989
14237
  const year = now.getUTCFullYear();
13990
14238
  const d = new Date(Date.UTC(year, parsed.month - 1, parsed.dStart));
13991
14239
  const weekday = WEEKDAYS2[d.getUTCDay() === 0 ? 6 : d.getUTCDay() - 1];
13992
- weeklyRows = db.prepare(
14240
+ weeklyRows = db2.prepare(
13993
14241
  "SELECT * FROM events WHERE status='pending' AND type='weekly' AND day=?"
13994
14242
  ).all(weekday);
13995
14243
  }
@@ -14000,7 +14248,7 @@ function addBatch(db, args) {
14000
14248
  continue;
14001
14249
  }
14002
14250
  const remindAt = computeRemindAt(dateStr, args.time, remindMin);
14003
- const r = db.prepare(
14251
+ const r = db2.prepare(
14004
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)
14005
14253
  VALUES ('date','pending',?,?,?,?,?,?,?,?,?,?,?)`
14006
14254
  ).run(args.event, dateStr, args.time, args.time, durationMin, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
@@ -14017,7 +14265,7 @@ ${skipped.map((s) => ` ${s}`).join("\n")}`;
14017
14265
  }
14018
14266
  return result2;
14019
14267
  }
14020
- function addTask(db, args) {
14268
+ function addTask(db2, args) {
14021
14269
  const { dateStr, timeExact, event, docPath } = args;
14022
14270
  if (!docPath || !docPath.trim()) {
14023
14271
  return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Aadd-task \u5FC5\u987B\u4F20 doc_path\u3002
@@ -14048,12 +14296,12 @@ function addTask(db, args) {
14048
14296
  else if (v.endsWith("h")) remindMin = parseInt(v.slice(0, -1)) * 60;
14049
14297
  else remindMin = parseInt(v) || 60;
14050
14298
  }
14051
- const taskRows = db.prepare(
14299
+ const taskRows = db2.prepare(
14052
14300
  "SELECT * FROM events WHERE status='pending' AND type='task' AND date_str=?"
14053
14301
  ).all(dateStr);
14054
14302
  const prox = checkTaskProximity(taskRows, timeExact);
14055
14303
  const remindAt = computeRemindAt(dateStr, timeExact, remindMin);
14056
- const r = db.prepare(
14304
+ const r = db2.prepare(
14057
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)
14058
14306
  VALUES ('task','pending',?,?,?,?,?,?,?,?,?,?)`
14059
14307
  ).run(event, dateStr, timeExact, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null, docPath);
@@ -14065,9 +14313,9 @@ function addTask(db, args) {
14065
14313
  }
14066
14314
  return msg2;
14067
14315
  }
14068
- function reschedule(db, args) {
14316
+ function reschedule(db2, args) {
14069
14317
  const { id, dateStr, timeExact } = args;
14070
- const row = db.prepare("SELECT * FROM events WHERE id=?").get(id);
14318
+ const row = db2.prepare("SELECT * FROM events WHERE id=?").get(id);
14071
14319
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14072
14320
  if (row.type !== "task") return `#${id} \u4E0D\u662F task \u7C7B\u578B\uFF08${row.type}\uFF09\uFF0Creschedule \u4EC5\u652F\u6301 task`;
14073
14321
  let remindMin = row.remind_before_min || 60;
@@ -14078,12 +14326,12 @@ function reschedule(db, args) {
14078
14326
  else remindMin = parseInt(v) || remindMin;
14079
14327
  }
14080
14328
  const remindAt = computeRemindAt(dateStr, timeExact, remindMin);
14081
- 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);
14082
14330
  return `#${id} \u5DF2\u6539\u671F: [${dateStr} ${timeExact}] ${row.event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
14083
14331
  }
14084
- function list(db, opts = {}) {
14332
+ function list(db2, opts = {}) {
14085
14333
  if (opts.all) {
14086
- 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();
14087
14335
  const out2 = ["## \u6BCF\u5468\u56FA\u5B9A"];
14088
14336
  for (const r of rows) if (r.type === "weekly") out2.push(fmtRow(r));
14089
14337
  out2.push("\n## \u6BCF\u65E5\u56FA\u5B9A");
@@ -14097,17 +14345,17 @@ function list(db, opts = {}) {
14097
14345
  const out = [`\u5F53\u524D\u65F6\u95F4: ${fmtNow()}`];
14098
14346
  const todayWeekday = getTodayWeekday();
14099
14347
  const events = [];
14100
- 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)) {
14101
14349
  events.push(` #${r.id} ${r.time || ""} ${r.event}`);
14102
14350
  }
14103
- 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()) {
14104
14352
  if (r.repeat_type === "weekdays") {
14105
14353
  const idx = new Date(Date.now() + 8 * 60 * 60 * 1e3).getUTCDay();
14106
14354
  if (idx === 0 || idx === 6) continue;
14107
14355
  }
14108
14356
  events.push(` #${r.id} ${r.time || ""} ${r.event}`);
14109
14357
  }
14110
- 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()) {
14111
14359
  const p = parseDateRange(r.date_str);
14112
14360
  if (p && isToday(p.month, p.dStart, p.dEnd)) {
14113
14361
  events.push(` #${r.id} ${r.event}`);
@@ -14121,14 +14369,14 @@ function list(db, opts = {}) {
14121
14369
  }
14122
14370
  return out.join("\n");
14123
14371
  }
14124
- function pending(db) {
14372
+ function pending(db2) {
14125
14373
  const out = [`\u5F53\u524D\u65F6\u95F4: ${fmtNow()}`];
14126
14374
  const todayWeekday = getTodayWeekday();
14127
14375
  const events = [];
14128
- 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)) {
14129
14377
  events.push(` #${r.id} [\u6BCF\u5468] ${r.time || ""} ${r.event}`);
14130
14378
  }
14131
- 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()) {
14132
14380
  if (r.repeat_type === "weekdays") {
14133
14381
  const idx = new Date(Date.now() + 8 * 60 * 60 * 1e3).getUTCDay();
14134
14382
  if (idx === 0 || idx === 6) continue;
@@ -14136,7 +14384,7 @@ function pending(db) {
14136
14384
  const label = r.repeat_type === "weekdays" ? "[\u5DE5\u4F5C\u65E5]" : "[\u6BCF\u5929]";
14137
14385
  events.push(` #${r.id} ${label} ${r.time || ""} ${r.event}`);
14138
14386
  }
14139
- 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()) {
14140
14388
  const p = parseDateRange(r.date_str);
14141
14389
  if (!p) continue;
14142
14390
  if (isToday(p.month, p.dStart, p.dEnd)) {
@@ -14155,31 +14403,31 @@ function pending(db) {
14155
14403
  }
14156
14404
  return out.join("\n");
14157
14405
  }
14158
- function done(db, id) {
14159
- 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");
14160
14408
  if (!row) return `\u672A\u627E\u5230 pending \u4E8B\u4EF6 #${id}`;
14161
14409
  if (row.type === "daily" || row.type === "weekly") {
14162
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}`;
14163
14411
  }
14164
- 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);
14165
14413
  return `#${id} \u5DF2\u6807\u8BB0\u5B8C\u6210: ${row.event}`;
14166
14414
  }
14167
- function linkDoc(db, id, docPath) {
14168
- 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);
14169
14417
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14170
- 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);
14171
14419
  return `#${id} \u5DF2\u5173\u8054\u6587\u6863: ${docPath}`;
14172
14420
  }
14173
- function findDoc(db, id) {
14174
- 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);
14175
14423
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14176
14424
  const parts = [`#${id} ${row.event}`];
14177
14425
  if (row.doc_path) parts.push(`\u{1F4C4} doc_path: ${row.doc_path}`);
14178
14426
  else parts.push(`\u{1F4C4} doc_path: (\u672A\u5173\u8054)`);
14179
14427
  return parts.join("\n");
14180
14428
  }
14181
- function search(db, keyword) {
14182
- 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}%`);
14183
14431
  if (rows.length > 0) {
14184
14432
  const out = [`\u67E5\u8BE2 '${keyword}' (${rows.length} \u6761):`];
14185
14433
  rows.forEach((r) => out.push(fmtRow(r)));
@@ -14187,29 +14435,29 @@ function search(db, keyword) {
14187
14435
  }
14188
14436
  return `\u67E5\u8BE2 '${keyword}' \u65E0\u7ED3\u679C`;
14189
14437
  }
14190
- function archive(db, id) {
14191
- 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");
14192
14440
  if (!row) return `\u672A\u627E\u5230\u4E8B\u4EF6 #${id}`;
14193
- 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);
14194
14442
  return `#${id} \u5DF2\u5F52\u6863: ${row.event}`;
14195
14443
  }
14196
- function cleanup(db) {
14197
- 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();
14198
14446
  let archived = 0;
14199
14447
  for (const r of rows) {
14200
14448
  const p = parseDateRange(r.date_str);
14201
14449
  if (p && isOverdue(p.month, p.dStart, p.dEnd)) {
14202
- 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);
14203
14451
  archived++;
14204
14452
  }
14205
14453
  }
14206
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";
14207
14455
  }
14208
- function stats(db) {
14209
- const total = db.prepare("SELECT COUNT(*) as c FROM events").get().c;
14210
- const pending2 = db.prepare("SELECT COUNT(*) as c FROM events WHERE status='pending'").get().c;
14211
- const done2 = db.prepare("SELECT COUNT(*) as c FROM events WHERE status='done'").get().c;
14212
- 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;
14213
14461
  return `\u65E5\u5386\u7EDF\u8BA1: \u603B\u8BA1 ${total} | pending ${pending2} | done ${done2} | archived ${archived}`;
14214
14462
  }
14215
14463
  var WEEKDAYS2;
@@ -14255,7 +14503,7 @@ var init_calendar = __esm({
14255
14503
  const action = args.action;
14256
14504
  if (!action) return { content: "Error: action is required", isError: true };
14257
14505
  try {
14258
- const db = openDb(ctx.workspace);
14506
+ const db2 = openDb(ctx.workspace);
14259
14507
  let result2;
14260
14508
  let isAddTask = false;
14261
14509
  if (action === "add") {
@@ -14265,22 +14513,22 @@ var init_calendar = __esm({
14265
14513
  const repeat = args.repeat || (args.weekly ? "weekly" : "once");
14266
14514
  if (repeat === "daily" || repeat === "weekdays") {
14267
14515
  if (!args.time) return { content: "Error: add daily/weekdays needs time (e.g. 23:00)", isError: true };
14268
- 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 });
14269
14517
  } else if (repeat === "weekly") {
14270
14518
  const day = args.day;
14271
14519
  if (!day) return { content: "Error: add weekly needs day", isError: true };
14272
- 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 });
14273
14521
  } else {
14274
14522
  const date = args.date?.trim();
14275
14523
  if (!date) return { content: "Error: add once needs date (e.g. 5/26)", isError: true };
14276
- 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 });
14277
14525
  }
14278
14526
  } else if (action === "add-batch") {
14279
14527
  const event = args.event?.trim();
14280
14528
  const datesInput = args.dates?.trim();
14281
14529
  if (!event) return { content: "Error: add-batch needs event", isError: true };
14282
14530
  if (!datesInput) return { content: 'Error: add-batch needs dates (e.g. "7/2,7/4,7/6-7/10")', isError: true };
14283
- 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 });
14284
14532
  } else if (action === "add-task") {
14285
14533
  isAddTask = true;
14286
14534
  const event = args.event?.trim();
@@ -14291,47 +14539,47 @@ var init_calendar = __esm({
14291
14539
  if (!date) return { content: "Error: add-task needs date (e.g. 7/5)", isError: true };
14292
14540
  if (!timeExact || !timeExact.includes(":")) return { content: "Error: add-task needs time_exact (HH:MM, e.g. 14:00)", isError: true };
14293
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 };
14294
- 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 });
14295
14543
  } else if (action === "reschedule") {
14296
14544
  if (args.id == null) return { content: "Error: reschedule needs id", isError: true };
14297
14545
  const date = args.date?.trim();
14298
14546
  const timeExact = args.time_exact?.trim();
14299
14547
  if (!date) return { content: "Error: reschedule needs date (e.g. 7/10)", isError: true };
14300
14548
  if (!timeExact || !timeExact.includes(":")) return { content: "Error: reschedule needs time_exact (HH:MM)", isError: true };
14301
- 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 });
14302
14550
  } else if (action === "link-doc") {
14303
14551
  if (args.id == null) return { content: "Error: link-doc needs id", isError: true };
14304
14552
  const docPath = args.doc_path?.trim();
14305
14553
  if (!docPath) return { content: "Error: link-doc needs doc_path", isError: true };
14306
- result2 = linkDoc(db, args.id, docPath);
14554
+ result2 = linkDoc(db2, args.id, docPath);
14307
14555
  } else if (action === "find-doc") {
14308
14556
  if (args.id == null) return { content: "Error: find-doc needs id", isError: true };
14309
- result2 = findDoc(db, args.id);
14557
+ result2 = findDoc(db2, args.id);
14310
14558
  } else if (action === "list") {
14311
- result2 = list(db, { all: !!args.all });
14559
+ result2 = list(db2, { all: !!args.all });
14312
14560
  } else if (action === "done") {
14313
14561
  if (args.id == null) return { content: "Error: done needs id", isError: true };
14314
- result2 = done(db, args.id);
14562
+ result2 = done(db2, args.id);
14315
14563
  } else if (action === "pending") {
14316
- result2 = pending(db);
14564
+ result2 = pending(db2);
14317
14565
  } else if (action === "search") {
14318
14566
  const kw = args.event?.trim();
14319
14567
  if (!kw) return { content: "Error: search needs keyword (event field)", isError: true };
14320
- result2 = search(db, kw);
14568
+ result2 = search(db2, kw);
14321
14569
  } else if (action === "archive") {
14322
14570
  if (args.id == null) return { content: "Error: archive needs id", isError: true };
14323
- result2 = archive(db, args.id);
14571
+ result2 = archive(db2, args.id);
14324
14572
  } else if (action === "delete") {
14325
14573
  if (args.id == null) return { content: "Error: delete needs id", isError: true };
14326
- result2 = archive(db, args.id);
14574
+ result2 = archive(db2, args.id);
14327
14575
  } else if (action === "cleanup") {
14328
- result2 = cleanup(db);
14576
+ result2 = cleanup(db2);
14329
14577
  } else if (action === "stats") {
14330
- result2 = stats(db);
14578
+ result2 = stats(db2);
14331
14579
  } else {
14332
14580
  return { content: `Error: unknown action '${action}'`, isError: true };
14333
14581
  }
14334
- db.close();
14582
+ db2.close();
14335
14583
  const isFailed = result2.startsWith("\u274C") || result2.includes("Error") || result2.includes("\u7528\u6CD5");
14336
14584
  if (isAddTask && !isFailed) {
14337
14585
  const { enqueueNotification: enqueueNotification2, buildCalendarNotification: buildCalendarNotification2 } = await Promise.resolve().then(() => (init_task_manager(), task_manager_exports));
@@ -14575,24 +14823,24 @@ var init_constants5 = __esm({
14575
14823
  });
14576
14824
 
14577
14825
  // src/tools/TodoWriteTool/TodoWriteTool.ts
14578
- import fs21 from "node:fs";
14579
- import path22 from "node:path";
14826
+ import fs22 from "node:fs";
14827
+ import path23 from "node:path";
14580
14828
  function todoFilePath(sessionId) {
14581
- return path22.join(todosDir, `${sessionId}.json`);
14829
+ return path23.join(todosDir, `${sessionId}.json`);
14582
14830
  }
14583
14831
  function loadTodos(sessionId) {
14584
14832
  if (!todosDir) return [];
14585
14833
  try {
14586
14834
  const filePath = todoFilePath(sessionId);
14587
- if (!fs21.existsSync(filePath)) return [];
14588
- return JSON.parse(fs21.readFileSync(filePath, "utf-8"));
14835
+ if (!fs22.existsSync(filePath)) return [];
14836
+ return JSON.parse(fs22.readFileSync(filePath, "utf-8"));
14589
14837
  } catch {
14590
14838
  return [];
14591
14839
  }
14592
14840
  }
14593
14841
  function saveTodos(sessionId, todos) {
14594
14842
  if (!todosDir) return;
14595
- fs21.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
14843
+ fs22.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
14596
14844
  }
14597
14845
  var todosDir;
14598
14846
  var init_TodoWriteTool = __esm({
@@ -14849,15 +15097,15 @@ var init_constants7 = __esm({
14849
15097
  });
14850
15098
 
14851
15099
  // src/utils/plans.ts
14852
- import * as fs22 from "node:fs";
14853
- import * as path23 from "node:path";
15100
+ import * as fs23 from "node:fs";
15101
+ import * as path24 from "node:path";
14854
15102
  import * as crypto4 from "node:crypto";
14855
15103
  function generateSlug() {
14856
15104
  return crypto4.randomBytes(4).toString("hex");
14857
15105
  }
14858
15106
  function getPlansDirectory(stateDir) {
14859
- const plansDir = path23.join(stateDir, "plans");
14860
- fs22.mkdirSync(plansDir, { recursive: true });
15107
+ const plansDir = path24.join(stateDir, "plans");
15108
+ fs23.mkdirSync(plansDir, { recursive: true });
14861
15109
  return plansDir;
14862
15110
  }
14863
15111
  function getPlanSlug(sessionId, stateDir) {
@@ -14866,8 +15114,8 @@ function getPlanSlug(sessionId, stateDir) {
14866
15114
  const plansDir = getPlansDirectory(stateDir);
14867
15115
  for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
14868
15116
  slug = generateSlug();
14869
- const filePath = path23.join(plansDir, `${slug}.md`);
14870
- if (!fs22.existsSync(filePath)) {
15117
+ const filePath = path24.join(plansDir, `${slug}.md`);
15118
+ if (!fs23.existsSync(filePath)) {
14871
15119
  break;
14872
15120
  }
14873
15121
  }
@@ -14878,21 +15126,21 @@ function getPlanSlug(sessionId, stateDir) {
14878
15126
  function getPlanFilePath(sessionId, stateDir, agentId) {
14879
15127
  const slug = getPlanSlug(sessionId, stateDir);
14880
15128
  if (!agentId) {
14881
- return path23.join(getPlansDirectory(stateDir), `${slug}.md`);
15129
+ return path24.join(getPlansDirectory(stateDir), `${slug}.md`);
14882
15130
  }
14883
- return path23.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
15131
+ return path24.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
14884
15132
  }
14885
15133
  function getPlan(sessionId, stateDir, agentId) {
14886
15134
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
14887
15135
  try {
14888
- return fs22.readFileSync(filePath, "utf-8");
15136
+ return fs23.readFileSync(filePath, "utf-8");
14889
15137
  } catch {
14890
15138
  return null;
14891
15139
  }
14892
15140
  }
14893
15141
  function writePlan(sessionId, stateDir, content, agentId) {
14894
15142
  const filePath = getPlanFilePath(sessionId, stateDir, agentId);
14895
- fs22.writeFileSync(filePath, content, "utf-8");
15143
+ fs23.writeFileSync(filePath, content, "utf-8");
14896
15144
  return filePath;
14897
15145
  }
14898
15146
  var MAX_SLUG_RETRIES, planSlugCache;
@@ -15040,28 +15288,28 @@ var init_constants8 = __esm({
15040
15288
  });
15041
15289
 
15042
15290
  // src/utils/tasks.ts
15043
- import * as fs23 from "node:fs";
15044
- import * as path24 from "node:path";
15291
+ import * as fs24 from "node:fs";
15292
+ import * as path25 from "node:path";
15045
15293
  function sanitizePathComponent2(input) {
15046
15294
  return input.replace(/[^a-zA-Z0-9_-]/g, "-");
15047
15295
  }
15048
15296
  function getTasksDir2(stateDir, listId) {
15049
- return path24.join(stateDir, "tasks", sanitizePathComponent2(listId));
15297
+ return path25.join(stateDir, "tasks", sanitizePathComponent2(listId));
15050
15298
  }
15051
15299
  function getTaskPath(stateDir, listId, taskId) {
15052
- return path24.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
15300
+ return path25.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
15053
15301
  }
15054
15302
  function ensureTasksDir2(stateDir, listId) {
15055
15303
  const dir = getTasksDir2(stateDir, listId);
15056
- fs23.mkdirSync(dir, { recursive: true });
15304
+ fs24.mkdirSync(dir, { recursive: true });
15057
15305
  return dir;
15058
15306
  }
15059
15307
  function getHighWaterMarkPath(stateDir, listId) {
15060
- return path24.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
15308
+ return path25.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
15061
15309
  }
15062
15310
  function readHighWaterMark(stateDir, listId) {
15063
15311
  try {
15064
- const content = fs23.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
15312
+ const content = fs24.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
15065
15313
  const value = parseInt(content, 10);
15066
15314
  return isNaN(value) ? 0 : value;
15067
15315
  } catch {
@@ -15069,20 +15317,20 @@ function readHighWaterMark(stateDir, listId) {
15069
15317
  }
15070
15318
  }
15071
15319
  function writeHighWaterMark(stateDir, listId, value) {
15072
- fs23.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
15320
+ fs24.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
15073
15321
  }
15074
15322
  function findHighestTaskIdFromFiles(stateDir, listId) {
15075
15323
  const dir = getTasksDir2(stateDir, listId);
15076
15324
  let files;
15077
15325
  try {
15078
- files = fs23.readdirSync(dir);
15326
+ files = fs24.readdirSync(dir);
15079
15327
  } catch {
15080
15328
  return 0;
15081
15329
  }
15082
15330
  let highest = 0;
15083
- for (const file of files) {
15084
- if (!file.endsWith(".json")) continue;
15085
- 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);
15086
15334
  if (!isNaN(taskId) && taskId > highest) {
15087
15335
  highest = taskId;
15088
15336
  }
@@ -15101,14 +15349,14 @@ function createTask(stateDir, listId, taskData) {
15101
15349
  const id = String(highestId + 1);
15102
15350
  const task = { id, ...taskData };
15103
15351
  const filePath = getTaskPath(stateDir, listId, id);
15104
- fs23.writeFileSync(filePath, JSON.stringify(task, null, 2));
15352
+ fs24.writeFileSync(filePath, JSON.stringify(task, null, 2));
15105
15353
  return id;
15106
15354
  });
15107
15355
  }
15108
15356
  function getTask2(stateDir, listId, taskId) {
15109
15357
  const filePath = getTaskPath(stateDir, listId, taskId);
15110
15358
  try {
15111
- const content = fs23.readFileSync(filePath, "utf-8");
15359
+ const content = fs24.readFileSync(filePath, "utf-8");
15112
15360
  return JSON.parse(content);
15113
15361
  } catch {
15114
15362
  return null;
@@ -15118,7 +15366,7 @@ function listTasks2(stateDir, listId) {
15118
15366
  const dir = getTasksDir2(stateDir, listId);
15119
15367
  let files;
15120
15368
  try {
15121
- files = fs23.readdirSync(dir);
15369
+ files = fs24.readdirSync(dir);
15122
15370
  } catch {
15123
15371
  return [];
15124
15372
  }
@@ -15130,7 +15378,7 @@ function updateTask(stateDir, listId, taskId, updates) {
15130
15378
  if (!existing) return null;
15131
15379
  const updated = { ...existing, ...updates, id: taskId };
15132
15380
  const filePath = getTaskPath(stateDir, listId, taskId);
15133
- fs23.writeFileSync(filePath, JSON.stringify(updated, null, 2));
15381
+ fs24.writeFileSync(filePath, JSON.stringify(updated, null, 2));
15134
15382
  return updated;
15135
15383
  }
15136
15384
  function deleteTask(stateDir, listId, taskId) {
@@ -15144,7 +15392,7 @@ function deleteTask(stateDir, listId, taskId) {
15144
15392
  }
15145
15393
  }
15146
15394
  try {
15147
- fs23.unlinkSync(filePath);
15395
+ fs24.unlinkSync(filePath);
15148
15396
  } catch {
15149
15397
  return false;
15150
15398
  }
@@ -16577,10 +16825,10 @@ function ensureLoaded(workspace, configIds) {
16577
16825
  if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
16578
16826
  }
16579
16827
  }
16580
- const path30 = join23(workspace, ".reply-blocklist.json");
16828
+ const path31 = join23(workspace, ".reply-blocklist.json");
16581
16829
  try {
16582
- if (existsSync18(path30)) {
16583
- const raw = readFileSync18(path30, "utf-8");
16830
+ if (existsSync18(path31)) {
16831
+ const raw = readFileSync18(path31, "utf-8");
16584
16832
  const parsed = JSON.parse(raw);
16585
16833
  if (parsed.blockedUserIds) {
16586
16834
  for (const id of parsed.blockedUserIds) {
@@ -16596,9 +16844,9 @@ function ensureLoaded(workspace, configIds) {
16596
16844
  loaded = true;
16597
16845
  }
16598
16846
  function save(workspace) {
16599
- const path30 = join23(workspace, ".reply-blocklist.json");
16847
+ const path31 = join23(workspace, ".reply-blocklist.json");
16600
16848
  try {
16601
- writeFileSync14(path30, JSON.stringify(state, null, 2), "utf-8");
16849
+ writeFileSync14(path31, JSON.stringify(state, null, 2), "utf-8");
16602
16850
  } catch (err) {
16603
16851
  console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
16604
16852
  }
@@ -17115,9 +17363,9 @@ function cosineSim(a, b) {
17115
17363
  }
17116
17364
  function readDbEmbeddings(dbPath) {
17117
17365
  const { DatabaseSync: DatabaseSync2 } = require3("node:sqlite");
17118
- const db = new DatabaseSync2(dbPath, { readOnly: true });
17366
+ const db2 = new DatabaseSync2(dbPath, { readOnly: true });
17119
17367
  try {
17120
- const stmt = db.prepare(`
17368
+ const stmt = db2.prepare(`
17121
17369
  SELECT file_path, name, description, mtime, embedding
17122
17370
  FROM files
17123
17371
  WHERE embedding IS NOT NULL AND deprecated_by IS NULL
@@ -17134,7 +17382,7 @@ function readDbEmbeddings(dbPath) {
17134
17382
  }
17135
17383
  return rows;
17136
17384
  } finally {
17137
- db.close();
17385
+ db2.close();
17138
17386
  }
17139
17387
  }
17140
17388
  async function llmRerank(query, candidates, topK, ollamaChatUrl, model) {
@@ -17511,6 +17759,69 @@ var init_light_mode = __esm({
17511
17759
  }
17512
17760
  });
17513
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
+
17514
17825
  // src/sender-context.ts
17515
17826
  import { readFileSync as readFileSync21, existsSync as existsSync20 } from "node:fs";
17516
17827
  import { join as join28 } from "node:path";
@@ -17678,8 +17989,8 @@ var extractMemories_exports = {};
17678
17989
  __export(extractMemories_exports, {
17679
17990
  createMemoryExtractor: () => createMemoryExtractor
17680
17991
  });
17681
- import * as fs24 from "fs";
17682
- import * as path25 from "path";
17992
+ import * as fs25 from "fs";
17993
+ import * as path26 from "path";
17683
17994
  function isModelVisibleMessage(message) {
17684
17995
  return message.role === "user" || message.role === "assistant";
17685
17996
  }
@@ -17702,13 +18013,13 @@ function getMemoryTools() {
17702
18013
  return allDefs.filter((d) => MEMORY_TOOL_NAMES.includes(d.function.name));
17703
18014
  }
17704
18015
  function getStatePath(workspace) {
17705
- return path25.join(workspace, STATE_FILE);
18016
+ return path26.join(workspace, STATE_FILE);
17706
18017
  }
17707
18018
  function loadPersistedState(workspace) {
17708
18019
  try {
17709
18020
  const p = getStatePath(workspace);
17710
- if (fs24.existsSync(p)) {
17711
- const data = JSON.parse(fs24.readFileSync(p, "utf-8"));
18021
+ if (fs25.existsSync(p)) {
18022
+ const data = JSON.parse(fs25.readFileSync(p, "utf-8"));
17712
18023
  for (const [sid, ts] of Object.entries(data.lastTs ?? {})) {
17713
18024
  lastTsMap.set(sid, ts);
17714
18025
  }
@@ -17728,7 +18039,7 @@ function persistState(workspace) {
17728
18039
  for (const [sid, ts] of lastTsMap.entries()) lastTs[sid] = ts;
17729
18040
  for (const [sid, ts] of lastExtractTimeMap.entries()) timestamps[sid] = ts;
17730
18041
  const data = JSON.stringify({ lastTs, timestamps }, null, 2);
17731
- fs24.writeFileSync(getStatePath(workspace), data, "utf-8");
18042
+ fs25.writeFileSync(getStatePath(workspace), data, "utf-8");
17732
18043
  } catch (e) {
17733
18044
  console.warn(`[memory] failed to persist extract state: ${e?.message ?? e}`);
17734
18045
  }
@@ -17769,11 +18080,11 @@ function createMemoryExtractor(workspace, enabled) {
17769
18080
  const existingMemories = formatMemoryManifest(
17770
18081
  await scanMemoryFiles2(memoryDir, new AbortController().signal)
17771
18082
  );
17772
- const extractOverridePath = path25.join(workspace, "prompts", "extract.md");
18083
+ const extractOverridePath = path26.join(workspace, "prompts", "extract.md");
17773
18084
  let systemPrompt;
17774
18085
  try {
17775
- if (fs24.existsSync(extractOverridePath)) {
17776
- systemPrompt = fs24.readFileSync(extractOverridePath, { encoding: "utf-8" });
18086
+ if (fs25.existsSync(extractOverridePath)) {
18087
+ systemPrompt = fs25.readFileSync(extractOverridePath, { encoding: "utf-8" });
17777
18088
  if (existingMemories.length > 0) {
17778
18089
  systemPrompt += `
17779
18090
 
@@ -17874,8 +18185,8 @@ var ingest_exports = {};
17874
18185
  __export(ingest_exports, {
17875
18186
  pushConversation: () => pushConversation
17876
18187
  });
17877
- import fs25 from "node:fs";
17878
- import path26 from "node:path";
18188
+ import fs26 from "node:fs";
18189
+ import path27 from "node:path";
17879
18190
  function parseMeta(text) {
17880
18191
  const m = text.match(/^\[meta:\s*(.+?)\s*\((.+?)\)\s*@(\S+)\s*[^\]]*\]/);
17881
18192
  if (!m) return null;
@@ -17908,9 +18219,9 @@ async function readConfig() {
17908
18219
  }
17909
18220
  function loadPushTs(workspace, sessionId) {
17910
18221
  try {
17911
- const p = path26.join(workspace, PUSH_STATE_FILE);
17912
- if (fs25.existsSync(p)) {
17913
- 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"));
17914
18225
  return typeof data[sessionId] === "number" ? data[sessionId] : 0;
17915
18226
  }
17916
18227
  } catch (e) {
@@ -17920,14 +18231,14 @@ function loadPushTs(workspace, sessionId) {
17920
18231
  }
17921
18232
  function savePushTs(workspace, sessionId, ts) {
17922
18233
  try {
17923
- const p = path26.join(workspace, PUSH_STATE_FILE);
18234
+ const p = path27.join(workspace, PUSH_STATE_FILE);
17924
18235
  let data = {};
17925
18236
  try {
17926
- 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"));
17927
18238
  } catch {
17928
18239
  }
17929
18240
  data[sessionId] = ts;
17930
- fs25.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
18241
+ fs26.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
17931
18242
  } catch (e) {
17932
18243
  console.warn(`[everos-ingest] save pushTs failed: ${e?.message ?? e}`);
17933
18244
  }
@@ -18576,11 +18887,11 @@ async function readLastConsolidatedAt(memoryDir) {
18576
18887
  }
18577
18888
  }
18578
18889
  async function tryAcquireConsolidationLock(memoryDir) {
18579
- const path30 = lockPath(memoryDir);
18890
+ const path31 = lockPath(memoryDir);
18580
18891
  let mtimeMs;
18581
18892
  let holderPid;
18582
18893
  try {
18583
- const [s, raw] = await Promise.all([stat3(path30), readFile5(path30, "utf8")]);
18894
+ const [s, raw] = await Promise.all([stat3(path31), readFile5(path31, "utf8")]);
18584
18895
  mtimeMs = s.mtimeMs;
18585
18896
  const parsed = parseInt(raw.trim(), 10);
18586
18897
  holderPid = Number.isFinite(parsed) ? parsed : void 0;
@@ -18593,10 +18904,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
18593
18904
  }
18594
18905
  }
18595
18906
  await mkdir3(memoryDir, { recursive: true });
18596
- await writeFile4(path30, String(process.pid));
18907
+ await writeFile4(path31, String(process.pid));
18597
18908
  let verify;
18598
18909
  try {
18599
- verify = await readFile5(path30, "utf8");
18910
+ verify = await readFile5(path31, "utf8");
18600
18911
  } catch {
18601
18912
  return null;
18602
18913
  }
@@ -18604,15 +18915,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
18604
18915
  return mtimeMs ?? 0;
18605
18916
  }
18606
18917
  async function rollbackConsolidationLock(memoryDir, priorMtime) {
18607
- const path30 = lockPath(memoryDir);
18918
+ const path31 = lockPath(memoryDir);
18608
18919
  try {
18609
18920
  if (priorMtime === 0) {
18610
- await unlink(path30);
18921
+ await unlink(path31);
18611
18922
  return;
18612
18923
  }
18613
- await writeFile4(path30, "");
18924
+ await writeFile4(path31, "");
18614
18925
  const t = priorMtime / 1e3;
18615
- await utimes(path30, t, t);
18926
+ await utimes(path31, t, t);
18616
18927
  } catch (e) {
18617
18928
  console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
18618
18929
  }
@@ -18895,34 +19206,30 @@ var handle_query_exports = {};
18895
19206
  __export(handle_query_exports, {
18896
19207
  handleQuery: () => handleQuery,
18897
19208
  resetSessionStartInjection: () => resetSessionStartInjection,
18898
- resetWorkModeInjection: () => resetWorkModeInjection,
18899
19209
  resolveSystemPrompt: () => resolveSystemPrompt
18900
19210
  });
18901
19211
  import { readFileSync as readFileSync25, existsSync as existsSync22 } from "node:fs";
18902
19212
  import { join as join33, resolve as resolve8 } from "node:path";
18903
- import * as path27 from "node:path";
19213
+ import * as path28 from "node:path";
18904
19214
  function resolveSystemPrompt(v) {
18905
19215
  return typeof v === "function" ? v() : v || "";
18906
19216
  }
18907
19217
  function resetSessionStartInjection(sessionId) {
18908
19218
  sessionStartDone.delete(sessionId);
18909
19219
  }
18910
- function resetWorkModeInjection(sessionId) {
18911
- workModeInjected.delete(sessionId);
18912
- }
18913
19220
  function loadExternalChanRules(workspace) {
18914
- const path30 = join33(workspace, "prompts", "external-chan-rules.md");
18915
- 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;
18916
19223
  let content = "";
18917
- if (existsSync22(path30)) {
19224
+ if (existsSync22(path31)) {
18918
19225
  try {
18919
- content = readFileSync25(path30, "utf-8").trim();
19226
+ content = readFileSync25(path31, "utf-8").trim();
18920
19227
  } catch (e) {
18921
19228
  console.warn(`[external-chan-rules] Failed to load: ${e}`);
18922
19229
  }
18923
19230
  }
18924
- externalChanRulesCache = { path: path30, content };
18925
- 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}`);
18926
19233
  return externalChanRulesCache;
18927
19234
  }
18928
19235
  function getExternalChanRulesBlock(inboundMeta, workspace) {
@@ -19130,7 +19437,13 @@ ${text}` : text });
19130
19437
  const isLight = isLightMode(chatMode, channelName) && chatMode !== "emotion";
19131
19438
  const lightN = resolveLightN(channelName);
19132
19439
  const lightHistory = buildLightHistory(history, { isLight, lightN, channelName, chatMode, recallFull: emotionStripped });
19133
- 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)];
19134
19447
  if (deps.mcpManager && !deps.mcpManager.isMcpDeltaSent(sessionId)) {
19135
19448
  const delta = deps.mcpManager.getMcpDelta();
19136
19449
  if (delta && delta.addedBlocks.length > 0) {
@@ -19184,30 +19497,6 @@ ${text}` : text });
19184
19497
  }
19185
19498
  }
19186
19499
  }
19187
- if (chatMode === "emotion") {
19188
- if (workModeInjected.has(sessionId)) workModeInjected.delete(sessionId);
19189
- } else if (!workModeInjected.has(sessionId)) {
19190
- workModeInjected.add(sessionId);
19191
- try {
19192
- const sr = await executeSessionStartHooks(channelName === "cli" ? "cli" : "channel", {
19193
- sessionId,
19194
- workspace,
19195
- cwd: workspace,
19196
- channel: channelName === "cli" ? "console" : channelName,
19197
- senderId: inboundMeta?.from || "",
19198
- channelType: inboundMeta?.channelType || "",
19199
- source
19200
- });
19201
- if (sr.additionalContexts && sr.additionalContexts.length > 0) {
19202
- const att = createAttachmentMessage({ type: "session_start", text: sr.additionalContexts.join("\n\n") });
19203
- history.push(att);
19204
- messages.push(att);
19205
- console.log(`[hooks] work-mode injection: ${sr.additionalContexts.length} additionalContext(s) at END of messages (session ${sessionId}, cache-safe, persisted)`);
19206
- }
19207
- } catch (err) {
19208
- console.warn(`[hooks] work-mode injection error: ${err.message}`);
19209
- }
19210
- }
19211
19500
  const pendingNotifications2 = drainPendingNotifications();
19212
19501
  if (pendingNotifications2.length > 0) {
19213
19502
  messages.push(createAttachmentMessage({
@@ -19228,7 +19517,7 @@ ${text}` : text });
19228
19517
  }));
19229
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(" | ")}`);
19230
19519
  }
19231
- if (channelName !== "heartbeat" && channelName !== "cron" && channelName !== "inner-voice" && channelName !== "cognifold") {
19520
+ if (channelName !== "heartbeat" && channelName !== "cron" && channelName !== "inner-voice" && channelName !== "proactive") {
19232
19521
  sessions.touch(sessionId);
19233
19522
  }
19234
19523
  const toolContext = {
@@ -19672,7 +19961,7 @@ stack: ${err.stack ?? "(none)"}`);
19672
19961
  }
19673
19962
  } catch (err) {
19674
19963
  try {
19675
- (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}
19676
19965
  stack: ${err.stack ?? "(none)"}
19677
19966
  `);
19678
19967
  } catch {
@@ -19690,7 +19979,7 @@ function roughTokenCount(messages) {
19690
19979
  }
19691
19980
  return total;
19692
19981
  }
19693
- var sessionStartDone, workModeInjected, externalChanRulesCache;
19982
+ var sessionStartDone, externalChanRulesCache;
19694
19983
  var init_handle_query = __esm({
19695
19984
  "src/handle-query.ts"() {
19696
19985
  "use strict";
@@ -19710,9 +19999,9 @@ var init_handle_query = __esm({
19710
19999
  init_findRelevantMemoriesEveros();
19711
20000
  init_paths();
19712
20001
  init_light_mode();
20002
+ init_voiceFastView();
19713
20003
  init_sender_context();
19714
20004
  sessionStartDone = /* @__PURE__ */ new Set();
19715
- workModeInjected = /* @__PURE__ */ new Set();
19716
20005
  externalChanRulesCache = null;
19717
20006
  }
19718
20007
  });
@@ -20218,20 +20507,20 @@ __export(cli_travel_exports, {
20218
20507
  loadTravelConfig: () => loadTravelConfig,
20219
20508
  saveTravelConfig: () => saveTravelConfig
20220
20509
  });
20221
- import * as path28 from "node:path";
20222
- import * as fs26 from "node:fs";
20510
+ import * as path29 from "node:path";
20511
+ import * as fs27 from "node:fs";
20223
20512
  import * as os4 from "node:os";
20224
20513
  import { execSync as execSync2 } from "node:child_process";
20225
20514
  function loadTravelConfig() {
20226
20515
  try {
20227
- if (!fs26.existsSync(CONFIG_PATH)) return null;
20228
- 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"));
20229
20518
  } catch {
20230
20519
  return null;
20231
20520
  }
20232
20521
  }
20233
20522
  function saveTravelConfig(cfg) {
20234
- fs26.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
20523
+ fs27.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
20235
20524
  }
20236
20525
  function sanitizeContent(content, dirs) {
20237
20526
  let result2 = content;
@@ -20256,7 +20545,7 @@ function restoreContent(content, dirs) {
20256
20545
  return result2;
20257
20546
  }
20258
20547
  function isTextFile(filePath) {
20259
- const ext = path28.extname(filePath).toLowerCase();
20548
+ const ext = path29.extname(filePath).toLowerCase();
20260
20549
  return TEXT_EXTENSIONS.has(ext);
20261
20550
  }
20262
20551
  function shouldExclude(name) {
@@ -20271,14 +20560,14 @@ function shouldExclude(name) {
20271
20560
  }
20272
20561
  function collectFiles(rootDir, includeSet, optionalSet) {
20273
20562
  const files = [];
20274
- const entries2 = fs26.readdirSync(rootDir, { withFileTypes: true });
20563
+ const entries2 = fs27.readdirSync(rootDir, { withFileTypes: true });
20275
20564
  for (const entry of entries2) {
20276
20565
  if (shouldExclude(entry.name)) continue;
20277
- const fullPath = path28.join(rootDir, entry.name);
20278
- const realPath = fs26.realpathSync(fullPath);
20566
+ const fullPath = path29.join(rootDir, entry.name);
20567
+ const realPath = fs27.realpathSync(fullPath);
20279
20568
  if (realPath !== fullPath) {
20280
20569
  try {
20281
- const lstat = fs26.lstatSync(fullPath);
20570
+ const lstat = fs27.lstatSync(fullPath);
20282
20571
  if (lstat.isSymbolicLink()) {
20283
20572
  continue;
20284
20573
  }
@@ -20299,12 +20588,12 @@ function collectFiles(rootDir, includeSet, optionalSet) {
20299
20588
  function collectAllFiles(dir) {
20300
20589
  const files = [];
20301
20590
  try {
20302
- const entries2 = fs26.readdirSync(dir, { withFileTypes: true });
20591
+ const entries2 = fs27.readdirSync(dir, { withFileTypes: true });
20303
20592
  for (const entry of entries2) {
20304
20593
  if (shouldExclude(entry.name)) continue;
20305
- const fullPath = path28.join(dir, entry.name);
20594
+ const fullPath = path29.join(dir, entry.name);
20306
20595
  try {
20307
- if (fs26.lstatSync(fullPath).isSymbolicLink()) continue;
20596
+ if (fs27.lstatSync(fullPath).isSymbolicLink()) continue;
20308
20597
  } catch {
20309
20598
  }
20310
20599
  if (entry.isDirectory()) {
@@ -20319,16 +20608,16 @@ function collectAllFiles(dir) {
20319
20608
  }
20320
20609
  function readMainEngineUuid(agentsDir) {
20321
20610
  try {
20322
- const platformMapPath = path28.join(agentsDir, "main", "sessions", "platform-map.json");
20323
- const indexMapPath = path28.join(agentsDir, "main", "sessions", "session-index.json");
20324
- if (!fs26.existsSync(platformMapPath) || !fs26.existsSync(indexMapPath)) return null;
20325
- 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"));
20326
20615
  const mainPlatformId = platformMap["scope:main"] || platformMap["main"];
20327
20616
  if (!mainPlatformId) return null;
20328
- const indexMap = JSON.parse(fs26.readFileSync(indexMapPath, "utf-8"));
20617
+ const indexMap = JSON.parse(fs27.readFileSync(indexMapPath, "utf-8"));
20329
20618
  const entry = indexMap[mainPlatformId];
20330
20619
  if (!entry || !entry.file) return null;
20331
- const basename8 = path28.basename(entry.file).replace(/\.jsonl$/, "");
20620
+ const basename8 = path29.basename(entry.file).replace(/\.jsonl$/, "");
20332
20621
  return basename8;
20333
20622
  } catch {
20334
20623
  return null;
@@ -20336,13 +20625,13 @@ function readMainEngineUuid(agentsDir) {
20336
20625
  }
20337
20626
  function collectRecentSessions(agentsDir, _days = 7) {
20338
20627
  const files = [];
20339
- if (!fs26.existsSync(agentsDir)) return files;
20628
+ if (!fs27.existsSync(agentsDir)) return files;
20340
20629
  const sessionGroups = /* @__PURE__ */ new Map();
20341
20630
  function scanSessionsDir(dir) {
20342
20631
  try {
20343
- const entries2 = fs26.readdirSync(dir, { withFileTypes: true });
20632
+ const entries2 = fs27.readdirSync(dir, { withFileTypes: true });
20344
20633
  for (const entry of entries2) {
20345
- const fullPath = path28.join(dir, entry.name);
20634
+ const fullPath = path29.join(dir, entry.name);
20346
20635
  if (entry.isDirectory()) {
20347
20636
  scanSessionsDir(fullPath);
20348
20637
  continue;
@@ -20366,7 +20655,7 @@ function collectRecentSessions(agentsDir, _days = 7) {
20366
20655
  if (entry.name.endsWith(".jsonl")) {
20367
20656
  group.jsonl = fullPath;
20368
20657
  } else {
20369
- const stat4 = fs26.statSync(fullPath);
20658
+ const stat4 = fs27.statSync(fullPath);
20370
20659
  group.archived.push({ file: fullPath, mtime: stat4.mtimeMs });
20371
20660
  }
20372
20661
  }
@@ -20385,37 +20674,37 @@ function collectRecentSessions(agentsDir, _days = 7) {
20385
20674
  }
20386
20675
  async function doExport(opts) {
20387
20676
  const { agentName, stateDir, note, dryRun: dryRun2 } = opts;
20388
- const workspace = (opts.workspace || path28.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
20389
- 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(/[/\\]+$/, "");
20390
20679
  console.log(`\u{1F4E6} engine7 export`);
20391
20680
  console.log(` agent: ${agentName}`);
20392
20681
  console.log(` state: ${stateDir}`);
20393
20682
  console.log(` workspace: ${workspace}`);
20394
- if (!fs26.existsSync(workspace)) {
20683
+ if (!fs27.existsSync(workspace)) {
20395
20684
  console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
20396
20685
  process.exit(1);
20397
20686
  }
20398
20687
  const dirs = { workspace, stateDir, engineHome };
20399
20688
  const wsFiles = collectFiles(workspace, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL);
20400
- const sessionFiles = collectRecentSessions(path28.join(stateDir, "agents"), 7);
20401
- const configsDir = path28.join(stateDir, "configs");
20689
+ const sessionFiles = collectRecentSessions(path29.join(stateDir, "agents"), 7);
20690
+ const configsDir = path29.join(stateDir, "configs");
20402
20691
  const configFiles = [];
20403
- if (fs26.existsSync(configsDir)) {
20692
+ if (fs27.existsSync(configsDir)) {
20404
20693
  for (const f of collectAllFiles(configsDir)) {
20405
- if (shouldExclude(path28.basename(f))) continue;
20694
+ if (shouldExclude(path29.basename(f))) continue;
20406
20695
  configFiles.push(f);
20407
20696
  }
20408
20697
  }
20409
20698
  const EVEROS_SKIP = /* @__PURE__ */ new Set([".tmp", ".lock", "import.log", "import_progress.json"]);
20410
- const everosDir = path28.join(stateDir, ".everos");
20699
+ const everosDir = path29.join(stateDir, ".everos");
20411
20700
  const everosFiles = [];
20412
- if (fs26.existsSync(everosDir)) {
20701
+ if (fs27.existsSync(everosDir)) {
20413
20702
  for (const f of collectAllFiles(everosDir)) {
20414
- if (EVEROS_SKIP.has(path28.basename(f))) continue;
20703
+ if (EVEROS_SKIP.has(path29.basename(f))) continue;
20415
20704
  everosFiles.push(f);
20416
20705
  }
20417
- const walFile = path28.join(everosDir, ".index", "sqlite", "system.db-wal");
20418
- 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) {
20419
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`);
20420
20709
  console.warn(` \u5EFA\u8BAE: \u5148\u505C everos \u670D\u52A1\u518D export\uFF0C\u6216 import \u540E\u91CD\u5EFA\u7D22\u5F15`);
20421
20710
  }
@@ -20423,16 +20712,16 @@ async function doExport(opts) {
20423
20712
  console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
20424
20713
  console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
20425
20714
  console.log(` configs: ${configFiles.length}`);
20426
- 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)`);
20427
20716
  if (dryRun2) {
20428
20717
  console.log(`
20429
20718
  [DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
20430
- 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)}`));
20431
20720
  if (wsFiles.length > 20) console.log(` ... \u8FD8\u6709 ${wsFiles.length - 20} \u4E2A\u6587\u4EF6`);
20432
20721
  if (everosFiles.length > 0) {
20433
20722
  console.log(`
20434
20723
  [DRY RUN] everos (${everosFiles.length} \u6587\u4EF6):`);
20435
- 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)}`));
20436
20725
  if (everosFiles.length > 10) console.log(` ... \u8FD8\u6709 ${everosFiles.length - 10} \u4E2A\u6587\u4EF6`);
20437
20726
  }
20438
20727
  console.log(`
@@ -20441,46 +20730,46 @@ async function doExport(opts) {
20441
20730
  }
20442
20731
  const now = /* @__PURE__ */ new Date();
20443
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")}`;
20444
- const tmpDir = path28.join(os4.tmpdir(), `engine7-export-${agentName}-${version}`);
20445
- fs26.mkdirSync(tmpDir, { recursive: true });
20446
- const stagingDir = path28.join(tmpDir, agentName);
20447
- 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 });
20448
20737
  let fileCount = 0;
20449
20738
  let totalSize = 0;
20450
20739
  let copyFail = 0;
20451
20740
  const copyOne = (srcFile, relRoot, destRoot) => {
20452
- const relPath = path28.relative(relRoot, srcFile);
20453
- const destFile = path28.join(destRoot, relPath);
20454
- 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 });
20455
20744
  try {
20456
20745
  if (isTextFile(srcFile)) {
20457
- const content = fs26.readFileSync(srcFile, "utf-8");
20458
- fs26.writeFileSync(destFile, sanitizeContent(content, dirs));
20746
+ const content = fs27.readFileSync(srcFile, "utf-8");
20747
+ fs27.writeFileSync(destFile, sanitizeContent(content, dirs));
20459
20748
  } else {
20460
- fs26.copyFileSync(srcFile, destFile);
20749
+ fs27.copyFileSync(srcFile, destFile);
20461
20750
  }
20462
20751
  fileCount++;
20463
- totalSize += fs26.statSync(srcFile).size;
20752
+ totalSize += fs27.statSync(srcFile).size;
20464
20753
  } catch (e) {
20465
20754
  copyFail++;
20466
20755
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
20467
20756
  }
20468
20757
  };
20469
- 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"));
20470
20759
  for (const srcFile of sessionFiles) {
20471
- const relPath = path28.relative(stateDir, srcFile);
20472
- const destFile = path28.join(stagingDir, relPath);
20473
- 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 });
20474
20763
  try {
20475
- let content = fs26.readFileSync(srcFile, "utf-8");
20764
+ let content = fs27.readFileSync(srcFile, "utf-8");
20476
20765
  content = sanitizeContent(content, dirs);
20477
- const baseName = path28.basename(srcFile);
20766
+ const baseName = path29.basename(srcFile);
20478
20767
  if (baseName === "session-index.json" || baseName === "platform-map.json") {
20479
20768
  content = content.split("\\\\").join("/");
20480
20769
  }
20481
- fs26.writeFileSync(destFile, content);
20770
+ fs27.writeFileSync(destFile, content);
20482
20771
  fileCount++;
20483
- totalSize += fs26.statSync(srcFile).size;
20772
+ totalSize += fs27.statSync(srcFile).size;
20484
20773
  } catch (e) {
20485
20774
  copyFail++;
20486
20775
  console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
@@ -20502,13 +20791,13 @@ async function doExport(opts) {
20502
20791
  totalSize,
20503
20792
  note
20504
20793
  };
20505
- fs26.writeFileSync(path28.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
20506
- 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`);
20507
20796
  console.log(`
20508
20797
  \u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
20509
20798
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
20510
20799
  execSync2(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
20511
- const archiveSize = fs26.statSync(archiveFile).size;
20800
+ const archiveSize = fs27.statSync(archiveFile).size;
20512
20801
  console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6${copyFail ? `, \u5931\u8D25 ${copyFail}` : ""})`);
20513
20802
  const cfg = loadTravelConfig();
20514
20803
  if (!cfg || !cfg.githubToken) {
@@ -20531,8 +20820,8 @@ async function doImport(opts) {
20531
20820
  console.error(` \u914D\u7F6E: \u7F16\u8F91 ${CONFIG_PATH}`);
20532
20821
  process.exit(1);
20533
20822
  }
20534
- const tmpDir = path28.join(os4.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
20535
- fs26.mkdirSync(tmpDir, { recursive: true });
20823
+ const tmpDir = path29.join(os4.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
20824
+ fs27.mkdirSync(tmpDir, { recursive: true });
20536
20825
  const archiveFile = await downloadFromGitHub(cfg, agentName, version, tmpDir);
20537
20826
  console.log(`\u2705 \u4E0B\u8F7D\u5B8C\u6210: ${archiveFile}`);
20538
20827
  if (dryRun2) {
@@ -20543,99 +20832,99 @@ async function doImport(opts) {
20543
20832
  console.log(`\u{1F4C2} \u89E3\u5305\u4E2D...`);
20544
20833
  const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
20545
20834
  execSync2(`"${tarExe}" -xzf "${archiveFile}" -C "${tmpDir}"`, { stdio: "pipe" });
20546
- const stagingDir = path28.join(tmpDir, agentName);
20547
- const manifestPath = path28.join(stagingDir, "manifest.json");
20548
- if (!fs26.existsSync(manifestPath)) {
20835
+ const stagingDir = path29.join(tmpDir, agentName);
20836
+ const manifestPath = path29.join(stagingDir, "manifest.json");
20837
+ if (!fs27.existsSync(manifestPath)) {
20549
20838
  console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
20550
20839
  process.exit(1);
20551
20840
  }
20552
- const manifest = JSON.parse(fs26.readFileSync(manifestPath, "utf-8"));
20553
- const workspace = path28.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
20554
- 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(/[/\\]+$/, "");
20555
20844
  const dirs = { workspace, stateDir: stateDir.replace(/\\/g, "/").replace(/[/\\]+$/, ""), engineHome };
20556
20845
  console.log(` \u7248\u672C: ${manifest.version}`);
20557
20846
  console.log(` \u521B\u5EFA: ${manifest.createdAt}`);
20558
20847
  console.log(` \u6587\u4EF6\u6570: ${manifest.fileCount}`);
20559
- const wsStaging = path28.join(stagingDir, "workspace");
20848
+ const wsStaging = path29.join(stagingDir, "workspace");
20560
20849
  let restoredCount = 0;
20561
20850
  let skipCount = 0;
20562
- if (fs26.existsSync(wsStaging)) {
20851
+ if (fs27.existsSync(wsStaging)) {
20563
20852
  const allFiles = collectAllFiles(wsStaging);
20564
20853
  for (const srcFile of allFiles) {
20565
- const relPath = path28.relative(wsStaging, srcFile);
20566
- const destFile = path28.join(workspace, relPath);
20567
- 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 });
20568
20857
  try {
20569
20858
  if (isTextFile(srcFile)) {
20570
- const content = fs26.readFileSync(srcFile, "utf-8");
20571
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20859
+ const content = fs27.readFileSync(srcFile, "utf-8");
20860
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20572
20861
  } else {
20573
- fs26.copyFileSync(srcFile, destFile);
20862
+ fs27.copyFileSync(srcFile, destFile);
20574
20863
  }
20575
20864
  restoredCount++;
20576
20865
  } catch (e) {
20577
20866
  skipCount++;
20578
- 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})`);
20579
20868
  }
20580
20869
  }
20581
20870
  }
20582
- const agentsStaging = path28.join(stagingDir, "agents");
20583
- if (fs26.existsSync(agentsStaging)) {
20871
+ const agentsStaging = path29.join(stagingDir, "agents");
20872
+ if (fs27.existsSync(agentsStaging)) {
20584
20873
  const sessionFiles = collectAllFiles(agentsStaging);
20585
20874
  for (const srcFile of sessionFiles) {
20586
- const relPath = path28.relative(stagingDir, srcFile);
20587
- const destFile = path28.join(stateDir, relPath);
20588
- fs26.mkdirSync(path28.dirname(destFile), { recursive: true });
20589
- const content = fs26.readFileSync(srcFile, "utf-8");
20590
- 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));
20591
20880
  restoredCount++;
20592
20881
  }
20593
20882
  }
20594
- const configsStaging = path28.join(stagingDir, "configs");
20595
- if (fs26.existsSync(configsStaging)) {
20883
+ const configsStaging = path29.join(stagingDir, "configs");
20884
+ if (fs27.existsSync(configsStaging)) {
20596
20885
  const cfgFiles = collectAllFiles(configsStaging);
20597
20886
  for (const srcFile of cfgFiles) {
20598
- const relPath = path28.relative(stagingDir, srcFile);
20599
- const destFile = path28.join(stateDir, relPath);
20600
- 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 });
20601
20890
  if (isTextFile(srcFile)) {
20602
- const content = fs26.readFileSync(srcFile, "utf-8");
20603
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20891
+ const content = fs27.readFileSync(srcFile, "utf-8");
20892
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20604
20893
  } else {
20605
- fs26.copyFileSync(srcFile, destFile);
20894
+ fs27.copyFileSync(srcFile, destFile);
20606
20895
  }
20607
20896
  restoredCount++;
20608
20897
  }
20609
20898
  }
20610
- const everosStaging = path28.join(stagingDir, ".everos");
20611
- if (fs26.existsSync(everosStaging)) {
20899
+ const everosStaging = path29.join(stagingDir, ".everos");
20900
+ if (fs27.existsSync(everosStaging)) {
20612
20901
  const everosFiles = collectAllFiles(everosStaging);
20613
20902
  for (const srcFile of everosFiles) {
20614
- const relPath = path28.relative(stagingDir, srcFile);
20615
- const destFile = path28.join(stateDir, relPath);
20616
- 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 });
20617
20906
  try {
20618
20907
  if (isTextFile(srcFile)) {
20619
- const content = fs26.readFileSync(srcFile, "utf-8");
20620
- fs26.writeFileSync(destFile, restoreContent(content, dirs));
20908
+ const content = fs27.readFileSync(srcFile, "utf-8");
20909
+ fs27.writeFileSync(destFile, restoreContent(content, dirs));
20621
20910
  } else {
20622
- fs26.copyFileSync(srcFile, destFile);
20911
+ fs27.copyFileSync(srcFile, destFile);
20623
20912
  }
20624
20913
  restoredCount++;
20625
20914
  } catch (e) {
20626
20915
  skipCount++;
20627
- 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})`);
20628
20917
  }
20629
20918
  }
20630
20919
  console.log(` everos: ${everosFiles.length} \u6587\u4EF6\u5DF2\u6062\u590D`);
20631
20920
  }
20632
20921
  console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}${skipCount ? ` (\u8DF3\u8FC7 ${skipCount})` : ""}`);
20633
20922
  const platformConfigName = process.platform === "darwin" ? "xiaoke-mac.json" : "xiaoke-win.json";
20634
- const restoredConfigPath = path28.join(stateDir, "configs", platformConfigName);
20635
- 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");
20636
20925
  console.log(`
20637
20926
  \u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config "${configToUse}"`);
20638
- fs26.rmSync(tmpDir, { recursive: true, force: true });
20927
+ fs27.rmSync(tmpDir, { recursive: true, force: true });
20639
20928
  }
20640
20929
  async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
20641
20930
  const repo = `${cfg.githubOwner}/${cfg.repoName}`;
@@ -20665,8 +20954,8 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
20665
20954
  }
20666
20955
  const release2 = await createRes.json();
20667
20956
  const uploadUrl = release2.upload_url.replace("{?name,label}", "");
20668
- const fileBuffer = fs26.readFileSync(archiveFile);
20669
- const fileName = path28.basename(archiveFile);
20957
+ const fileBuffer = fs27.readFileSync(archiveFile);
20958
+ const fileName = path29.basename(archiveFile);
20670
20959
  const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
20671
20960
  method: "POST",
20672
20961
  headers: {
@@ -20689,7 +20978,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
20689
20978
  throw e;
20690
20979
  }
20691
20980
  try {
20692
- fs26.rmSync(path28.dirname(archiveFile), { recursive: true, force: true });
20981
+ fs27.rmSync(path29.dirname(archiveFile), { recursive: true, force: true });
20693
20982
  } catch {
20694
20983
  }
20695
20984
  }
@@ -20721,8 +21010,8 @@ async function downloadFromGitHub(cfg, agentName, version, destDir) {
20721
21010
  throw new Error(`\u4E0B\u8F7D asset \u5931\u8D25: ${downloadRes.status}`);
20722
21011
  }
20723
21012
  const buffer = Buffer.from(await downloadRes.arrayBuffer());
20724
- const archiveFile = path28.join(destDir, asset.name);
20725
- fs26.writeFileSync(archiveFile, buffer);
21013
+ const archiveFile = path29.join(destDir, asset.name);
21014
+ fs27.writeFileSync(archiveFile, buffer);
20726
21015
  return archiveFile;
20727
21016
  }
20728
21017
  async function getLatestReleaseTag(cfg, agentName) {
@@ -20747,7 +21036,7 @@ var CONFIG_PATH, PATH_PLACEHOLDERS, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL, WORKS
20747
21036
  var init_cli_travel = __esm({
20748
21037
  "src/cli-travel.ts"() {
20749
21038
  "use strict";
20750
- CONFIG_PATH = path28.join(os4.homedir(), ".engine7-travel.json");
21039
+ CONFIG_PATH = path29.join(os4.homedir(), ".engine7-travel.json");
20751
21040
  PATH_PLACEHOLDERS = [
20752
21041
  { placeholder: "{{WORKSPACE}}", getOriginal: (d) => d.workspace },
20753
21042
  { placeholder: "{{ENGINE_HOME}}", getOriginal: (d) => d.engineHome },
@@ -20823,8 +21112,8 @@ var init_cli_travel = __esm({
20823
21112
  init_feishu_quick_register();
20824
21113
  init_wechat();
20825
21114
  init_qr_render();
20826
- import * as path29 from "node:path";
20827
- import * as fs27 from "node:fs";
21115
+ import * as path30 from "node:path";
21116
+ import * as fs28 from "node:fs";
20828
21117
  import * as readline3 from "node:readline";
20829
21118
  import { fileURLToPath } from "node:url";
20830
21119
  var origEmitWarning = process.emitWarning.bind(process);
@@ -20835,7 +21124,7 @@ process.emitWarning = (warning, ...rest) => {
20835
21124
  return origEmitWarning(warning, ...rest);
20836
21125
  };
20837
21126
  var __filename = fileURLToPath(import.meta.url);
20838
- var __dirname = path29.dirname(__filename);
21127
+ var __dirname = path30.dirname(__filename);
20839
21128
  var SCHEMA_VERSION = 1;
20840
21129
  function parseArgs() {
20841
21130
  const args = process.argv.slice(2);
@@ -20860,10 +21149,10 @@ function parseArgs() {
20860
21149
  }
20861
21150
  }
20862
21151
  if (!stateDir) {
20863
- stateDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21152
+ stateDir = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
20864
21153
  console.log(` \u4F7F\u7528\u9ED8\u8BA4\u76EE\u5F55: ${stateDir}`);
20865
21154
  }
20866
- stateDir = path29.resolve(stateDir);
21155
+ stateDir = path30.resolve(stateDir);
20867
21156
  return { stateDir, quick, dryRun: dryRun2, force };
20868
21157
  }
20869
21158
  function printHelp() {
@@ -20964,10 +21253,10 @@ function getDefaultValues(stateDir) {
20964
21253
  };
20965
21254
  }
20966
21255
  function loadExistingValues(stateDir) {
20967
- const configPath = path29.join(stateDir, "configs", "main7.json");
21256
+ const configPath = path30.join(stateDir, "configs", "main7.json");
20968
21257
  try {
20969
- if (!fs27.existsSync(configPath)) return {};
20970
- const j = JSON.parse(fs27.readFileSync(configPath, "utf8"));
21258
+ if (!fs28.existsSync(configPath)) return {};
21259
+ const j = JSON.parse(fs28.readFileSync(configPath, "utf8"));
20971
21260
  const out = {};
20972
21261
  if (j.agents?.defaults?.name) out.agentName = j.agents.defaults.name;
20973
21262
  const providers = j.models?.providers || {};
@@ -21022,15 +21311,15 @@ function loadExistingValues(stateDir) {
21022
21311
  }
21023
21312
  function readSecretsValue(stateDir, envName) {
21024
21313
  try {
21025
- const secretsDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
21026
- 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);
21027
21316
  const candidates = [
21028
- path29.join(secretsDir, `${cfgBase}.env`),
21029
- path29.join(stateDir, "configs", `.env.${cfgBase}`)
21317
+ path30.join(secretsDir, `${cfgBase}.env`),
21318
+ path30.join(stateDir, "configs", `.env.${cfgBase}`)
21030
21319
  ];
21031
21320
  for (const p of candidates) {
21032
- if (fs27.existsSync(p)) {
21033
- 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")) {
21034
21323
  const eq = line.indexOf("=");
21035
21324
  if (eq > 0 && line.slice(0, eq).trim() === envName) {
21036
21325
  return line.slice(eq + 1).trim();
@@ -21256,7 +21545,7 @@ async function configureWechat(rl, v) {
21256
21545
  }
21257
21546
  }
21258
21547
  function generateConfig(v) {
21259
- const workspace = path29.join(v.stateDir, "workspace").replace(/\\/g, "/");
21548
+ const workspace = path30.join(v.stateDir, "workspace").replace(/\\/g, "/");
21260
21549
  const config = {
21261
21550
  schemaVersion: SCHEMA_VERSION,
21262
21551
  stateDir: v.stateDir.replace(/\\/g, "/"),
@@ -21406,45 +21695,45 @@ function generateConfig(v) {
21406
21695
  }
21407
21696
  function buildDirTree(v) {
21408
21697
  const d = v.stateDir;
21409
- const w = path29.join(d, "workspace");
21698
+ const w = path30.join(d, "workspace");
21410
21699
  const now = (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false });
21411
21700
  return [
21412
21701
  // 目录
21413
- { path: path29.join(d, "configs"), type: "dir" },
21414
- { path: path29.join(d, "state", "agents", "main", "sessions"), type: "dir" },
21415
- { path: path29.join(w, "prompts"), type: "dir" },
21416
- { path: path29.join(w, "memory", "daily"), type: "dir" },
21417
- { path: path29.join(w, "docs", "research"), type: "dir" },
21418
- { path: path29.join(w, "docs", "todo"), type: "dir" },
21419
- { path: path29.join(w, "docs", "decisions"), type: "dir" },
21420
- { path: path29.join(w, "docs", "knowledge"), type: "dir" },
21421
- { path: path29.join(w, "docs", "sop"), type: "dir" },
21422
- { path: path29.join(d, "logs"), type: "dir" },
21423
- { 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" },
21424
21713
  // workspace 文件
21425
21714
  {
21426
- path: path29.join(w, "SESSION-STATE.md"),
21715
+ path: path30.join(w, "SESSION-STATE.md"),
21427
21716
  type: "file",
21428
21717
  content: readTemplate("workspace/SESSION-STATE.md").replace("{{CURRENT_TIME}}", now)
21429
21718
  },
21430
- { 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") },
21431
21720
  {
21432
- path: path29.join(w, "SOUL.md"),
21721
+ path: path30.join(w, "SOUL.md"),
21433
21722
  type: "file",
21434
21723
  content: readTemplate("workspace/SOUL.md").replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
21435
21724
  },
21436
- { 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") },
21437
21726
  {
21438
- path: path29.join(w, "prompts", "contacts.md"),
21727
+ path: path30.join(w, "prompts", "contacts.md"),
21439
21728
  type: "file",
21440
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")
21441
21730
  },
21442
- { path: path29.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
21443
- { 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" },
21444
- { 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" },
21445
21734
  // package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
21446
21735
  {
21447
- path: path29.join(d, "package.json"),
21736
+ path: path30.join(d, "package.json"),
21448
21737
  type: "file",
21449
21738
  content: JSON.stringify({
21450
21739
  name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
@@ -21455,7 +21744,7 @@ function buildDirTree(v) {
21455
21744
  },
21456
21745
  // 启动脚本(根据 OS 生成)
21457
21746
  ...process.platform === "win32" ? [{
21458
- path: path29.join(d, "start.cmd"),
21747
+ path: path30.join(d, "start.cmd"),
21459
21748
  type: "file",
21460
21749
  content: `@echo off
21461
21750
  rem Engine 7 startup script
@@ -21487,7 +21776,7 @@ if %ERRORLEVEL% NEQ 0 (
21487
21776
  )
21488
21777
  `
21489
21778
  }] : [{
21490
- path: path29.join(d, "start.sh"),
21779
+ path: path30.join(d, "start.sh"),
21491
21780
  type: "file",
21492
21781
  content: `#!/bin/bash
21493
21782
  # Engine 7 startup script
@@ -21520,13 +21809,13 @@ node "$ENGINE7_BIN" --engine-config configs/main7.json
21520
21809
  }
21521
21810
  function readTemplate(relativePath) {
21522
21811
  const candidates = [
21523
- path29.join(__dirname, "..", "templates", relativePath),
21524
- path29.join(__dirname, "..", "..", "templates", relativePath),
21525
- 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)
21526
21815
  ];
21527
21816
  for (const p of candidates) {
21528
- if (fs27.existsSync(p)) {
21529
- return fs27.readFileSync(p, "utf-8");
21817
+ if (fs28.existsSync(p)) {
21818
+ return fs28.readFileSync(p, "utf-8");
21530
21819
  }
21531
21820
  }
21532
21821
  throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
@@ -21541,11 +21830,11 @@ function dryRun(entries2) {
21541
21830
  function execute(entries2) {
21542
21831
  for (const e of entries2) {
21543
21832
  if (e.type === "dir") {
21544
- fs27.mkdirSync(e.path, { recursive: true });
21833
+ fs28.mkdirSync(e.path, { recursive: true });
21545
21834
  console.log(` \u{1F4C1} ${e.path}`);
21546
21835
  } else {
21547
- fs27.mkdirSync(path29.dirname(e.path), { recursive: true });
21548
- 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");
21549
21838
  console.log(` \u{1F4C4} ${e.path}`);
21550
21839
  }
21551
21840
  }
@@ -21579,8 +21868,8 @@ async function main() {
21579
21868
  if (subcommand === "--version" || subcommand === "-v") {
21580
21869
  let ver = "unknown";
21581
21870
  try {
21582
- const pkgPath = path29.join(path29.dirname(__filename), "..", "package.json");
21583
- 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";
21584
21873
  } catch {
21585
21874
  }
21586
21875
  console.log(`engine7 ${ver}`);
@@ -21598,18 +21887,18 @@ async function main() {
21598
21887
  else if (args[i] === "--config" && args[i + 1]) configName = args[++i].trim();
21599
21888
  }
21600
21889
  if (!stateDir) {
21601
- const cwd = path29.resolve(process.cwd());
21602
- if (fs27.existsSync(path29.join(cwd, "configs"))) {
21890
+ const cwd = path30.resolve(process.cwd());
21891
+ if (fs28.existsSync(path30.join(cwd, "configs"))) {
21603
21892
  stateDir = cwd;
21604
21893
  } else {
21605
- const pointer = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
21606
- if (fs27.existsSync(pointer)) {
21894
+ const pointer = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
21895
+ if (fs28.existsSync(pointer)) {
21607
21896
  try {
21608
- stateDir = JSON.parse(fs27.readFileSync(pointer, "utf8")).stateDir || "";
21897
+ stateDir = JSON.parse(fs28.readFileSync(pointer, "utf8")).stateDir || "";
21609
21898
  } catch {
21610
21899
  }
21611
21900
  }
21612
- 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");
21613
21902
  }
21614
21903
  }
21615
21904
  if (!target && !isLegacyAddchannel) {
@@ -21629,12 +21918,12 @@ async function main() {
21629
21918
  process.exit(0);
21630
21919
  }
21631
21920
  if (channel === "channels") {
21632
- const configsDir = path29.join(stateDir, "configs");
21633
- if (fs27.existsSync(configsDir)) {
21634
- 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"));
21635
21924
  for (const f of files) {
21636
21925
  try {
21637
- const j = JSON.parse(fs27.readFileSync(path29.join(configsDir, f), "utf8"));
21926
+ const j = JSON.parse(fs28.readFileSync(path30.join(configsDir, f), "utf8"));
21638
21927
  if (!j.channels) continue;
21639
21928
  console.log(`
21640
21929
  \u{1F4C4} ${f}:`);
@@ -21680,14 +21969,14 @@ async function main() {
21680
21969
  console.error("\u274C \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25");
21681
21970
  process.exit(1);
21682
21971
  }
21683
- const configsDir2 = path29.join(stateDir, "configs");
21684
- let configFile2 = configName ? path29.join(configsDir2, configName) : "";
21685
- if (!configFile2 || !fs27.existsSync(configFile2)) {
21686
- if (fs27.existsSync(configsDir2)) {
21687
- for (const f of fs27.readdirSync(configsDir2).filter((f2) => f2.endsWith(".json"))) {
21688
- 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);
21689
21978
  try {
21690
- if (JSON.parse(fs27.readFileSync(full, "utf8")).channels) {
21979
+ if (JSON.parse(fs28.readFileSync(full, "utf8")).channels) {
21691
21980
  configFile2 = full;
21692
21981
  break;
21693
21982
  }
@@ -21696,11 +21985,11 @@ async function main() {
21696
21985
  }
21697
21986
  }
21698
21987
  }
21699
- if (configFile2 && fs27.existsSync(configFile2)) {
21700
- const j = JSON.parse(fs27.readFileSync(configFile2, "utf8"));
21988
+ if (configFile2 && fs28.existsSync(configFile2)) {
21989
+ const j = JSON.parse(fs28.readFileSync(configFile2, "utf8"));
21701
21990
  j.channels = j.channels || {};
21702
21991
  j.channels.feishu = { enabled: true, appId: result2.appId, appSecret: result2.appSecret, connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" };
21703
- fs27.writeFileSync(configFile2, JSON.stringify(j, null, 2), "utf8");
21992
+ fs28.writeFileSync(configFile2, JSON.stringify(j, null, 2), "utf8");
21704
21993
  console.log("\u2705 \u98DE\u4E66\u901A\u9053\u5DF2\u5199\u5165: " + configFile2);
21705
21994
  console.log("\u91CD\u542F\u751F\u6548: engine7 restart");
21706
21995
  } else {
@@ -21718,16 +22007,16 @@ async function main() {
21718
22007
  console.error("\u274C \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25\uFF0C\u672A\u4FEE\u6539\u4EFB\u4F55\u914D\u7F6E");
21719
22008
  process.exit(1);
21720
22009
  }
21721
- const configsDir = path29.join(stateDir, "configs");
22010
+ const configsDir = path30.join(stateDir, "configs");
21722
22011
  let configFile = "";
21723
22012
  if (configName) {
21724
- configFile = path29.join(configsDir, configName);
21725
- } else if (fs27.existsSync(configsDir)) {
21726
- 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"));
21727
22016
  for (const f of candidates) {
21728
- const full = path29.join(configsDir, f);
22017
+ const full = path30.join(configsDir, f);
21729
22018
  try {
21730
- const j2 = JSON.parse(fs27.readFileSync(full, "utf8"));
22019
+ const j2 = JSON.parse(fs28.readFileSync(full, "utf8"));
21731
22020
  if (j2.channels) {
21732
22021
  configFile = full;
21733
22022
  break;
@@ -21735,14 +22024,14 @@ async function main() {
21735
22024
  } catch {
21736
22025
  }
21737
22026
  }
21738
- if (!configFile && candidates.length) configFile = path29.join(configsDir, candidates[0]);
22027
+ if (!configFile && candidates.length) configFile = path30.join(configsDir, candidates[0]);
21739
22028
  }
21740
- if (!configFile || !fs27.existsSync(configFile)) {
22029
+ if (!configFile || !fs28.existsSync(configFile)) {
21741
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");
21742
22031
  console.log(JSON.stringify({ wechat: { enabled: true, token: cred.token, accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } } }, null, 2));
21743
22032
  process.exit(0);
21744
22033
  }
21745
- const j = JSON.parse(fs27.readFileSync(configFile, "utf8"));
22034
+ const j = JSON.parse(fs28.readFileSync(configFile, "utf8"));
21746
22035
  j.channels = j.channels || {};
21747
22036
  j.channels.wechat = {
21748
22037
  enabled: true,
@@ -21751,7 +22040,7 @@ async function main() {
21751
22040
  dmPolicy: "pairing",
21752
22041
  group: { policy: "disabled" }
21753
22042
  };
21754
- fs27.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
22043
+ fs28.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
21755
22044
  console.log(`
21756
22045
  \u2705 \u5FAE\u4FE1\u901A\u9053\u5DF2\u5199\u5165: ${configFile}`);
21757
22046
  console.log(` accountId: ${cred.accountId}`);
@@ -21779,8 +22068,8 @@ async function main() {
21779
22068
  else if (args[i] === "--note" && args[i + 1]) note = args[++i];
21780
22069
  else if (args[i] === "--dry-run") dryRun2 = true;
21781
22070
  }
21782
- if (!exportStateDir) exportStateDir = path29.resolve(process.cwd());
21783
- if (!agentName) agentName = path29.basename(exportStateDir);
22071
+ if (!exportStateDir) exportStateDir = path30.resolve(process.cwd());
22072
+ if (!agentName) agentName = path30.basename(exportStateDir);
21784
22073
  await doExport2({ agentName, stateDir: exportStateDir, note, dryRun: dryRun2 });
21785
22074
  process.exit(0);
21786
22075
  }
@@ -21800,7 +22089,7 @@ async function main() {
21800
22089
  console.error("\u274C import \u9700\u8981 --state-dir <path>");
21801
22090
  process.exit(1);
21802
22091
  }
21803
- if (!agentName) agentName = path29.basename(importStateDir);
22092
+ if (!agentName) agentName = path30.basename(importStateDir);
21804
22093
  await doImport2({ agentName, stateDir: importStateDir, version, dryRun: dryRun2 });
21805
22094
  process.exit(0);
21806
22095
  }
@@ -21825,18 +22114,18 @@ engine7 start \u2014 \u542F\u52A8 Engine
21825
22114
  }
21826
22115
  }
21827
22116
  if (!configPath2) {
21828
- const defaultCfg = path29.join("configs", "main7.json");
21829
- const homeCfg = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
21830
- 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)) {
21831
22120
  configPath2 = defaultCfg;
21832
- } else if (fs27.existsSync(homeCfg)) {
22121
+ } else if (fs28.existsSync(homeCfg)) {
21833
22122
  configPath2 = homeCfg;
21834
22123
  console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
21835
22124
  } else {
21836
22125
  const ptr = readHomePointer();
21837
22126
  if (ptr?.stateDir) {
21838
- const ptrCfg = path29.join(ptr.stateDir, "configs", "main7.json");
21839
- if (fs27.existsSync(ptrCfg)) {
22127
+ const ptrCfg = path30.join(ptr.stateDir, "configs", "main7.json");
22128
+ if (fs28.existsSync(ptrCfg)) {
21840
22129
  configPath2 = ptrCfg;
21841
22130
  console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
21842
22131
  }
@@ -21851,19 +22140,19 @@ engine7 start \u2014 \u542F\u52A8 Engine
21851
22140
  }
21852
22141
  const { execSync: execSync3, spawn: spawn5 } = await import("node:child_process");
21853
22142
  let enginePath;
21854
- const localPath = path29.join("node_modules", "engine7", "dist", "main.mjs");
21855
- if (fs27.existsSync(localPath)) {
22143
+ const localPath = path30.join("node_modules", "engine7", "dist", "main.mjs");
22144
+ if (fs28.existsSync(localPath)) {
21856
22145
  enginePath = localPath;
21857
22146
  } else {
21858
- const cliPath = path29.resolve(process.argv[1]);
21859
- const distDir = path29.dirname(cliPath);
21860
- const candidate = path29.join(distDir, "main.mjs");
21861
- 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)) {
21862
22151
  enginePath = candidate;
21863
22152
  } else {
21864
22153
  try {
21865
22154
  const globalRoot = execSync3("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
21866
- enginePath = path29.join(globalRoot, "engine7", "dist", "main.mjs");
22155
+ enginePath = path30.join(globalRoot, "engine7", "dist", "main.mjs");
21867
22156
  } catch {
21868
22157
  console.error("\u274C \u627E\u4E0D\u5230 engine7 main.mjs");
21869
22158
  process.exit(1);
@@ -21873,7 +22162,7 @@ engine7 start \u2014 \u542F\u52A8 Engine
21873
22162
  console.log(label);
21874
22163
  console.log(` config: ${configPath2}`);
21875
22164
  console.log(` engine: ${enginePath}`);
21876
- const configName = path29.basename(configPath2);
22165
+ const configName = path30.basename(configPath2);
21877
22166
  const myPid = process.pid;
21878
22167
  try {
21879
22168
  if (process.platform === "win32") {
@@ -21891,16 +22180,16 @@ engine7 start \u2014 \u542F\u52A8 Engine
21891
22180
  }
21892
22181
  console.log("");
21893
22182
  const envForChild = { ...process.env };
21894
- const secretsDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
21895
- 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");
21896
22185
  const secretCandidates = [
21897
- path29.join(secretsDir, `${cfgBase}.env`),
21898
- path29.join(path29.dirname(configPath2), `.env.${cfgBase}`),
21899
- 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")
21900
22189
  ];
21901
22190
  for (const secretPath of secretCandidates) {
21902
- if (fs27.existsSync(secretPath)) {
21903
- const content = fs27.readFileSync(secretPath, "utf-8");
22191
+ if (fs28.existsSync(secretPath)) {
22192
+ const content = fs28.readFileSync(secretPath, "utf-8");
21904
22193
  for (const line of content.split("\n")) {
21905
22194
  const trimmed = line.trim();
21906
22195
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -21975,14 +22264,14 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
21975
22264
  console.error(`\u274C \u672A\u77E5\u6A21\u5F0F: ${mode}\uFF08\u53EF\u9009: archive / drop-last / strip-images\uFF09`);
21976
22265
  process.exit(1);
21977
22266
  }
21978
- const configRaw = JSON.parse(fs27.readFileSync(configPath2, "utf-8"));
22267
+ const configRaw = JSON.parse(fs28.readFileSync(configPath2, "utf-8"));
21979
22268
  const stateDir = configRaw.stateDir;
21980
22269
  if (!stateDir) {
21981
22270
  console.error("\u274C config \u91CC\u6CA1\u6709 stateDir");
21982
22271
  process.exit(1);
21983
22272
  }
21984
- const sessionsDir = path29.join(stateDir, "agents", "main", "sessions");
21985
- if (!fs27.existsSync(sessionsDir)) {
22273
+ const sessionsDir = path30.join(stateDir, "agents", "main", "sessions");
22274
+ if (!fs28.existsSync(sessionsDir)) {
21986
22275
  console.error(`\u274C sessions \u76EE\u5F55\u4E0D\u5B58\u5728: ${sessionsDir}`);
21987
22276
  process.exit(1);
21988
22277
  }
@@ -21990,37 +22279,37 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
21990
22279
  console.log(` config: ${configPath2}`);
21991
22280
  console.log(` mode: ${mode}`);
21992
22281
  if (mode === "drop-last") console.log(` n: ${dropN}`);
21993
- const platformMapPath = path29.join(sessionsDir, "platform-map.json");
21994
- 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");
21995
22284
  let sessionFileUUID = null;
21996
- if (fs27.existsSync(indexPath)) {
21997
- const index = JSON.parse(fs27.readFileSync(indexPath, "utf-8"));
22285
+ if (fs28.existsSync(indexPath)) {
22286
+ const index = JSON.parse(fs28.readFileSync(indexPath, "utf-8"));
21998
22287
  const entries2 = Object.values(index);
21999
22288
  if (entries2.length > 0) {
22000
22289
  const fileVal = entries2[0].file || "";
22001
- sessionFileUUID = path29.isAbsolute(fileVal) ? path29.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
22290
+ sessionFileUUID = path30.isAbsolute(fileVal) ? path30.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
22002
22291
  }
22003
22292
  }
22004
22293
  if (!sessionFileUUID) {
22005
- 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);
22006
22295
  if (jsonlFiles.length === 0) {
22007
22296
  console.error("\u274C \u627E\u4E0D\u5230\u6D3B\u8DC3\u7684 session JSONL \u6587\u4EF6");
22008
22297
  process.exit(1);
22009
22298
  }
22010
22299
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
22011
22300
  }
22012
- let jsonlPath = path29.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22013
- if (!fs27.existsSync(jsonlPath)) {
22014
- 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);
22015
22304
  if (jsonlFiles.length === 0) {
22016
22305
  console.error(`\u274C JSONL \u6587\u4EF6\u4E0D\u5B58\u5728: ${jsonlPath}`);
22017
22306
  process.exit(1);
22018
22307
  }
22019
22308
  sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
22020
- jsonlPath = path29.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22309
+ jsonlPath = path30.join(sessionsDir, `${sessionFileUUID}.jsonl`);
22021
22310
  }
22022
22311
  console.log(` file: ${jsonlPath}`);
22023
- const configName = path29.basename(configPath2);
22312
+ const configName = path30.basename(configPath2);
22024
22313
  if (autoRestart) {
22025
22314
  try {
22026
22315
  const myPid = process.pid;
@@ -22036,10 +22325,10 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
22036
22325
  }
22037
22326
  }
22038
22327
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
22039
- const { readFileSync: readFileSync29, writeFileSync: writeFileSync20, renameSync: renameSync4 } = fs27;
22328
+ const { readFileSync: readFileSync29, writeFileSync: writeFileSync20, renameSync: renameSync5 } = fs28;
22040
22329
  if (mode === "archive") {
22041
22330
  const archiveName = `${sessionFileUUID}.jsonl.archived.${timestamp}`;
22042
- renameSync4(jsonlPath, path29.join(sessionsDir, archiveName));
22331
+ renameSync5(jsonlPath, path30.join(sessionsDir, archiveName));
22043
22332
  console.log(`
22044
22333
  \u2705 \u5F52\u6863\u5B8C\u6210: ${archiveName}`);
22045
22334
  console.log(` \u91CD\u542F\u540E\u5C06\u4ECE\u7A7A\u767D\u4F1A\u8BDD\u5F00\u59CB`);
@@ -22114,12 +22403,12 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
22114
22403
  \u2705 \u6458\u9664 ${stripped} \u884C\u56FE\u7247\u76F8\u5173\u5185\u5BB9`);
22115
22404
  }
22116
22405
  if (autoRestart) {
22117
- const realCliPath = fs27.realpathSync(process.argv[1]);
22118
- const cliDir = path29.dirname(realCliPath);
22119
- const pkgRoot = path29.resolve(cliDir, "..");
22120
- let enginePath = path29.join(pkgRoot, "dist", "main.mjs");
22121
- if (!fs27.existsSync(enginePath)) {
22122
- 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");
22123
22412
  }
22124
22413
  console.log(`
22125
22414
  \u{1F680} \u62C9\u8D77 engine...`);
@@ -22162,18 +22451,18 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
22162
22451
  else if (args[i] === "--cwd" && args[i + 1]) cwd = args[++i];
22163
22452
  }
22164
22453
  if (!configPath2) {
22165
- const defaultCfg = path29.join(cwd, "configs", "main7.json");
22166
- const homeCfg = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
22167
- 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)) {
22168
22457
  configPath2 = defaultCfg;
22169
- } else if (fs27.existsSync(homeCfg)) {
22458
+ } else if (fs28.existsSync(homeCfg)) {
22170
22459
  configPath2 = homeCfg;
22171
- cwd = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
22460
+ cwd = path30.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
22172
22461
  } else {
22173
22462
  const ptr = readHomePointer();
22174
22463
  if (ptr?.stateDir) {
22175
- const ptrCfg = path29.join(ptr.stateDir, "configs", "main7.json");
22176
- if (fs27.existsSync(ptrCfg)) {
22464
+ const ptrCfg = path30.join(ptr.stateDir, "configs", "main7.json");
22465
+ if (fs28.existsSync(ptrCfg)) {
22177
22466
  configPath2 = ptrCfg;
22178
22467
  cwd = ptr.stateDir;
22179
22468
  }
@@ -22192,14 +22481,14 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
22192
22481
  if (process.platform === "win32") {
22193
22482
  const taskName = "Engine7";
22194
22483
  const nodeExe = process.execPath;
22195
- const cliMjs = path29.resolve(engine7Bin);
22196
- const absConfig = path29.resolve(configPath2);
22197
- 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");
22198
22487
  const wrapperContent = `@echo off\r
22199
22488
  cd /d "${cwd}"\r
22200
22489
  "${nodeExe}" "${cliMjs}" start --config "${absConfig}"\r
22201
22490
  `;
22202
- fs27.writeFileSync(wrapperPath, wrapperContent);
22491
+ fs28.writeFileSync(wrapperPath, wrapperContent);
22203
22492
  try {
22204
22493
  execSync3(`schtasks /create /tn "${taskName}" /tr "${wrapperPath}" /sc onlogon /rl highest /f`, { stdio: "inherit", shell: true });
22205
22494
  console.log(`\u2705 Windows \u8BA1\u5212\u4EFB\u52A1 "${taskName}" \u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
@@ -22210,11 +22499,11 @@ cd /d "${cwd}"\r
22210
22499
  }
22211
22500
  } else if (process.platform === "darwin") {
22212
22501
  const label = "com.engine7.agent";
22213
- const plistDir = path29.join(process.env.HOME, "Library", "LaunchAgents");
22214
- fs27.mkdirSync(plistDir, { recursive: true });
22215
- const plistPath = path29.join(plistDir, `${label}.plist`);
22216
- const localCli = path29.join("node_modules", "engine7", "dist", "cli.mjs");
22217
- 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");
22218
22507
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
22219
22508
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
22220
22509
  <plist version="1.0">
@@ -22226,14 +22515,14 @@ cd /d "${cwd}"\r
22226
22515
  <string>${cliMjs}</string>
22227
22516
  <string>start</string>
22228
22517
  <string>--config</string>
22229
- <string>${path29.resolve(configPath2)}</string>
22518
+ <string>${path30.resolve(configPath2)}</string>
22230
22519
  </array>
22231
22520
  <key>WorkingDirectory</key><string>${cwd}</string>
22232
22521
  <key>RunAtLoad</key><true/>
22233
22522
  <key>KeepAlive</key><true/>
22234
22523
  </dict>
22235
22524
  </plist>`;
22236
- fs27.writeFileSync(plistPath, plist);
22525
+ fs28.writeFileSync(plistPath, plist);
22237
22526
  try {
22238
22527
  execSync3(`launchctl load "${plistPath}"`, { stdio: "inherit" });
22239
22528
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
@@ -22244,9 +22533,9 @@ cd /d "${cwd}"\r
22244
22533
  }
22245
22534
  } else {
22246
22535
  const svcName = "engine7";
22247
- const svcDir = path29.join(process.env.HOME, ".config", "systemd", "user");
22248
- fs27.mkdirSync(svcDir, { recursive: true });
22249
- 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`);
22250
22539
  const svc = `[Unit]
22251
22540
  Description=Engine 7 Agent
22252
22541
  After=network.target
@@ -22254,13 +22543,13 @@ After=network.target
22254
22543
  [Service]
22255
22544
  Type=simple
22256
22545
  WorkingDirectory=${cwd}
22257
- ExecStart=${process.execPath} ${engine7Bin} start --config ${path29.resolve(configPath2)}
22546
+ ExecStart=${process.execPath} ${engine7Bin} start --config ${path30.resolve(configPath2)}
22258
22547
  Restart=on-failure
22259
22548
  RestartSec=10
22260
22549
 
22261
22550
  [Install]
22262
22551
  WantedBy=default.target`;
22263
- fs27.writeFileSync(svcPath, svc);
22552
+ fs28.writeFileSync(svcPath, svc);
22264
22553
  try {
22265
22554
  execSync3(`systemctl --user daemon-reload`, { stdio: "inherit" });
22266
22555
  execSync3(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
@@ -22281,13 +22570,13 @@ WantedBy=default.target`;
22281
22570
  process.exit(1);
22282
22571
  }
22283
22572
  } else if (process.platform === "darwin") {
22284
- 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");
22285
22574
  try {
22286
22575
  execSync3(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
22287
22576
  } catch {
22288
22577
  }
22289
22578
  try {
22290
- fs27.unlinkSync(plistPath);
22579
+ fs28.unlinkSync(plistPath);
22291
22580
  } catch {
22292
22581
  }
22293
22582
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
@@ -22296,9 +22585,9 @@ WantedBy=default.target`;
22296
22585
  execSync3(`systemctl --user disable engine7`, { stdio: "inherit" });
22297
22586
  } catch {
22298
22587
  }
22299
- 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");
22300
22589
  try {
22301
- fs27.unlinkSync(svcPath);
22590
+ fs28.unlinkSync(svcPath);
22302
22591
  } catch {
22303
22592
  }
22304
22593
  try {
@@ -22315,8 +22604,8 @@ WantedBy=default.target`;
22315
22604
  console.log("\u274C \u672A\u5B89\u88C5");
22316
22605
  }
22317
22606
  } else if (process.platform === "darwin") {
22318
- const plistPath = path29.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
22319
- if (fs27.existsSync(plistPath)) {
22607
+ const plistPath = path30.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
22608
+ if (fs28.existsSync(plistPath)) {
22320
22609
  console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
22321
22610
  } else {
22322
22611
  console.log("\u274C \u672A\u5B89\u88C5");
@@ -22339,16 +22628,16 @@ WantedBy=default.target`;
22339
22628
  console.log(`
22340
22629
  \u{1F680} engine7 init`);
22341
22630
  console.log(` state-dir: ${opts.stateDir}`);
22342
- if (fs27.existsSync(opts.stateDir) && !opts.dryRun) {
22343
- const files = fs27.readdirSync(opts.stateDir);
22631
+ if (fs28.existsSync(opts.stateDir) && !opts.dryRun) {
22632
+ const files = fs28.readdirSync(opts.stateDir);
22344
22633
  if (files.length > 0) {
22345
22634
  if (opts.force) {
22346
22635
  console.log(`
22347
22636
  \u26A0\uFE0F --force: \u6E05\u7A7A\u5DF2\u6709\u76EE\u5F55 ${opts.stateDir}`);
22348
- fs27.rmSync(opts.stateDir, { recursive: true, force: true });
22637
+ fs28.rmSync(opts.stateDir, { recursive: true, force: true });
22349
22638
  } else {
22350
- const existingConfig = path29.join(opts.stateDir, "configs", "main7.json");
22351
- if (fs27.existsSync(existingConfig)) {
22639
+ const existingConfig = path30.join(opts.stateDir, "configs", "main7.json");
22640
+ if (fs28.existsSync(existingConfig)) {
22352
22641
  console.log(`
22353
22642
  \u267B\uFE0F \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E: ${existingConfig}`);
22354
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`);
@@ -22372,7 +22661,7 @@ WantedBy=default.target`;
22372
22661
  rl.close();
22373
22662
  }
22374
22663
  const config = generateConfig(values);
22375
- const configPath = path29.join(opts.stateDir, "configs", "main7.json");
22664
+ const configPath = path30.join(opts.stateDir, "configs", "main7.json");
22376
22665
  const tree = buildDirTree(values);
22377
22666
  tree.push({
22378
22667
  path: configPath,
@@ -22383,9 +22672,9 @@ WantedBy=default.target`;
22383
22672
  dryRun(tree);
22384
22673
  const skillsSrc = findTemplateDir("skills");
22385
22674
  if (skillsSrc) {
22386
- const skills = fs27.readdirSync(skillsSrc);
22675
+ const skills = fs28.readdirSync(skillsSrc);
22387
22676
  for (const s of skills) {
22388
- console.log(` \u{1F4C1} ${path29.join(opts.stateDir, "workspace", "skills", s)}`);
22677
+ console.log(` \u{1F4C1} ${path30.join(opts.stateDir, "workspace", "skills", s)}`);
22389
22678
  }
22390
22679
  }
22391
22680
  } else {
@@ -22393,16 +22682,16 @@ WantedBy=default.target`;
22393
22682
  execute(tree);
22394
22683
  if (values.primaryApiKey && values.primaryApiKey.trim()) {
22395
22684
  const envName = values.primaryProvider.toUpperCase().replace(/[^A-Z0-9_]/g, "_") + "_API_KEY";
22396
- const secretsDir = path29.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
22397
- if (!fs27.existsSync(secretsDir)) fs27.mkdirSync(secretsDir, { recursive: true });
22398
- 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");
22399
22688
  let envContent = "";
22400
- if (fs27.existsSync(envFile)) envContent = fs27.readFileSync(envFile, "utf8");
22689
+ if (fs28.existsSync(envFile)) envContent = fs28.readFileSync(envFile, "utf8");
22401
22690
  const lines = envContent.split("\n").filter((l) => l && !l.startsWith(envName + "="));
22402
22691
  lines.push(envName + "=" + values.primaryApiKey.trim());
22403
- fs27.writeFileSync(envFile, lines.join("\n") + "\n", "utf8");
22692
+ fs28.writeFileSync(envFile, lines.join("\n") + "\n", "utf8");
22404
22693
  try {
22405
- fs27.chmodSync(envFile, 384);
22694
+ fs28.chmodSync(envFile, 384);
22406
22695
  } catch {
22407
22696
  }
22408
22697
  console.log("\u{1F511} API key \u5DF2\u5B58\u5165: " + envFile);
@@ -22410,55 +22699,55 @@ WantedBy=default.target`;
22410
22699
  }
22411
22700
  const skillsSrc = findTemplateDir("skills");
22412
22701
  if (skillsSrc) {
22413
- const skillsDest = path29.join(opts.stateDir, "workspace", "skills");
22414
- fs27.mkdirSync(skillsDest, { recursive: true });
22415
- 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);
22416
22705
  for (const s of skills) {
22417
- copyDirRecursive(path29.join(skillsSrc, s), path29.join(skillsDest, s));
22706
+ copyDirRecursive(path30.join(skillsSrc, s), path30.join(skillsDest, s));
22418
22707
  console.log(` \u{1F4E6} skill: ${s}`);
22419
22708
  }
22420
22709
  }
22421
22710
  console.log(`
22422
22711
  \u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
22423
22712
  `);
22424
- 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");
22425
22714
  const pointerData = { stateDir: opts.stateDir };
22426
- fs27.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
22715
+ fs28.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
22427
22716
  console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
22428
22717
  console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
22429
22718
  console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
22430
22719
  console.log(` 2. \u542F\u52A8 Engine: engine7 start\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
22431
22720
  console.log(` 3. \u5F00\u673A\u81EA\u542F: engine7 service install\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
22432
- console.log(` 4. \u67E5\u770B workspace: ${path29.join(opts.stateDir, "workspace")}`);
22721
+ console.log(` 4. \u67E5\u770B workspace: ${path30.join(opts.stateDir, "workspace")}`);
22433
22722
  }
22434
22723
  }
22435
22724
  function copyDirRecursive(src, dest) {
22436
- fs27.mkdirSync(dest, { recursive: true });
22437
- for (const entry of fs27.readdirSync(src, { withFileTypes: true })) {
22438
- const srcPath = path29.join(src, entry.name);
22439
- 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);
22440
22729
  if (entry.isDirectory()) {
22441
22730
  copyDirRecursive(srcPath, destPath);
22442
22731
  } else {
22443
- fs27.copyFileSync(srcPath, destPath);
22732
+ fs28.copyFileSync(srcPath, destPath);
22444
22733
  }
22445
22734
  }
22446
22735
  }
22447
22736
  function findTemplateDir(name) {
22448
22737
  const candidates = [
22449
- path29.join(__dirname, "..", "templates", name),
22450
- path29.join(__dirname, "..", "..", "templates", name),
22451
- 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)
22452
22741
  ];
22453
22742
  for (const p of candidates) {
22454
- if (fs27.existsSync(p)) return p;
22743
+ if (fs28.existsSync(p)) return p;
22455
22744
  }
22456
22745
  return null;
22457
22746
  }
22458
22747
  function readHomePointer() {
22459
- 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");
22460
22749
  try {
22461
- return JSON.parse(fs27.readFileSync(ptrPath, "utf-8"));
22750
+ return JSON.parse(fs28.readFileSync(ptrPath, "utf-8"));
22462
22751
  } catch {
22463
22752
  return null;
22464
22753
  }
@@ -22469,4 +22758,3 @@ main().catch((err) => {
22469
22758
  console.error(err.stack);
22470
22759
  process.exit(1);
22471
22760
  });
22472
- //# sourceMappingURL=cli.mjs.map