@ai-setting/roy-agent-core 1.7.77 → 1.7.88

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.
Files changed (155) hide show
  1. package/dist/config/config-protection.d.ts +89 -0
  2. package/dist/config/index.d.ts +1 -0
  3. package/dist/config/index.js +23 -7
  4. package/dist/env/agent/agent-component.d.ts +43 -22
  5. package/dist/env/agent/agent-component.js +13 -12
  6. package/dist/env/agent/index.js +13 -12
  7. package/dist/env/agent/types.d.ts +46 -12
  8. package/dist/env/commands/index.js +7 -7
  9. package/dist/env/context/index.js +3 -3
  10. package/dist/env/debug/index.js +7 -7
  11. package/dist/env/error-reply.d.ts +6 -0
  12. package/dist/env/error-reply.js +1 -1
  13. package/dist/env/event-source/bounty-im-handler.d.ts +8 -0
  14. package/dist/env/event-source/es-command.d.ts +39 -0
  15. package/dist/env/event-source/es-plugins.d.ts +68 -0
  16. package/dist/env/event-source/event-source-component.d.ts +15 -0
  17. package/dist/env/event-source/event-source-handlers.d.ts +84 -0
  18. package/dist/env/event-source/event-source-handlers.js +40 -23
  19. package/dist/env/event-source/event-store.js +2 -2
  20. package/dist/env/event-source/index.d.ts +5 -1
  21. package/dist/env/event-source/index.js +75 -23
  22. package/dist/env/event-source/timer-handler.d.ts +98 -0
  23. package/dist/env/event-source/types.d.ts +154 -2
  24. package/dist/env/event-source/wecom-card-action-handler.d.ts +373 -0
  25. package/dist/env/event-source/wecom-card-builder.d.ts +426 -0
  26. package/dist/env/event-source/wecom-cli-handler.d.ts +291 -0
  27. package/dist/env/event-source/wecom-cli-sender.d.ts +88 -0
  28. package/dist/env/event-source/wecom-media.d.ts +130 -0
  29. package/dist/env/event-source/wecom-respond-registry.d.ts +151 -0
  30. package/dist/env/event-source/wecom-respond-registry.js +33 -0
  31. package/dist/env/event-source/wecom-session-card-sender.d.ts +135 -0
  32. package/dist/env/event-source/wecom-session-card-sender.js +153 -0
  33. package/dist/env/event-source/wecom-ws-bridge.d.ts +213 -0
  34. package/dist/env/hook/index.js +5 -5
  35. package/dist/env/index.js +51 -45
  36. package/dist/env/llm/index.js +9 -8
  37. package/dist/env/log-trace/index.js +7 -7
  38. package/dist/env/log-trace/trace-filters.d.ts +6 -1
  39. package/dist/env/mcp/index.js +7 -7
  40. package/dist/env/memory/index.js +7 -7
  41. package/dist/env/plugin/index.js +7 -7
  42. package/dist/env/prompt/index.js +8 -8
  43. package/dist/env/prompt/prompts-index.d.ts +1 -1
  44. package/dist/env/session/group-session-link.d.ts +99 -0
  45. package/dist/env/session/index.js +11 -10
  46. package/dist/env/session/session-component.d.ts +89 -0
  47. package/dist/env/session/storage/index.js +5 -4
  48. package/dist/env/session/types.d.ts +10 -0
  49. package/dist/env/skill/index.js +7 -7
  50. package/dist/env/task/delegate/delegate-channel-hint.d.ts +39 -0
  51. package/dist/env/task/delegate/delegate-tool.d.ts +132 -7
  52. package/dist/env/task/delegate/delegate-tool.js +13 -9
  53. package/dist/env/task/delegate/index.js +8 -8
  54. package/dist/env/task/index.js +18 -18
  55. package/dist/env/task/mcp/index.js +4 -4
  56. package/dist/env/task/plugins/card-subject.d.ts +117 -0
  57. package/dist/env/task/plugins/index.d.ts +2 -0
  58. package/dist/env/task/plugins/index.js +39 -16
  59. package/dist/env/task/plugins/lark-card-action-handler.d.ts +261 -6
  60. package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +542 -2
  61. package/dist/env/task/plugins/lark-card-patch-notifier.js +12 -2
  62. package/dist/env/task/plugins/lark-card-state-store.d.ts +60 -0
  63. package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +61 -0
  64. package/dist/env/task/plugins/sub-session-activity.d.ts +415 -0
  65. package/dist/env/task/plugins/wecom-card-state-store.d.ts +121 -0
  66. package/dist/env/task/plugins/wecom-session-card-store.d.ts +134 -0
  67. package/dist/env/task/plugins/wecom-session-card-store.js +23 -0
  68. package/dist/env/task/plugins/wecom-task-notify-plugin.d.ts +264 -0
  69. package/dist/env/task/storage/index.js +3 -3
  70. package/dist/env/task/tools/index.js +4 -4
  71. package/dist/env/tool/built-in/index.d.ts +2 -0
  72. package/dist/env/tool/built-in/index.js +9 -2
  73. package/dist/env/tool/index.js +14 -9
  74. package/dist/env/tool/types.d.ts +25 -0
  75. package/dist/env/tool/validator.d.ts +8 -0
  76. package/dist/env/workflow/engine/index.js +12 -12
  77. package/dist/env/workflow/hooks/index.js +7 -7
  78. package/dist/env/workflow/index.js +24 -23
  79. package/dist/env/workflow/nodes/index.js +2 -2
  80. package/dist/env/workflow/plugins/index.js +10 -8
  81. package/dist/env/workflow/service/index.js +2 -2
  82. package/dist/env/workflow/storage/index.js +3 -3
  83. package/dist/env/workflow/tools/index.js +16 -15
  84. package/dist/env/workflow/utils/index.js +4 -4
  85. package/dist/index.d.ts +1 -1
  86. package/dist/index.js +118 -62
  87. package/dist/shared/@ai-setting/{roy-agent-core-dc9zq75z.js → roy-agent-core-0crmsc12.js} +3 -3
  88. package/dist/shared/@ai-setting/{roy-agent-core-aa2j7bk9.js → roy-agent-core-0sbmdz8d.js} +171 -36
  89. package/dist/shared/@ai-setting/{roy-agent-core-87942bw4.js → roy-agent-core-1mhyh4c5.js} +1 -1
  90. package/dist/shared/@ai-setting/{roy-agent-core-v6vr6za7.js → roy-agent-core-1vv4fx15.js} +4 -4
  91. package/dist/shared/@ai-setting/roy-agent-core-2stt4rp5.js +134 -0
  92. package/dist/shared/@ai-setting/{roy-agent-core-nwbfepba.js → roy-agent-core-3e040tc5.js} +1 -1
  93. package/dist/shared/@ai-setting/roy-agent-core-418zc9ha.js +288 -0
  94. package/dist/shared/@ai-setting/{roy-agent-core-r5wt1h3c.js → roy-agent-core-4fkxy2gv.js} +1 -1
  95. package/dist/shared/@ai-setting/{roy-agent-core-na18zwj0.js → roy-agent-core-4t3yskp8.js} +1 -1
  96. package/dist/shared/@ai-setting/{roy-agent-core-5pr4zp88.js → roy-agent-core-5kzhaap1.js} +1 -1
  97. package/dist/shared/@ai-setting/{roy-agent-core-qq96p0tj.js → roy-agent-core-5s2t8z00.js} +22 -1
  98. package/dist/shared/@ai-setting/{roy-agent-core-6rh8k6ba.js → roy-agent-core-6gj1hc5z.js} +7 -7
  99. package/dist/shared/@ai-setting/{roy-agent-core-ezvpreqz.js → roy-agent-core-6k8mb7zx.js} +1 -1
  100. package/dist/shared/@ai-setting/{roy-agent-core-g8htfwxj.js → roy-agent-core-7f10p7m2.js} +1 -1
  101. package/dist/shared/@ai-setting/roy-agent-core-7kvpc0w5.js +177 -0
  102. package/dist/shared/@ai-setting/{roy-agent-core-h21gngxf.js → roy-agent-core-7yh5wps0.js} +1 -1
  103. package/dist/shared/@ai-setting/{roy-agent-core-efkjyh69.js → roy-agent-core-9710zwwz.js} +1 -1
  104. package/dist/shared/@ai-setting/{roy-agent-core-6cy43nss.js → roy-agent-core-9c565frx.js} +49 -9
  105. package/dist/shared/@ai-setting/{roy-agent-core-fghc2m8z.js → roy-agent-core-aa8kv18f.js} +34 -2
  106. package/dist/shared/@ai-setting/{roy-agent-core-ew6qb5yx.js → roy-agent-core-an35dzbf.js} +6 -6
  107. package/dist/shared/@ai-setting/{roy-agent-core-mww0mnd9.js → roy-agent-core-azyz78ky.js} +7 -7
  108. package/dist/shared/@ai-setting/{roy-agent-core-264qexac.js → roy-agent-core-b7h39vrc.js} +4 -4
  109. package/dist/shared/@ai-setting/{roy-agent-core-dqxec05w.js → roy-agent-core-bjtc9d35.js} +2 -2
  110. package/dist/shared/@ai-setting/roy-agent-core-c4ec7k0p.js +426 -0
  111. package/dist/shared/@ai-setting/{roy-agent-core-ddyk1rc0.js → roy-agent-core-cre2y2ct.js} +160 -4
  112. package/dist/shared/@ai-setting/{roy-agent-core-tr3ep81v.js → roy-agent-core-d6zdbgtc.js} +1 -1
  113. package/dist/shared/@ai-setting/{roy-agent-core-0qyrk5k0.js → roy-agent-core-ds6qzmf8.js} +14 -5
  114. package/dist/shared/@ai-setting/{roy-agent-core-cgtq6427.js → roy-agent-core-e08bvpaq.js} +1 -1
  115. package/dist/shared/@ai-setting/{roy-agent-core-12n08pg5.js → roy-agent-core-e69qxdyy.js} +1 -1
  116. package/dist/shared/@ai-setting/{roy-agent-core-rhtdspx6.js → roy-agent-core-fan8g0z1.js} +10 -10
  117. package/dist/shared/@ai-setting/{roy-agent-core-xcp8vwax.js → roy-agent-core-fepm835e.js} +2 -2
  118. package/dist/shared/@ai-setting/{roy-agent-core-6j02sbee.js → roy-agent-core-fhg03v43.js} +1 -1
  119. package/dist/shared/@ai-setting/{roy-agent-core-99nwgj84.js → roy-agent-core-fzw9xzm1.js} +1 -1
  120. package/dist/shared/@ai-setting/{roy-agent-core-dvtg4sn0.js → roy-agent-core-g8yr733d.js} +1 -1
  121. package/dist/shared/@ai-setting/{roy-agent-core-3gpygqcx.js → roy-agent-core-gr5h1dyr.js} +2753 -358
  122. package/dist/shared/@ai-setting/roy-agent-core-h1e1fm9b.js +380 -0
  123. package/dist/shared/@ai-setting/{roy-agent-core-c2gbt68e.js → roy-agent-core-h83zdsrq.js} +2 -2
  124. package/dist/shared/@ai-setting/{roy-agent-core-8ez6mccb.js → roy-agent-core-k3gcvybs.js} +5 -1
  125. package/dist/shared/@ai-setting/{roy-agent-core-pgvcf91v.js → roy-agent-core-m39v7qpx.js} +2 -2
  126. package/dist/shared/@ai-setting/{roy-agent-core-tm1mxttk.js → roy-agent-core-mf5p38yf.js} +2 -2
  127. package/dist/shared/@ai-setting/{roy-agent-core-83bewqx8.js → roy-agent-core-mvh0td7p.js} +2 -2
  128. package/dist/shared/@ai-setting/{roy-agent-core-v85n42ve.js → roy-agent-core-mx855td4.js} +17 -38
  129. package/dist/shared/@ai-setting/{roy-agent-core-v87njmq7.js → roy-agent-core-n197medr.js} +13 -13
  130. package/dist/shared/@ai-setting/{roy-agent-core-cmprygrp.js → roy-agent-core-nqkfkpf4.js} +4 -4
  131. package/dist/shared/@ai-setting/{roy-agent-core-7cbpmk4q.js → roy-agent-core-p31ftgq9.js} +1 -1
  132. package/dist/shared/@ai-setting/{roy-agent-core-vffccgf6.js → roy-agent-core-qwd2dq5q.js} +10 -3
  133. package/dist/shared/@ai-setting/{roy-agent-core-rsn44n9y.js → roy-agent-core-ra66sf50.js} +2526 -942
  134. package/dist/shared/@ai-setting/{roy-agent-core-1v4g0d4x.js → roy-agent-core-rm7seqwb.js} +1 -1
  135. package/dist/shared/@ai-setting/{roy-agent-core-w0qjeq2v.js → roy-agent-core-shb1qsyg.js} +1041 -18
  136. package/dist/shared/@ai-setting/{roy-agent-core-ax9e9szb.js → roy-agent-core-smf94h73.js} +1 -1
  137. package/dist/shared/@ai-setting/{roy-agent-core-acj8ag08.js → roy-agent-core-tjnabyvq.js} +1 -1
  138. package/dist/shared/@ai-setting/{roy-agent-core-qqaak24r.js → roy-agent-core-tkpp1ba0.js} +1 -1
  139. package/dist/shared/@ai-setting/{roy-agent-core-9vhq7fvv.js → roy-agent-core-tpm1dd1g.js} +34 -88
  140. package/dist/shared/@ai-setting/{roy-agent-core-ed233k5z.js → roy-agent-core-v1n0106v.js} +1 -1
  141. package/dist/shared/@ai-setting/{roy-agent-core-zxz5fkwj.js → roy-agent-core-v6yshv0z.js} +1 -1
  142. package/dist/shared/@ai-setting/{roy-agent-core-mcy5apay.js → roy-agent-core-vf9sp6s3.js} +1 -1
  143. package/dist/shared/@ai-setting/{roy-agent-core-q813vafd.js → roy-agent-core-vpcxv1ty.js} +1 -1
  144. package/dist/shared/@ai-setting/{roy-agent-core-bxkjk7zx.js → roy-agent-core-vx8zc847.js} +4 -1
  145. package/dist/shared/@ai-setting/{roy-agent-core-xvt7kf7p.js → roy-agent-core-w9ryeg2p.js} +3 -3
  146. package/dist/shared/@ai-setting/{roy-agent-core-es203w7p.js → roy-agent-core-wqs6yypq.js} +1 -1
  147. package/dist/shared/@ai-setting/{roy-agent-core-hd3n57zs.js → roy-agent-core-wr1qexzq.js} +5 -5
  148. package/dist/shared/@ai-setting/roy-agent-core-wxrkcb17.js +56 -0
  149. package/dist/shared/@ai-setting/{roy-agent-core-0snm5hc5.js → roy-agent-core-y6shd91r.js} +1 -1
  150. package/dist/shared/@ai-setting/{roy-agent-core-9vxh6f8h.js → roy-agent-core-y7fqtzk2.js} +7 -7
  151. package/dist/shared/@ai-setting/{roy-agent-core-cpcd24n2.js → roy-agent-core-yet36q5k.js} +2 -2
  152. package/dist/shared/@ai-setting/{roy-agent-core-3fh1f7s7.js → roy-agent-core-yfpnkc4z.js} +5 -5
  153. package/dist/shared/@ai-setting/{roy-agent-core-0v27y99n.js → roy-agent-core-yh68z1bg.js} +65 -4
  154. package/package.json +18 -1
  155. /package/dist/shared/@ai-setting/{roy-agent-core-b4x6x4k2.js → roy-agent-core-m1fgtnrc.js} +0 -0
