duclaw-cli 1.8.37 → 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.37" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.8.39" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -32629,7 +32629,7 @@ var chokidar_default = { watch, FSWatcher };
32629
32629
  var import_node_cron = __toESM(require_node_cron());
32630
32630
 
32631
32631
  // src/agent/createAgent.ts
32632
- var import_node_crypto11 = require("node:crypto");
32632
+ var import_node_crypto12 = require("node:crypto");
32633
32633
  var import_node_fs7 = require("node:fs");
32634
32634
 
32635
32635
  // src/background/BackgroundManager.ts
@@ -41407,10 +41407,10 @@ var goalDelete = {
41407
41407
  };
41408
41408
 
41409
41409
  // src/tools/tools/department/DepartmentCreate.ts
41410
- var import_node_crypto5 = require("node:crypto");
41410
+ var import_node_crypto6 = require("node:crypto");
41411
41411
 
41412
41412
  // src/department/mailbox/mailbox.ts
41413
- var import_node_crypto4 = require("node:crypto");
41413
+ var import_node_crypto5 = require("node:crypto");
41414
41414
 
41415
41415
  // src/db/createDB.ts
41416
41416
  var import_better_sqlite3 = __toESM(require("better-sqlite3"));
@@ -41433,6 +41433,7 @@ var _ensure_table_exist = () => {
41433
41433
  create_workspace_table();
41434
41434
  create_mailbox_table();
41435
41435
  create_mailbox_events_table();
41436
+ create_ceo_followups_table();
41436
41437
  create_agent_events_table();
41437
41438
  };
41438
41439
  var create_workspace_table = () => {
@@ -41565,6 +41566,34 @@ var create_mailbox_events_table = () => {
41565
41566
  } catch (_) {
41566
41567
  }
41567
41568
  };
