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.
package/dist/main.mjs CHANGED
@@ -739,9 +739,9 @@ async function execCommandHook(hook, hookEvent, hookName, jsonInput, signal, hoo
739
739
  child.stderr.on("data", (chunk) => {
740
740
  stderr += chunk;
741
741
  });
742
- const exitCode = await new Promise((resolve11) => {
743
- child.on("close", (code) => resolve11(code ?? 0));
744
- child.on("error", () => resolve11(1));
742
+ const exitCode = await new Promise((resolve12) => {
743
+ child.on("close", (code) => resolve12(code ?? 0));
744
+ child.on("error", () => resolve12(1));
745
745
  });
746
746
  if (timeoutHandle) clearTimeout(timeoutHandle);
747
747
  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(args2, searchPath, signal) {
7356
- return new Promise((resolve11) => {
7356
+ return new Promise((resolve12) => {
7357
7357
  const fullArgs = [...args2, searchPath];
7358
7358
  const child = execFile2("rg", fullArgs, {
7359
7359
  maxBuffer: 50 * 1024 * 1024,
@@ -7362,11 +7362,11 @@ function ripGrep(args2, 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 = args2.command.trim();
11496
11496
  const timeout = args2.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
  });
@@ -12479,15 +12479,15 @@ async function canStealStaleLock(lockPath2) {
12479
12479
  return !isProcessLikelyAlive(ownerPid);
12480
12480
  }
12481
12481
  async function sleep5(ms) {
12482
- await new Promise((resolve11) => {
12483
- setTimeout(resolve11, ms);
12482
+ await new Promise((resolve12) => {
12483
+ setTimeout(resolve12, ms);
12484
12484
  });
12485
12485
  }
12486
12486
  async function withInProcessShortTermLock(lockPath2, task) {
12487
12487
  const previous = inProcessShortTermLocks.get(lockPath2) ?? Promise.resolve();
12488
12488
  let releaseCurrent;
12489
- const current = new Promise((resolve11) => {
12490
- releaseCurrent = resolve11;
12489
+ const current = new Promise((resolve12) => {
12490
+ releaseCurrent = resolve12;
12491
12491
  });
12492
12492
  const queued = previous.catch(() => void 0).then(() => current);
12493
12493
  inProcessShortTermLocks.set(lockPath2, queued);
@@ -23473,7 +23473,7 @@ var init_handler = __esm({
23473
23473
  this._addToNodeFs(path55, initialAdd, wh, depth + 1);
23474
23474
  }
23475
23475
  }).on(EV.ERROR, this._boundHandleError);
23476
- return new Promise((resolve11, reject) => {
23476
+ return new Promise((resolve12, reject) => {
23477
23477
  if (!stream)
23478
23478
  return reject();
23479
23479
  stream.once(STR_END, () => {
@@ -23482,7 +23482,7 @@ var init_handler = __esm({
23482
23482
  return;
23483
23483
  }
23484
23484
  const wasThrottled = throttler ? throttler.clear() : false;
23485
- resolve11(void 0);
23485
+ resolve12(void 0);
23486
23486
  previous.getChildren().filter((item) => {
23487
23487
  return item !== directory && !current.has(item);
23488
23488
  }).forEach((item) => {
@@ -24782,8 +24782,8 @@ function createSessionSyncYield(total) {
24782
24782
  return async () => {
24783
24783
  completed += 1;
24784
24784
  if (completed < total && completed % SESSION_SYNC_YIELD_EVERY === 0) {
24785
- await new Promise((resolve11) => {
24786
- setImmediate(resolve11);
24785
+ await new Promise((resolve12) => {
24786
+ setImmediate(resolve12);
24787
24787
  });
24788
24788
  }
24789
24789
  };
@@ -24985,8 +24985,8 @@ var init_manager_sync_ops = __esm({
24985
24985
  );
24986
24986
  rowCount += 1;
24987
24987
  if (rowCount % SEED_EMBEDDING_YIELD_EVERY === 0) {
24988
- await new Promise((resolve11) => {
24989
- setImmediate(resolve11);
24988
+ await new Promise((resolve12) => {
24989
+ setImmediate(resolve12);
24990
24990
  });
24991
24991
  }
24992
24992
  }
@@ -26263,7 +26263,7 @@ var init_manager_embedding_ops = __esm({
26263
26263
  EMBEDDING_RETRY_MAX_DELAY_MS
26264
26264
  );
26265
26265
  log2.warn(`memory embeddings rate limited; ${action} in ${waitMs}ms`);
26266
- await new Promise((resolve11) => setTimeout(resolve11, waitMs));
26266
+ await new Promise((resolve12) => setTimeout(resolve12, waitMs));
26267
26267
  }
26268
26268
  resolveEmbeddingTimeout(kind) {
26269
26269
  return resolveEmbeddingTimeoutMs({
@@ -26305,8 +26305,8 @@ var init_manager_embedding_ops = __esm({
26305
26305
  async withBatchFailureLock(fn) {
26306
26306
  let release2;
26307
26307
  const wait = this.batchFailureLock;
26308
- this.batchFailureLock = new Promise((resolve11) => {
26309
- release2 = resolve11;
26308
+ this.batchFailureLock = new Promise((resolve12) => {
26309
+ release2 = resolve12;
26310
26310
  });
26311
26311
  await wait;
26312
26312
  try {
@@ -29303,7 +29303,7 @@ var reply_blocklist_exports = {};
29303
29303
  __export(reply_blocklist_exports, {
29304
29304
  isUserBlocked: () => isUserBlocked
29305
29305
  });
29306
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync15, existsSync as existsSync23 } from "node:fs";
29306
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync15, existsSync as existsSync24 } from "node:fs";
29307
29307
  import { join as join39 } from "node:path";
29308
29308
  function ensureLoaded(workspace, configIds) {
29309
29309
  if (loaded) return;
@@ -29314,7 +29314,7 @@ function ensureLoaded(workspace, configIds) {
29314
29314
  }
29315
29315
  const path55 = join39(workspace, ".reply-blocklist.json");
29316
29316
  try {
29317
- if (existsSync23(path55)) {
29317
+ if (existsSync24(path55)) {
29318
29318
  const raw = readFileSync26(path55, "utf-8");
29319
29319
  const parsed = JSON.parse(raw);
29320
29320
  if (parsed.blockedUserIds) {
@@ -30057,12 +30057,12 @@ var MAX_DELAY_MS = 32e3;
30057
30057
  var DEFAULT_TIMEOUT_MS = 6e5;
30058
30058
  var READ_TIMEOUT_MS = 6e4;
30059
30059
  function sleep(ms, signal) {
30060
- return new Promise((resolve11, reject) => {
30060
+ return new Promise((resolve12, reject) => {
30061
30061
  if (signal?.aborted) {
30062
30062
  reject(new DOMException("Aborted", "AbortError"));
30063
30063
  return;
30064
30064
  }
30065
- const timer = setTimeout(resolve11, ms);
30065
+ const timer = setTimeout(resolve12, ms);
30066
30066
  const onAbort = () => {
30067
30067
  clearTimeout(timer);
30068
30068
  reject(new DOMException("Aborted", "AbortError"));
@@ -34173,7 +34173,7 @@ var MAX_TRANSCRIPT_READ_BYTES = 50 * 1024 * 1024;
34173
34173
  async function readSessionHeader(filePath) {
34174
34174
  const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
34175
34175
  const rl = readline.createInterface({ input: stream });
34176
- return new Promise((resolve11) => {
34176
+ return new Promise((resolve12) => {
34177
34177
  let resolved = false;
34178
34178
  rl.on("line", (line) => {
34179
34179
  try {
@@ -34182,7 +34182,7 @@ async function readSessionHeader(filePath) {
34182
34182
  resolved = true;
34183
34183
  rl.close();
34184
34184
  stream.destroy();
34185
- resolve11({
34185
+ resolve12({
34186
34186
  id: obj.id,
34187
34187
  timestamp: obj.timestamp,
34188
34188
  cwd: obj.cwd,
@@ -34194,10 +34194,10 @@ async function readSessionHeader(filePath) {
34194
34194
  }
34195
34195
  });
34196
34196
  rl.on("close", () => {
34197
- if (!resolved) resolve11(null);
34197
+ if (!resolved) resolve12(null);
34198
34198
  });
34199
34199
  rl.on("error", () => {
34200
- if (!resolved) resolve11(null);
34200
+ if (!resolved) resolve12(null);
34201
34201
  });
34202
34202
  });
34203
34203
  }
@@ -34425,9 +34425,9 @@ async function readAllLines(filePath) {
34425
34425
  const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
34426
34426
  const rl = readline.createInterface({ input: stream });
34427
34427
  const lines = [];
34428
- return new Promise((resolve11, reject) => {
34428
+ return new Promise((resolve12, reject) => {
34429
34429
  rl.on("line", (line) => lines.push(line));
34430
- rl.on("close", () => resolve11(lines));
34430
+ rl.on("close", () => resolve12(lines));
34431
34431
  rl.on("error", (err) => reject(err));
34432
34432
  });
34433
34433
  }
@@ -37118,8 +37118,8 @@ function startCliLoop(deps, cliConfig, channelManager, dispatcher) {
37118
37118
  process.stdout.write("AI> ");
37119
37119
  let inToolCall = false;
37120
37120
  let resolveDone;
37121
- const done2 = new Promise((resolve11) => {
37122
- resolveDone = resolve11;
37121
+ const done2 = new Promise((resolve12) => {
37122
+ resolveDone = resolve12;
37123
37123
  });
37124
37124
  dispatcher.submitMessage({
37125
37125
  text: trimmed,
@@ -37415,8 +37415,8 @@ ${basePrompt}`;
37415
37415
  }, timeoutMs);
37416
37416
  if (this.dispatcher) {
37417
37417
  let resolveDone;
37418
- const done2 = new Promise((resolve11) => {
37419
- resolveDone = resolve11;
37418
+ const done2 = new Promise((resolve12) => {
37419
+ resolveDone = resolve12;
37420
37420
  });
37421
37421
  this.dispatcher.submitMessage({
37422
37422
  text: prompt,
@@ -37791,7 +37791,7 @@ var NudgePlugin = class {
37791
37791
  }, intervalMs);
37792
37792
  this.registerStopHook(sessions);
37793
37793
  }
37794
- /** 注册 Stop hook:agent 停止前用 LLM 判断是否在等外部条件 → 注册 5min notification */
37794
+ /** 注册 Stop hook:你停止前用 LLM 判断是否在等外部条件 → 注册 5min notification */
37795
37795
  registerStopHook(sessions) {
37796
37796
  registerCallbackHook("Stop", {
37797
37797
  type: "callback",
@@ -37805,7 +37805,7 @@ var NudgePlugin = class {
37805
37805
  console.log(`[stop-hook] skipping voice-chat (channel=${msgChannel})`);
37806
37806
  return { outcome: { outcome: "success" } };
37807
37807
  }
37808
- if (!lastMsg || lastMsg.length < 10) {
37808
+ if (!lastMsg) {
37809
37809
  return { outcome: { outcome: "success" } };
37810
37810
  }
37811
37811
  let contextStr = "";
@@ -37821,9 +37821,10 @@ var NudgePlugin = class {
37821
37821
  console.warn(`[stop-hook] recentMessages error: ${e.message}`);
37822
37822
  }
37823
37823
  const judgeInput = `${contextStr}
37824
- agent: ${lastMsg.slice(0, 300)}`;
37824
+ \u4F60: ${lastMsg.slice(0, 300)}`;
37825
37825
  let isWaiting = false;
37826
37826
  let waitDesc = "";
37827
+ let pushedDecision = false;
37827
37828
  try {
37828
37829
  const excludeCases = this.cfg.stopHookExcludeCases || [];
37829
37830
  const excludeSection = excludeCases.length > 0 ? [
@@ -37834,20 +37835,22 @@ agent: ${lastMsg.slice(0, 300)}`;
37834
37835
  const stream = this.provider.streamChat({
37835
37836
  model: this.model,
37836
37837
  systemPrompt: [
37837
- "\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",
37838
+ "\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",
37838
37839
  "",
37839
37840
  "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",
37840
37841
  '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',
37841
37842
  "3. \u9047\u5230\u95EE\u9898\u6CA1\u6709\u81EA\u5DF1\u89E3\u51B3\u4E5F\u6CA1\u6709\u6392\u8FDB calendar\uFF0C\u53EA\u662F\u6401\u7F6E\u7740",
37842
37843
  "",
37843
- "\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",
37844
- "\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",
37845
- "\u5982\u679C agent \u5DF2\u7ECF\u505A\u4E86\u51B3\u5B9A\u5E76\u6392\u8FDB calendar \u6216\u5DF2\u5F00\u59CB\u6267\u884C \u2192 waiting=false",
37844
+ "\u5173\u952E\u533A\u5206\uFF1A",
37845
+ '- \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',
37846
+ '- \u7B49\u771F\u6B63\u7684\u5916\u90E8\u6761\u4EF6\uFF08\u670D\u52A1\u3001SSH\u3001\u5F02\u6B65\u4EFB\u52A1\uFF09 \u2192 "waiting": true',
37847
+ "- \u4F60\u5DF2\u7ECF\u505A\u4E86\u51B3\u5B9A\u5E76\u6392\u8FDB calendar \u6216\u5DF2\u5F00\u59CB\u6267\u884C \u2192 \u4E24\u4E2A\u90FD false",
37846
37848
  excludeSection,
37847
37849
  "",
37848
37850
  "\u53EA\u56DE\u590D JSON\uFF1A",
37849
- '- \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"}',
37850
- '- \u4E0D\u7B26\u5408\uFF1A{"waiting": false}'
37851
+ '- \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"}',
37852
+ '- \u771F\u7B49\u5916\u90E8\u6761\u4EF6\uFF1A{"waiting": true, "desc": "\u7B80\u77ED\u8BF4\u660E"}',
37853
+ '- \u4E0D\u7B26\u5408\uFF1A{"waiting": false, "pushedDecision": false}'
37851
37854
  ].join("\n"),
37852
37855
  messages: [{ role: "user", content: judgeInput }],
37853
37856
  maxTokens: 128,
@@ -37865,11 +37868,37 @@ agent: ${lastMsg.slice(0, 300)}`;
37865
37868
  const parsed = JSON.parse(match[0]);
37866
37869
  isWaiting = !!parsed.waiting;
37867
37870
  waitDesc = parsed.desc || "";
37871
+ pushedDecision = !!parsed.pushedDecision;
37868
37872
  }
37869
- console.log(`[stop-hook] Judge result: waiting=${isWaiting}, desc="${waitDesc}"`);
37873
+ console.log(`[stop-hook] Judge result: waiting=${isWaiting}, pushedDecision=${pushedDecision}, desc="${waitDesc}"`);
37870
37874
  } catch (e) {
37871
37875
  console.warn(`[stop-hook] LLM judge error: ${e.message}`);
37872
37876
  }
37877
+ if (pushedDecision && waitDesc) {
37878
+ console.log(`[stop-hook] DETECTED pushedDecision! Injecting corrective message to ${sessionId}`);
37879
+ try {
37880
+ const correctiveMsg = [
37881
+ "\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",
37882
+ "",
37883
+ `\u8BCA\u65AD\uFF1A${waitDesc}`,
37884
+ "",
37885
+ "\u660E\u77E5\u9053\u600E\u4E48\u505A\u5BF9\u7684\u4E8B \u2192 \u76F4\u63A5\u505A \u2192 \u6C47\u62A5\u7ED3\u679C\u3002",
37886
+ "\u95EE = \u5361\u4F4F\u3002",
37887
+ "",
37888
+ "\u8BF7\u7ACB\u523B\uFF1A",
37889
+ "1. \u64A4\u56DE\u4F60\u7684\u95EE\u9898\uFF08\u4E0D\u8981\u7B49\u5BF9\u65B9\u56DE\u590D\uFF09",
37890
+ "2. \u81EA\u5DF1\u9009\u6700\u4F18\u65B9\u6848\u76F4\u63A5\u6267\u884C",
37891
+ '3. \u6267\u884C\u5B8C\u6C47\u62A5\u7ED3\u679C\uFF08"\u5DF2\u5904\u7406" / "\u5DF2 commit" / "\u5DF2 archive"\uFF09',
37892
+ "",
37893
+ "\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"
37894
+ ].join("\n");
37895
+ if (this.dispatcher) {
37896
+ this.dispatcher.submitMessage(correctiveMsg, sessionId);
37897
+ }
37898
+ } catch (e) {
37899
+ console.warn(`[stop-hook] Failed to inject corrective message: ${e.message}`);
37900
+ }
37901
+ }
37873
37902
  if (!isWaiting) {
37874
37903
  return { outcome: { outcome: "success" } };
37875
37904
  }
@@ -37888,13 +37917,15 @@ agent: ${lastMsg.slice(0, 300)}`;
37888
37917
  }
37889
37918
  }
37890
37919
  const wakeAt = new Date(Date.now() + 5 * 6e4).toISOString();
37920
+ const notifId = `wake-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
37891
37921
  notifs.push({
37922
+ id: notifId,
37892
37923
  description: waitDesc || lastMsg.slice(0, 200),
37893
37924
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
37894
37925
  wakeAt
37895
37926
  });
37896
37927
  fs17.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
37897
- console.log(`[stop-hook] Registered wake-up at ${wakeAt} (sessionId=${sessionId}): ${waitDesc}`);
37928
+ console.log(`[stop-hook] Registered wake-up ${notifId} at ${wakeAt} (sessionId=${sessionId}): ${waitDesc}`);
37898
37929
  } catch (e) {
37899
37930
  console.warn(`[stop-hook] Failed to register: ${e.message}`);
37900
37931
  }
@@ -37927,7 +37958,7 @@ agent: ${lastMsg.slice(0, 300)}`;
37927
37958
  return null;
37928
37959
  }
37929
37960
  }
37930
- /** 检查 stop-hook-notifications:agent 停止前注册的等待唤起 */
37961
+ /** 检查 stop-hook-notifications:你停止前注册的等待唤起 */
37931
37962
  checkStopHookNotifications() {
37932
37963
  const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
37933
37964
  try {
@@ -37935,26 +37966,56 @@ agent: ${lastMsg.slice(0, 300)}`;
37935
37966
  const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
37936
37967
  if (notifs.length === 0) return null;
37937
37968
  const now = Date.now();
37938
- const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now);
37969
+ const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now && !n.notified);
37939
37970
  if (due.length === 0) return null;
37940
37971
  const latest = due[due.length - 1];
37941
- console.log(`[nudge] Stop-hook notification triggered: ${latest.description.slice(0, 80)}...`);
37942
- const remaining = notifs.filter((n) => new Date(n.wakeAt).getTime() > now);
37943
- if (remaining.length > 0) {
37944
- fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
37945
- } else {
37946
- fs17.unlinkSync(notifPath);
37947
- }
37972
+ console.log(`[nudge] Stop-hook notification ${latest.id} triggered: ${latest.description.slice(0, 80)}...`);
37973
+ const updated = notifs.map((n) => n.id === latest.id ? { ...n, notified: true } : n);
37974
+ fs17.writeFileSync(notifPath, JSON.stringify(updated, null, 2));
37948
37975
  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
37949
37976
 
37977
+ [\u901A\u77E5ID: ${latest.id}]
37950
37978
  \u4E0A\u6B21\u8BF4\uFF1A${latest.description}
37951
37979
 
37952
- \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`);
37980
+ \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`);
37953
37981
  } catch (e) {
37954
37982
  console.warn(`[nudge] checkStopHookNotifications error: ${e.message}`);
37955
37983
  return null;
37956
37984
  }
37957
37985
  }
37986
+ /** 读最近消息,如果发现"<notifId> 过期了"→ 精确清理对应的 wake-up notification */
37987
+ cleanupStaleNotificationsFromMessages(sessions) {
37988
+ try {
37989
+ const recent = recentMessages(sessions, 0.5, 6);
37990
+ const fiveMinAgo = Date.now() - 5 * 60 * 1e3;
37991
+ const recentTexts = recent.filter((r) => new Date(r.timestamp || r.createdAt || Date.now()).getTime() > fiveMinAgo).map((r) => r.text);
37992
+ const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
37993
+ if (!fs17.existsSync(notifPath)) return;
37994
+ const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
37995
+ if (notifs.length === 0) return;
37996
+ const expiredIds = /* @__PURE__ */ new Set();
37997
+ for (const text of recentTexts) {
37998
+ for (const n of notifs) {
37999
+ if (text.includes(`${n.id} \u8FC7\u671F\u4E86`) || text.includes(`${n.id}\u8FC7\u671F\u4E86`)) {
38000
+ expiredIds.add(n.id);
38001
+ }
38002
+ }
38003
+ }
38004
+ if (expiredIds.size === 0) return;
38005
+ const remaining = notifs.filter((n) => !expiredIds.has(n.id));
38006
+ const cleaned = notifs.length - remaining.length;
38007
+ if (cleaned > 0) {
38008
+ if (remaining.length > 0) {
38009
+ fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
38010
+ } else {
38011
+ fs17.unlinkSync(notifPath);
38012
+ }
38013
+ console.log(`[nudge] Cleaned ${cleaned} stale notification(s) by explicit id: ${[...expiredIds].join(", ")}`);
38014
+ }
38015
+ } catch (e) {
38016
+ console.warn(`[nudge] cleanupStaleNotificationsFromMessages error: ${e.message}`);
38017
+ }
38018
+ }
37958
38019
  async tick(sessions, deps) {
37959
38020
  if (this.running) {
37960
38021
  console.log("[nudge] Previous tick still running, skipping");
@@ -37980,6 +38041,7 @@ agent: ${lastMsg.slice(0, 300)}`;
37980
38041
  }
37981
38042
  this.running = true;
37982
38043
  try {
38044
+ this.cleanupStaleNotificationsFromMessages(sessions);
37983
38045
  const stopNotifs = this.checkStopHookNotifications();
37984
38046
  if (stopNotifs) {
37985
38047
  const route2 = this.getRoute(sessions);
@@ -39426,6 +39488,8 @@ function formatBeijingTs(d) {
39426
39488
  }
39427
39489
 
39428
39490
  // src/calendar/commands.ts
39491
+ import { existsSync as existsSync13, statSync as statSync7 } from "node:fs";
39492
+ import { isAbsolute as isAbsolute4, resolve as resolve7 } from "node:path";
39429
39493
  var WEEKDAYS2 = ["\u5468\u4E00", "\u5468\u4E8C", "\u5468\u4E09", "\u5468\u56DB", "\u5468\u4E94", "\u5468\u516D", "\u5468\u65E5"];
39430
39494
  function fmtEnd(start, durationMin) {
39431
39495
  const [hh, mm] = start.split(":").map(Number);
@@ -39588,7 +39652,29 @@ ${skipped.map((s2) => ` ${s2}`).join("\n")}`;
39588
39652
  return result;
39589
39653
  }
39590
39654
  function addTask(db, args2) {
39591
- const { dateStr, timeExact, event } = args2;
39655
+ const { dateStr, timeExact, event, docPath } = args2;
39656
+ if (!docPath || !docPath.trim()) {
39657
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Aadd-task \u5FC5\u987B\u4F20 doc_path\u3002
39658
+ \u6CA1\u6709\u6587\u6863\u652F\u6491\u7684 task \u4E0D\u662F\u5408\u683C\u7684 task\u3002
39659
+ \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`;
39660
+ }
39661
+ try {
39662
+ const absPath = isAbsolute4(docPath) ? docPath : resolve7(process.cwd(), docPath);
39663
+ if (!existsSync13(absPath)) {
39664
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728
39665
+ \u8DEF\u5F84: ${docPath}
39666
+ \u89E3\u6790\u540E: ${absPath}
39667
+ \u8BF7\u5148\u521B\u5EFA\u6587\u6863\u518D add-task\u3002`;
39668
+ }
39669
+ const stat8 = statSync7(absPath);
39670
+ if (!stat8.isFile()) {
39671
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u4E0D\u662F\u6587\u4EF6\uFF08\u53EF\u80FD\u662F\u76EE\u5F55\uFF09
39672
+ \u8DEF\u5F84: ${docPath}`;
39673
+ }
39674
+ } catch (err) {
39675
+ return `\u274C \u521B\u5EFA\u5931\u8D25\uFF1Adoc_path \u6821\u9A8C\u51FA\u9519\uFF1A${err.message}
39676
+ \u8DEF\u5F84: ${docPath}`;
39677
+ }
39592
39678
  let remindMin = 60;
39593
39679
  if (args2.remind) {
39594
39680
  const v2 = args2.remind;
@@ -39602,10 +39688,11 @@ function addTask(db, args2) {
39602
39688
  const prox = checkTaskProximity(taskRows, timeExact);
39603
39689
  const remindAt = computeRemindAt(dateStr, timeExact, remindMin);
39604
39690
  const r = db.prepare(
39605
- `INSERT INTO events (type,status,event,date_str,time_exact,remind_before_min,remind_at,reminded,created_at,created_channel,created_channel_target)
39606
- VALUES ('task','pending',?,?,?,?,?,?,?,?,?)`
39607
- ).run(event, dateStr, timeExact, remindMin, remindAt, 0, nowIso(), args2.channel || null, args2.channelTarget || null);
39608
- let msg2 = `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0\u4EFB\u52A1: [${dateStr} ${timeExact}] ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)`;
39691
+ `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)
39692
+ VALUES ('task','pending',?,?,?,?,?,?,?,?,?,?)`
39693
+ ).run(event, dateStr, timeExact, remindMin, remindAt, 0, nowIso(), args2.channel || null, args2.channelTarget || null, docPath);
39694
+ let msg2 = `#${r.lastInsertRowid} \u5DF2\u6DFB\u52A0\u4EFB\u52A1: [${dateStr} ${timeExact}] ${event} (\u63D0\u524D${remindMin}min\u63D0\u9192)
39695
+ \u{1F4C4} \u6587\u6863: ${docPath}`;
39609
39696
  if (prox) {
39610
39697
  msg2 += `
39611
39698
  \u26A0\uFE0F \u65F6\u95F4\u63A5\u8FD1\uFF1A\u4E0E #${prox.id}\u300C${prox.event}\u300D(${prox.time}) \u4EC5\u76F8\u5DEE ${prox.diffMin}min`;
@@ -39939,7 +40026,7 @@ function registerVoiceChatBridge(httpServer, dispatcher, deps, config2, sessions
39939
40026
  const https = await import("node:https");
39940
40027
  const url = new URL(callbackUrl);
39941
40028
  const postData = JSON.stringify({ session_id: ctx.inbound.from, text: ctx.response });
39942
- await new Promise((resolve11, reject) => {
40029
+ await new Promise((resolve12, reject) => {
39943
40030
  const req = https.request(url, {
39944
40031
  method: "POST",
39945
40032
  headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) },
@@ -39947,7 +40034,7 @@ function registerVoiceChatBridge(httpServer, dispatcher, deps, config2, sessions
39947
40034
  }, (res) => {
39948
40035
  console.log(`[voice-chat] Reply POST ${callbackUrl}: ${res.statusCode} (${ctx.response.length} chars)`);
39949
40036
  res.resume();
39950
- resolve11();
40037
+ resolve12();
39951
40038
  });
39952
40039
  req.on("error", reject);
39953
40040
  req.write(postData);
@@ -40236,27 +40323,27 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
40236
40323
  };
40237
40324
  }
40238
40325
  async isPortAlive(port) {
40239
- return new Promise((resolve11) => {
40326
+ return new Promise((resolve12) => {
40240
40327
  const socket = new net.Socket();
40241
40328
  socket.setTimeout(2e3);
40242
40329
  socket.on("connect", () => {
40243
40330
  socket.destroy();
40244
- resolve11(true);
40331
+ resolve12(true);
40245
40332
  });
40246
40333
  socket.on("timeout", () => {
40247
40334
  socket.destroy();
40248
- resolve11(false);
40335
+ resolve12(false);
40249
40336
  });
40250
40337
  socket.on("error", () => {
40251
40338
  socket.destroy();
40252
- resolve11(false);
40339
+ resolve12(false);
40253
40340
  });
40254
40341
  socket.connect(port, "127.0.0.1");
40255
40342
  });
40256
40343
  }
40257
40344
  async killProcessOnPort(port) {
40258
- const run = (cmd) => new Promise((resolve11) => {
40259
- exec(cmd, { timeout: 5e3 }, (err, stdout) => resolve11(err ? "" : stdout));
40345
+ const run = (cmd) => new Promise((resolve12) => {
40346
+ exec(cmd, { timeout: 5e3 }, (err, stdout) => resolve12(err ? "" : stdout));
40260
40347
  });
40261
40348
  try {
40262
40349
  if (process.platform === "win32") {
@@ -40745,27 +40832,27 @@ var CogniFoldPlugin = class {
40745
40832
  throw new Error(`CogniFold not ready after ${timeoutMs}ms at ${url}`);
40746
40833
  }
40747
40834
  async isPortAlive(port) {
40748
- return new Promise((resolve11) => {
40835
+ return new Promise((resolve12) => {
40749
40836
  const socket = new net2.Socket();
40750
40837
  socket.setTimeout(2e3);
40751
40838
  socket.on("connect", () => {
40752
40839
  socket.destroy();
40753
- resolve11(true);
40840
+ resolve12(true);
40754
40841
  });
40755
40842
  socket.on("timeout", () => {
40756
40843
  socket.destroy();
40757
- resolve11(false);
40844
+ resolve12(false);
40758
40845
  });
40759
40846
  socket.on("error", () => {
40760
40847
  socket.destroy();
40761
- resolve11(false);
40848
+ resolve12(false);
40762
40849
  });
40763
40850
  socket.connect(port, "127.0.0.1");
40764
40851
  });
40765
40852
  }
40766
40853
  async killProcessOnPort(port) {
40767
- const run = (cmd) => new Promise((resolve11) => {
40768
- exec2(cmd, { timeout: 5e3 }, (err, stdout) => resolve11(err ? "" : stdout));
40854
+ const run = (cmd) => new Promise((resolve12) => {
40855
+ exec2(cmd, { timeout: 5e3 }, (err, stdout) => resolve12(err ? "" : stdout));
40769
40856
  });
40770
40857
  try {
40771
40858
  if (process.platform === "win32") {
@@ -42010,7 +42097,7 @@ registry.register({
42010
42097
  init_registry();
42011
42098
  registry.register({
42012
42099
  name: "calendar",
42013
- 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.',
42100
+ 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.',
42014
42101
  schema: {
42015
42102
  type: "object",
42016
42103
  properties: {
@@ -42027,7 +42114,7 @@ registry.register({
42027
42114
  remind: { type: "string", description: "\u63D0\u524D\u63D0\u9192\uFF08add-task \u7528\uFF0C\u5982 30m=30\u5206\u949F, 1h=1\u5C0F\u65F6, \u9ED8\u8BA460m\uFF09" },
42028
42115
  id: { type: "number", description: "\u4E8B\u4EF6 ID\uFF08done/archive/reschedule/link-doc/find-doc \u7528\uFF09" },
42029
42116
  all: { type: "boolean", description: "\u67E5\u770B\u5168\u90E8\uFF08list \u7528\uFF09" },
42030
- doc_path: { type: "string", description: "\u6587\u6863\u8DEF\u5F84\uFF08link-doc \u7528\uFF0C\u5982 docs/todo/xxx.md\uFF09" }
42117
+ 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" }
42031
42118
  },
42032
42119
  required: ["action"]
42033
42120
  },
@@ -42066,10 +42153,12 @@ registry.register({
42066
42153
  const event = args2.event?.trim();
42067
42154
  const date = args2.date?.trim();
42068
42155
  const timeExact = args2.time_exact?.trim();
42156
+ const docPath = args2.doc_path?.trim();
42069
42157
  if (!event) return { content: "Error: add-task needs event", isError: true };
42070
42158
  if (!date) return { content: "Error: add-task needs date (e.g. 7/5)", isError: true };
42071
42159
  if (!timeExact || !timeExact.includes(":")) return { content: "Error: add-task needs time_exact (HH:MM, e.g. 14:00)", isError: true };
42072
- result = addTask(db, { dateStr: date, timeExact, event, remind: args2.remind, channel: ctx.channel, channelTarget: ctx.channelTarget });
42160
+ 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 };
42161
+ result = addTask(db, { dateStr: date, timeExact, event, remind: args2.remind, channel: ctx.channel, channelTarget: ctx.channelTarget, docPath });
42073
42162
  } else if (action === "reschedule") {
42074
42163
  if (args2.id == null) return { content: "Error: reschedule needs id", isError: true };
42075
42164
  const date = args2.date?.trim();
@@ -42110,7 +42199,8 @@ registry.register({
42110
42199
  return { content: `Error: unknown action '${action}'`, isError: true };
42111
42200
  }
42112
42201
  db.close();
42113
- if (isAddTask && !result.includes("Error") && !result.includes("\u7528\u6CD5")) {
42202
+ const isFailed = result.startsWith("\u274C") || result.includes("Error") || result.includes("\u7528\u6CD5");
42203
+ if (isAddTask && !isFailed) {
42114
42204
  const { enqueueNotification: enqueueNotification2, buildCalendarNotification: buildCalendarNotification2 } = await Promise.resolve().then(() => (init_task_manager(), task_manager_exports));
42115
42205
  const sessionId = ctx.sessionId || "main";
42116
42206
  const channel = ctx.channel;
@@ -42221,7 +42311,7 @@ registry.register({
42221
42311
  lines.push(`start: spawned PID ${pid} (background${svcArgs ? ", args=" + svcArgs : ""})`);
42222
42312
  if (svc.healthCheck) {
42223
42313
  for (let i = 0; i < 6; i++) {
42224
- await new Promise((resolve11) => setTimeout(resolve11, 5e3));
42314
+ await new Promise((resolve12) => setTimeout(resolve12, 5e3));
42225
42315
  const after2 = await checkStatus();
42226
42316
  if (after2.running) {
42227
42317
  lines.push(`health: \u2705 running (after ${(i + 1) * 5}s)`);
@@ -42231,7 +42321,7 @@ registry.register({
42231
42321
  const after = await checkStatus();
42232
42322
  lines.push(`health: \u274C not responding after 30s \u2014 ${after.detail}`);
42233
42323
  } else {
42234
- await new Promise((resolve11) => setTimeout(resolve11, 3e3));
42324
+ await new Promise((resolve12) => setTimeout(resolve12, 3e3));
42235
42325
  lines.push(`start: PID ${pid} spawned (no healthCheck, waited 3s)`);
42236
42326
  }
42237
42327
  } else {
@@ -42256,7 +42346,7 @@ registry.register({
42256
42346
  const before = await checkStatus();
42257
42347
  if (before.running) {
42258
42348
  results.push(await doStop());
42259
- await new Promise((resolve11) => setTimeout(resolve11, 2e3));
42349
+ await new Promise((resolve12) => setTimeout(resolve12, 2e3));
42260
42350
  } else {
42261
42351
  results.push("stop: already stopped");
42262
42352
  }
@@ -43326,7 +43416,7 @@ var AgentChannelRegistry = class {
43326
43416
  const pending2 = this.waiters.get(agentName);
43327
43417
  if (pending2) {
43328
43418
  this.waiters.delete(agentName);
43329
- for (const resolve11 of pending2) resolve11(channelId);
43419
+ for (const resolve12 of pending2) resolve12(channelId);
43330
43420
  }
43331
43421
  }
43332
43422
  /**
@@ -43336,10 +43426,10 @@ var AgentChannelRegistry = class {
43336
43426
  waitForChannel(agentName) {
43337
43427
  const existing = this.findByAgentName(agentName);
43338
43428
  if (existing?.channelId) return Promise.resolve(existing.channelId);
43339
- return new Promise((resolve11) => {
43429
+ return new Promise((resolve12) => {
43340
43430
  const list2 = this.waiters.get(agentName);
43341
- if (list2) list2.push(resolve11);
43342
- else this.waiters.set(agentName, [resolve11]);
43431
+ if (list2) list2.push(resolve12);
43432
+ else this.waiters.set(agentName, [resolve12]);
43343
43433
  });
43344
43434
  }
43345
43435
  /** 查找 agent 对应的频道 ID */
@@ -43871,7 +43961,7 @@ async function startEngine(config2, opts) {
43871
43961
  if (!fs54.existsSync(dailyDir)) {
43872
43962
  fs54.mkdirSync(dailyDir, { recursive: true });
43873
43963
  }
43874
- const sessionsDir = path54.join(workspace, "sessions");
43964
+ const sessionsDir = path54.join(config2.stateDir, "agents", "main", "sessions");
43875
43965
  const sessionFile = path54.join(sessionsDir, `${sessionId}.jsonl`);
43876
43966
  const recentLines = [];
43877
43967
  if (fs54.existsSync(sessionFile)) {
@@ -45823,7 +45913,7 @@ ${actionsJson}
45823
45913
  }
45824
45914
  }
45825
45915
  }
45826
- const shutdownPromise = new Promise((resolve11) => {
45916
+ const shutdownPromise = new Promise((resolve12) => {
45827
45917
  const shutdown = (signal) => {
45828
45918
  console.log(`[engine] ${signal} received, shutting down...`);
45829
45919
  try {
@@ -45831,7 +45921,7 @@ ${actionsJson}
45831
45921
  } catch {
45832
45922
  }
45833
45923
  engine.interrupt();
45834
- resolve11();
45924
+ resolve12();
45835
45925
  };
45836
45926
  process.on("SIGTERM", () => shutdown("SIGTERM"));
45837
45927
  process.on("SIGINT", () => shutdown("SIGINT"));