engine7 7.1.6 → 7.1.8

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.
@@ -480,9 +480,9 @@ async function execCommandHook(hook, hookEvent, hookName, jsonInput, signal, hoo
480
480
  child.stderr.on("data", (chunk) => {
481
481
  stderr += chunk;
482
482
  });
483
- const exitCode = await new Promise((resolve11) => {
484
- child.on("close", (code) => resolve11(code ?? 0));
485
- child.on("error", () => resolve11(1));
483
+ const exitCode = await new Promise((resolve12) => {
484
+ child.on("close", (code) => resolve12(code ?? 0));
485
+ child.on("error", () => resolve12(1));
486
486
  });
487
487
  if (timeoutHandle) clearTimeout(timeoutHandle);
488
488
  signal.removeEventListener("abort", onAbort);
@@ -4117,7 +4117,7 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
4117
4117
  const osMod = await import("node:os");
4118
4118
  const outputFile = path10.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
4119
4119
  const outputHandle = await fs9.promises.open(outputFile, "w");
4120
- return new Promise((resolve11) => {
4120
+ return new Promise((resolve12) => {
4121
4121
  const { shell, args: shellArgs } = findShell();
4122
4122
  const child = spawn2(shell, [...shellArgs, command], {
4123
4123
  cwd,
@@ -4164,7 +4164,7 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
4164
4164
  errorMessage = errorMessage ? `${timeoutMsg} ${errorMessage}` : timeoutMsg;
4165
4165
  }
4166
4166
  const parts = [processedStdout, errorMessage, truncationSuffix].filter(Boolean);
4167
- resolve11({
4167
+ resolve12({
4168
4168
  content: parts.join("\n") || "(no output)",
4169
4169
  isError: aborted
4170
4170
  });
@@ -4579,16 +4579,16 @@ async function writeTeamFileAsync(teamName, teamFile) {
4579
4579
  }
4580
4580
  async function withTeamFileLock(teamName, fn) {
4581
4581
  const prev = teamFileMutex.get(teamName) || Promise.resolve();
4582
- let resolve11;
4582
+ let resolve12;
4583
4583
  const next = new Promise((r) => {
4584
- resolve11 = r;
4584
+ resolve12 = r;
4585
4585
  });
4586
4586
  teamFileMutex.set(teamName, next);
4587
4587
  await prev;
4588
4588
  try {
4589
4589
  return await fn();
4590
4590
  } finally {
4591
- resolve11();
4591
+ resolve12();
4592
4592
  if (teamFileMutex.get(teamName) === next) teamFileMutex.delete(teamName);
4593
4593
  }
4594
4594
  }
@@ -4725,7 +4725,7 @@ async function ensureInboxDir(teamName) {
4725
4725
  await mkdir2(inboxDir, { recursive: true });
4726
4726
  }
4727
4727
  async function sleep3(ms) {
4728
- return new Promise((resolve11) => setTimeout(resolve11, ms));
4728
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
4729
4729
  }
4730
4730
  function parseLockContent(raw) {
4731
4731
  const [pidStr, tsStr] = raw.split("-");
@@ -6468,15 +6468,15 @@ function blockTask(stateDir, listId, fromTaskId, toTaskId) {
6468
6468
  }
6469
6469
  function withTaskLock(listId, fn) {
6470
6470
  const prev = taskMutex.get(listId) || Promise.resolve();
6471
- let resolve11;
6471
+ let resolve12;
6472
6472
  const next = new Promise((r) => {
6473
- resolve11 = r;
6473
+ resolve12 = r;
6474
6474
  });
6475
6475
  taskMutex.set(listId, next);
6476
6476
  try {
6477
6477
  return fn();
6478
6478
  } finally {
6479
- resolve11();
6479
+ resolve12();
6480
6480
  if (taskMutex.get(listId) === next) taskMutex.delete(listId);
6481
6481
  }
6482
6482
  }
@@ -7263,7 +7263,7 @@ function findFiles(dir, pattern, limit, baseDir) {
7263
7263
  if (VCS_DIRS.has(entry.name)) continue;
7264
7264
  walk(fullPath);
7265
7265
  } else if (entry.isFile()) {
7266
- const relativePath = path36.relative(baseDir, fullPath);
7266
+ const relativePath = path36.relative(baseDir, fullPath).replace(/\\/g, "/");
7267
7267
  const patternsToTry = [pattern];
7268
7268
  if (pattern.startsWith("**/")) {
7269
7269
  patternsToTry.push(pattern.slice(3));
@@ -7353,7 +7353,7 @@ var grep_exports = {};
7353
7353
  import { execFile as execFile2 } from "node:child_process";
7354
7354
  import * as path37 from "node:path";
7355
7355
  function ripGrep(args, searchPath, signal) {
7356
- return new Promise((resolve11) => {
7356
+ return new Promise((resolve12) => {
7357
7357
  const fullArgs = [...args, searchPath];
7358
7358
  const child = execFile2("rg", fullArgs, {
7359
7359
  maxBuffer: 50 * 1024 * 1024,
@@ -7362,11 +7362,11 @@ function ripGrep(args, searchPath, signal) {
7362
7362
  signal
7363
7363
  }, (error, stdout, stderr) => {
7364
7364
  if (error && error.killed) {
7365
- resolve11({ lines: [], exitCode: -1, timedOut: true });
7365
+ resolve12({ lines: [], exitCode: -1, timedOut: true });
7366
7366
  return;
7367
7367
  }
7368
7368
  const lines = stdout ? stdout.split("\n").filter(Boolean) : [];
7369
- resolve11({ lines, exitCode: error ? error.code || 1 : 0, timedOut: false });
7369
+ resolve12({ lines, exitCode: error ? error.code || 1 : 0, timedOut: false });
7370
7370
  });
7371
7371
  });
7372
7372
  }
@@ -7553,7 +7553,7 @@ ${filenames.join("\n")}${truncatedNote}`
7553
7553
  // src/tools/task-output.ts
7554
7554
  var task_output_exports = {};
7555
7555
  async function sleep4(ms) {
7556
- return new Promise((resolve11) => setTimeout(resolve11, ms));
7556
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
7557
7557
  }
7558
7558
  async function waitForTaskCompletion(taskId, timeoutMs, signal) {
7559
7559
  const startTime = Date.now();
@@ -8581,13 +8581,13 @@ function waitForAllIdle(timeoutMs = 6e4) {
8581
8581
  ([, info]) => info.status === "running"
8582
8582
  );
8583
8583
  if (working.length === 0) return Promise.resolve({ timedOut: false, remaining: 0 });
8584
- return new Promise((resolve11) => {
8584
+ return new Promise((resolve12) => {
8585
8585
  let remaining = working.length;
8586
8586
  let settled = false;
8587
8587
  const done2 = (timedOut) => {
8588
8588
  if (settled) return;
8589
8589
  settled = true;
8590
- resolve11({ timedOut, remaining });
8590
+ resolve12({ timedOut, remaining });
8591
8591
  };
8592
8592
  const timer = setTimeout(() => {
8593
8593
  console.warn(`[spawnInProcess] waitForAllIdle timed out after ${timeoutMs}ms, ${remaining} still running`);
@@ -11044,8 +11044,8 @@ async function executeAndDeliver(task, now, deps) {
11044
11044
  }
11045
11045
  }
11046
11046
  let resolveResult;
11047
- const resultPromise = new Promise((resolve11) => {
11048
- resolveResult = resolve11;
11047
+ const resultPromise = new Promise((resolve12) => {
11048
+ resolveResult = resolve12;
11049
11049
  });
11050
11050
  deps.dispatcher.submitMessage({
11051
11051
  text: promptText,
@@ -11075,7 +11075,7 @@ async function executeAndDeliver(task, now, deps) {
11075
11075
  const inputFile = path55.join(resultsDirTmp, `${task.id}.input.txt`);
11076
11076
  fs54.writeFileSync(inputFile, result, "utf-8");
11077
11077
  const { execFile: execFile3 } = await import("child_process");
11078
- await new Promise((resolve11) => {
11078
+ await new Promise((resolve12) => {
11079
11079
  execFile3("python", [scriptPath, "main", "--file", inputFile], {
11080
11080
  cwd: deps.sessions["config"].stateDir,
11081
11081
  timeout: 3e4,
@@ -11092,7 +11092,7 @@ async function executeAndDeliver(task, now, deps) {
11092
11092
  }
11093
11093
  if (stderr) console.log(`[cron] postProcess stderr: ${stderr.trim()}`);
11094
11094
  }
11095
- resolve11();
11095
+ resolve12();
11096
11096
  });
11097
11097
  });
11098
11098
  } catch (err) {
@@ -11495,7 +11495,7 @@ var init_wx_query = __esm({
11495
11495
  const cmd = args.command.trim();
11496
11496
  const timeout = args.timeout || 12e4;
11497
11497
  const fullCmd = `${PYTHON} "${SCRIPT}" ${cmd.replace(/^python3\s+.*wx_query\.py\s*/, "")}`;
11498
- return new Promise((resolve11) => {
11498
+ return new Promise((resolve12) => {
11499
11499
  const child = spawn7(shell.shell, [...shell.args, fullCmd], {
11500
11500
  timeout,
11501
11501
  env: { ...process.env }
@@ -11510,16 +11510,16 @@ var init_wx_query = __esm({
11510
11510
  });
11511
11511
  child.on("close", (code) => {
11512
11512
  if (code === 0) {
11513
- resolve11({ content: stdout });
11513
+ resolve12({ content: stdout });
11514
11514
  } else {
11515
- resolve11({
11515
+ resolve12({
11516
11516
  content: stderr || stdout || "(no output)",
11517
11517
  isError: true
11518
11518
  });
11519
11519
  }
11520
11520
  });
11521
11521
  child.on("error", (err) => {
11522
- resolve11({
11522
+ resolve12({
11523
11523
  content: `wx_query error: ${err.message}`,
11524
11524
  isError: true
11525
11525
  });
@@ -12124,15 +12124,15 @@ async function canStealStaleLock(lockPath2) {
12124
12124
  return !isProcessLikelyAlive(ownerPid);
12125
12125
  }
12126
12126
  async function sleep5(ms) {
12127
- await new Promise((resolve11) => {
12128
- setTimeout(resolve11, ms);
12127
+ await new Promise((resolve12) => {
12128
+ setTimeout(resolve12, ms);
12129
12129
  });
12130
12130
  }
12131
12131
  async function withInProcessShortTermLock(lockPath2, task) {
12132
12132
  const previous = inProcessShortTermLocks.get(lockPath2) ?? Promise.resolve();
12133
12133
  let releaseCurrent;
12134
- const current = new Promise((resolve11) => {
12135
- releaseCurrent = resolve11;
12134
+ const current = new Promise((resolve12) => {
12135
+ releaseCurrent = resolve12;
12136
12136
  });
12137
12137
  const queued = previous.catch(() => void 0).then(() => current);
12138
12138
  inProcessShortTermLocks.set(lockPath2, queued);
@@ -23118,7 +23118,7 @@ var init_handler = __esm({
23118
23118
  this._addToNodeFs(path55, initialAdd, wh, depth + 1);
23119
23119
  }
23120
23120
  }).on(EV.ERROR, this._boundHandleError);
23121
- return new Promise((resolve11, reject) => {
23121
+ return new Promise((resolve12, reject) => {
23122
23122
  if (!stream)
23123
23123
  return reject();
23124
23124
  stream.once(STR_END, () => {
@@ -23127,7 +23127,7 @@ var init_handler = __esm({
23127
23127
  return;
23128
23128
  }
23129
23129
  const wasThrottled = throttler ? throttler.clear() : false;
23130
- resolve11(void 0);
23130
+ resolve12(void 0);
23131
23131
  previous.getChildren().filter((item) => {
23132
23132
  return item !== directory && !current.has(item);
23133
23133
  }).forEach((item) => {
@@ -24427,8 +24427,8 @@ function createSessionSyncYield(total) {
24427
24427
  return async () => {
24428
24428
  completed += 1;
24429
24429
  if (completed < total && completed % SESSION_SYNC_YIELD_EVERY === 0) {
24430
- await new Promise((resolve11) => {
24431
- setImmediate(resolve11);
24430
+ await new Promise((resolve12) => {
24431
+ setImmediate(resolve12);
24432
24432
  });
24433
24433
  }
24434
24434
  };
@@ -24630,8 +24630,8 @@ var init_manager_sync_ops = __esm({
24630
24630
  );
24631
24631
  rowCount += 1;
24632
24632
  if (rowCount % SEED_EMBEDDING_YIELD_EVERY === 0) {
24633
- await new Promise((resolve11) => {
24634
- setImmediate(resolve11);
24633
+ await new Promise((resolve12) => {
24634
+ setImmediate(resolve12);
24635
24635
  });
24636
24636
  }
24637
24637
  }
@@ -25908,7 +25908,7 @@ var init_manager_embedding_ops = __esm({
25908
25908
  EMBEDDING_RETRY_MAX_DELAY_MS
25909
25909
  );
25910
25910
  log2.warn(`memory embeddings rate limited; ${action} in ${waitMs}ms`);
25911
- await new Promise((resolve11) => setTimeout(resolve11, waitMs));
25911
+ await new Promise((resolve12) => setTimeout(resolve12, waitMs));
25912
25912
  }
25913
25913
  resolveEmbeddingTimeout(kind) {
25914
25914
  return resolveEmbeddingTimeoutMs({
@@ -25950,8 +25950,8 @@ var init_manager_embedding_ops = __esm({
25950
25950
  async withBatchFailureLock(fn) {
25951
25951
  let release2;
25952
25952
  const wait = this.batchFailureLock;
25953
- this.batchFailureLock = new Promise((resolve11) => {
25954
- release2 = resolve11;
25953
+ this.batchFailureLock = new Promise((resolve12) => {
25954
+ release2 = resolve12;
25955
25955
  });
25956
25956
  await wait;
25957
25957
  try {
@@ -28948,7 +28948,7 @@ var reply_blocklist_exports = {};
28948
28948
  __export(reply_blocklist_exports, {
28949
28949
  isUserBlocked: () => isUserBlocked
28950
28950
  });
28951
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync15, existsSync as existsSync23 } from "node:fs";
28951
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync15, existsSync as existsSync24 } from "node:fs";
28952
28952
  import { join as join39 } from "node:path";
28953
28953
  function ensureLoaded(workspace, configIds) {
28954
28954
  if (loaded) return;
@@ -28959,7 +28959,7 @@ function ensureLoaded(workspace, configIds) {
28959
28959
  }
28960
28960
  const path55 = join39(workspace, ".reply-blocklist.json");
28961
28961
  try {
28962
- if (existsSync23(path55)) {
28962
+ if (existsSync24(path55)) {
28963
28963
  const raw = readFileSync26(path55, "utf-8");
28964
28964
  const parsed = JSON.parse(raw);
28965
28965
  if (parsed.blockedUserIds) {
@@ -29699,12 +29699,12 @@ var MAX_DELAY_MS = 32e3;
29699
29699
  var DEFAULT_TIMEOUT_MS = 6e5;
29700
29700
  var READ_TIMEOUT_MS = 6e4;
29701
29701
  function sleep(ms, signal) {
29702
- return new Promise((resolve11, reject) => {
29702
+ return new Promise((resolve12, reject) => {
29703
29703
  if (signal?.aborted) {
29704
29704
  reject(new DOMException("Aborted", "AbortError"));
29705
29705
  return;
29706
29706
  }
29707
- const timer = setTimeout(resolve11, ms);
29707
+ const timer = setTimeout(resolve12, ms);
29708
29708
  const onAbort = () => {
29709
29709
  clearTimeout(timer);
29710
29710
  reject(new DOMException("Aborted", "AbortError"));
@@ -33815,7 +33815,7 @@ var MAX_TRANSCRIPT_READ_BYTES = 50 * 1024 * 1024;
33815
33815
  async function readSessionHeader(filePath) {
33816
33816
  const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
33817
33817
  const rl = readline.createInterface({ input: stream });
33818
- return new Promise((resolve11) => {
33818
+ return new Promise((resolve12) => {
33819
33819
  let resolved = false;
33820
33820
  rl.on("line", (line) => {
33821
33821
  try {
@@ -33824,7 +33824,7 @@ async function readSessionHeader(filePath) {
33824
33824
  resolved = true;
33825
33825
  rl.close();
33826
33826
  stream.destroy();
33827
- resolve11({
33827
+ resolve12({
33828
33828
  id: obj.id,
33829
33829
  timestamp: obj.timestamp,
33830
33830
  cwd: obj.cwd,
@@ -33836,10 +33836,10 @@ async function readSessionHeader(filePath) {
33836
33836
  }
33837
33837
  });
33838
33838
  rl.on("close", () => {
33839
- if (!resolved) resolve11(null);
33839
+ if (!resolved) resolve12(null);
33840
33840
  });
33841
33841
  rl.on("error", () => {
33842
- if (!resolved) resolve11(null);
33842
+ if (!resolved) resolve12(null);
33843
33843
  });
33844
33844
  });
33845
33845
  }
@@ -34067,9 +34067,9 @@ async function readAllLines(filePath) {
34067
34067
  const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
34068
34068
  const rl = readline.createInterface({ input: stream });
34069
34069
  const lines = [];
34070
- return new Promise((resolve11, reject) => {
34070
+ return new Promise((resolve12, reject) => {
34071
34071
  rl.on("line", (line) => lines.push(line));
34072
- rl.on("close", () => resolve11(lines));
34072
+ rl.on("close", () => resolve12(lines));
34073
34073
  rl.on("error", (err) => reject(err));
34074
34074
  });
34075
34075
  }
@@ -36760,8 +36760,8 @@ function startCliLoop(deps, cliConfig, channelManager, dispatcher) {
36760
36760
  process.stdout.write("AI> ");
36761
36761
  let inToolCall = false;
36762
36762
  let resolveDone;
36763
- const done2 = new Promise((resolve11) => {
36764
- resolveDone = resolve11;
36763
+ const done2 = new Promise((resolve12) => {
36764
+ resolveDone = resolve12;
36765
36765
  });
36766
36766
  dispatcher.submitMessage({
36767
36767
  text: trimmed,
@@ -37057,8 +37057,8 @@ ${basePrompt}`;
37057
37057
  }, timeoutMs);
37058
37058
  if (this.dispatcher) {
37059
37059
  let resolveDone;
37060
- const done2 = new Promise((resolve11) => {
37061
- resolveDone = resolve11;
37060
+ const done2 = new Promise((resolve12) => {
37061
+ resolveDone = resolve12;
37062
37062
  });
37063
37063
  this.dispatcher.submitMessage({
37064
37064
  text: prompt,
@@ -37433,7 +37433,7 @@ var NudgePlugin = class {
37433
37433
  }, intervalMs);
37434
37434
  this.registerStopHook(sessions);
37435
37435
  }
37436
- /** 注册 Stop hook:agent 停止前用 LLM 判断是否在等外部条件 → 注册 5min notification */
37436
+ /** 注册 Stop hook:你停止前用 LLM 判断是否在等外部条件 → 注册 5min notification */
37437
37437
  registerStopHook(sessions) {
37438
37438
  registerCallbackHook("Stop", {
37439
37439
  type: "callback",
@@ -37447,7 +37447,7 @@ var NudgePlugin = class {
37447
37447
  console.log(`[stop-hook] skipping voice-chat (channel=${msgChannel})`);
37448
37448
  return { outcome: { outcome: "success" } };
37449
37449
  }
37450
- if (!lastMsg || lastMsg.length < 10) {
37450
+ if (!lastMsg) {
37451
37451
  return { outcome: { outcome: "success" } };
37452
37452
  }
37453
37453
  let contextStr = "";
@@ -37463,9 +37463,10 @@ var NudgePlugin = class {
37463
37463
  console.warn(`[stop-hook] recentMessages error: ${e.message}`);
37464
37464
  }
37465
37465
  const judgeInput = `${contextStr}
37466
- agent: ${lastMsg.slice(0, 300)}`;
37466
+ \u4F60: ${lastMsg.slice(0, 300)}`;
37467
37467
  let isWaiting = false;
37468
37468
  let waitDesc = "";
37469
+ let pushedDecision = false;
37469
37470
  try {
37470
37471
  const excludeCases = this.cfg.stopHookExcludeCases || [];
37471
37472
  const excludeSection = excludeCases.length > 0 ? [
@@ -37476,20 +37477,22 @@ agent: ${lastMsg.slice(0, 300)}`;
37476
37477
  const stream = this.provider.streamChat({
37477
37478
  model: this.model,
37478
37479
  systemPrompt: [
37479
- "\u4F60\u662F\u4E00\u4E2A\u5224\u65AD\u5668\u3002\u8BFB agent \u6700\u8FD1\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u5224\u65AD agent \u662F\u5426\u5904\u4E8E\u4EE5\u4E0B\u72B6\u6001\u4E4B\u4E00\uFF1A",
37480
+ "\u4F60\u662F\u4E00\u4E2A\u5224\u65AD\u5668\u3002\u8BFB\u4F60\u6700\u8FD1\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u5224\u65AD\u4F60\uFF08\u5C0F\u67EF\uFF09\u662F\u5426\u5904\u4E8E\u4EE5\u4E0B\u72B6\u6001\u4E4B\u4E00\uFF1A",
37480
37481
  "",
37481
37482
  "1. \u5728\u7B49\u5F85\u67D0\u4E2A\u5916\u90E8\u6761\u4EF6\uFF08\u670D\u52A1\u91CD\u542F\u3001SSH\u6062\u590D\u3001\u6587\u4EF6\u52A0\u8F7D\u3001\u5F02\u6B65\u4EFB\u52A1\u5B8C\u6210\u7B49\uFF09",
37482
37483
  '2. \u628A\u672C\u8BE5\u81EA\u5DF1\u505A\u7684\u51B3\u5B9A\u63A8\u7ED9\u4E86\u5BF9\u65B9\uFF08\u4F8B\u5982\u95EE"\u8981\u73B0\u5728\u6539\u8FD8\u662F\u6392\u540E\u9762\uFF1F""\u8981\u4E0D\u8981\u8BD5\u8BD5X\uFF1F"\u4F46\u660E\u660E\u81EA\u5DF1\u80FD\u5B9A\uFF09',
37483
37484
  "3. \u9047\u5230\u95EE\u9898\u6CA1\u6709\u81EA\u5DF1\u89E3\u51B3\u4E5F\u6CA1\u6709\u6392\u8FDB calendar\uFF0C\u53EA\u662F\u6401\u7F6E\u7740",
37484
37485
  "",
37485
- "\u5173\u952E\u533A\u5206\uFF1A\u5982\u679C agent \u5728\u7B49\u5BF9\u65B9\u56DE\u590D\u4E00\u4E2A\u81EA\u5DF1\u5C31\u80FD\u505A\u7684\u51B3\u5B9A \u2192 waiting=true",
37486
- "\u5982\u679C agent \u5728\u7B49\u771F\u6B63\u7684\u5916\u90E8\u6761\u4EF6\uFF08\u670D\u52A1\u3001SSH\u3001\u5F02\u6B65\u4EFB\u52A1\uFF09 \u2192 \u4E5F waiting=true",
37487
- "\u5982\u679C agent \u5DF2\u7ECF\u505A\u4E86\u51B3\u5B9A\u5E76\u6392\u8FDB calendar \u6216\u5DF2\u5F00\u59CB\u6267\u884C \u2192 waiting=false",
37486
+ "\u5173\u952E\u533A\u5206\uFF1A",
37487
+ '- \u7B49\u5BF9\u65B9\u56DE\u590D\u4E00\u4E2A\u81EA\u5DF1\u5C31\u80FD\u505A\u7684\u51B3\u5B9A \u2192 "pushedDecision": true\uFF08\u4E0D\u662F\u5355\u7EAF waiting\uFF0C\u8FD9\u662F\u66F4\u4E25\u91CD\u7684\u8FDD\u89C4\uFF09',
37488
+ '- \u7B49\u771F\u6B63\u7684\u5916\u90E8\u6761\u4EF6\uFF08\u670D\u52A1\u3001SSH\u3001\u5F02\u6B65\u4EFB\u52A1\uFF09 \u2192 "waiting": true',
37489
+ "- \u4F60\u5DF2\u7ECF\u505A\u4E86\u51B3\u5B9A\u5E76\u6392\u8FDB calendar \u6216\u5DF2\u5F00\u59CB\u6267\u884C \u2192 \u4E24\u4E2A\u90FD false",
37488
37490
  excludeSection,
37489
37491
  "",
37490
37492
  "\u53EA\u56DE\u590D JSON\uFF1A",
37491
- '- \u7B26\u5408\u4E0A\u8FF0\u4EFB\u4E00\u72B6\u6001\uFF1A{"waiting": true, "desc": "\u7B80\u77ED\u8BF4\u660E\uFF0C\u5982\u679C\u662F\u63A8\u51B3\u5B9A\u7ED9\u5BF9\u65B9\u8981\u6307\u51FA"}',
37492
- '- \u4E0D\u7B26\u5408\uFF1A{"waiting": false}'
37493
+ '- \u63A8\u51B3\u5B9A\u7ED9\u5BF9\u65B9\uFF08\u81EA\u5DF1\u80FD\u5B9A\u5374\u95EE\uFF09\uFF1A{"pushedDecision": true, "desc": "\u7B80\u77ED\u8BF4\u660E + \u5EFA\u8BAE\u600E\u4E48\u505A"}',
37494
+ '- \u771F\u7B49\u5916\u90E8\u6761\u4EF6\uFF1A{"waiting": true, "desc": "\u7B80\u77ED\u8BF4\u660E"}',
37495
+ '- \u4E0D\u7B26\u5408\uFF1A{"waiting": false, "pushedDecision": false}'
37493
37496
  ].join("\n"),
37494
37497
  messages: [{ role: "user", content: judgeInput }],
37495
37498
  maxTokens: 128,
@@ -37507,11 +37510,37 @@ agent: ${lastMsg.slice(0, 300)}`;
37507
37510
  const parsed = JSON.parse(match[0]);
37508
37511
  isWaiting = !!parsed.waiting;
37509
37512
  waitDesc = parsed.desc || "";
37513
+ pushedDecision = !!parsed.pushedDecision;
37510
37514
  }
37511
- console.log(`[stop-hook] Judge result: waiting=${isWaiting}, desc="${waitDesc}"`);
37515
+ console.log(`[stop-hook] Judge result: waiting=${isWaiting}, pushedDecision=${pushedDecision}, desc="${waitDesc}"`);
37512
37516
  } catch (e) {
37513
37517
  console.warn(`[stop-hook] LLM judge error: ${e.message}`);
37514
37518
  }
37519
+ if (pushedDecision && waitDesc) {
37520
+ console.log(`[stop-hook] DETECTED pushedDecision! Injecting corrective message to ${sessionId}`);
37521
+ try {
37522
+ const correctiveMsg = [
37523
+ "\u{1F6A8} [stop-hook \u81EA\u4E3B\u6267\u884C\u7EA0\u6B63] \u4F60\u521A\u624D\u628A\u4E00\u4E2A\u81EA\u5DF1\u80FD\u5B9A\u7684\u51B3\u5B9A\u63A8\u7ED9\u4E86\u5BF9\u65B9\u3002",
37524
+ "",
37525
+ `\u8BCA\u65AD\uFF1A${waitDesc}`,
37526
+ "",
37527
+ "\u660E\u77E5\u9053\u600E\u4E48\u505A\u5BF9\u7684\u4E8B \u2192 \u76F4\u63A5\u505A \u2192 \u6C47\u62A5\u7ED3\u679C\u3002",
37528
+ "\u95EE = \u5361\u4F4F\u3002",
37529
+ "",
37530
+ "\u8BF7\u7ACB\u523B\uFF1A",
37531
+ "1. \u64A4\u56DE\u4F60\u7684\u95EE\u9898\uFF08\u4E0D\u8981\u7B49\u5BF9\u65B9\u56DE\u590D\uFF09",
37532
+ "2. \u81EA\u5DF1\u9009\u6700\u4F18\u65B9\u6848\u76F4\u63A5\u6267\u884C",
37533
+ '3. \u6267\u884C\u5B8C\u6C47\u62A5\u7ED3\u679C\uFF08"\u5DF2\u5904\u7406" / "\u5DF2 commit" / "\u5DF2 archive"\uFF09',
37534
+ "",
37535
+ "\u5982\u679C\u4E0D\u662F\u5FC5\u987B\u95EE\u7684\uFF08\u6D89\u53CA\u82B1\u94B1/\u5BF9\u5916\u53D1\u5E03/\u91CD\u5927\u51B3\u7B56\uFF09\uFF0C\u4E0D\u8981\u95EE\u3002"
37536
+ ].join("\n");
37537
+ if (this.dispatcher) {
37538
+ this.dispatcher.submitMessage(correctiveMsg, sessionId);
37539
+ }
37540
+ } catch (e) {
37541
+ console.warn(`[stop-hook] Failed to inject corrective message: ${e.message}`);
37542
+ }
37543
+ }
37515
37544
  if (!isWaiting) {
37516
37545
  return { outcome: { outcome: "success" } };
37517
37546
  }
@@ -37530,13 +37559,15 @@ agent: ${lastMsg.slice(0, 300)}`;
37530
37559
  }
37531
37560
  }
37532
37561
  const wakeAt = new Date(Date.now() + 5 * 6e4).toISOString();
37562
+ const notifId = `wake-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
37533
37563
  notifs.push({
37564
+ id: notifId,
37534
37565
  description: waitDesc || lastMsg.slice(0, 200),
37535
37566
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
37536
37567
  wakeAt
37537
37568
  });
37538
37569
  fs17.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
37539
- console.log(`[stop-hook] Registered wake-up at ${wakeAt} (sessionId=${sessionId}): ${waitDesc}`);
37570
+ console.log(`[stop-hook] Registered wake-up ${notifId} at ${wakeAt} (sessionId=${sessionId}): ${waitDesc}`);
37540
37571
  } catch (e) {
37541
37572
  console.warn(`[stop-hook] Failed to register: ${e.message}`);
37542
37573
  }
@@ -37569,7 +37600,7 @@ agent: ${lastMsg.slice(0, 300)}`;
37569
37600
  return null;
37570
37601
  }
37571
37602
  }
37572
- /** 检查 stop-hook-notifications:agent 停止前注册的等待唤起 */
37603
+ /** 检查 stop-hook-notifications:你停止前注册的等待唤起 */
37573
37604
  checkStopHookNotifications() {
37574
37605
  const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
37575
37606
  try {
@@ -37577,26 +37608,56 @@ agent: ${lastMsg.slice(0, 300)}`;
37577
37608
  const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
37578
37609
  if (notifs.length === 0) return null;
37579
37610
  const now = Date.now();
37580
- const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now);
37611
+ const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now && !n.notified);
37581
37612
  if (due.length === 0) return null;
37582
37613
  const latest = due[due.length - 1];
37583
- console.log(`[nudge] Stop-hook notification triggered: ${latest.description.slice(0, 80)}...`);
37584
- const remaining = notifs.filter((n) => new Date(n.wakeAt).getTime() > now);
37585
- if (remaining.length > 0) {
37586
- fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
37587
- } else {
37588
- fs17.unlinkSync(notifPath);
37589
- }
37614
+ console.log(`[nudge] Stop-hook notification ${latest.id} triggered: ${latest.description.slice(0, 80)}...`);
37615
+ const updated = notifs.map((n) => n.id === latest.id ? { ...n, notified: true } : n);
37616
+ fs17.writeFileSync(notifPath, JSON.stringify(updated, null, 2));
37590
37617
  return buildNudgeNotification("wake", `\u4F60\u4E4B\u524D\u5728\u7B49\u5F85\u67D0\u4E2A\u5916\u90E8\u6761\u4EF6\uFF0C\u65F6\u95F4\u5230\u4E86\uFF0C\u56DE\u53BB\u68C0\u67E5\uFF01
37591
37618
 
37619
+ [\u901A\u77E5ID: ${latest.id}]
37592
37620
  \u4E0A\u6B21\u8BF4\uFF1A${latest.description}
37593
37621
 
37594
- \u68C0\u67E5\u6761\u4EF6\u662F\u5426\u6EE1\u8DB3\uFF0C\u6EE1\u8DB3\u5C31\u7EE7\u7EED\u5E72\u6D3B\uFF0C\u4E0D\u6EE1\u8DB3\u5C31\u4E0D\u7528\u7BA1\u4E86\u3002`);
37622
+ \u68C0\u67E5\u6761\u4EF6\u662F\u5426\u6EE1\u8DB3\uFF0C\u6EE1\u8DB3\u5C31\u7EE7\u7EED\u5E72\u6D3B\uFF0C\u4E0D\u6EE1\u8DB3\u5C31\u56DE\u590D"${latest.id} \u8FC7\u671F\u4E86"\u544A\u8BC9 nudge \u7CBE\u786E\u6E05\u7406\u8FD9\u6761\u3002`);
37595
37623
  } catch (e) {
37596
37624
  console.warn(`[nudge] checkStopHookNotifications error: ${e.message}`);
37597
37625
  return null;
37598
37626
  }
37599
37627
  }
37628
+ /** 读最近消息,如果发现"<notifId> 过期了"→ 精确清理对应的 wake-up notification */
37629
+ cleanupStaleNotificationsFromMessages(sessions) {
37630
+ try {
37631
+ const recent = recentMessages(sessions, 0.5, 6);
37632
+ const fiveMinAgo = Date.now() - 5 * 60 * 1e3;
37633
+ const recentTexts = recent.filter((r) => new Date(r.timestamp || r.createdAt || Date.now()).getTime() > fiveMinAgo).map((r) => r.text);
37634
+ const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
37635
+ if (!fs17.existsSync(notifPath)) return;
37636
+ const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
37637
+ if (notifs.length === 0) return;
37638
+ const expiredIds = /* @__PURE__ */ new Set();
37639
+ for (const text of recentTexts) {
37640
+ for (const n of notifs) {
37641
+ if (text.includes(`${n.id} \u8FC7\u671F\u4E86`) || text.includes(`${n.id}\u8FC7\u671F\u4E86`)) {
37642
+ expiredIds.add(n.id);
37643
+ }
37644
+ }
37645
+ }
37646
+ if (expiredIds.size === 0) return;
37647
+ const remaining = notifs.filter((n) => !expiredIds.has(n.id));
37648
+ const cleaned = notifs.length - remaining.length;
37649
+ if (cleaned > 0) {
37650
+ if (remaining.length > 0) {
37651
+ fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
37652
+ } else {
37653
+ fs17.unlinkSync(notifPath);
37654
+ }
37655
+ console.log(`[nudge] Cleaned ${cleaned} stale notification(s) by explicit id: ${[...expiredIds].join(", ")}`);
37656
+ }
37657
+ } catch (e) {
37658
+ console.warn(`[nudge] cleanupStaleNotificationsFromMessages error: ${e.message}`);
37659
+ }
37660
+ }
37600
37661
  async tick(sessions, deps) {
37601
37662
  if (this.running) {
37602
37663
  console.log("[nudge] Previous tick still running, skipping");
@@ -37622,6 +37683,7 @@ agent: ${lastMsg.slice(0, 300)}`;
37622
37683
  }
37623
37684
  this.running = true;
37624
37685
  try {
37686
+ this.cleanupStaleNotificationsFromMessages(sessions);
37625
37687
  const stopNotifs = this.checkStopHookNotifications();
37626
37688
  if (stopNotifs) {
37627
37689
  const route2 = this.getRoute(sessions);
@@ -39068,6 +39130,8 @@ function formatBeijingTs(d) {
39068
39130
  }
39069
39131
 
39070
39132
  // src/calendar/commands.ts
39133
+ import { existsSync as existsSync13, statSync as statSync7 } from "node:fs";
39134
+ import { isAbsolute as isAbsolute4, resolve as resolve7 } from "node:path";
39071
39135
  var WEEKDAYS2 = ["\u5468\u4E00", "\u5468\u4E8C", "\u5468\u4E09", "\u5468\u56DB", "\u5468\u4E94", "\u5468\u516D", "\u5468\u65E5"];
39072
39136
  function fmtEnd(start, durationMin) {
39073
39137
  const [hh, mm] = start.split(":").map(Number);
@@ -39230,7 +39294,29 @@ ${skipped.map((s2) => ` ${s2}`).join("\n")}`;
39230
39294
  return result;
39231
39295
  }
39232
39296
  function addTask(db, args) {
39233
- const { dateStr, timeExact, event } = args;
39297
+ const { dateStr, timeExact, event, docPath } = args;
39298
+ if (!docPath || !docPath.trim()) {
39299
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Aadd-task \u5FC5\u987B\u4F20 doc_path\u3002
39300
+ \u6CA1\u6709\u6587\u6863\u652F\u6491\u7684 task \u4E0D\u662F\u5408\u683C\u7684 task\u3002
39301
+ \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`;
39302
+ }
39303
+ try {
39304
+ const absPath = isAbsolute4(docPath) ? docPath : resolve7(process.cwd(), docPath);
39305
+ if (!existsSync13(absPath)) {
39306
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728
39307
+ \u8DEF\u5F84: ${docPath}
39308
+ \u89E3\u6790\u540E: ${absPath}
39309
+ \u8BF7\u5148\u521B\u5EFA\u6587\u6863\u518D add-task\u3002`;
39310
+ }
39311
+ const stat8 = statSync7(absPath);
39312
+ if (!stat8.isFile()) {
39313
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u4E0D\u662F\u6587\u4EF6\uFF08\u53EF\u80FD\u662F\u76EE\u5F55\uFF09
39314
+ \u8DEF\u5F84: ${docPath}`;
39315
+ }
39316
+ } catch (err) {
39317
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u6821\u9A8C\u51FA\u9519\uFF1A${err.message}
39318
+ \u8DEF\u5F84: ${docPath}`;
39319
+ }
39234
39320
  let remindMin = 60;
39235
39321
  if (args.remind) {
39236
39322
  const v2 = args.remind;
@@ -39244,10 +39330,11 @@ function addTask(db, args) {
39244
39330
  const prox = checkTaskProximity(taskRows, timeExact);
39245
39331
  const remindAt = computeRemindAt(dateStr, timeExact, remindMin);
39246
39332
  const r = db.prepare(
39247
- `INSERT INTO events (type,status,event,date_str,time_exact,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target)
39248
- VALUES ('task','pending',?,?,?,?,?,?,?,?,?)`
39249
- ).run(event, dateStr, timeExact, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null);
39250
- let msg2 = `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0\u4EFB\u52A1: [${dateStr} ${timeExact}] ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
39333
+ `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)
39334
+ VALUES ('task','pending',?,?,?,?,?,?,?,?,?,?)`
39335
+ ).run(event, dateStr, timeExact, remindMin, remindAt, 0, nowIso(), args.channel || null, args.channelTarget || null, docPath);
39336
+ let msg2 = `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0\u4EFB\u52A1: [${dateStr} ${timeExact}] ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)
39337
+ \u{1F4C4} \u6587\u6863: ${docPath}`;
39251
39338
  if (prox) {
39252
39339
  msg2 += `
39253
39340
  \u26A0\uFE0F \u65F6\u95F4\u63A5\u8FD1\uFF1A\u4E0E #${prox.id}\u300C${prox.event}\u300D(${prox.time}) \u4EC5\u76F8\u5DEE ${prox.diffMin}min`;
@@ -39581,7 +39668,7 @@ function registerVoiceChatBridge(httpServer, dispatcher, deps, config, sessions,
39581
39668
  const https = await import("node:https");
39582
39669
  const url = new URL(callbackUrl);
39583
39670
  const postData = JSON.stringify({ session_id: ctx.inbound.from, text: ctx.response });
39584
- await new Promise((resolve11, reject) => {
39671
+ await new Promise((resolve12, reject) => {
39585
39672
  const req = https.request(url, {
39586
39673
  method: "POST",
39587
39674
  headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) },
@@ -39589,7 +39676,7 @@ function registerVoiceChatBridge(httpServer, dispatcher, deps, config, sessions,
39589
39676
  }, (res) => {
39590
39677
  console.log(`[voice-chat] Reply POST ${callbackUrl}: ${res.statusCode} (${ctx.response.length} chars)`);
39591
39678
  res.resume();
39592
- resolve11();
39679
+ resolve12();
39593
39680
  });
39594
39681
  req.on("error", reject);
39595
39682
  req.write(postData);
@@ -39878,27 +39965,27 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
39878
39965
  };
39879
39966
  }
39880
39967
  async isPortAlive(port) {
39881
- return new Promise((resolve11) => {
39968
+ return new Promise((resolve12) => {
39882
39969
  const socket = new net.Socket();
39883
39970
  socket.setTimeout(2e3);
39884
39971
  socket.on("connect", () => {
39885
39972
  socket.destroy();
39886
- resolve11(true);
39973
+ resolve12(true);
39887
39974
  });
39888
39975
  socket.on("timeout", () => {
39889
39976
  socket.destroy();
39890
- resolve11(false);
39977
+ resolve12(false);
39891
39978
  });
39892
39979
  socket.on("error", () => {
39893
39980
  socket.destroy();
39894
- resolve11(false);
39981
+ resolve12(false);
39895
39982
  });
39896
39983
  socket.connect(port, "127.0.0.1");
39897
39984
  });
39898
39985
  }
39899
39986
  async killProcessOnPort(port) {
39900
- const run = (cmd) => new Promise((resolve11) => {
39901
- exec(cmd, { timeout: 5e3 }, (err, stdout) => resolve11(err ? "" : stdout));
39987
+ const run = (cmd) => new Promise((resolve12) => {
39988
+ exec(cmd, { timeout: 5e3 }, (err, stdout) => resolve12(err ? "" : stdout));
39902
39989
  });
39903
39990
  try {
39904
39991
  if (process.platform === "win32") {
@@ -40387,27 +40474,27 @@ var CogniFoldPlugin = class {
40387
40474
  throw new Error(`CogniFold not ready after ${timeoutMs}ms at ${url}`);
40388
40475
  }
40389
40476
  async isPortAlive(port) {
40390
- return new Promise((resolve11) => {
40477
+ return new Promise((resolve12) => {
40391
40478
  const socket = new net2.Socket();
40392
40479
  socket.setTimeout(2e3);
40393
40480
  socket.on("connect", () => {
40394
40481
  socket.destroy();
40395
- resolve11(true);
40482
+ resolve12(true);
40396
40483
  });
40397
40484
  socket.on("timeout", () => {
40398
40485
  socket.destroy();
40399
- resolve11(false);
40486
+ resolve12(false);
40400
40487
  });
40401
40488
  socket.on("error", () => {
40402
40489
  socket.destroy();
40403
- resolve11(false);
40490
+ resolve12(false);
40404
40491
  });
40405
40492
  socket.connect(port, "127.0.0.1");
40406
40493
  });
40407
40494
  }
40408
40495
  async killProcessOnPort(port) {
40409
- const run = (cmd) => new Promise((resolve11) => {
40410
- exec2(cmd, { timeout: 5e3 }, (err, stdout) => resolve11(err ? "" : stdout));
40496
+ const run = (cmd) => new Promise((resolve12) => {
40497
+ exec2(cmd, { timeout: 5e3 }, (err, stdout) => resolve12(err ? "" : stdout));
40411
40498
  });
40412
40499
  try {
40413
40500
  if (process.platform === "win32") {
@@ -41652,7 +41739,7 @@ registry.register({
41652
41739
  init_registry();
41653
41740
  registry.register({
41654
41741
  name: "calendar",
41655
- description: 'Manage family calendar (SQLite). add: \u52A0\u65E5\u7A0B (repeat=daily \u6BCF\u5929/weekdays \u5DE5\u4F5C\u65E5/weekly \u6BCF\u5468\u9009\u5468\u51E0/once \u4E00\u6B21\u6027) \u2014 **\u7528\u4E8E\u65E5\u5E38\u65F6\u95F4\u5B89\u6392** (\u4E0A\u8BFE/\u7EA6\u4F1A/\u8BFE\u8868). add-batch: \u6279\u91CF\u52A0\u65E5\u7A0B (dates=\u9017\u53F7\u5206\u9694\u65E5\u671F\u6216\u8303\u56F4, \u5982 "7/2,7/4,7/6-7/10") \u2014 **\u7528\u4E8E\u65E5\u5E38\u65F6\u95F4\u5B89\u6392**. add-task: \u52A0\u4EFB\u52A1 (\u5F3A\u5236\u5E26\u65E5\u671F+\u65F6\u95F4, \u662F\u52A0\u4EFB\u52A1\u7684\u552F\u4E00\u5165\u53E3) \u2014 **\u4EC5\u7528\u4E8E\u5DE5\u4F5C\u7C7B\u4EFB\u52A1** (\u6D3E\u6D3B/\u8DDF\u8FDB/\u9650\u65F6\u4EA4\u4ED8). list: \u67E5\u770B (all=true \u5168\u90E8). done <id>: \u6807\u8BB0\u5B8C\u6210. search <keyword>: \u68C0\u7D22. pending: \u5F85\u5904\u7406. archive <id>: \u5F52\u6863\uFF08\u4E0D\u5220\u9664\uFF0C\u53EF\u6062\u590D\uFF09. reschedule <id>: \u6539\u671F\uFF08\u9700\u8981 date + time_exact\uFF09. cleanup: \u81EA\u52A8\u5F52\u6863\u8FC7\u671F. stats: \u7EDF\u8BA1. **\u6838\u5FC3\u89C4\u5219**\uFF1A\u5B69\u5B50\u4EEC\u7684\u8BFE\u3001\u4E0A\u8BFE/\u7EA6\u4F1A/\u5BB6\u5EAD\u6D3B\u52A8\u7528 add \u6216 add-batch\uFF08\u4E00\u6B21\u6027\u6216\u6BCF\u5468\u56FA\u5B9A\uFF09\uFF1B\u5DE5\u4F5C\u6D3E\u6D3B/\u9650\u65F6\u4EFB\u52A1\u7528 add-task. **\u6DF7\u6DC6\u8FD9\u4E24\u7C7B\u4F1A\u5BFC\u81F4\uFF1Aadd \u7684\u4E8B\u4EF6\u6709\u51B2\u7A81\u68C0\u6D4B\u3001add-task \u6CA1\u6709**. Triggers: \u8BB0\u65E5\u7A0B/\u52A0\u65E5\u5386/\u52A0\u4EFB\u52A1/\u4ECA\u5929\u6709\u4EC0\u4E48/\u65E5\u7A0B/\u63D0\u9192/\u5220\u9664\u65E5\u7A0B/\u6E05\u7406\u65E5\u5386/\u67E5\u65E5\u7A0B.',
41742
+ description: 'Manage family calendar (SQLite). add: \u52A0\u65E5\u7A0B (repeat=daily \u6BCF\u5929/weekdays \u5DE5\u4F5C\u65E5/weekly \u6BCF\u5468\u9009\u5468\u51E0/once \u4E00\u6B21\u6027) \u2014 **\u7528\u4E8E\u65E5\u5E38\u65F6\u95F4\u5B89\u6392** (\u4E0A\u8BFE/\u7EA6\u4F1A/\u8BFE\u8868). add-batch: \u6279\u91CF\u52A0\u65E5\u7A0B (dates=\u9017\u53F7\u5206\u9694\u65E5\u671F\u6216\u8303\u56F4, \u5982 "7/2,7/4,7/6-7/10") \u2014 **\u7528\u4E8E\u65E5\u5E38\u65F6\u95F4\u5B89\u6392**. add-task: \u52A0\u4EFB\u52A1 (\u5F3A\u5236\u5E26\u65E5\u671F+\u65F6\u95F4, \u662F\u52A0\u4EFB\u52A1\u7684\u552F\u4E00\u5165\u53E3) \u2014 **\u4EC5\u7528\u4E8E\u5DE5\u4F5C\u7C7B\u4EFB\u52A1** (\u6D3E\u6D3B/\u8DDF\u8FDB/\u9650\u65F6\u4EA4\u4ED8). **\u5F3A\u5236\u8981\u6C42 doc_path** \u2014 \u6CA1\u6587\u6863\u652F\u6491\u7684 task \u4E0D\u662F\u5408\u683C\u7684 task,add-task \u4F1A\u62D2\u7EDD\u521B\u5EFA\u5E76\u63D0\u793A\u6587\u6863\u8DEF\u5F84. list: \u67E5\u770B (all=true \u5168\u90E8). done <id>: \u6807\u8BB0\u5B8C\u6210. search <keyword>: \u68C0\u7D22. pending: \u5F85\u5904\u7406. archive <id>: \u5F52\u6863\uFF08\u4E0D\u5220\u9664\uFF0C\u53EF\u6062\u590D\uFF09. reschedule <id>: \u6539\u671F\uFF08\u9700\u8981 date + time_exact\uFF09. cleanup: \u81EA\u52A8\u5F52\u6863\u8FC7\u671F. stats: \u7EDF\u8BA1. **\u6838\u5FC3\u89C4\u5219**\uFF1A\u5B69\u5B50\u4EEC\u7684\u8BFE\u3001\u4E0A\u8BFE/\u7EA6\u4F1A/\u5BB6\u5EAD\u6D3B\u52A8\u7528 add \u6216 add-batch\uFF08\u4E00\u6B21\u6027\u6216\u6BCF\u5468\u56FA\u5B9A\uFF09\uFF1B\u5DE5\u4F5C\u6D3E\u6D3B/\u9650\u65F6\u4EFB\u52A1\u7528 add-task. **\u6DF7\u6DC6\u8FD9\u4E24\u7C7B\u4F1A\u5BFC\u81F4\uFF1Aadd \u7684\u4E8B\u4EF6\u6709\u51B2\u7A81\u68C0\u6D4B\u3001add-task \u6CA1\u6709**. Triggers: \u8BB0\u65E5\u7A0B/\u52A0\u65E5\u5386/\u52A0\u4EFB\u52A1/\u4ECA\u5929\u6709\u4EC0\u4E48/\u65E5\u7A0B/\u63D0\u9192/\u5220\u9664\u65E5\u7A0B/\u6E05\u7406\u65E5\u5386/\u67E5\u65E5\u7A0B.',
41656
41743
  schema: {
41657
41744
  type: "object",
41658
41745
  properties: {
@@ -41669,7 +41756,7 @@ registry.register({
41669
41756
  remind: { type: "string", description: "\u63D0\u524D\u63D0\u9192\uFF08add-task \u7528\uFF0C\u5982 30m=30\u5206\u949F, 1h=1\u5C0F\u65F6, \u9ED8\u8BA460m\uFF09" },
41670
41757
  id: { type: "number", description: "\u4E8B\u4EF6 ID\uFF08done/archive/reschedule/link-doc/find-doc \u7528\uFF09" },
41671
41758
  all: { type: "boolean", description: "\u67E5\u770B\u5168\u90E8\uFF08list \u7528\uFF09" },
41672
- doc_path: { type: "string", description: "\u6587\u6863\u8DEF\u5F84\uFF08link-doc \u7528\uFF0C\u5982 docs/todo/xxx.md\uFF09" }
41759
+ doc_path: { type: "string", description: "\u6587\u6863\u8DEF\u5F84\uFF08link-doc \u7528\uFF0C\u5982 docs/todo/xxx.md\uFF1Badd-task \u5FC5\u586B\uFF0C\u76F8\u5BF9 workspace \u7684\u8DEF\u5F84\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09" }
41673
41760
  },
41674
41761
  required: ["action"]
41675
41762
  },
@@ -41708,10 +41795,12 @@ registry.register({
41708
41795
  const event = args.event?.trim();
41709
41796
  const date = args.date?.trim();
41710
41797
  const timeExact = args.time_exact?.trim();
41798
+ const docPath = args.doc_path?.trim();
41711
41799
  if (!event) return { content: "Error: add-task needs event", isError: true };
41712
41800
  if (!date) return { content: "Error: add-task needs date (e.g. 7/5)", isError: true };
41713
41801
  if (!timeExact || !timeExact.includes(":")) return { content: "Error: add-task needs time_exact (HH:MM, e.g. 14:00)", isError: true };
41714
- result = addTask(db, { dateStr: date, timeExact, event, remind: args.remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
41802
+ 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 };
41803
+ result = addTask(db, { dateStr: date, timeExact, event, remind: args.remind, channel: ctx.channel, channelTarget: ctx.channelTarget, docPath });
41715
41804
  } else if (action === "reschedule") {
41716
41805
  if (args.id == null) return { content: "Error: reschedule needs id", isError: true };
41717
41806
  const date = args.date?.trim();
@@ -41752,7 +41841,8 @@ registry.register({
41752
41841
  return { content: `Error: unknown action '${action}'`, isError: true };
41753
41842
  }
41754
41843
  db.close();
41755
- if (isAddTask && !result.includes("Error") && !result.includes("\u7528\u6CD5")) {
41844
+ const isFailed = result.startsWith("\u274C") || result.includes("Error") || result.includes("\u7528\u6CD5");
41845
+ if (isAddTask && !isFailed) {
41756
41846
  const { enqueueNotification: enqueueNotification2, buildCalendarNotification: buildCalendarNotification2 } = await Promise.resolve().then(() => (init_task_manager(), task_manager_exports));
41757
41847
  const sessionId = ctx.sessionId || "main";
41758
41848
  const channel = ctx.channel;
@@ -41863,7 +41953,7 @@ registry.register({
41863
41953
  lines.push(`start: spawned PID ${pid} (background${svcArgs ? ", args=" + svcArgs : ""})`);
41864
41954
  if (svc.healthCheck) {
41865
41955
  for (let i = 0; i < 6; i++) {
41866
- await new Promise((resolve11) => setTimeout(resolve11, 5e3));
41956
+ await new Promise((resolve12) => setTimeout(resolve12, 5e3));
41867
41957
  const after2 = await checkStatus();
41868
41958
  if (after2.running) {
41869
41959
  lines.push(`health: \u2705 running (after ${(i + 1) * 5}s)`);
@@ -41873,7 +41963,7 @@ registry.register({
41873
41963
  const after = await checkStatus();
41874
41964
  lines.push(`health: \u274C not responding after 30s \u2014 ${after.detail}`);
41875
41965
  } else {
41876
- await new Promise((resolve11) => setTimeout(resolve11, 3e3));
41966
+ await new Promise((resolve12) => setTimeout(resolve12, 3e3));
41877
41967
  lines.push(`start: PID ${pid} spawned (no healthCheck, waited 3s)`);
41878
41968
  }
41879
41969
  } else {
@@ -41898,7 +41988,7 @@ registry.register({
41898
41988
  const before = await checkStatus();
41899
41989
  if (before.running) {
41900
41990
  results.push(await doStop());
41901
- await new Promise((resolve11) => setTimeout(resolve11, 2e3));
41991
+ await new Promise((resolve12) => setTimeout(resolve12, 2e3));
41902
41992
  } else {
41903
41993
  results.push("stop: already stopped");
41904
41994
  }
@@ -43260,7 +43350,7 @@ var AgentChannelRegistry = class {
43260
43350
  const pending2 = this.waiters.get(agentName);
43261
43351
  if (pending2) {
43262
43352
  this.waiters.delete(agentName);
43263
- for (const resolve11 of pending2) resolve11(channelId);
43353
+ for (const resolve12 of pending2) resolve12(channelId);
43264
43354
  }
43265
43355
  }
43266
43356
  /**
@@ -43270,10 +43360,10 @@ var AgentChannelRegistry = class {
43270
43360
  waitForChannel(agentName) {
43271
43361
  const existing = this.findByAgentName(agentName);
43272
43362
  if (existing?.channelId) return Promise.resolve(existing.channelId);
43273
- return new Promise((resolve11) => {
43363
+ return new Promise((resolve12) => {
43274
43364
  const list2 = this.waiters.get(agentName);
43275
- if (list2) list2.push(resolve11);
43276
- else this.waiters.set(agentName, [resolve11]);
43365
+ if (list2) list2.push(resolve12);
43366
+ else this.waiters.set(agentName, [resolve12]);
43277
43367
  });
43278
43368
  }
43279
43369
  /** 查找 agent 对应的频道 ID */
@@ -43805,7 +43895,7 @@ async function startEngine(config, opts) {
43805
43895
  if (!fs54.existsSync(dailyDir)) {
43806
43896
  fs54.mkdirSync(dailyDir, { recursive: true });
43807
43897
  }
43808
- const sessionsDir = path54.join(workspace, "sessions");
43898
+ const sessionsDir = path54.join(config.stateDir, "agents", "main", "sessions");
43809
43899
  const sessionFile = path54.join(sessionsDir, `${sessionId}.jsonl`);
43810
43900
  const recentLines = [];
43811
43901
  if (fs54.existsSync(sessionFile)) {
@@ -45757,7 +45847,7 @@ ${actionsJson}
45757
45847
  }
45758
45848
  }
45759
45849
  }
45760
- const shutdownPromise = new Promise((resolve11) => {
45850
+ const shutdownPromise = new Promise((resolve12) => {
45761
45851
  const shutdown = (signal) => {
45762
45852
  console.log(`[engine] ${signal} received, shutting down...`);
45763
45853
  try {
@@ -45765,7 +45855,7 @@ ${actionsJson}
45765
45855
  } catch {
45766
45856
  }
45767
45857
  engine.interrupt();
45768
- resolve11();
45858
+ resolve12();
45769
45859
  };
45770
45860
  process.on("SIGTERM", () => shutdown("SIGTERM"));
45771
45861
  process.on("SIGINT", () => shutdown("SIGINT"));