duclaw-cli 1.9.6 → 1.9.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/bundle.js CHANGED
@@ -30242,7 +30242,7 @@ function printHelp() {
30242
30242
  `);
30243
30243
  }
30244
30244
  function printVersion() {
30245
- console.log(`duclaw-cli v${true ? "1.9.6" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.9.8" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -31213,6 +31213,12 @@ var inferMimeType = (fileName = "") => {
31213
31213
  if (ext === ".gif") return "image/gif";
31214
31214
  if (ext === ".webp") return "image/webp";
31215
31215
  if (ext === ".pdf") return "application/pdf";
31216
+ if (ext === ".doc") return "application/msword";
31217
+ if (ext === ".docx") return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
31218
+ if (ext === ".xls") return "application/vnd.ms-excel";
31219
+ if (ext === ".xlsx") return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
31220
+ if (ext === ".ppt") return "application/vnd.ms-powerpoint";
31221
+ if (ext === ".pptx") return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
31216
31222
  return "application/octet-stream";
31217
31223
  };
31218
31224
  var inferAttachmentType = (mimeType = "", fileName = "") => {
@@ -43742,7 +43748,8 @@ var checkDepartmentReplies = {
43742
43748
  `\u51E0\u53E5\u63D0\u9192\uFF1A`,
43743
43749
  `- \u8FD9\u4E0D\u4EE3\u8868\u8981\u4F60\u4EB2\u81EA\u4E0B\u573A read/bash/\u6D4B\u8BD5/\u6539\u4EE3\u7801\u2014\u2014\u56E2\u961F\u6CA1\u56DE\uFF0C\u4E0D\u662F\u4F60\u8BE5\u63A5\u624B\u7684\u4FE1\u53F7\u3002`,
43744
43750
  `- \u8001\u677F\u8981\u662F\u6B63\u7B49\u7740\uFF0C\u5148\u7528 send_message \u5982\u5B9E\u8DDF\u4ED6\u8BF4\u4E00\u53E5\u201C\u8D1F\u8D23\u4EBA\u8FD8\u5728\u5904\u7406\uFF0C\u6211\u62FF\u5230\u7ED3\u679C\u5C31\u540C\u6B65\u201D\u3002`,
43745
- `- \u5DF2\u7ECF\u7B49\u4E86\u4E00\u9635\uFF0C\u5C31\u7528 mailbox_followup \u6216 department_communicate \u53BB\u50AC\u5BF9\u5E94 Department Head\uFF0C\u95EE\u95EE\u771F\u5B9E\u8FDB\u5C55\u3001\u5361\u5728\u54EA\u3001\u5927\u6982\u4EC0\u4E48\u65F6\u5019\u597D\u3002`,
43751
+ `- \u5982\u679C\u4EFB\u52A1\u521A\u6D3E\u51FA\u53BB\uFF0C\u4E0D\u8981\u5728\u540C\u4E00\u8F6E\u9A6C\u4E0A\u50AC\u529E\uFF1B\u7ED9\u8D1F\u8D23\u4EBA\u5408\u7406\u5904\u7406\u65F6\u95F4\u3002`,
43752
+ `- \u5DF2\u7ECF\u7B49\u4E86\u4E00\u9635\u3001\u8001\u677F\u53C8\u8FFD\u95EE\uFF0C\u6216\u53D1\u73B0\u660E\u786E\u98CE\u9669\u65F6\uFF0C\u518D\u7528 mailbox_followup \u6216 department_communicate \u53BB\u95EE\u5BF9\u5E94 Department Head \u771F\u5B9E\u8FDB\u5C55\u3001\u5361\u5728\u54EA\u3001\u5927\u6982\u4EC0\u4E48\u65F6\u5019\u597D\u3002`,
43746
43753
  `- \u522B\u5728\u8FD9\u4E00\u8F6E\u91CC\u53CD\u590D\u7A7A\u67E5 check_department_replies\uFF1B\u7B49\u56E2\u961F\u56DE\u4FE1\u3001\u8001\u677F\u8FFD\u95EE\u6216\u50AC\u529E\u6709\u4E86\u56DE\u97F3\uFF0C\u518D\u6765\u770B\u3002`
43747
43754
  ].join("\n");
43748
43755
  }
@@ -44346,6 +44353,11 @@ var departmentProposalCreate = {
44346
44353
 
44347
44354
  // src/tools/tools/department/MailboxFollowup.ts
44348
44355
  var CEO_MAILBOX_ID2 = `manager`;
44356
+ var DEFAULT_CEO_NUDGE_COOLDOWN_MS = 10 * 6e4;
44357
+ var getCeoNudgeCooldownMs = () => {
44358
+ const configured = Number(process.env.CEO_MAILBOX_NUDGE_COOLDOWN_MS ?? DEFAULT_CEO_NUDGE_COOLDOWN_MS);
44359
+ return Number.isFinite(configured) && configured >= 0 ? configured : DEFAULT_CEO_NUDGE_COOLDOWN_MS;
44360
+ };
44349
44361
  var DESCRIPTION28 = `
44350
44362
  \u5728\u5F53\u524D mailbox \u7EBF\u7A0B\u4E2D\u8FFD\u52A0\u4E00\u6761\u8865\u5145\u6D88\u606F\uFF0C\u4F46\u4E0D\u7ED3\u675F\u539F\u6D88\u606F\u7684\u5904\u7406\u3002
44351
44363
 
@@ -44369,6 +44381,10 @@ var DESCRIPTION28 = `
44369
44381
  - \u5982\u679C\u4F60\u5DF2\u7ECF\u5F62\u6210\u5BF9\u5F53\u524D\u6D88\u606F\u7684\u6B63\u5F0F\u7B54\u590D\uFF0C\u5E94\u4F7F\u7528 reply_mailbox
44370
44382
  - \u5BF9 CEO \u800C\u8A00\uFF0C\u8FD9\u901A\u5E38\u662F\u201C\u628A\u8FD4\u5DE5\u9700\u6C42\u9000\u56DE\u539F\u8D23\u4EFB\u6210\u5458\u201D\u7684\u9996\u9009\u5DE5\u5177\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u76F4\u63A5\u91CD\u505A
44371
44383
  `;
44384
+ var looksLikeCeoNudge = (content, kind) => {
44385
+ if (kind === `nudge`) return true;
44386
+ return /催|进展|怎么样|如何了|好了没|尽快|抓紧|reply|update|progress/i.test(content);
44387
+ };
44372
44388
  var mailboxFollowup = {
44373
44389
  name: `mailbox_followup`,
44374
44390
  description: DESCRIPTION28,
@@ -44405,6 +44421,7 @@ var mailboxFollowup = {
44405
44421
  id,
44406
44422
  from_mailbox_id as fromMailboxId,
44407
44423
  to_mailbox_id as toMailboxId,
44424
+ send_time as sendTime,
44408
44425
  status,
44409
44426
  origin_user_id as originUserId,
44410
44427
  origin_platform as originPlatform,
@@ -44420,6 +44437,19 @@ var mailboxFollowup = {
44420
44437
  return `[mailboxFollowup] \u8BE5\u90AE\u4EF6\u4E0D\u5C5E\u4E8E\u4F60\u7684\u7EBF\u7A0B\u4E0A\u4E0B\u6587\uFF0C\u65E0\u6CD5\u8DDF\u8FDB`;
44421
44438
  }
44422
44439
  const counterpartMailboxId = anchorMsg.toMailboxId === myMailboxId ? anchorMsg.fromMailboxId : anchorMsg.toMailboxId;
44440
+ const cooldownMs = getCeoNudgeCooldownMs();
44441
+ const elapsedMs = Date.now() - anchorMsg.sendTime;
44442
+ const isCeoFollowingOwnDelegation = myMailboxId === CEO_MAILBOX_ID2 && anchorMsg.fromMailboxId === CEO_MAILBOX_ID2 && anchorMsg.toMailboxId !== CEO_MAILBOX_ID2;
44443
+ if (isCeoFollowingOwnDelegation && looksLikeCeoNudge(content, kind) && elapsedMs < cooldownMs) {
44444
+ const waitMinutes = Math.max(1, Math.ceil((cooldownMs - elapsedMs) / 6e4));
44445
+ return [
44446
+ `[mailboxFollowup] \u5DF2\u62D2\u7EDD\u53D1\u9001\u8FC7\u65E9\u7684\u50AC\u529E\u3002`,
44447
+ `CEO \u521A\u628A\u4EFB\u52A1\u6D3E\u7ED9 ${counterpartMailboxId}\uFF0C\u77ED\u65F6\u95F4\u5185\u4E0D\u8981\u7ACB\u523B\u8FFD\u95EE\u201C\u8FDB\u5C55\u600E\u4E48\u6837/\u5C3D\u5FEB\u56DE\u590D/\u5DF2\u7ECF\u50AC\u4E86\u51E0\u6B21\u201D\u3002`,
44448
+ `\u8BF7\u5148\u7ED9\u8D1F\u8D23\u4EBA\u5408\u7406\u5904\u7406\u65F6\u95F4\uFF1B\u5982\u679C\u8001\u677F\u6B63\u5728\u7B49\uFF0C\u53EF\u4EE5\u7528 send_message \u5982\u5B9E\u8BF4\u660E\u201C\u5DF2\u5B89\u6392\u56E2\u961F\u5904\u7406\uFF0C\u62FF\u5230\u7ED3\u679C\u9A6C\u4E0A\u540C\u6B65\u201D\u3002`,
44449
+ `\u5982\u786E\u6709\u65B0\u80CC\u666F\u6216\u660E\u786E\u4FEE\u6B63\u9700\u6C42\uFF0C\u8BF7\u6539\u5199\u4E3A\u5177\u4F53\u8865\u5145\u4FE1\u606F\uFF1B\u7EAF\u50AC\u529E\u8BF7\u7EA6 ${waitMinutes} \u5206\u949F\u540E\u518D\u53D1\u3002`
44450
+ ].join(`
44451
+ `);
44452
+ }
44423
44453
  const followupMsg = sendMessage2(myMailboxId, counterpartMailboxId, content, {
44424
44454
  originUserId: anchorMsg.originUserId,
44425
44455
  originPlatform: anchorMsg.originPlatform,
@@ -44478,6 +44508,7 @@ var MAX_SESSION_OUTPUT_LENGTH = 5e4;
44478
44508
  var DEFAULT_TIMEOUT_MS = 3e4;
44479
44509
  var DEFAULT_SESSION_TTL_MS = 30 * 60 * 1e3;
44480
44510
  var SHELL_CANDIDATES2 = ["/bin/sh", "/usr/bin/sh", "/bin/bash"];
44511
+ var DEFAULT_PROTECTED_PORTS = ["3100"];
44481
44512
  var sessions = /* @__PURE__ */ new Map();
44482
44513
  function findExecutableShell2() {
44483
44514
  for (const shell of SHELL_CANDIDATES2) {
@@ -44508,6 +44539,36 @@ function validateCwd(cwd) {
44508
44539
  return `[bash] \u9519\u8BEF: cwd \u4E0D\u53EF\u7528: ${cwd} (${err.message})`;
44509
44540
  }
44510
44541
  }
44542
+ function getProtectedPorts() {
44543
+ const configured = process.env.DUCLAW_BASH_PROTECTED_PORTS ?? [process.env.KANBAN_PORT, process.env.PORT, ...DEFAULT_PROTECTED_PORTS].filter(Boolean).join(",");
44544
+ return [...new Set(
44545
+ configured.split(",").map((port) => port.trim()).filter((port) => /^\d{1,5}$/.test(port))
44546
+ )];
44547
+ }
44548
+ function validateProtectedRuntimeCommand(command) {
44549
+ const ports = getProtectedPorts();
44550
+ if (ports.length === 0) return null;
44551
+ for (const port of ports) {
44552
+ const portRef = new RegExp(`(^|[^\\d])(:${port}|-${port}\\b|${port}/tcp\\b)`);
44553
+ const targetsProtectedPort = portRef.test(command);
44554
+ if (!targetsProtectedPort) continue;
44555
+ const killsProcess = /\b(kill|pkill|killall|fuser)\b/.test(command) || /\blsof\b[\s\S]*\bxargs\b[\s\S]*\bkill\b/.test(command) || /\bss\b[\s\S]*\bxargs\b[\s\S]*\bkill\b/.test(command);
44556
+ if (killsProcess) {
44557
+ return [
44558
+ `[bash] \u62D2\u7EDD\u6267\u884C: \u547D\u4EE4\u8BD5\u56FE\u6E05\u7406 Duclaw runtime \u4FDD\u7559\u7AEF\u53E3 ${port}\u3002`,
44559
+ `\u8BE5\u7AEF\u53E3\u627F\u8F7D\u5F53\u524D\u667A\u80FD\u4F53\u7684 HTTP/gateway\uFF0C\u6740\u6389\u5B83\u4F1A\u5BFC\u81F4 iOS \u663E\u793A\u5DF2\u5173\u673A\u6216 502\u3002`,
44560
+ `\u8BF7\u6362\u7528\u9879\u76EE\u81EA\u5DF1\u7684\u5F00\u53D1\u7AEF\u53E3\uFF08\u4F8B\u5982 3001/5173\uFF09\uFF0C\u4E0D\u8981\u5BF9 ${port} \u6267\u884C kill/lsof/fuser/pkill\u3002`
44561
+ ].join("\n");
44562
+ }
44563
+ }
44564
+ if (/\b(pkill|killall)\b[\s\S]*\b(node|tsx|pnpm|npm)\b/.test(command)) {
44565
+ return [
44566
+ `[bash] \u62D2\u7EDD\u6267\u884C: \u547D\u4EE4\u4F1A\u6309\u8FDB\u7A0B\u540D\u6279\u91CF\u7EC8\u6B62 Node/JS \u8FDB\u7A0B\u3002`,
44567
+ `\u8FD9\u53EF\u80FD\u8BEF\u6740 Duclaw runtime\u3002\u8BF7\u53EA\u7EC8\u6B62\u660E\u786E\u5C5E\u4E8E\u5F53\u524D\u9879\u76EE\u7684 PID \u6216 session_id\u3002`
44568
+ ].join("\n");
44569
+ }
44570
+ return null;
44571
+ }
44511
44572
  function truncateOutput(output, limit = MAX_OUTPUT_LENGTH) {
44512
44573
  if (output.length <= limit) return output;
44513
44574
  return output.slice(0, limit) + `
@@ -44629,6 +44690,8 @@ var bashTool = {
44629
44690
  if (!command || command.trim() === "") {
44630
44691
  return `[bash] \u9519\u8BEF: command \u4E0D\u80FD\u4E3A\u7A7A`;
44631
44692
  }
44693
+ const protectedCommandError = validateProtectedRuntimeCommand(command);
44694
+ if (protectedCommandError) return protectedCommandError;
44632
44695
  if (userRequest?.workspacePath && explicitCwd) {
44633
44696
  const rejection = validateWorkspacePath(explicitCwd, userRequest.workspacePath);
44634
44697
  if (rejection) return `[bash] ${rejection}`;
@@ -46488,13 +46551,13 @@ The user will primarily request you perform software engineering tasks. This inc
46488
46551
 
46489
46552
  \u516C\u53F8\u91CC\u6709\u5404\u4E2A\u90E8\u95E8\u548C\u5B83\u4EEC\u7684\u8D1F\u8D23\u4EBA\uFF08Department Head\uFF09\u3002\u4E13\u4E1A\u7684\u6D3B\u2014\u2014\u5199\u4EE3\u7801\u3001\u8BFB\u4EE3\u7801\u5B9A\u4F4D\u95EE\u9898\u3001\u6539\u6587\u4EF6\u3001\u8DD1\u6D4B\u8BD5\u3001\u8C03\u8BD5\u3001\u90E8\u7F72\uFF0C\u5904\u7406\u6570\u636E/\u6587\u6863/\u97F3\u89C6\u9891/\u56FE\u7247\uFF0C\u67E5\u8BC1\u5916\u90E8 API\uFF0C\u751F\u6210\u590D\u6742\u4EA7\u7269\u7B49\u2014\u2014\u4F60\u7684\u7B2C\u4E00\u53CD\u5E94\u662F\u627E\u5BF9\u5E94\u56E2\u961F\u7684 Head\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u4E0A\u624B\u3002\u4F60\u80FD\u770B\u5230\u7684\u53EA\u6709\u90E8\u95E8\u548C\u5B83\u4EEC\u7684 Head\uFF1BExecutor \u7531\u5404 Head \u81EA\u5DF1\u7BA1\u7406\uFF0C\u9ED8\u8BA4\u4E0D\u5728\u4F60\u7684\u89C6\u91CE\u91CC\u3002
46490
46553
 
46491
- \u4F60\u548C\u56E2\u961F\u534F\u4F5C\u7684\u65B9\u5F0F\u5F88\u81EA\u7136\uFF1A\u9700\u8981\u56E2\u961F\u505A\u4E8B\u6216\u60F3\u77E5\u9053\u8FDB\u5C55\uFF0C\u5C31\u7ED9\u5BF9\u5E94 Head \u53D1\u6D88\u606F\uFF08department_communicate\uFF09\uFF1B\u60F3\u50AC\u4E00\u4E0B\u6216\u8865\u5145\u4E0A\u4E0B\u6587\uFF0C\u7528 mailbox_followup \u63A5\u56DE\u539F\u6765\u7684\u7EBF\u7A0B\uFF1B\u60F3\u770B\u56E2\u961F\u56DE\u4E86\u4EC0\u4E48\uFF0C\u7528 check_department_replies \u6536\u4E00\u4E0B\u3002\u7EC4\u7EC7\u91CC\u8FD8\u6CA1\u6709\u5BF9\u53E3\u7684\u56E2\u961F\u65F6\uFF0C\u4F60\u624D\u5F20\u7F57\u7740\u5EFA\u90E8\u95E8\u3001\u62DB Head\uFF08\u5EFA\u597D\u90E8\u95E8\u5148\u7528 department_member_create \u51FA\u4E00\u4E2A Head\uFF0C\u518D\u628A\u5177\u4F53\u4EFB\u52A1\u6D3E\u7ED9\u4ED6\uFF09\u3002
46554
+ \u4F60\u548C\u56E2\u961F\u534F\u4F5C\u7684\u65B9\u5F0F\u5F88\u81EA\u7136\uFF1A\u9700\u8981\u56E2\u961F\u505A\u4E8B\uFF0C\u5C31\u7ED9\u5BF9\u5E94 Head \u53D1\u6D88\u606F\uFF08department_communicate\uFF09\uFF1B\u6709\u65B0\u7684\u80CC\u666F\u3001\u4FEE\u6B63\u8981\u6C42\u3001\u7528\u6237\u53CD\u9988\u6216\u5DF2\u7ECF\u8FC7\u4E86\u5408\u7406\u7B49\u5F85\u65F6\u95F4\u518D\u60F3\u50AC\u4E00\u4E0B\uFF0C\u7528 mailbox_followup \u63A5\u56DE\u539F\u6765\u7684\u7EBF\u7A0B\uFF1B\u60F3\u770B\u56E2\u961F\u56DE\u4E86\u4EC0\u4E48\uFF0C\u7528 check_department_replies \u6536\u4E00\u4E0B\u3002\u7EC4\u7EC7\u91CC\u8FD8\u6CA1\u6709\u5BF9\u53E3\u7684\u56E2\u961F\u65F6\uFF0C\u4F60\u624D\u5F20\u7F57\u7740\u5EFA\u90E8\u95E8\u3001\u62DB Head\uFF08\u5EFA\u597D\u90E8\u95E8\u5148\u7528 department_member_create \u51FA\u4E00\u4E2A Head\uFF0C\u518D\u628A\u5177\u4F53\u4EFB\u52A1\u6D3E\u7ED9\u4ED6\uFF09\u3002
46492
46555
 
46493
46556
  \u8001\u677F\u95EE\u4F60\u4EFB\u4F55\u4E8B\u2014\u2014\u5305\u62EC\u201C\u73B0\u5728\u8FDB\u5EA6\u5982\u4F55\u201D\u201C\u6D4B\u8BD5\u5F97\u600E\u4E48\u6837\u201D\u201C\u90A3\u8FB9\u9760\u8C31\u5417\u201D\u201C\u5361\u5728\u54EA\u4E86\u201D\u8FD9\u7C7B\u2014\u2014\u4F60\u7ED9\u7684\u90FD\u662F\u4F60\u5411\u56E2\u961F\u6838\u5B9E\u8FC7\u7684\u771F\u5B9E\u60C5\u51B5\uFF0C\u7EDD\u4E0D\u662F\u51ED\u5370\u8C61\u7F16\u51FA\u6765\u7684\u3002\u5982\u679C\u8FD9\u4F1A\u513F\u8FD8\u6CA1\u62FF\u5230\u51C6\u4FE1\uFF0C\u4F60\u5B81\u53EF\u5148\u56DE\u8001\u677F\u4E00\u53E5\u201C\u6211\u53BB\u8DDF\u56E2\u961F\u786E\u8BA4\uFF0C\u7A0D\u540E\u7ED9\u4F60\u56DE\u201D\uFF0C\u4E5F\u4E0D\u7CCA\u5F04\u4E00\u4E2A\u7B54\u6848\u3002\u5728\u4F60\u628A\u771F\u5B9E\u7ED3\u8BBA\u4EA4\u5230\u8001\u677F\u624B\u4E0A\u4E4B\u524D\uFF0C\u8FD9\u4EF6\u4E8B\u5BF9\u4F60\u90FD\u6CA1\u7B97\u5B8C\u3002
46494
46557
 
46495
46558
  \u67D0\u4E2A Head \u5DF2\u7ECF\u8D1F\u8D23\u7684\u4EA7\u51FA\uFF0C\u540E\u7EED\u7684\u8FD4\u5DE5\u3001bug \u4FEE\u590D\u3001\u201C\u6253\u4E0D\u5F00\u201D\u201C\u5E2E\u6211\u6539\u4E00\u4E0B\u201D\u201C\u518D\u51FA\u4E00\u7248\u201D\uFF0C\u9ED8\u8BA4\u8FD8\u5F52\u4ED6\u2014\u2014\u4F60\u987A\u7740\u539F\u6765\u7684\u7EBF\u7A0B\u628A\u53CD\u9988\u8FFD\u52A0\u7ED9\u4ED6\uFF08mailbox_followup\uFF09\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u63A5\u624B\u91CD\u505A\u3002
46496
46559
 
46497
- \u53EA\u6709\u8FD9\u51E0\u79CD\u60C5\u51B5\u4F60\u624D\u81EA\u5DF1\u4E0A\u624B\uFF1A\u8001\u677F\u660E\u786E\u8981\u4F60\u4EB2\u81EA\u505A\u3001\u7EC4\u7EC7\u91CC\u786E\u5B9E\u6CA1\u6709\u4E5F\u6765\u4E0D\u53CA\u7EC4\u5EFA\u5BF9\u53E3\u56E2\u961F\u3001\u6216\u56E2\u961F\u660E\u786E\u505A\u4E0D\u6210\u4E14\u8001\u677F\u540C\u610F\u4F60\u63A5\u7BA1\u3002\u9664\u6B64\u4E4B\u5916\uFF0C\u56E2\u961F\u56DE\u5F97\u6162\u3001\u6682\u65F6\u6CA1\u56DE\u3001check \u8FD8\u6CA1\u7ED3\u679C\uFF0C\u90FD\u4E0D\u662F\u4F60\u4E0B\u573A\u5E72\u6D3B\u7684\u7406\u7531\u2014\u2014\u8BE5\u505A\u7684\u662F\u50AC\u8D1F\u8D23\u4EBA\uFF0C\u6216\u5982\u5B9E\u8DDF\u8001\u677F\u8BF4\u201C\u56E2\u961F\u8FD8\u5728\u5904\u7406\uFF0C\u6211\u62FF\u5230\u7ED3\u679C\u5C31\u540C\u6B65\u201D\uFF0C\u7136\u540E\u628A\u8FD9\u4E00\u8F6E\u6536\u4F4F\uFF0C\u7B49\u56E2\u961F\u56DE\u4FE1\u6216\u8001\u677F\u65B0\u7684\u6D88\u606F\u3002
46560
+ \u53EA\u6709\u8FD9\u51E0\u79CD\u60C5\u51B5\u4F60\u624D\u81EA\u5DF1\u4E0A\u624B\uFF1A\u8001\u677F\u660E\u786E\u8981\u4F60\u4EB2\u81EA\u505A\u3001\u7EC4\u7EC7\u91CC\u786E\u5B9E\u6CA1\u6709\u4E5F\u6765\u4E0D\u53CA\u7EC4\u5EFA\u5BF9\u53E3\u56E2\u961F\u3001\u6216\u56E2\u961F\u660E\u786E\u505A\u4E0D\u6210\u4E14\u8001\u677F\u540C\u610F\u4F60\u63A5\u7BA1\u3002\u9664\u6B64\u4E4B\u5916\uFF0C\u56E2\u961F\u56DE\u5F97\u6162\u3001\u6682\u65F6\u6CA1\u56DE\u3001check \u8FD8\u6CA1\u7ED3\u679C\uFF0C\u90FD\u4E0D\u662F\u4F60\u4E0B\u573A\u5E72\u6D3B\u7684\u7406\u7531\u3002\u521A\u628A\u4EFB\u52A1\u6D3E\u51FA\u53BB\u65F6\uFF0C\u4E0D\u8981\u7ACB\u523B\u50AC\u529E\uFF0C\u4E5F\u4E0D\u8981\u5728\u540C\u4E00\u8F6E\u8FDE\u7EED\u8FFD\u95EE\uFF1B\u8BE5\u505A\u7684\u662F\u5982\u5B9E\u8DDF\u8001\u677F\u8BF4\u201C\u5DF2\u5B89\u6392\u56E2\u961F\u5904\u7406\uFF0C\u6211\u62FF\u5230\u7ED3\u679C\u5C31\u540C\u6B65\u201D\uFF0C\u7136\u540E\u628A\u8FD9\u4E00\u8F6E\u6536\u4F4F\u3002\u53EA\u6709\u5DF2\u7ECF\u7B49\u5F85\u8FC7\u5408\u7406\u65F6\u95F4\u3001\u8001\u677F\u53C8\u8FFD\u95EE\u8FDB\u5EA6\u3001\u6216\u4F60\u53D1\u73B0\u660E\u786E\u98CE\u9669/\u963B\u585E\u65F6\uFF0C\u624D\u6CBF\u539F\u7EBF\u7A0B\u9002\u5EA6\u50AC\u8D1F\u8D23\u4EBA\u3002
46498
46561
 
46499
46562
  \u5F02\u5E38\u7B80\u5355\u3001\u4F4E\u98CE\u9669\u3001\u4E00\u4E24\u6B65\u5C31\u80FD\u5B8C\u6210\u7684\u5C0F\u4E8B\uFF08\u7B80\u5355\u95EE\u7B54\u3001\u89E3\u91CA\u5DF2\u6709\u4FE1\u606F\u3001\u770B\u4E2A\u5217\u8868\u3001\u67E5\u4E2A\u72B6\u6001\u3001\u8BFB\u4E00\u5C0F\u6BB5\u6587\u4EF6\uFF09\uFF0C\u4F60\u53EF\u4EE5\u987A\u624B\u81EA\u5DF1\u505A\uFF0C\u4E0D\u5FC5\u4EC0\u4E48\u90FD\u7EC4\u7EC7\u5316\u3002
46500
46563
  </\u4F60\u7684\u8EAB\u4EFD>
@@ -47995,19 +48058,47 @@ var getMailboxLivenessSnapshot = () => {
47995
48058
  };
47996
48059
  };
47997
48060
  var hasUnresolvedInternalWork = (snapshot) => snapshot.pendingMailbox > 0 || snapshot.processingMailbox > 0 || snapshot.pendingCeoFollowups > 0 || snapshot.processingCeoFollowups > 0 || snapshot.failedCeoFollowups > 0;
48061
+ var pollCount = 0;
48062
+ var lastHeartbeatLogAt = 0;
48063
+ var lastActiveLivenessLogAt = 0;
48064
+ var MAILBOX_HEARTBEAT_LOG_MS = Number(process.env.MAILBOX_HEARTBEAT_LOG_MS ?? 6e4);
47998
48065
  var looksLikePseudoManagerMailbox2 = (mailboxId) => mailboxId !== "manager" && mailboxId.includes("::") && PSEUDO_MANAGER_MAILBOX_PATTERN.test(mailboxId.trim());
47999
48066
  var reportMailboxLiveness = async (snapshot) => {
48000
48067
  if (!hasUnresolvedInternalWork(snapshot)) return;
48001
- await reportRuntimeActivity({
48002
- kind: "mailbox",
48003
- toolName: "mailbox_poller",
48004
- status: "active",
48005
- metadata: {
48006
- ...snapshot,
48007
- inFlightDepartmentMailboxes: Array.from(inFlightDepartmentMailboxes),
48008
- inFlightCeoFollowups: Array.from(inFlightCeoReplyMessages)
48009
- }
48010
- });
48068
+ const metadata = {
48069
+ ...snapshot,
48070
+ pollCount,
48071
+ inFlightDepartmentMailboxes: Array.from(inFlightDepartmentMailboxes),
48072
+ inFlightCeoFollowups: Array.from(inFlightCeoReplyMessages)
48073
+ };
48074
+ const now = Date.now();
48075
+ if (now - lastActiveLivenessLogAt >= MAILBOX_HEARTBEAT_LOG_MS) {
48076
+ lastActiveLivenessLogAt = now;
48077
+ console.log(`[mailbox] poller active liveness ${JSON.stringify(metadata)}`);
48078
+ }
48079
+ try {
48080
+ await reportRuntimeActivity({
48081
+ kind: "mailbox",
48082
+ toolName: "mailbox_poller",
48083
+ status: "active",
48084
+ metadata
48085
+ });
48086
+ } catch (err) {
48087
+ console.warn(`[mailbox] poller runtime activity \u4E0A\u62A5\u5931\u8D25: ${err.message}`);
48088
+ }
48089
+ };
48090
+ var logMailboxPollerHeartbeat = (snapshot) => {
48091
+ if (MAILBOX_HEARTBEAT_LOG_MS <= 0) return;
48092
+ const now = Date.now();
48093
+ if (now - lastHeartbeatLogAt < MAILBOX_HEARTBEAT_LOG_MS) return;
48094
+ lastHeartbeatLogAt = now;
48095
+ console.log(`[mailbox] poller heartbeat ${JSON.stringify({
48096
+ pollCount,
48097
+ ...snapshot,
48098
+ polling,
48099
+ inFlightDepartmentMailboxes: Array.from(inFlightDepartmentMailboxes),
48100
+ inFlightCeoFollowups: Array.from(inFlightCeoReplyMessages)
48101
+ })}`);
48011
48102
  };
48012
48103
  var recoverStaleProcessingMailboxMessages = () => {
48013
48104
  const staleMs = Number(process.env.MAILBOX_PROCESSING_STALE_MS ?? DEFAULT_MAILBOX_PROCESSING_STALE_MS);
@@ -48314,9 +48405,12 @@ var inFlightCeoReplyUsers = /* @__PURE__ */ new Set();
48314
48405
  var pollMailbox = async () => {
48315
48406
  if (polling) return;
48316
48407
  polling = true;
48408
+ pollCount += 1;
48317
48409
  try {
48318
48410
  recoverStaleProcessingWork();
48319
- await reportMailboxLiveness(getMailboxLivenessSnapshot());
48411
+ const livenessSnapshot = getMailboxLivenessSnapshot();
48412
+ logMailboxPollerHeartbeat(livenessSnapshot);
48413
+ await reportMailboxLiveness(livenessSnapshot);
48320
48414
  const mailBoxMsgs = selectStmt.all("pending");
48321
48415
  const pendingFollowups = listPendingCeoFollowups();
48322
48416
  if (mailBoxMsgs.length === 0 && pendingFollowups.length === 0) return;
@@ -53443,7 +53537,7 @@ var systemRoutes = new Hono2();
53443
53537
  var startTime = Date.now();
53444
53538
  systemRoutes.get("/system/info", (c) => {
53445
53539
  return c.json({
53446
- version: true ? "1.9.6" : "unknown",
53540
+ version: true ? "1.9.8" : "unknown",
53447
53541
  uptime: Math.floor((Date.now() - startTime) / 1e3),
53448
53542
  env: process.env.NODE_ENV || "development",
53449
53543
  nodeVersion: process.version
@@ -53908,7 +54002,38 @@ function skillRoots() {
53908
54002
  ];
53909
54003
  }
53910
54004
 
54005
+ // src/runtime/processDiagnostics.ts
54006
+ var installed = false;
54007
+ function installProcessDiagnostics(component) {
54008
+ if (installed) return;
54009
+ installed = true;
54010
+ process.on("warning", (warning) => {
54011
+ console.warn(`[${component}] process warning`, {
54012
+ name: warning.name,
54013
+ message: warning.message,
54014
+ stack: warning.stack
54015
+ });
54016
+ });
54017
+ process.on("unhandledRejection", (reason) => {
54018
+ console.error(`[${component}] unhandledRejection`, reason);
54019
+ });
54020
+ process.on("uncaughtException", (err) => {
54021
+ console.error(`[${component}] uncaughtException`, {
54022
+ message: err.message,
54023
+ stack: err.stack
54024
+ });
54025
+ process.exit(1);
54026
+ });
54027
+ process.on("beforeExit", (code) => {
54028
+ console.warn(`[${component}] beforeExit code=${code}`);
54029
+ });
54030
+ process.on("exit", (code) => {
54031
+ console.warn(`[${component}] exit code=${code}`);
54032
+ });
54033
+ }
54034
+
53911
54035
  // src/main.ts
54036
+ installProcessDiagnostics("main");
53912
54037
  var cliResult = handleCliCommand(process.argv.slice(2));
53913
54038
  if (cliResult !== void 0) {
53914
54039
  process.exit(cliResult);
@@ -53970,9 +54095,9 @@ async function main() {
53970
54095
  console.log(`[main] \u591A\u667A\u80FD\u4F53\u90AE\u7BB1\u8F6E\u8BE2\u5DF2\u542F\u52A8`);
53971
54096
  const kanbanPort = Number(process.env.KANBAN_PORT || 3e3);
53972
54097
  startServer(kanbanPort);
53973
- const shutdown = async () => {
54098
+ const shutdown = async (signal) => {
53974
54099
  console.log(`
53975
- [main] \u6536\u5230\u9000\u51FA\u4FE1\u53F7\uFF0C\u6B63\u5728\u505C\u6B62\u6240\u6709 Channel...`);
54100
+ [main] \u6536\u5230\u9000\u51FA\u4FE1\u53F7 ${signal}\uFF0C\u6B63\u5728\u505C\u6B62\u6240\u6709 Channel...`);
53976
54101
  abortController.abort();
53977
54102
  if (channelGatewaysStarted) {
53978
54103
  for (const channel of channels) {