41569
+ var create_ceo_followups_table = () => {
41570
+ const db3 = createSqliteDB();
41571
+ db3.exec(`
41572
+ CREATE TABLE IF NOT EXISTS ceo_followups (
41573
+ id TEXT PRIMARY KEY,
41574
+ source_message_id TEXT NOT NULL UNIQUE,
41575
+ status TEXT DEFAULT ('pending') NOT NULL,
41576
+ origin_user_id TEXT NOT NULL,
41577
+ origin_platform TEXT NOT NULL,
41578
+ from_mailbox_id TEXT NOT NULL,
41579
+ thread_id TEXT,
41580
+ parent_message_id TEXT,
41581
+ work_item_id TEXT,
41582
+ content TEXT NOT NULL,
41583
+ attempts INTEGER DEFAULT 0 NOT NULL,
41584
+ last_error TEXT,
41585
+ created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41586
+ updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41587
+ completed_at INTEGER
41588
+ );
41589
+
41590
+ CREATE INDEX IF NOT EXISTS idx_ceo_followups_status_created
41591
+ ON ceo_followups(status, created_at);
41592
+
41593
+ CREATE INDEX IF NOT EXISTS idx_ceo_followups_user_status
41594
+ ON ceo_followups(origin_user_id, status, created_at);
41595
+ `);
41596
+ };
41568
41597
  var create_agent_events_table = () => {
41569
41598
  const db3 = createSqliteDB();
41570
41599
  db3.exec(`
@@ -41771,11 +41800,21 @@ var renderAgentEventReminder = (events) => {
41771
41800
  summary ? `summary=${summary}` : ""
41772
41801
  ].filter(Boolean).join(" ");
41773
41802
  }).join("\n");
41803
+ const hasCeoFollowup = events.some((event) => event.type === "ceo.followup_required");
41804
+ const ceoFollowupInstruction = hasCeoFollowup ? [
41805
+ ``,
41806
+ `CEO followup \u786C\u89C4\u5219\uFF1A`,
41807
+ `- type=ceo.followup_required \u8868\u793A Department Head/Executor \u5DF2\u7ECF\u628A\u5185\u90E8\u7ED3\u679C\u56DE\u7ED9 Main Manager/CEO\u3002`,
41808
+ `- \u8FD9\u4E0D\u662F\u666E\u901A\u63D0\u9192\uFF1BBoss/User \u6B63\u5728\u7B49\u5F85\u6700\u7EC8\u53EF\u89C1\u7ED3\u679C\u3002`,
41809
+ `- \u4F60\u5FC5\u987B\u8BFB\u53D6 summary/contentPreview\uFF0C\u76F4\u63A5\u8C03\u7528 send_message \u5411 Boss/User \u6C47\u62A5\u7ED3\u679C\u3002`,
41810
+ `- \u4E0D\u8981\u53EA\u8BF4\u201C\u6682\u65E0\u56DE\u4FE1/\u8FD8\u5728\u6267\u884C/\u7A0D\u540E\u540C\u6B65\u201D\uFF0C\u9664\u975E summary \u660E\u786E\u8BF4\u660E\u4ECD\u5728\u7B49\u5F85\u6216\u5931\u8D25\u3002`
41811
+ ].join("\n") : "";
41774
41812
  return `<system-reminder>
41775
41813
  \u672C\u8F6E\u6709 ${events.length} \u6761\u5185\u90E8\u4E8B\u4EF6\u53EF\u7528\uFF1A
41776
41814
  ${lines}
41777
41815
 
41778
41816
  \u8FD9\u4E9B\u4E8B\u4EF6\u4E0D\u662F\u7528\u6237\u7684\u65B0\u8BF7\u6C42\uFF0C\u4E5F\u4E0D\u5E94\u8BE5\u4F5C\u4E3A\u7528\u6237\u786E\u8BA4\u3002\u82E5\u4E8B\u4EF6\u7C7B\u578B\u662F mailbox.message_received\uFF0C\u8868\u793A\u4F60\u7684 mailbox \u5728\u5F53\u524D\u5DE5\u4F5C\u671F\u95F4\u6536\u5230\u65B0\u5185\u90E8\u534F\u4F5C\u6D88\u606F\uFF1B\u8BF7\u5C3D\u5FEB\u8C03\u7528 list_mailbox \u67E5\u770B\u961F\u5217\uFF0C\u5E76\u5728\u9700\u8981\u65F6\u7528 get_mailbox(message_id) \u9886\u53D6\u5173\u8054\u6D88\u606F\u3002\u4E0D\u8981\u76F4\u63A5\u628A\u4E8B\u4EF6\u5F53\u4F5C\u5DF2\u9886\u53D6\u90AE\u4EF6\u3002\u8BF7\u53EA\u5728\u9700\u8981\u65F6\u81EA\u7136\u5730\u6C47\u603B\u7ED9\u7528\u6237\uFF1B\u5982\u9700\u7EE7\u7EED\u534F\u4F5C\uFF0C\u4F18\u5148\u4F7F\u7528\u4E8B\u4EF6\u4E2D\u5173\u8054\u7684 mailboxMessageId/thread \u7EE7\u7EED\u5904\u7406\u3002\u4E0D\u8981\u590D\u8FF0\u672C system-reminder\u3002
41817
+ ${ceoFollowupInstruction}
41779
41818
  </system-reminder>`;
41780
41819
  };
41781
41820
 
@@ -42104,6 +42143,221 @@ var deleteDepartmentMemberById = (departmentName, memberId) => {
42104
42143
  deleteWorkspace(workspaceId);
42105
42144
  };
42106
42145
 
42146
+ // src/department/mailbox/ceoFollowup.ts
42147
+ var import_node_crypto4 = require("node:crypto");
42148
+ var rowToFollowup = (row) => ({
42149
+ id: row.id,
42150
+ sourceMessageId: row.sourceMessageId,
42151
+ status: row.status,
42152
+ originUserId: row.originUserId,
42153
+ originPlatform: row.originPlatform,
42154
+ fromMailboxId: row.fromMailboxId,
42155
+ threadId: row.threadId ?? void 0,
42156
+ parentMessageId: row.parentMessageId ?? void 0,
42157
+ workItemId: row.workItemId ?? void 0,
42158
+ content: row.content,
42159
+ attempts: row.attempts,
42160
+ lastError: row.lastError ?? void 0,
42161
+ createdAt: row.createdAt,
42162
+ updatedAt: row.updatedAt,
42163
+ completedAt: row.completedAt ?? void 0
42164
+ });
42165
+ var selectById = (id) => {
42166
+ const db3 = createSqliteDB();
42167
+ const row = db3.prepare(`
42168
+ SELECT
42169
+ id,
42170
+ source_message_id as sourceMessageId,
42171
+ status,
42172
+ origin_user_id as originUserId,
42173
+ origin_platform as originPlatform,
42174
+ from_mailbox_id as fromMailboxId,
42175
+ thread_id as threadId,
42176
+ parent_message_id as parentMessageId,
42177
+ work_item_id as workItemId,
42178
+ content,
42179
+ attempts,
42180
+ last_error as lastError,
42181
+ created_at as createdAt,
42182
+ updated_at as updatedAt,
42183
+ completed_at as completedAt
42184
+ FROM ceo_followups
42185
+ WHERE id = ?
42186
+ `).get(id);
42187
+ return row ? rowToFollowup(row) : null;
42188
+ };
42189
+ var enqueueCeoFollowupFromMailbox = (message) => {
42190
+ if (message.toMailboxId !== "manager") return null;
42191
+ if (!message.originUserId || !message.originPlatform) return null;
42192
+ const db3 = createSqliteDB();
42193
+ const now = Date.now();
42194
+ const id = `cfu_${(0, import_node_crypto4.randomUUID)().slice(0, 12)}`;
42195
+ db3.prepare(`
42196
+ INSERT INTO ceo_followups (
42197
+ id,
42198
+ source_message_id,
42199
+ status,
42200
+ origin_user_id,
42201
+ origin_platform,
42202
+ from_mailbox_id,
42203
+ thread_id,
42204
+ parent_message_id,
42205
+ work_item_id,
42206
+ content,
42207
+ created_at,
42208
+ updated_at
42209
+ ) VALUES (?, ?, 'pending', ?, ?, ?, ?, ?, ?, ?, ?, ?)
42210
+ ON CONFLICT(source_message_id) DO UPDATE SET
42211
+ status = CASE
42212
+ WHEN ceo_followups.status = 'completed' THEN ceo_followups.status
42213
+ ELSE 'pending'
42214
+ END,
42215
+ origin_user_id = excluded.origin_user_id,
42216
+ origin_platform = excluded.origin_platform,
42217
+ from_mailbox_id = excluded.from_mailbox_id,
42218
+ thread_id = excluded.thread_id,
42219
+ parent_message_id = excluded.parent_message_id,
42220
+ work_item_id = excluded.work_item_id,
42221
+ content = excluded.content,
42222
+ updated_at = excluded.updated_at
42223
+ `).run(
42224
+ id,
42225
+ message.id,
42226
+ message.originUserId,
42227
+ message.originPlatform,
42228
+ message.fromMailboxId,
42229
+ message.threadId ?? message.id,
42230
+ message.parentMessageId ?? null,
42231
+ message.workItemId ?? null,
42232
+ message.content,
42233
+ now,
42234
+ now
42235
+ );
42236
+ const row = db3.prepare(`
42237
+ SELECT id FROM ceo_followups WHERE source_message_id = ?
42238
+ `).get(message.id);
42239
+ return row ? selectById(row.id) : null;
42240
+ };
42241
+ var listPendingCeoFollowups = (limit = 10) => {
42242
+ const db3 = createSqliteDB();
42243
+ const rows = db3.prepare(`
42244
+ SELECT
42245
+ id,
42246
+ source_message_id as sourceMessageId,
42247
+ status,
42248
+ origin_user_id as originUserId,
42249
+ origin_platform as originPlatform,
42250
+ from_mailbox_id as fromMailboxId,
42251
+ thread_id as threadId,
42252
+ parent_message_id as parentMessageId,
42253
+ work_item_id as workItemId,
42254
+ content,
42255
+ attempts,
42256
+ last_error as lastError,
42257
+ created_at as createdAt,
42258
+ updated_at as updatedAt,
42259
+ completed_at as completedAt
42260
+ FROM ceo_followups
42261
+ WHERE status IN ('pending', 'failed')
42262
+ ORDER BY created_at ASC
42263
+ LIMIT ?
42264
+ `).all(limit);
42265
+ return rows.map(rowToFollowup);
42266
+ };
42267
+ var claimCeoFollowup = (id) => {
42268
+ const db3 = createSqliteDB();
42269
+ const now = Date.now();
42270
+ const result = db3.prepare(`
42271
+ UPDATE ceo_followups
42272
+ SET status = 'processing',
42273
+ attempts = attempts + 1,
42274
+ updated_at = ?
42275
+ WHERE id = ?
42276
+ AND status IN ('pending', 'failed')
42277
+ `).run(now, id);
42278
+ if (result.changes === 0) return null;
42279
+ return selectById(id);
42280
+ };
42281
+ var completeCeoFollowup = (id) => {
42282
+ const db3 = createSqliteDB();
42283
+ const now = Date.now();
42284
+ db3.prepare(`
42285
+ UPDATE ceo_followups
42286
+ SET status = 'completed',
42287
+ completed_at = COALESCE(completed_at, ?),
42288
+ updated_at = ?,
42289
+ last_error = NULL
42290
+ WHERE id = ?
42291
+ AND status IN ('pending', 'processing', 'failed')
42292
+ `).run(now, now, id);
42293
+ db3.prepare(`
42294
+ UPDATE mailbox
42295
+ SET status = 'done',
42296
+ updated_at = ?
42297
+ WHERE id = (SELECT source_message_id FROM ceo_followups WHERE id = ?)
42298
+ AND status IN ('pending', 'processing', 'read')
42299
+ `).run(now, id);
42300
+ };
42301
+ var failCeoFollowup = (id, error) => {
42302
+ const db3 = createSqliteDB();
42303
+ const now = Date.now();
42304
+ db3.prepare(`
42305
+ UPDATE ceo_followups
42306
+ SET status = 'failed',
42307
+ last_error = ?,
42308
+ updated_at = ?
42309
+ WHERE id = ?
42310
+ AND status IN ('pending', 'processing', 'failed')
42311
+ `).run(error.slice(0, 1e3), now, id);
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
+ };
42326
+ var completePendingCeoFollowupsForUser = (originUserId) => {
42327
+ const db3 = createSqliteDB();
42328
+ const now = Date.now();
42329
+ const rows = db3.prepare(`
42330
+ SELECT id, source_message_id as sourceMessageId
42331
+ FROM ceo_followups
42332
+ WHERE origin_user_id = ?
42333
+ AND status IN ('pending', 'processing', 'failed')
42334
+ `).all(originUserId);
42335
+ const tx = db3.transaction((items) => {
42336
+ const completeStmt = db3.prepare(`
42337
+ UPDATE ceo_followups
42338
+ SET status = 'completed',
42339
+ completed_at = COALESCE(completed_at, ?),
42340
+ updated_at = ?,
42341
+ last_error = NULL
42342
+ WHERE id = ?
42343
+ AND status IN ('pending', 'processing', 'failed')
42344
+ `);
42345
+ const doneStmt = db3.prepare(`
42346
+ UPDATE mailbox
42347
+ SET status = 'done',
42348
+ updated_at = ?
42349
+ WHERE id = ?
42350
+ AND status IN ('pending', 'processing', 'read')
42351
+ `);
42352
+ for (const item of items) {
42353
+ completeStmt.run(now, now, item.id);
42354
+ doneStmt.run(now, item.sourceMessageId);
42355
+ }
42356
+ });
42357
+ tx(rows);
42358
+ return rows.length;
42359
+ };
42360
+
42107
42361
  // src/department/mailbox/mailbox.ts
42108
42362
  var getMailBoxId = (departmentName, memberName) => {
42109
42363
  return `${departmentName}::${memberName}`;
@@ -42267,7 +42521,7 @@ var recordMailboxReceivedAgentEvent = (msg) => {
42267
42521
  };
42268
42522
  var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
42269
42523
  const db3 = createSqliteDB();
42270
- const id = (0, import_node_crypto4.randomUUID)().slice(0, 8);
42524
+ const id = (0, import_node_crypto5.randomUUID)().slice(0, 8);
42271
42525
  const threadId = options?.threadId || id;
42272
42526
  const workItemContext = resolveWorkItemContext(fromMailboxId, toMailboxId, id, options);
42273
42527
  const stmt = db3.prepare(`insert into mailbox (
@@ -42332,6 +42586,7 @@ var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
42332
42586
  });
42333
42587
  recordMailboxReceivedAgentEvent(mailboxMsg);
42334
42588
  queueMailboxInterruptIfRunning(mailboxMsg);
42589
+ enqueueCeoFollowupFromMailbox(mailboxMsg);
42335
42590
  return mailboxMsg;
42336
42591
  };