@@ -55,6 +55,8 @@
55
55
  * await notifier.finishTask({ messageId, status: "completed" });
56
56
  * ```
57
57
  */
58
+ import { type LarkSessionCardStore } from "./lark-card-state-store";
59
+ import { type ActivityMessage, type ToolCallView, type SubSessionActivity } from "./sub-session-activity";
58
60
  /**
59
61
  * 卡片状态。
60
62
  *
@@ -79,7 +81,14 @@ export type CardStatus = "running" | "completed" | "failed" | "stopped"
79
81
  * 语义上必须分开:用户看到「🚫 已取消」会以为任务还能找回来;
80
82
  * 硬删除后任务真的没了,卡片应显示「🗑️ 已删除」。
81
83
  */
82
- | "deleted";
84
+ | "deleted"
85
+ /**
86
+ * ★ Task #5164 需求 2b:任务进入「待验证」(两阶段验收,
87
+ * task_pre_complete 置 to_validate)。**非终态**活跃等待态:
88
+ * 卡片保持可更新,但 header 第二行显示专属短语「🔍 待验证」,
89
+ * 让用户一眼看出任务在等验收而不是在跑。
90
+ */
91
+ | "to_validate";
83
92
  /** workflow 卡片状态(与 CardStatus 同集合;语义别名,便于阅读) */
84
93
  export type WorkflowCardStatus = CardStatus;
85
94
  /** 里程碑(关键节点):时间 + 标题 + 描述 */
@@ -151,6 +160,13 @@ export interface ProcessStep {
151
160
  export interface TaskMeta {
152
161
  /** 任务 ID(#4223) */
153
162
  id?: number | string;
163
+ /**
164
+ * ★ 澄清 22:37:该任务所属的 sub-session(卡片**真正**的主键)。
165
+ *
166
+ * task 卡渲染时把它放进「刷新活性」按钮 value —— 因为刷新永远读 session
167
+ * store。缺省时该按钮退化为 task 兜底路径(见 handler 注释)。
168
+ */
169
+ sessionId?: string;
154
170
  /** 任务标题 */
155
171
  title?: string;
156
172
  /** 任务描述 */
@@ -236,6 +252,14 @@ export interface FinishTaskOptions {
236
252
  /** 终态补充说明(会作为最后一条里程碑 append) */
237
253
  finalStep?: string;
238
254
  progress?: number;
255
+ /**
256
+ * ★ Task #5384(CV R2 MINOR-5):本次新增的过程步骤。
257
+ *
258
+ * 与 {@link UpdateTaskOptions.processSteps} 同义 —— 终态/暂停路径同样要能
259
+ * 携带过程信息,否则「收尾前那几步」在 session 卡上会整段丢失
260
+ * (task 卡路径原本也没有,但 session 卡有「执行动态」,不该丢)。
261
+ */
262
+ processSteps?: ProcessStep[];
239
263
  /**
240
264
  * 收尾里程碑的自定义标题(Task #4536 / xval round2 NIT 3)
241
265
  *
@@ -262,7 +286,22 @@ export interface StartTaskResult {
262
286
  export interface LarkCardPatchNotifierOptions {
263
287
  /** 启动时是否 pin(默认 true) */
264
288
  pinOnStart?: boolean;
265
- /** 结束时是否 unpin(默认 true) */
289
+ /**
290
+ * ★ CV R3 M3:**session 卡持久层**(默认取进程单例)。
291
+ *
292
+ * 为什么不复用 task 卡持久层:`lark_card.task_id INTEGER PRIMARY KEY` 装不下
293
+ * `session_xxx`。没有这张表时,「重启 + 无 task」的 session 会**又发一张卡**
294
+ * (reviewer M3,属实)。
295
+ *
296
+ * 传 `null` 可显式关闭持久化(单测用,避免污染真实库)。
297
+ */
298
+ sessionCardStore?: LarkSessionCardStore | null;
299
+ /**
300
+ * 结束时是否 unpin(Task #5164 需求 2a:**默认 false**)
301
+ *
302
+ * 任务完成/暂停时不再自动取消置顶 —— pin 去留由用户手动决定。
303
+ * 需要旧行为(自动 unpin)的调用方显式传 true。
304
+ */
266
305
  unpinOnFinish?: boolean;
267
306
  }
268
307
  export interface CardPayload {
@@ -559,6 +598,147 @@ export declare function buildTaskCard(opts: {
559
598
  * running/stopped 折叠)。
560
599
  */
561
600
  expandTimeline?: boolean;
601
+ /**
602
+ * ★ Task #5360:sub-session 活性快照(用户点「🔄 刷新活性」后才有)
603
+ *
604
+ * ## 为什么是 `undefined` / `null` 三态
605
+ *
606
+ * - `undefined` —— 调用方**没查过**活性(首次发卡 / 普通 patch):
607
+ * 整个活性面板**不渲染**,卡片与改造前逐字节一致(零回归风险)。
608
+ * - 非 undefined(含 `null`)—— 调用方**查过了**:
609
+ * 渲染 `⚡ 子会话活性` 面板;`null` 表示"查了但没数据",渲染「暂无数据」。
610
+ *
611
+ * 这样区分很重要:用户点刷新后如果什么都没有,"面板消失"会让人以为
612
+ * 按钮没生效;"面板在但写暂无数据"才是诚实的反馈。
613
+ */
614
+ activity?: SubSessionActivity | null;
615
+ /** ★ Task #5360:活性面板的时间基准(注入便于测试;缺省 `Date.now()`) */
616
+ activityNow?: number;
617
+ /** ★ Task #5360:任务是否已终态(决定活性档位报「已结束」而非「疑似停滞」) */
618
+ activityTerminal?: boolean;
619
+ }): CardPayload;
620
+ /**
621
+ * ★ Task #5360(补充需求 22:31)—— 构造**无 task**(session-only)的卡片。
622
+ *
623
+ * ## 用户需求
624
+ *
625
+ * > 「有 sub-session 但无 task —— 也要能刷新看 subsession 情况」
626
+ *
627
+ * ## 与 `buildTaskCard` 的关系:**并列而非复用**
628
+ *
629
+ * 为什么不给 `buildTaskCard` 加一堆 `if (无 task)` 分支:
630
+ * - task 卡有「建群/解散群」「任务详情(ID/目标/父任务/优先级)」「进度 %」
631
+ * —— 这些对 session 全都无意义,硬塞会渲染出一堆 `undefined` 占位
632
+ * - 反过来 session 需要的「会话详情(sessionId / 所属 agent / 起止)」
633
+ * task 卡没有
634
+ *
635
+ * 所以是**两张卡**,但**共用**同一套零件:
636
+ * `buildCollapsiblePanel` / `appendHr` / `formatActivityLines` /
637
+ * `sanitizeInlineText` / `truncateHeadTitle`
638
+ * —— 活性判定与文案口径因此与 task 卡**逐字一致**(不会出现同一个
639
+ * session 在两张卡里颜色不同)。
640
+ *
641
+ * ## 按钮:刷新活性**始终有**;建群/解散群**仅在有 task 时**渲染
642
+ *
643
+ * - 刷新活性:session 主键,任何 session 卡都有(这是本次改造的核心)
644
+ * - 建群/解散群:绑定在 task 上,无 task 时 `value.taskId` 无从填充 ——
645
+ * 渲染一个点不动的按钮比不渲染更糟,所以有 task 才出。
646
+ */
647
+ /** session 卡累计状态(notifier 内部 + patch 复用) */
648
+ export interface SessionCardState {
649
+ title?: string;
650
+ statusPhrase?: string;
651
+ agentType?: string;
652
+ startedAt?: string;
653
+ elapsedText?: string;
654
+ milestones: Milestone[];
655
+ updateCount: number;
656
+ lifecycle?: "running" | "completed" | "timeout" | "failed" | "stopped";
657
+ profile?: string;
658
+ sessionId?: string;
659
+ /** ★ CV R5:上次的活性快照(patch 未传时沿用,避免擦掉消息数/最近消息) */
660
+ activity?: SubSessionActivity | null;
661
+ /** ★ Task #5420:上次的最近消息列表(patch 未传时沿用,避免擦面板) */
662
+ recentMessages?: ActivityMessage[] | ToolCallView[];
663
+ /**
664
+ * ★ Task #5364 返工(BLOCKER-5):该 session 内创建的 roy 任务(**可选增强**)。
665
+ *
666
+ * 用户 08:13 定稿第 2 点:「若该会话有任务相关信息 → 把原任务卡的信息渲染在
667
+ * 这张子会话卡上(**合并**,不是并列)」。
668
+ *
669
+ * 上一版只把它当「刷新时的临时入参」传,首卡(startSessionCard)不传 ⇒
670
+ * 生产上 task 卡链路照旧独立发一张,两张并列 —— 直接违背定稿。
671
+ *
672
+ * 现在纳入 state:里程碑式的 task 更新(进度/状态/操作记录)在 patch 时
673
+ * **沿用上一次已知的 task 快照**,不会因为二次事件没带 task 就消失。
674
+ */
675
+ task?: NonNullable<Parameters<typeof buildSessionCard>[0]["task"]>;
676
+ /** task 专属群 chatId(有群时渲染「进入专属群」/「解散该群」) */
677
+ perTaskChatId?: string;
678
+ perTaskChatName?: string;
679
+ }
680
+ export declare function buildSessionCard(opts: {
681
+ /** sub-session id(卡片主键) */
682
+ sessionId: string;
683
+ /** 会话标题(自定义 agent 名 / 任务描述);缺省显示 sessionId 截断 */
684
+ title?: string;
685
+ /** 状态短语(已运行 / 已结束 …);缺省按 lifecycle 推导 */
686
+ statusPhrase?: string;
687
+ /**
688
+ * ★ 澄清(22:37):session 层的**生命周期**。
689
+ *
690
+ * 与 task 无关 —— 没建 task 的 sub-session 一样会 完成/超时/被停。
691
+ * 缺省 `running`。
692
+ */
693
+ lifecycle?: "running" | "completed" | "timeout" | "failed" | "stopped";
694
+ /** ★ 澄清(22:37):task 专属群 chatId(有 task 且已建群时渲染「进入群」) */
695
+ perTaskChatId?: string;
696
+ /**
697
+ * ★ 澄清(22:37):该 session 内创建的 roy 任务(**可选增强**)。
698
+ *
699
+ * 有 → 卡片多一块「📋 任务信息」面板(taskId / title / 状态 / 进度 /
700
+ * 操作记录),**原有 task 信息一个不少**;
701
+ * 无 → 只显示 session 活性,卡片身份不变。
702
+ */
703
+ task?: {
704
+ id: number;
705
+ title?: string;
706
+ status?: string;
707
+ progress?: number;
708
+ currentStatus?: string;
709
+ /** 操作记录(里程碑形态,渲染成时间线) */
710
+ milestones?: Milestone[];
711
+ /** ★ CV MAJOR-5:其余元信息(用户要求「一个不少」) */
712
+ priority?: string;
713
+ parentTaskId?: number;
714
+ goals?: string;
715
+ createdAt?: string;
716
+ updatedAt?: string;
717
+ };
718
+ /** 所属 agent(subagentType),可选 */
719
+ agentType?: string;
720
+ /** 开始时间(ISO) */
721
+ startedAt?: string;
722
+ /** 已运行时长(人类可读,如 "12m")—— 由调用方算好,避免本模块读时钟 */
723
+ elapsedText?: string;
724
+ /** 最近的活动里程碑(session 没有 task 时间线,用事件级的短列表) */
725
+ milestones?: Milestone[];
726
+ /** ★ 活性快照(与 task 卡同源渲染)。undefined = 不渲染;null = 暂无数据 */
727
+ activity?: SubSessionActivity | null;
728
+ /**
729
+ * ★ Task #5420:最近消息列表(「💬 会话查看」面板)。
730
+ *
731
+ * ⚠️ 返工(2026-11-13 08:21):面板改为展示**最近 5 条工具调用**
732
+ * (工具名 + reason)。字段名保留 recentMessages(存量状态兼容,
733
+ * state 沿用逻辑不动),但装配点现在装的是 ToolCallView[]。
734
+ *
735
+ * undefined = 不渲染面板(首卡零噪音);
736
+ * [] = 查了确实没有 → 面板显示「暂无工具调用」(诚实)。
737
+ */
738
+ recentMessages?: ActivityMessage[] | import("./sub-session-activity").ToolCallView[];
739
+ activityNow?: number;
740
+ /** 更新计数(spinner 轮换 + "第 N 次更新") */
741
+ updateCount?: number;
562
742
  }): CardPayload;
563
743
  /**
564
744
  * 生成"打开飞书群"的 app link(Task #4230 follow-up 修复)
@@ -661,6 +841,19 @@ export declare class LarkCardPatchNotifier {
661
841
  * unpin 基础设施,只是渲染的卡片与自持的时间线不同。
662
842
  */
663
843
  private readonly workflowStates;
844
+ /**
845
+ * ★ 补充需求(22:31):**session 卡**的累计状态(key = messageId)。
846
+ *
847
+ * 与 `states`(task 卡)分开存:
848
+ * - task 卡状态里的 `meta` 是 `TaskMeta`(含 goals/priority/progress)
849
+ * - session 卡只有 `sessionId` + 少量展示字段
850
+ * 混在一个 Map 里会让 `buildCardWithActivity` 取到 session 状态并当成
851
+ * task meta 渲染(输出一堆 undefined 占位)。分开最省心。
852
+ */
853
+ private readonly sessionStates;
854
+ /** CV R4:session 卡状态别名(渲染 + patch 都需要) */
855
+ /** ★ CV R3 M3:session 卡持久层(`null` = 显式关闭) */
856
+ private readonly sessionStore?;
664
857
  constructor(options?: LarkCardPatchNotifierOptions);
665
858
  /** 取(或创建)某 messageId 的 mutex —— 不同卡片互不阻塞 */
666
859
  private mutexFor;
@@ -787,6 +980,283 @@ export declare class LarkCardPatchNotifier {
787
980
  updateMetaAndBuildCard(messageId: string, meta: TaskMeta, opts?: {
788
981
  clearPerTaskChat?: boolean;
789
982
  }): CardPayload | undefined;
983
+ /**
984
+ * ★ Task #5360 — 用活性快照重建卡片(用户点「🔄 刷新活性」时调用)。
985
+ *
986
+ * ## 为什么需要这个专门方法(不复用 `updateMetaAndBuildCard`)
987
+ *
988
+ * `updateMetaAndBuildCard` 是给"群建/解散"用的:它只改 meta 再 rebuild。
989
+ * 刷新活性要的是**同一张卡的累计状态 + 一份新活性快照**,且**绝不能**
990
+ * 走 `updateTask`(那会 patch + updateCount+1,用户点 5 次刷新 = 时间线
991
+ * 少 5 次"更新"预算,还把 spinner 转乱)。
992
+ *
993
+ * ## 返回 undefined 的语义
994
+ *
995
+ * notifier 没有该 messageId 的状态(进程重启后还没 hydrate)→ undefined。
996
+ * 调用方(action handler)据此 fallback 重建卡片 —— 与
997
+ * `buildCardAfterGroupChange` 完全同一套降级语义。
998
+ */
999
+ buildCardWithActivity(messageId: string, activity: SubSessionActivity | null, opts?: {
1000
+ terminal?: boolean;
1001
+ now?: number;
1002
+ }): CardPayload | undefined;
1003
+ /**
1004
+ * ★ CV R4 BLOCKER:**给已存在的 session 卡发 patch**(生命周期推进时用)。
1005
+ *
1006
+ * ## 为什么必须有它(用户需求没被真正满足)
1007
+ *
1008
+ * 「超时、完成等生命周期事件也体现在卡片上」—— 但 `startSessionCard`
1009
+ * 每次都是 `messages-send` = **发一条新消息**。若每个生命周期都 start:
1010
+ * - 一个 session 会产出「启动卡 + 完成卡」**两张**(用户看到重复卡)
1011
+ * - 每张都被 pin ⇒ 置顶堆积
1012
+ * - 「一张卡承载整个生命周期」这个语义根本没实现
1013
+ *
1014
+ * 正确做法:`running` 发首卡,后续生命周期 **patch 同一张**。
1015
+ *
1016
+ * ## 返回值语义
1017
+ *
1018
+ * `false` = 本 notifier 没有该 session 的卡记录(重启未 hydrate / 从没发过)
1019
+ * ⇒ 调用方据此走 `startSessionCard` 发首卡。
1020
+ */
1021
+ updateSessionCard(opts: {
1022
+ sessionId: string;
1023
+ chatId?: string;
1024
+ profile?: string;
1025
+ lifecycle: "running" | "completed" | "timeout" | "failed" | "stopped";
1026
+ /** 追加的里程碑(如「子会话完成」) */
1027
+ milestones?: Milestone[];
1028
+ activity?: SubSessionActivity | null;
1029
+ /** ★ Task #5364 返工:该 session 内的任务信息(渲染进**同一张** session 卡) */
1030
+ task?: Parameters<typeof buildSessionCard>[0]["task"];
1031
+ perTaskChatId?: string;
1032
+ perTaskChatName?: string;
1033
+ }): Promise<boolean>;
1034
+ /** sessionId → messageId 映射(用于「patch 同一张卡」查找) */
1035
+ private readonly sessionCardIds;
1036
+ /**
1037
+ * ★ Task #5364 返工:taskId → sessionId 反向索引。
1038
+ *
1039
+ * 用途(两处,都是「手里只有 taskId」的场景):
1040
+ * 1. `LarkCliTaskNotifyHook` 收到 task 事件时要知道该 patch **哪张 session 卡**
1041
+ * (一张卡的语义要求 task 更新写进 session 卡,而不是另发 task 卡)
1042
+ * 2. 旧 task 卡的「🔄 刷新活性」按钮 value 只有 taskId
1043
+ * (`resolveSessionIdByTask` 端口的同步兜底)
1044
+ *
1045
+ * ⚠️ 内存索引(进程内)。进程重启后由 hook 层从 lark_card 表 hydrate 补齐。
1046
+ */
1047
+ private readonly taskToSessionId;
1048
+ /** 按 sessionId 找这张卡的状态(找不到 → undefined) */
1049
+ private findSessionCardBySessionId;
1050
+ /** 这个 messageId 是否属于一张 **session 卡**(★ Task #5384 守卫入口)。 */
1051
+ isSessionCardMessage(messageId: string): boolean;
1052
+ /**
1053
+ * ★ Task #5384:把 **task 侧的更新**应用进 session 卡,返回可 patch 的卡片。
1054
+ *
1055
+ * 语义(保证「信息一个不少」且「卡身份不变」):
1056
+ * - 卡身份:`buildSessionCard` 渲染 ⇒ header 恒为「📊 子会话实时更新(…)」,
1057
+ * 「🔄 刷新活性」按钮与「🆔 会话 ID」面板恒在。
1058
+ * - 信息不丢:本次里程碑并进执行动态;task 的 meta/status/progress
1059
+ * 合并进「📋 任务信息」面板(carry-forward,未传则沿用上一次)。
1060
+ * - 过程步骤(task 侧的 processSteps)没有独立面板,转成里程碑形态并入,
1061
+ * 宁可换一种展示也不能丢(用户看的是「发生了什么」)。
1062
+ */
1063
+ private applyTaskEventToSessionCard;
1064
+ /**
1065
+ * ★ Task #5364 返工:登记 `taskId → sessionId` 映射(生产装配 / 持久层恢复用)。
1066
+ *
1067
+ * 为什么暴露成公开方法:hook 层的事件上下文里可能只有 taskId(`task:after.*`
1068
+ * 的 payload 不带 sub-session),而卡片更新必须落到 session 卡上。
1069
+ */
1070
+ bindTaskToSession(taskId: number, sessionId: string): void;
1071
+ /**
1072
+ * ★ Task #5364 返工(BLOCKER-4 重启分支):**认领**一张已存在的 session 卡。
1073
+ *
1074
+ * ## 为什么必须有
1075
+ *
1076
+ * `sessionCardIds` / `sessionStates` 是内存字段。进程重启后它们都是空的,
1077
+ * 此时若只靠 `getSessionCardMessageId()` 判断「有没有卡」,答案恒为"没有"
1078
+ * ⇒ `upsertSessionCard` 会走 `startSessionCard` 再发一张。
1079
+ * 于是**每次重启都会给同一个 session 多一张卡**(用户「一个 session 只有一张卡」
1080
+ * 的硬要求被静默破坏)。
1081
+ *
1082
+ * 本方法让调用方(hook 的 `restoreCardState`)用持久层里的权威 messageId
1083
+ * 把内存索引补回来 —— 之后的所有 patch 都会命中同一张卡。
1084
+ */
1085
+ adoptSessionCard(sessionId: string, messageId: string, state?: Partial<SessionCardState>): void;
1086
+ /** ★ CV R3 M3:把 session 卡写进持久层(失败只 warn,不阻断发卡) */
1087
+ private persistSessionCardRecord;
1088
+ /**
1089
+ * ★ CV R3 M3:从持久层**回灌**全部已知 session 卡(启动时调用)。
1090
+ *
1091
+ * 语义:把 `lark_session_card` 里的 `sessionId → messageId` 灌回内存索引,
1092
+ * 让重启后的第一次 `upsertSessionCard` 走 **patch** 而不是 `startSessionCard`。
1093
+ *
1094
+ * @returns 回灌的条数(诊断用)
1095
+ */
1096
+ restoreSessionCardsFromStore(): number;
1097
+ applySessionGroupChange(messageId: string, opts: {
1098
+ sessionId: string;
1099
+ /** 新群 chatId;缺省/空 ⇒ 视为「解散」,清掉卡上的群与链接 */
1100
+ perTaskChatId?: string;
1101
+ perTaskChatName?: string;
1102
+ }): CardPayload | undefined;
1103
+ /** ★ Task #5364 返工:按 taskId 反查 sessionId(没有 → undefined,**不猜**)。 */
1104
+ getSessionIdByTask(taskId: number): string | undefined;
1105
+ /** ★ Task #5364 返工:按 sessionId 查已发的卡 messageId(诊断 / 幂等断言用)。 */
1106
+ getSessionCardMessageId(sessionId: string): string | undefined;
1107
+ /** ★ Task #5364 返工:该 session 卡当前的累计状态(**生产形状测试**断言用)。 */
1108
+ getSessionCardState(sessionId: string): SessionCardState | undefined;
1109
+ /**
1110
+ * ★ Task #5417:把原 session 的进展**双写**到关联群 session 的卡上。
1111
+ *
1112
+ * ## 设计(方案 A,用户定稿)
1113
+ *
1114
+ * 新群有自己的卡(session_id = 群 session id = chatId)。
1115
+ * 原 session 的进展事件 patch 原卡后,调用方用本方法把同一条
1116
+ * 进展同步到新群卡 —— 新群卡的 state **独立累积**(不是复制原卡),
1117
+ * 符合 #5364 单卡规格(每 session 每 chat 一张)。
1118
+ *
1119
+ * ## 语义
1120
+ *
1121
+ * - `findGroupSession` 未注入 / 反查不到群 / 群 session 就是原 session
1122
+ * ⇒ no-op(返回 false,不报错)
1123
+ * - 新群还没有卡 ⇒ `upsertSessionCard` 会为群 session 发首卡
1124
+ * (best-effort;发送失败向上抛,调用方 warn)
1125
+ * - 已有卡 ⇒ patch 同一张(不重发)
1126
+ *
1127
+ * @param originSessionId 原 session id
1128
+ * @param opts 与 upsertSessionCard 同形的增量(lifecycle/milestones/…)
1129
+ * @param findGroupSession 反查端口(SessionComponent.findGroupChatForSession)
1130
+ */
1131
+ syncGroupCardFromOrigin(originSessionId: string, opts: {
1132
+ lifecycle?: "running" | "completed" | "timeout" | "failed" | "stopped";
1133
+ milestones?: Array<{
1134
+ title: string;
1135
+ timestamp: string;
1136
+ description?: string;
1137
+ }>;
1138
+ title?: string;
1139
+ }, findGroupSession?: (sid: string) => Promise<{
1140
+ chatId: string;
1141
+ aliasSessionId?: string;
1142
+ } | undefined>): Promise<boolean>;
1143
+ /**
1144
+ * ★ CV R4:按 sessionId **复用或新建** session 卡(生命周期推进的正确入口)。
1145
+ *
1146
+ * - 已有卡 → patch(一张卡承载整个生命周期)
1147
+ * - 没有卡 → start(首卡 + pin)
1148
+ *
1149
+ * 这才是「生命周期事件体现在卡片上」的正确实现;调用方不该自己判断。
1150
+ */
1151
+ upsertSessionCard(opts: {
1152
+ chatId: string;
1153
+ profile?: string;
1154
+ sessionId: string;
1155
+ title?: string;
1156
+ statusPhrase?: string;
1157
+ agentType?: string;
1158
+ startedAt?: string;
1159
+ elapsedText?: string;
1160
+ milestones?: Milestone[];
1161
+ lifecycle: "running" | "completed" | "timeout" | "failed" | "stopped";
1162
+ activity?: SubSessionActivity | null;
1163
+ /** ★ Task #5364 返工(BLOCKER-5):session 内的任务信息(合并渲染) */
1164
+ task?: Parameters<typeof buildSessionCard>[0]["task"];
1165
+ perTaskChatId?: string;
1166
+ perTaskChatName?: string;
1167
+ }): Promise<{
1168
+ messageId: string;
1169
+ created: boolean;
1170
+ }>;
1171
+ /**
1172
+ * ★ Task #5364 返工:per-session 的 upsert 串行化锁(见 upsertSessionCard 注释)。
1173
+ *
1174
+ * key = sessionId;只保护「读有没有卡 → 决定 start/update」这一段,
1175
+ * 不保护 patch 本身(那个有 `mutexFor(messageId)` 自己的锁)。
1176
+ */
1177
+ private readonly sessionUpsertMutexes;
1178
+ /**
1179
+ * ★ CV R3 BLOCKER-2:**首次发 session 卡**(无 task 的 sub-session 也要有卡)。
1180
+ *
1181
+ * 与 `startTask` 并列:同一个 notifier、同一套 send/pin 基础设施,
1182
+ * 只是渲染 `buildSessionCard` 且状态存进 `sessionStates`。
1183
+ *
1184
+ * 发完把 messageId 记进 `sessionStates`,之后 `buildSessionCardWithActivity`
1185
+ * 才能 patch 同一张卡(而不是每次刷新都 fallback 重建)。
1186
+ */
1187
+ startSessionCard(opts: {
1188
+ chatId: string;
1189
+ profile?: string;
1190
+ sessionId: string;
1191
+ title?: string;
1192
+ statusPhrase?: string;
1193
+ agentType?: string;
1194
+ startedAt?: string;
1195
+ elapsedText?: string;
1196
+ milestones?: Milestone[];
1197
+ lifecycle?: "running" | "completed" | "timeout" | "failed" | "stopped";
1198
+ /** ★ CV R5:首卡也记下活性(后续 patch 未传时可沿用) */
1199
+ activity?: SubSessionActivity | null;
1200
+ /**
1201
+ * ★ Task #5364 返工(BLOCKER-5):首卡就带上 task 区块。
1202
+ *
1203
+ * 上一版首卡不传 task ⇒ task 卡链路独立再发一张 ⇒ 两张并列。
1204
+ * 用户 08:13 定稿:**一张 session 卡**,task 信息是卡上的区块。
1205
+ */
1206
+ task?: Parameters<typeof buildSessionCard>[0]["task"];
1207
+ perTaskChatId?: string;
1208
+ perTaskChatName?: string;
1209
+ }): Promise<StartTaskResult>;
1210
+ /**
1211
+ * ★ 补充需求(22:31)—— session-only 卡片按 messageId 重建(带活性)。
1212
+ *
1213
+ * 与 `buildCardWithActivity` 的区别:那个按 messageId 取 **task** 卡的
1214
+ * 累计状态;session 卡的状态另存一份(`sessionStates`),互不干扰。
1215
+ *
1216
+ * 返回 `undefined` = 本 notifier 没有这张 session 卡的状态(重启未 hydrate)
1217
+ * ⇒ 调用方 fallback 重建。session 卡没有 task 的 title/status 可丢,
1218
+ * 所以重建损失最小。
1219
+ */
1220
+ buildSessionCardWithActivity(messageId: string, sessionId: string, activity: SubSessionActivity | null, opts?: {
1221
+ now?: number;
1222
+ /** ★ 澄清 22:37:session 层生命周期(完成/超时/停止) */
1223
+ lifecycle?: "running" | "completed" | "timeout" | "failed" | "stopped";
1224
+ /** ★ 澄清 22:37:关联 task 的增强信息(有则渲染任务面板) */
1225
+ task?: Parameters<typeof buildSessionCard>[0]["task"];
1226
+ /**
1227
+ * ★ Task #5420:最近消息列表(「💬 会话查看」面板)。
1228
+ * undefined = 本次没查(沿用 state 里的上次值,与 activity 同语义)。
1229
+ */
1230
+ recentMessages?: ActivityMessage[] | ToolCallView[];
1231
+ }): CardPayload | undefined;
1232
+ /**
1233
+ * ★ 补充需求(22:31)—— 记录 session 卡的累计状态(供 refresh 重建)。
1234
+ *
1235
+ * 只存渲染必需的最小字段,不存活性快照本身(活性每次刷新都要重读,
1236
+ * 缓存它会显示过期数据 —— 那正是用户点刷新要避免的)。
1237
+ */
1238
+ rememberSessionCard(messageId: string, state: {
1239
+ title?: string;
1240
+ statusPhrase?: string;
1241
+ agentType?: string;
1242
+ startedAt?: string;
1243
+ elapsedText?: string;
1244
+ milestones?: Milestone[];
1245
+ updateCount?: number;
1246
+ /** ★ 澄清 22:37:session 层生命周期 */
1247
+ lifecycle?: "running" | "completed" | "timeout" | "failed" | "stopped";
1248
+ /** ★ CV R4:patch 时要用 profile(多 appId)与 sessionId(反查) */
1249
+ profile?: string;
1250
+ sessionId?: string;
1251
+ /** ★ CV R5:上次的活性快照 */
1252
+ activity?: SubSessionActivity | null;
1253
+ /** ★ Task #5420:上次的最近消息列表 */
1254
+ recentMessages?: ActivityMessage[] | ToolCallView[];
1255
+ /** ★ Task #5364 返工:任务区块 + 专属群(合并渲染) */
1256
+ task?: NonNullable<Parameters<typeof buildSessionCard>[0]["task"]>;
1257
+ perTaskChatId?: string;
1258
+ perTaskChatName?: string;
1259
+ }): void;
790
1260
  /**
791
1261
  * ★ Task #5020 —— 已经走到**真终态**的卡片(review round-4 MAJOR)。
792
1262
  *
@@ -805,6 +1275,33 @@ export declare class LarkCardPatchNotifier {
805
1275
  * 不会被旧 messageId 的终态记录误伤。
806
1276
  */
807
1277
  private finalisedCards;
1278
+ /**
1279
+ * ★ Task #5182 follow-up:解除某张卡片的终态标记(reopen 用)。
1280
+ *
1281
+ * ## 为什么需要
1282
+ *
1283
+ * `finalisedCards` 守卫(Task #5020)会吞掉 finishTask 之后的
1284
+ * 一切 updateTask —— 这对「迟到的并发更新」是正确语义,但对
1285
+ * **reopen**(closed 卡片 + 任务重新激活 → 复用原卡)是错的:
1286
+ * reopen 本来就是要"复活"这张卡。真网取证(2026-11-08 18:00):
1287
+ * reopenReuseCard 打了「已复用原卡」日志 + pin 成功,但 patch
1288
+ * 被守卫静默吞掉,卡片内容停在「已完成」。
1289
+ *
1290
+ * ## 行为
1291
+ *
1292
+ * - 从 finalisedCards 删除 messageId(守卫解除)
1293
+ * - 内存态不存在时从 exportState 快照恢复?—— 不,states 已被
1294
+ * finishTask delete,快照无从取。调用方(reopenReuseCard)
1295
+ * 会经 mergeTimelineState/updateTask 的默认 state 重建时间线,
1296
+ * 并由 hook 层 hydrate(restoreCardState → hydrateState)补齐。
1297
+ * - 对未终结的卡是 no-op(finalisedCards 本就没有该 id)
1298
+ */
1299
+ unfinaliseCard(messageId: string): void;
1300
+ /**
1301
+ * ★ Task #5182 follow-up:测试注入点 —— 替换 runLarkCli 的执行器。
1302
+ * 仅测试使用(生产路径不设置),避免真 spawn lark-cli。
1303
+ */
1304
+ testRunner?: (argv: string[], op: string) => Promise<string>;
808
1305
  /** 诊断:当前跟踪中的卡片数(测试/自检用) */
809
1306
  trackedCardCount(): number;
810
1307
  /** 诊断:当前跟踪中的 workflow 卡片数(测试/自检用) */
@@ -893,3 +1390,46 @@ export declare class LarkCardPatchNotifier {
893
1390
  */
894
1391
  private extractMessageId;
895
1392
  }
1393
+ /**
1394
+ * ## 为什么必须有这个单例(真机事故复盘)
1395
+ *
1396
+ * `sessionCardIds` / `sessionStates` / `states` 都是 **notifier 实例字段**。
1397
+ * 只要「发首卡」和「后续 patch」不是同一个实例,就必然发生:
1398
+ *
1399
+ * ```
1400
+ * 事件 1(running) → 实例 A:没有该 session 的卡 → startSessionCard 发**新卡**
1401
+ * 事件 2(completed)→ 实例 B:还是没有 → 又发**新卡**
1402
+ * ```
1403
+ *
1404
+ * 真机取证(2026-11-12 gonglin 群,单 session):0813 定稿「一个 session 只有
1405
+ * 一张卡」,实测发出 **3 张**(2 张 session 卡 + 1 张 task 卡)。
1406
+ *
1407
+ * 根因是上一版靠 `env.getPluginInstance()/env._pluginInstances` 去「借」插件的
1408
+ * notifier —— 但生产 `Environment` **根本没有这两个属性**(全仓 grep 只有那
1409
+ * 一处引用、从无注入方)⇒ 每次调用都落 `?? new LarkCardPatchNotifier()`。
1410
+ *
1411
+ * ## 语义
1412
+ *
1413
+ * - **进程内唯一**:`LarkCliTaskNotifyHook` 默认构造、卡片 action handler、
1414
+ * 事件线程的 `sessionCardSender` 全部走这里取同一个实例
1415
+ * - 单测要隔离:显式传 `cardNotifier` 构造参数(既有 55 条测试都这么做),
1416
+ * 或者调用 {@link __resetSharedLarkCardNotifierForTest}
1417
+ */
1418
+ /**
1419
+ * ★ Task #5364 返工:session 卡上「任务信息」区块的渲染载荷类型。
1420
+ *
1421
+ * 显式导出,避免调用方写 `Parameters<typeof buildSessionCard>[0]["task"]`
1422
+ * 这种又长又容易写错的类型(也确实被写错过一次:内联 import(...) 语法非法)。
1423
+ */
1424
+ export type SessionCardTaskPayload = NonNullable<Parameters<typeof buildSessionCard>[0]["task"]>;
1425
+ /**
1426
+ * 取进程级共享 notifier(首次调用时创建)。
1427
+ *
1428
+ * ⚠️ 只在**生产装配**里用。任何需要独立状态的场景(单测 / 多租户)都要
1429
+ * 显式 `new LarkCardPatchNotifier()` 并注入。
1430
+ */
1431
+ export declare function getSharedLarkCardNotifier(): LarkCardPatchNotifier;
1432
+ /** 测试钩子:丢弃单例(避免用例间状态串味)。 */
1433
+ export declare function __resetSharedLarkCardNotifierForTest(): void;
1434
+ /** 诊断:当前是否已有单例(不创建)。 */
1435
+ export declare function hasSharedLarkCardNotifier(): boolean;
@@ -2,13 +2,17 @@ import {
2
2
  DEFAULT_APP_LINK_BASE,
3
3
  HEAD_TITLE_MAX_WIDTH,
4
4
  LarkCardPatchNotifier,
5
+ __resetSharedLarkCardNotifierForTest,
5
6
  buildChatAppLink,
6
7
  buildCollapsiblePanel,
8
+ buildSessionCard,
7
9
  buildTaskCard,
8
10
  buildWorkflowCard,
9
11
  formatDateTimeForDisplay,
10
12
  formatDurationMs,
11
13
  formatTimestampForDisplay,
14
+ getSharedLarkCardNotifier,
15
+ hasSharedLarkCardNotifier,
12
16
  humanizeValue,
13
17
  isTerminalStatusForTimeline,
14
18
  isTerminalStatusForWorkflowTimeline,
@@ -22,8 +26,10 @@ import {
22
26
  resolveTaskTitleForDisplay,
23
27
  sanitizeInlineText,
24
28
  truncateHeadTitle
25
- } from "../../../shared/@ai-setting/roy-agent-core-w0qjeq2v.js";
26
- import"../../../shared/@ai-setting/roy-agent-core-qq96p0tj.js";
29
+ } from "../../../shared/@ai-setting/roy-agent-core-shb1qsyg.js";
30
+ import"../../../shared/@ai-setting/roy-agent-core-418zc9ha.js";
31
+ import"../../../shared/@ai-setting/roy-agent-core-6k8mb7zx.js";
32
+ import"../../../shared/@ai-setting/roy-agent-core-5s2t8z00.js";
27
33
  import"../../../shared/@ai-setting/roy-agent-core-7f7t9wwp.js";
28
34
  import"../../../shared/@ai-setting/roy-agent-core-85xyctnb.js";
29
35
  import"../../../shared/@ai-setting/roy-agent-core-fs0mn2jk.js";
@@ -41,13 +47,17 @@ export {
41
47
  isTerminalStatusForWorkflowTimeline,
42
48
  isTerminalStatusForTimeline,
43
49
  humanizeValue,
50
+ hasSharedLarkCardNotifier,
51
+ getSharedLarkCardNotifier,
44
52
  formatTimestampForDisplay,
45
53
  formatDurationMs,
46
54
  formatDateTimeForDisplay,
47
55
  buildWorkflowCard,
48
56
  buildTaskCard,
57
+ buildSessionCard,
49
58
  buildCollapsiblePanel,
50
59
  buildChatAppLink,
60
+ __resetSharedLarkCardNotifierForTest,
51
61
  LarkCardPatchNotifier,
52
62
  HEAD_TITLE_MAX_WIDTH,
53
63
  DEFAULT_APP_LINK_BASE