duclaw-cli 1.8.38 → 1.8.39

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.8.38" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.8.39" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -42310,6 +42310,19 @@ var failCeoFollowup = (id, error) => {
42310
42310
  AND status IN ('pending', 'processing', 'failed')
42311
42311
  `).run(error.slice(0, 1e3), now, id);
42312
42312
  };
42313
+ var recoverStaleProcessingCeoFollowups = (staleBefore) => {
42314
+ const db3 = createSqliteDB();
42315
+ const now = Date.now();
42316
+ const result = db3.prepare(`
42317
+ UPDATE ceo_followups
42318
+ SET status = 'failed',
42319
+ last_error = 'stale_processing_recovered',
42320
+ updated_at = ?
42321
+ WHERE status = 'processing'
42322
+ AND updated_at < ?
42323
+ `).run(now, staleBefore);
42324
+ return result.changes;
42325
+ };
42313
42326
  var completePendingCeoFollowupsForUser = (originUserId) => {
42314
42327
  const db3 = createSqliteDB();
42315
42328
  const now = Date.now();
@@ -47042,6 +47055,7 @@ var replyMailbox = {
47042
47055
 
47043
47056
  // src/cron/mailbox.ts
47044
47057
  var db2 = createSqliteDB();
47058
+ var DEFAULT_MAILBOX_PROCESSING_STALE_MS = 15 * 6e4;
47045
47059
  var selectStmt = db2.prepare(`select
47046
47060
  id,
47047
47061
  to_mailbox_id as toMailboxId,
@@ -47057,6 +47071,78 @@ var selectStmt = db2.prepare(`select
47057
47071
  work_item_role as workItemRole,
47058
47072
  upstream_message_id as upstreamMessageId
47059
47073
  from mailbox where status = ?`);
47074
+ var getMailboxLivenessSnapshot = () => {
47075
+ const mailboxRows = db2.prepare(`
47076
+ SELECT status, COUNT(*) as count
47077
+ FROM mailbox
47078
+ WHERE status IN ('pending', 'processing')
47079
+ GROUP BY status
47080
+ `).all();
47081
+ const followupRows = db2.prepare(`
47082
+ SELECT status, COUNT(*) as count
47083
+ FROM ceo_followups
47084
+ WHERE status IN ('pending', 'processing', 'failed')
47085
+ GROUP BY status
47086
+ `).all();
47087
+ const mailboxCount = (status) => mailboxRows.find((row) => row.status === status)?.count ?? 0;
47088
+ const followupCount = (status) => followupRows.find((row) => row.status === status)?.count ?? 0;
47089
+ return {
47090
+ pendingMailbox: mailboxCount("pending"),
47091
+ processingMailbox: mailboxCount("processing"),
47092
+ pendingCeoFollowups: followupCount("pending"),
47093
+ processingCeoFollowups: followupCount("processing"),
47094
+ failedCeoFollowups: followupCount("failed")
47095
+ };
47096
+ };
47097
+ var hasUnresolvedInternalWork = (snapshot) => snapshot.pendingMailbox > 0 || snapshot.processingMailbox > 0 || snapshot.pendingCeoFollowups > 0 || snapshot.processingCeoFollowups > 0 || snapshot.failedCeoFollowups > 0;
47098
+ var reportMailboxLiveness = async (snapshot) => {
47099
+ if (!hasUnresolvedInternalWork(snapshot)) return;
47100
+ await reportRuntimeActivity({
47101
+ kind: "mailbox",
47102
+ toolName: "mailbox_poller",
47103
+ status: "active",
47104
+ metadata: {
47105
+ ...snapshot,
47106
+ inFlightDepartmentMailboxes: Array.from(inFlightDepartmentMailboxes),
47107
+ inFlightCeoFollowups: Array.from(inFlightCeoReplyMessages)
47108
+ }
47109
+ });
47110
+ };
47111
+ var recoverStaleProcessingMailboxMessages = () => {
47112
+ const staleMs = Number(process.env.MAILBOX_PROCESSING_STALE_MS ?? DEFAULT_MAILBOX_PROCESSING_STALE_MS);
47113
+ if (staleMs <= 0) return 0;
47114
+ const staleBefore = Date.now() - staleMs;
47115
+ const rows = db2.prepare(`
47116
+ SELECT
47117
+ id,
47118
+ to_mailbox_id as toMailboxId
47119
+ FROM mailbox
47120
+ WHERE status = 'processing'
47121
+ AND updated_at < ?
47122
+ `).all(staleBefore);
47123
+ let recovered = 0;
47124
+ for (const row of rows) {
47125
+ if (row.toMailboxId === "manager") continue;
47126
+ if (hasRunningAgent(row.toMailboxId) || inFlightDepartmentMailboxes.has(row.toMailboxId)) continue;
47127
+ if (updateMailboxMessageStatus(row.id, "pending", {
47128
+ fromStatus: "processing",
47129
+ actorMailboxId: row.toMailboxId,
47130
+ reason: "stale_processing_recovered"
47131
+ })) {
47132
+ recovered += 1;
47133
+ }
47134
+ }
47135
+ return recovered;
47136
+ };
47137
+ var recoverStaleProcessingWork = () => {
47138
+ const staleMs = Number(process.env.MAILBOX_PROCESSING_STALE_MS ?? DEFAULT_MAILBOX_PROCESSING_STALE_MS);
47139
+ if (staleMs <= 0) return;
47140
+ const mailboxRecovered = recoverStaleProcessingMailboxMessages();
47141
+ const followupsRecovered = recoverStaleProcessingCeoFollowups(Date.now() - staleMs);
47142
+ if (mailboxRecovered > 0 || followupsRecovered > 0) {
47143
+ console.warn(`[mailbox] \u5DF2\u6062\u590D stale processing: mailbox=${mailboxRecovered}, ceo_followups=${followupsRecovered}`);
47144
+ }
47145
+ };
47060
47146
  var markMailboxStatus = (msgId, status) => {
47061
47147
  const fromStatusMap = {
47062
47148
  processing: ["pending"],
@@ -47303,6 +47389,8 @@ var pollMailbox = async () => {
47303
47389
  if (polling) return;
47304
47390
  polling = true;
47305
47391
  try {
47392
+ recoverStaleProcessingWork();
47393
+ await reportMailboxLiveness(getMailboxLivenessSnapshot());
47306
47394
  const mailBoxMsgs = selectStmt.all("pending");
47307
47395
  const pendingFollowups = listPendingCeoFollowups();
47308
47396
  if (mailBoxMsgs.length === 0 && pendingFollowups.length === 0) return;
@@ -52432,7 +52520,7 @@ var systemRoutes = new Hono2();
52432
52520
  var startTime = Date.now();
52433
52521
  systemRoutes.get("/system/info", (c) => {
52434
52522
  return c.json({
52435
- version: true ? "1.8.38" : "unknown",
52523
+ version: true ? "1.8.39" : "unknown",
52436
52524
  uptime: Math.floor((Date.now() - startTime) / 1e3),
52437
52525
  env: process.env.NODE_ENV || "development",
52438
52526
  nodeVersion: process.version