42337
42592
  var updateMailboxMessageStatus = (messageId, nextStatus, options) => {
@@ -42409,7 +42664,7 @@ var departmentCreate = {
42409
42664
  return `[departmentCreate] \u4E0D\u5B58\u5728 id=${sourceGoalId} \u7684\u76EE\u6807`;
42410
42665
  }
42411
42666
  let departmentDefinition = {
42412
- id: (0, import_node_crypto5.randomUUID)().slice(0, 8),
42667
+ id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
42413
42668
  name,
42414
42669
  charter,
42415
42670
  sourceGoalId,
@@ -42652,7 +42907,7 @@ var departmentList = {
42652
42907
  };
42653
42908
 
42654
42909
  // src/tools/tools/department/DepartmentMemberCreate.ts
42655
- var import_node_crypto6 = require("node:crypto");
42910
+ var import_node_crypto7 = require("node:crypto");
42656
42911
  var DESCRIPTION24 = `
42657
42912
  \u521B\u5EFA\u90E8\u95E8\u6210\u5458\u3002
42658
42913
 
@@ -42718,7 +42973,7 @@ var departmentMemberCreate = {
42718
42973
  }
42719
42974
  }
42720
42975
  let departmentMember = {
42721
- id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
42976
+ id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
42722
42977
  name,
42723
42978
  departmentId: department.id,
42724
42979
  mailBoxId: getMailBoxId(department.name, name),
@@ -42909,7 +43164,7 @@ ${replies}`;
42909
43164
  // src/department/learning.ts
42910
43165
  var import_node_fs4 = require("node:fs");
42911
43166
  var import_node_path12 = __toESM(require("node:path"));
42912
- var import_node_crypto7 = require("node:crypto");
43167
+ var import_node_crypto8 = require("node:crypto");
42913
43168
 
42914
43169
  // src/skill/SkillValidator.ts
42915
43170
  var import_node_fs3 = require("node:fs");
@@ -43147,7 +43402,7 @@ var listDepartmentMemories = (departmentName) => {
43147
43402
  var createDepartmentMemory = (departmentName, input) => {
43148
43403
  const now = Date.now();
43149
43404
  const memory = {
43150
- id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
43405
+ id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43151
43406
  departmentName,
43152
43407
  title: input.title,
43153
43408
  content: input.content,
@@ -43198,7 +43453,7 @@ ${formatSkillValidationIssues(validation)}`);
43198
43453
  }
43199
43454
  const now = Date.now();
43200
43455
  const skill = {
43201
- id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
43456
+ id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43202
43457
  departmentName,
43203
43458
  skillName: input.skillName,
43204
43459
  description: input.description,
@@ -43250,7 +43505,7 @@ var createDepartmentProposal = (input) => {
43250
43505
  const records = readJsonArray(proposalsPath());
43251
43506
  const proposal = {
43252
43507
  ...input,
43253
- id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
43508
+ id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43254
43509
  status: "pending",
43255
43510
  createdAt: Date.now()
43256
43511
  };
@@ -43581,7 +43836,7 @@ var mailboxFollowup = {
43581
43836
 
43582
43837
  // src/tools/tools/Bash.ts
43583
43838
  var import_node_child_process = require("node:child_process");
43584
- var import_node_crypto8 = require("node:crypto");
43839
+ var import_node_crypto9 = require("node:crypto");
43585
43840
  var import_node_fs5 = require("node:fs");
43586
43841
  var DESCRIPTION29 = `\u5728\u7CFB\u7EDF shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002
43587
43842
 
@@ -43785,7 +44040,7 @@ var bashTool = {
43785
44040
  ...options,
43786
44041
  stdio: ["pipe", "pipe", "pipe"]
43787
44042
  });
43788
- const id = (0, import_node_crypto8.randomUUID)().slice(0, 8);
44043
+ const id = (0, import_node_crypto9.randomUUID)().slice(0, 8);
43789
44044
  const session = {
43790
44045
  id,
43791
44046
  command,
@@ -44366,7 +44621,7 @@ var readDreamHistoryLimit = () => {
44366
44621
  var import_node_fs6 = require("node:fs");
44367
44622
  var import_node_os2 = require("node:os");
44368
44623
  var import_node_path13 = require("node:path");
44369
- var import_node_crypto9 = require("node:crypto");
44624
+ var import_node_crypto10 = require("node:crypto");
44370
44625
  var SkillForgeEngine = class {
44371
44626
  proposalStorage;
44372
44627
  draftRoot;
@@ -44400,7 +44655,7 @@ ${formatSkillValidationIssues(validation)}`);
44400
44655
  if (pending.some((p) => p.skillName === skillName)) {
44401
44656
  return null;
44402
44657
  }
44403
- const id = (0, import_node_crypto9.randomBytes)(4).toString("hex");
44658
+ const id = (0, import_node_crypto10.randomBytes)(4).toString("hex");
44404
44659
  const draftDir = (0, import_node_path13.join)(this.draftRoot, userId, id);
44405
44660
  (0, import_node_fs6.mkdirSync)(draftDir, { recursive: true });
44406
44661
  (0, import_node_fs6.writeFileSync)((0, import_node_path13.join)(draftDir, "SKILL.md"), skillMd, "utf-8");
@@ -44682,7 +44937,7 @@ var skillForgeDrop = (engine) => ({
44682
44937
  });
44683
44938
 
44684
44939
  // src/memory/MemoryEngine.ts
44685
- var import_node_crypto10 = require("node:crypto");
44940
+ var import_node_crypto11 = require("node:crypto");
44686
44941
  var MemoryEngine = class {
44687
44942
  storage;
44688
44943
  recallIndexStorage;
@@ -44710,7 +44965,7 @@ var MemoryEngine = class {
44710
44965
  }
44711
44966
  const now = Date.now();
44712
44967
  const memory = {
44713
- id: (0, import_node_crypto10.randomBytes)(4).toString("hex"),
44968
+ id: (0, import_node_crypto11.randomBytes)(4).toString("hex"),
44714
44969
  userId,
44715
44970
  title,
44716
44971
  content,
@@ -45376,7 +45631,7 @@ var isAbortError2 = (error) => {
45376
45631
  return error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("AbortError");
45377
45632
  };
45378
45633
  var llmRequestIdForTurn = (request, messages, system, tools) => {
45379
- const hash = (0, import_node_crypto11.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
45634
+ const hash = (0, import_node_crypto12.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
45380
45635
  return `dreq_${hash}`;
45381
45636
  };
45382
45637
  var getDefaultAgentConfig = (tools, systemPrompt) => {
@@ -45982,6 +46237,7 @@ ${memoryInjection}` : "") + dreamInjection;
45982
46237
  }
45983
46238
  hasSentMessage = true;
45984
46239
  sentMessageContent = answer;
46240
+ completePendingCeoFollowupsForUser(request.userId);
45985
46241
  }
45986
46242
  }
45987
46243
  if (useBlock.name === `send_file`) {
@@ -46799,12 +47055,98 @@ var replyMailbox = {
46799
47055
 
46800
47056
  // src/cron/mailbox.ts
46801
47057
  var db2 = createSqliteDB();
46802
- var selectStmt = db2.prepare(`select id, to_mailbox_id as toMailboxId, from_mailbox_id as fromMailboxId, content, send_time as sendTime, status
47058
+ var DEFAULT_MAILBOX_PROCESSING_STALE_MS = 15 * 6e4;
47059
+ var selectStmt = db2.prepare(`select
47060
+ id,
47061
+ to_mailbox_id as toMailboxId,
47062
+ from_mailbox_id as fromMailboxId,
47063
+ content,
47064
+ send_time as sendTime,
47065
+ status,
47066
+ origin_user_id as originUserId,
47067
+ origin_platform as originPlatform,
47068
+ thread_id as threadId,
47069
+ parent_message_id as parentMessageId,
47070
+ work_item_id as workItemId,
47071
+ work_item_role as workItemRole,
47072
+ upstream_message_id as upstreamMessageId
46803
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
+ };
46804
47146
  var markMailboxStatus = (msgId, status) => {
46805
47147
  const fromStatusMap = {
46806
47148
  processing: ["pending"],
46807
- done: ["processing"],
47149
+ done: ["pending", "processing", "read"],
46808
47150
  failed: ["processing"],
46809
47151
  cancelled: ["pending", "processing"],
46810
47152
  pending: ["processing"]
@@ -46814,75 +47156,87 @@ var markMailboxStatus = (msgId, status) => {
46814
47156
  reason: "mailbox_poller"
46815
47157
  });
46816
47158
  };
46817
- var handleCeoReply = async (replyMsg) => {
46818
- const { fromMailboxId, content } = replyMsg;
46819
- const originStmt = db2.prepare(
46820
- `SELECT origin_user_id as originUserId, origin_platform as originPlatform
46821
- FROM mailbox
46822
- WHERE from_mailbox_id = 'manager' AND to_mailbox_id = ? AND origin_user_id IS NOT NULL
46823
- ORDER BY send_time DESC LIMIT 1`
46824
- );
46825
- const origin = originStmt.get(fromMailboxId);
46826
- if (!origin || !origin.originUserId) {
46827
- console.warn(`[mailbox] \u65E0\u6CD5\u627E\u5230 ${fromMailboxId} \u7684\u539F\u59CB\u7528\u6237\u4E0A\u4E0B\u6587\uFF0C\u8DF3\u8FC7\u5524\u9192`);
46828
- return;
46829
- }
46830
- console.log(`[mailbox] \u627E\u5230\u539F\u59CB\u7528\u6237\u4E0A\u4E0B\u6587: userId=${origin.originUserId}, platform=${origin.originPlatform}`);
47159
+ var handleCeoFollowup = async (followup) => {
46831
47160
  const event = recordAgentEvent({
46832
- userId: origin.originUserId,
46833
- type: "department.reply_received",
46834
- source: "mailbox",
46835
- sourceId: replyMsg.id,
47161
+ userId: followup.originUserId,
47162
+ type: "ceo.followup_required",
47163
+ source: "ceo_followup",
47164
+ sourceId: followup.id,
46836
47165
  payload: {
46837
- ownerMailboxId: fromMailboxId,
46838
- mailboxMessageId: replyMsg.id,
46839
- threadId: replyMsg.threadId || replyMsg.id,
46840
- parentMessageId: replyMsg.parentMessageId || null,
46841
- contentPreview: content.slice(0, 600),
46842
- originPlatform: origin.originPlatform
47166
+ ownerMailboxId: followup.fromMailboxId,
47167
+ mailboxMessageId: followup.sourceMessageId,
47168
+ ceoFollowupId: followup.id,
47169
+ threadId: followup.threadId || followup.sourceMessageId,
47170
+ parentMessageId: followup.parentMessageId || null,
47171
+ workItemId: followup.workItemId || null,
47172
+ contentPreview: followup.content.slice(0, 1200),
47173
+ summary: `\u90E8\u95E8\u5DF2\u56DE\u4FE1\uFF0CMain Manager/CEO \u5FC5\u987B\u5C06\u7ED3\u679C\u901A\u8FC7 send_message \u6C47\u62A5\u7ED9 Boss/User\uFF1A${followup.content.slice(0, 400)}`,
47174
+ originPlatform: followup.originPlatform
46843
47175
  }
46844
47176
  });
46845
- if (hasRunningAgent(origin.originUserId)) {
46846
- queueInterrupt(origin.originUserId, {
47177
+ if (hasRunningAgent(followup.originUserId)) {
47178
+ queueInterrupt(followup.originUserId, {
46847
47179
  content: "",
46848
47180
  metadata: {
46849
47181
  internalOnly: true,
46850
47182
  eventId: event.id,
46851
- trigger: "department.reply_received"
47183
+ trigger: "ceo.followup_required"
46852
47184
  }
46853
47185
  });
46854
- console.log(`[mailbox] \u4E3B agent \u6B63\u5728\u8FD0\u884C\u4E2D\uFF0C${fromMailboxId} \u7684\u56DE\u4FE1\u5DF2\u5165\u961F\u7B49\u5F85\u4E2D\u65AD\u6CE8\u5165`);
46855
- return;
47186
+ console.log(`[mailbox] \u4E3B agent \u6B63\u5728\u8FD0\u884C\u4E2D\uFF0C${followup.fromMailboxId} \u7684\u56DE\u4FE1\u5DF2\u5165\u961F\u7B49\u5F85\u4E2D\u65AD\u6CE8\u5165 followup=${followup.id}`);
47187
+ return "queued";
46856
47188
  }
46857
47189
  const request = {
46858
- platform: origin.originPlatform,
46859
- userId: origin.originUserId,
46860
- requestId: replyMsg.id,
47190
+ platform: followup.originPlatform,
47191
+ userId: followup.originUserId,
47192
+ requestId: followup.sourceMessageId,
46861
47193
  departmentAgentId: "",
46862
47194
  content: "",
46863
47195
  metadata: {
46864
47196
  internalOnly: true,
46865
47197
  eventId: event.id,
46866
- trigger: "department.reply_received"
47198
+ trigger: "ceo.followup_required",
47199
+ ceoFollowupId: followup.id
46867
47200
  }
46868
47201
  };
46869
47202
  const config2 = getDefaultAgentConfig();
46870
47203
  const mainAgent = createAgent(config2);
46871
47204
  const result = await mainAgent(request);
46872
- console.log(`[mailbox] \u4E3B agent \u5904\u7406\u5B8C ${fromMailboxId} \u7684\u56DE\u4FE1, alreadySent=${result.alreadySent}`);
46873
- if (!result.alreadySent && result.content && config2.channelPlugin) {
47205
+ console.log(`[mailbox] \u4E3B agent \u5904\u7406\u5B8C ${followup.fromMailboxId} \u7684\u56DE\u4FE1, alreadySent=${result.alreadySent}`);
47206
+ if (result.alreadySent) return "completed";
47207
+ const fallback = result.content?.trim() || followup.content;
47208
+ if (fallback && config2.channelPlugin) {
46874
47209
  try {
46875
47210
  await config2.channelPlugin.outbound.sendText({
46876
47211
  cfg: {},
46877
- to: origin.originUserId,
46878
- text: result.content,
46879
- accountId: replyMsg.id
47212
+ to: followup.originUserId,
47213
+ text: fallback,
47214
+ accountId: followup.sourceMessageId
46880
47215
  });
46881
- console.log(`[mailbox] \u4E3B agent \u672A\u4E3B\u52A8\u53D1\u9001\uFF0C\u5DF2\u901A\u8FC7\u6E20\u9053\u8865\u53D1\u7ED3\u679C\u7ED9\u7528\u6237 ${origin.originUserId}`);
47216
+ console.log(`[mailbox] \u4E3B agent \u672A\u4E3B\u52A8\u53D1\u9001\uFF0C\u5DF2\u901A\u8FC7\u6E20\u9053\u8865\u53D1 followup=${followup.id} \u7ED9\u7528\u6237 ${followup.originUserId}`);
47217
+ return "completed";
46882
47218
  } catch (sendErr) {
46883
47219
  console.error(`[mailbox] \u8865\u53D1\u6D88\u606F\u5931\u8D25:`, sendErr);
47220
+ throw sendErr;
46884
47221
  }
46885
47222
  }
47223
+ if (fallback && !config2.channelPlugin) return "completed";
47224
+ throw new Error(`ceo_followup_no_user_visible_message:${followup.id}`);
47225
+ };
47226
+ var processCeoFollowup = async (followup) => {
47227
+ const claimed = claimCeoFollowup(followup.id);
47228
+ if (!claimed) return;
47229
+ try {
47230
+ markMailboxStatus(claimed.sourceMessageId, "processing");
47231
+ const outcome = await handleCeoFollowup(claimed);
47232
+ if (outcome === "queued") return;
47233
+ completeCeoFollowup(claimed.id);
47234
+ markMailboxStatus(claimed.sourceMessageId, "done");
47235
+ } catch (err) {
47236
+ const message = err.message;
47237
+ failCeoFollowup(claimed.id, message);
47238
+ console.error(`[mailbox] CEO followup \u5904\u7406\u5931\u8D25 followup=${claimed.id}:`, err);
47239
+ }
46886
47240
  };
46887
47241
  var wakeDepartmentAgent = async (mailboxId, msgIds) => {
46888
47242
  try {
@@ -47035,8 +47389,11 @@ var pollMailbox = async () => {
47035
47389
  if (polling) return;
47036
47390
  polling = true;
47037
47391
  try {
47392
+ recoverStaleProcessingWork();
47393
+ await reportMailboxLiveness(getMailboxLivenessSnapshot());
47038
47394
  const mailBoxMsgs = selectStmt.all("pending");
47039
- if (mailBoxMsgs.length === 0) return;
47395
+ const pendingFollowups = listPendingCeoFollowups();
47396
+ if (mailBoxMsgs.length === 0 && pendingFollowups.length === 0) return;
47040
47397
  console.log(`[mailbox] \u62C9\u53D6\u5230 ${mailBoxMsgs.length} \u6761\u5F85\u5904\u7406\u6D88\u606F`);
47041
47398
  const grouped = /* @__PURE__ */ new Map();
47042
47399
  for (const msg of mailBoxMsgs) {
@@ -47046,20 +47403,28 @@ var pollMailbox = async () => {
47046
47403
  }
47047
47404
  const ceoMsgs = grouped.get("manager") || [];
47048
47405
  grouped.delete("manager");
47406
+ const newFollowups = [];
47049
47407
  for (const msg of ceoMsgs) {
47050
- if (inFlightCeoReplyMessages.has(msg.id)) continue;
47051
- inFlightCeoReplyMessages.add(msg.id);
47052
- console.log(`[mailbox] \u6536\u5230 department agent \u56DE\u4FE1\uFF08\u6765\u81EA ${msg.fromMailboxId}\uFF09\uFF0C\u6B63\u5728\u5524\u9192\u4E3B agent...`);
47408
+ const followup = enqueueCeoFollowupFromMailbox(msg);
47409
+ if (followup) {
47410
+ newFollowups.push(followup);
47411
+ } else {
47412
+ console.warn(`[mailbox] \u6536\u5230\u53D1\u7ED9 manager \u7684\u56DE\u4FE1 ${msg.id}\uFF0C\u4F46\u7F3A\u5C11\u7528\u6237\u4E0A\u4E0B\u6587\uFF0C\u65E0\u6CD5\u521B\u5EFA CEO followup`);
47413
+ }
47414
+ }
47415
+ const followups = [...pendingFollowups, ...newFollowups];
47416
+ const uniqueFollowups = Array.from(new Map(followups.map((followup) => [followup.id, followup])).values());
47417
+ for (const followup of uniqueFollowups) {
47418
+ if (inFlightCeoReplyMessages.has(followup.id)) continue;
47419
+ inFlightCeoReplyMessages.add(followup.id);
47420
+ console.log(`[mailbox] \u6536\u5230 department agent \u56DE\u4FE1\uFF08\u6765\u81EA ${followup.fromMailboxId}\uFF09\uFF0C\u6B63\u5728\u5524\u9192\u4E3B agent followup=${followup.id}...`);
47053
47421
  void (async () => {
47054
47422
  try {
47055
- markMailboxStatus(msg.id, "processing");
47056
- await handleCeoReply(msg);
47057
- markMailboxStatus(msg.id, "done");
47423
+ await processCeoFollowup(followup);
47058
47424
  } catch (err) {
47059
47425
  console.error(`[mailbox] \u5524\u9192\u4E3B agent \u5904\u7406\u56DE\u4FE1\u5931\u8D25:`, err);
47060
- markMailboxStatus(msg.id, "failed");
47061
47426
  } finally {
47062
- inFlightCeoReplyMessages.delete(msg.id);
47427
+ inFlightCeoReplyMessages.delete(followup.id);
47063
47428
  }
47064
47429
  })();
47065
47430
  }
@@ -52155,7 +52520,7 @@ var systemRoutes = new Hono2();
52155
52520
  var startTime = Date.now();
52156
52521
  systemRoutes.get("/system/info", (c) => {
52157
52522
  return c.json({
52158
- version: true ? "1.8.37" : "unknown",
52523
+ version: true ? "1.8.39" : "unknown",
52159
52524
  uptime: Math.floor((Date.now() - startTime) / 1e3),
52160
52525
  env: process.env.NODE_ENV || "development",
52161
52526
  nodeVersion: process.version