@ai-setting/roy-agent-core 1.7.59 → 1.7.62

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 (138) hide show
  1. package/dist/config/index.js +8 -8
  2. package/dist/env/agent/agent-component.js +41 -0
  3. package/dist/env/agent/index.js +18 -16
  4. package/dist/env/commands/index.js +8 -8
  5. package/dist/env/context/index.js +4 -4
  6. package/dist/env/debug/index.js +8 -8
  7. package/dist/env/error-reply.js +18 -0
  8. package/dist/env/event-source/cli-command-handler.d.ts +90 -0
  9. package/dist/env/event-source/cli-command-handler.js +17 -0
  10. package/dist/env/event-source/event-source-handlers.d.ts +1 -0
  11. package/dist/env/event-source/event-source-handlers.js +58 -0
  12. package/dist/env/event-source/event-store.js +18 -0
  13. package/dist/env/event-source/idempotency-key.js +20 -0
  14. package/dist/env/event-source/index.d.ts +3 -1
  15. package/dist/env/event-source/index.js +37 -22
  16. package/dist/env/event-source/types.d.ts +21 -1
  17. package/dist/env/hook/index.js +6 -6
  18. package/dist/env/index.js +54 -48
  19. package/dist/env/lark-mention-utils.js +9 -0
  20. package/dist/env/llm/index.js +9 -9
  21. package/dist/env/log-trace/index.d.ts +1 -1
  22. package/dist/env/log-trace/index.js +12 -8
  23. package/dist/env/log-trace/logger.d.ts +2 -0
  24. package/dist/env/log-trace/logger.js +39 -0
  25. package/dist/env/mcp/index.js +9 -9
  26. package/dist/env/mcp/tool/index.js +2 -2
  27. package/dist/env/memory/index.js +9 -9
  28. package/dist/env/memory/plugin/index.js +2 -2
  29. package/dist/env/plugin/index.js +9 -9
  30. package/dist/env/prompt/index.js +8 -8
  31. package/dist/env/session/index.js +11 -11
  32. package/dist/env/session/storage/index.js +5 -5
  33. package/dist/env/skill/index.js +8 -8
  34. package/dist/env/task/delegate/delegate-tool.js +42 -0
  35. package/dist/env/task/delegate/index.js +13 -11
  36. package/dist/env/task/index.js +17 -16
  37. package/dist/env/task/mcp/index.d.ts +16 -0
  38. package/dist/env/task/mcp/index.js +222 -0
  39. package/dist/env/task/mcp/task-mcp-server.d.ts +142 -0
  40. package/dist/env/task/plugins/index.d.ts +1 -0
  41. package/dist/env/task/plugins/index.js +47 -12
  42. package/dist/env/task/plugins/lark-card-patch-notifier.js +42 -0
  43. package/dist/env/task/storage/index.js +4 -4
  44. package/dist/env/task/storage/migrations/log-migration.d.ts +19 -0
  45. package/dist/env/task/storage/sqlite-task-store.d.ts +29 -0
  46. package/dist/env/task/task-component.d.ts +48 -3
  47. package/dist/env/task/tools/index.js +4 -4
  48. package/dist/env/task/tools/task-types.d.ts +60 -11
  49. package/dist/env/tool/built-in/index.js +4 -4
  50. package/dist/env/tool/index.js +12 -11
  51. package/dist/env/tool/types.js +1 -0
  52. package/dist/env/workflow/engine/index.js +13 -13
  53. package/dist/env/workflow/hooks/index.js +8 -8
  54. package/dist/env/workflow/index.js +23 -23
  55. package/dist/env/workflow/nodes/index.js +3 -3
  56. package/dist/env/workflow/plugins/index.js +9 -9
  57. package/dist/env/workflow/service/index.js +3 -3
  58. package/dist/env/workflow/storage/index.js +4 -4
  59. package/dist/env/workflow/tools/index.js +15 -15
  60. package/dist/env/workflow/tools/run-workflow.d.ts +30 -0
  61. package/dist/env/workflow/utils/index.js +5 -5
  62. package/dist/env/workflow/utils/session-recovery.d.ts +27 -0
  63. package/dist/index.js +91 -73
  64. package/dist/shared/@ai-setting/{roy-agent-core-ygn5tzt1.js → roy-agent-core-06jakebr.js} +2 -2
  65. package/dist/shared/@ai-setting/{roy-agent-core-m68z3pw1.js → roy-agent-core-084zthqx.js} +1 -1
  66. package/dist/shared/@ai-setting/{roy-agent-core-cyefe8z5.js → roy-agent-core-2hkyp51n.js} +1 -1
  67. package/dist/shared/@ai-setting/{roy-agent-core-029r8kdw.js → roy-agent-core-2pma868e.js} +4 -4
  68. package/dist/shared/@ai-setting/{roy-agent-core-c7w2h47a.js → roy-agent-core-2veqhrxa.js} +3 -3
  69. package/dist/shared/@ai-setting/{roy-agent-core-t64nmayv.js → roy-agent-core-32ck9rqt.js} +2 -2
  70. package/dist/shared/@ai-setting/{roy-agent-core-m97jn2ra.js → roy-agent-core-33hn1beg.js} +1 -1
  71. package/dist/shared/@ai-setting/{roy-agent-core-8p63s836.js → roy-agent-core-386wa4wy.js} +1 -1
  72. package/dist/shared/@ai-setting/{roy-agent-core-kq9pz2a7.js → roy-agent-core-48h4zh60.js} +4 -4
  73. package/dist/shared/@ai-setting/{roy-agent-core-eanq305k.js → roy-agent-core-5bj0xfjk.js} +13 -27
  74. package/dist/shared/@ai-setting/{roy-agent-core-7q4wdze2.js → roy-agent-core-5mrynf9g.js} +1 -1
  75. package/dist/shared/@ai-setting/{roy-agent-core-rt115qfc.js → roy-agent-core-6awgfh3x.js} +14 -4
  76. package/dist/shared/@ai-setting/{roy-agent-core-9zhkdg6w.js → roy-agent-core-6wxww10t.js} +2 -2
  77. package/dist/shared/@ai-setting/{roy-agent-core-baaa4wtp.js → roy-agent-core-79gyka2q.js} +2 -2
  78. package/dist/shared/@ai-setting/{roy-agent-core-ytd5eztz.js → roy-agent-core-7tce05jt.js} +1 -1
  79. package/dist/shared/@ai-setting/{roy-agent-core-x6c45yqd.js → roy-agent-core-99nwgj84.js} +1 -1
  80. package/dist/shared/@ai-setting/roy-agent-core-9nvyffxg.js +414 -0
  81. package/dist/shared/@ai-setting/{roy-agent-core-e1w17tht.js → roy-agent-core-9qgrc9dy.js} +158 -158
  82. package/dist/shared/@ai-setting/{roy-agent-core-2ctyjy62.js → roy-agent-core-a08dpf71.js} +17 -2
  83. package/dist/shared/@ai-setting/{roy-agent-core-e250355z.js → roy-agent-core-a6cz4d23.js} +3 -3
  84. package/dist/shared/@ai-setting/{roy-agent-core-tze5596n.js → roy-agent-core-anb53t3v.js} +3 -3
  85. package/dist/shared/@ai-setting/{roy-agent-core-caevk7xd.js → roy-agent-core-arx535cs.js} +30 -8
  86. package/dist/shared/@ai-setting/{roy-agent-core-vh0qzb24.js → roy-agent-core-as0dd70m.js} +36 -15
  87. package/dist/shared/@ai-setting/{roy-agent-core-w93z6a42.js → roy-agent-core-bpvz1dqr.js} +12 -12
  88. package/dist/shared/@ai-setting/{roy-agent-core-ck60j1q9.js → roy-agent-core-bxkjk7zx.js} +2 -1
  89. package/dist/shared/@ai-setting/{roy-agent-core-hs41gx9w.js → roy-agent-core-c4t4y18j.js} +5 -5
  90. package/dist/shared/@ai-setting/{roy-agent-core-t4x089js.js → roy-agent-core-c57278kx.js} +1 -1
  91. package/dist/shared/@ai-setting/{roy-agent-core-em4hks9t.js → roy-agent-core-c8xvy6hj.js} +4 -4
  92. package/dist/shared/@ai-setting/{roy-agent-core-991pk4ss.js → roy-agent-core-cqpd41gf.js} +18 -16
  93. package/dist/shared/@ai-setting/{roy-agent-core-psg6f1v6.js → roy-agent-core-cxpgd415.js} +6 -6
  94. package/dist/shared/@ai-setting/{roy-agent-core-vgdhxbx3.js → roy-agent-core-dfqhc9ey.js} +2 -2
  95. package/dist/shared/@ai-setting/{roy-agent-core-6bradb0j.js → roy-agent-core-fqandv0a.js} +9 -107
  96. package/dist/shared/@ai-setting/{roy-agent-core-en2xqxs9.js → roy-agent-core-fr296a53.js} +39 -14
  97. package/dist/shared/@ai-setting/{roy-agent-core-rcgvmtms.js → roy-agent-core-gc6wcd7z.js} +1 -1
  98. package/dist/shared/@ai-setting/{roy-agent-core-7nb23tdd.js → roy-agent-core-gjsvehfs.js} +1 -1
  99. package/dist/shared/@ai-setting/{roy-agent-core-0kn3zt1t.js → roy-agent-core-gtdtzbs7.js} +2 -2
  100. package/dist/shared/@ai-setting/{roy-agent-core-84rs0c8d.js → roy-agent-core-gz2jnaan.js} +7 -7
  101. package/dist/shared/@ai-setting/{roy-agent-core-0yn7a78e.js → roy-agent-core-h3fwjbhp.js} +14 -14
  102. package/dist/shared/@ai-setting/{roy-agent-core-4096f575.js → roy-agent-core-hczj1ryh.js} +4 -4
  103. package/dist/shared/@ai-setting/{roy-agent-core-syyw58p9.js → roy-agent-core-hfyxv2kx.js} +2 -2
  104. package/dist/shared/@ai-setting/{roy-agent-core-d75t8gea.js → roy-agent-core-hwkc0bg2.js} +1 -1
  105. package/dist/shared/@ai-setting/{roy-agent-core-vath15kt.js → roy-agent-core-ja4sr63d.js} +6 -6
  106. package/dist/shared/@ai-setting/roy-agent-core-jagkferh.js +16 -0
  107. package/dist/shared/@ai-setting/roy-agent-core-jm136jzh.js +99 -0
  108. package/dist/shared/@ai-setting/{roy-agent-core-14bq77wr.js → roy-agent-core-jw63js86.js} +1 -1
  109. package/dist/shared/@ai-setting/{roy-agent-core-89sxsrc7.js → roy-agent-core-kmvw6b4v.js} +1 -1
  110. package/dist/shared/@ai-setting/{roy-agent-core-47s81t6g.js → roy-agent-core-kvq4a4p6.js} +2 -2
  111. package/dist/shared/@ai-setting/{roy-agent-core-c36335nw.js → roy-agent-core-m3w3ytxt.js} +15 -3
  112. package/dist/shared/@ai-setting/{roy-agent-core-64f22h1g.js → roy-agent-core-m880qz3y.js} +7 -1
  113. package/dist/shared/@ai-setting/{roy-agent-core-2fk8c9ax.js → roy-agent-core-mbwaxqs0.js} +3 -3
  114. package/dist/shared/@ai-setting/{roy-agent-core-jjhw9am6.js → roy-agent-core-mkpsz128.js} +4 -4
  115. package/dist/shared/@ai-setting/{roy-agent-core-20m8je6e.js → roy-agent-core-mrrv80jy.js} +1 -1
  116. package/dist/shared/@ai-setting/{roy-agent-core-6q5m1qk5.js → roy-agent-core-nmn853z0.js} +333 -1183
  117. package/dist/shared/@ai-setting/roy-agent-core-p37kh0kt.js +155 -0
  118. package/dist/shared/@ai-setting/{roy-agent-core-08njdcpj.js → roy-agent-core-p6a4v4fq.js} +1 -1
  119. package/dist/shared/@ai-setting/{roy-agent-core-gksw1gjb.js → roy-agent-core-p8rf4z89.js} +1 -1
  120. package/dist/shared/@ai-setting/roy-agent-core-pnj0zh25.js +0 -0
  121. package/dist/shared/@ai-setting/{roy-agent-core-q4gdfypk.js → roy-agent-core-prnry2mw.js} +3 -3
  122. package/dist/shared/@ai-setting/{roy-agent-core-84xtww7d.js → roy-agent-core-qmqe8ds3.js} +3 -3
  123. package/dist/shared/@ai-setting/{roy-agent-core-txwptxk1.js → roy-agent-core-sj4y3wdm.js} +3 -3
  124. package/dist/shared/@ai-setting/{roy-agent-core-fbjd7bt6.js → roy-agent-core-th92f833.js} +64 -29
  125. package/dist/shared/@ai-setting/{roy-agent-core-yphwdm9x.js → roy-agent-core-v7mwj8eq.js} +2 -2
  126. package/dist/shared/@ai-setting/{roy-agent-core-5f7myqnb.js → roy-agent-core-vvb4cyyy.js} +11 -5
  127. package/dist/shared/@ai-setting/{roy-agent-core-jjxdmedn.js → roy-agent-core-vwzan9v0.js} +2 -2
  128. package/dist/shared/@ai-setting/{roy-agent-core-fw6k4w1h.js → roy-agent-core-w2ev3z5q.js} +12 -14
  129. package/dist/shared/@ai-setting/roy-agent-core-w2h6xt6k.js +473 -0
  130. package/dist/shared/@ai-setting/{roy-agent-core-n0p0hwgd.js → roy-agent-core-wzp4tbsn.js} +1 -1
  131. package/dist/shared/@ai-setting/{roy-agent-core-ge87xbas.js → roy-agent-core-x1d6edkh.js} +1 -1
  132. package/dist/shared/@ai-setting/{roy-agent-core-8bngppw0.js → roy-agent-core-ye4bfzqg.js} +13 -13
  133. package/dist/shared/@ai-setting/{roy-agent-core-geh6j7bw.js → roy-agent-core-zjgckbdd.js} +2 -2
  134. package/dist/shared/@ai-setting/{roy-agent-core-hefarcp0.js → roy-agent-core-zy8vkbnk.js} +1 -1
  135. package/dist/test-utils/child-process-mock.js +23 -0
  136. package/dist/utils/temp-file-manager/index.js +2 -2
  137. package/package.json +76 -1
  138. /package/dist/shared/@ai-setting/{roy-agent-core-3ztzc83c.js → roy-agent-core-5enxfga2.js} +0 -0
@@ -1,59 +1,301 @@
1
1
  import {
2
2
  defaultLarkCliRunner
3
- } from "./roy-agent-core-ck60j1q9.js";
3
+ } from "./roy-agent-core-bxkjk7zx.js";
4
+ import {
5
+ notifyReactFailure
6
+ } from "./roy-agent-core-9nvyffxg.js";
7
+ import {
8
+ cliCommandHandler
9
+ } from "./roy-agent-core-p37kh0kt.js";
4
10
  import {
5
11
  TaskTagPlugin,
6
12
  createLarkCliTaskNotifyHook,
7
13
  createPerTaskGroupChatPlugin,
8
14
  extractPerTaskChatId,
9
15
  extractPerTaskChatName
10
- } from "./roy-agent-core-8bngppw0.js";
16
+ } from "./roy-agent-core-ye4bfzqg.js";
11
17
  import {
12
18
  getSharedEventStore
13
- } from "./roy-agent-core-2ctyjy62.js";
19
+ } from "./roy-agent-core-a08dpf71.js";
14
20
  import {
15
21
  createLarkCliWorkflowNotifyHook
16
- } from "./roy-agent-core-psg6f1v6.js";
22
+ } from "./roy-agent-core-cxpgd415.js";
17
23
  import {
18
24
  LarkCardPatchNotifier,
19
25
  buildTaskCard
20
- } from "./roy-agent-core-c36335nw.js";
26
+ } from "./roy-agent-core-m3w3ytxt.js";
21
27
  import {
22
28
  normalizeLarkAtMentions
23
- } from "./roy-agent-core-64f22h1g.js";
24
- import {
25
- envKeyToConfigKey
26
- } from "./roy-agent-core-7hh0brvs.js";
27
- import {
28
- BaseComponent
29
- } from "./roy-agent-core-0kn3zt1t.js";
29
+ } from "./roy-agent-core-m880qz3y.js";
30
30
  import {
31
31
  globalHookManager,
32
32
  init_global_hook_manager
33
- } from "./roy-agent-core-yphwdm9x.js";
33
+ } from "./roy-agent-core-v7mwj8eq.js";
34
34
  import {
35
35
  init_context
36
- } from "./roy-agent-core-m97jn2ra.js";
36
+ } from "./roy-agent-core-33hn1beg.js";
37
37
  import {
38
38
  createEnvContext,
39
39
  normalizeParentTaskId,
40
40
  runWithEnvContext
41
- } from "./roy-agent-core-syyw58p9.js";
41
+ } from "./roy-agent-core-hfyxv2kx.js";
42
42
  import {
43
43
  TracedAs,
44
44
  init_decorator,
45
45
  wrapFunction
46
- } from "./roy-agent-core-8p63s836.js";
46
+ } from "./roy-agent-core-386wa4wy.js";
47
47
  import {
48
48
  createLogger,
49
49
  getTracerProvider,
50
50
  init_logger
51
- } from "./roy-agent-core-rt115qfc.js";
51
+ } from "./roy-agent-core-6awgfh3x.js";
52
52
  import {
53
53
  __legacyDecorateClassTS,
54
54
  __require
55
55
  } from "./roy-agent-core-fs0mn2jk.js";
56
56
 
57
+ // src/env/event-source/event-source-handlers.ts
58
+ import { spawn as spawn2, exec as execSync } from "child_process";
59
+ import { promisify as promisify2 } from "node:util";
60
+ init_global_hook_manager();
61
+ init_context();
62
+
63
+ // src/env/task/plugins/lark-card-action-handler.ts
64
+ init_logger();
65
+ import { exec } from "node:child_process";
66
+ import { promisify } from "node:util";
67
+ var logger = createLogger("lark-card-action-handler");
68
+ var execAsync = promisify(exec);
69
+ var CTX_FIELD_CHAT_ID = "larkPerTaskChatId";
70
+ var CTX_FIELD_CHAT_NAME = "larkPerTaskChatName";
71
+ var CTX_FIELD_CHAT_CREATED_AT = "larkPerTaskChatCreatedAt";
72
+ var CTX_FIELD_CHAT_TASK_ID = "larkPerTaskChatTaskId";
73
+ var CTX_FIELD_CHAT_INVITEES = "larkPerTaskChatInvitees";
74
+ var cardActionInflight = new Map;
75
+ async function handleCardAction(event, ports) {
76
+ const { action, taskId: taskIdRaw } = event.actionValue;
77
+ const taskId = typeof taskIdRaw === "string" ? parseInt(taskIdRaw, 10) : taskIdRaw;
78
+ if (!taskId || Number.isNaN(taskId)) {
79
+ return { ok: false, action, error: `Invalid taskId: ${taskIdRaw}` };
80
+ }
81
+ if (action !== "create_group" && action !== "disband_group") {
82
+ return { ok: false, action, error: `Unknown action: ${action}` };
83
+ }
84
+ const inflightKey = `${event.profile ?? "-"}:${event.messageId || String(taskId)}:${action}`;
85
+ const inflight = cardActionInflight.get(inflightKey);
86
+ if (inflight) {
87
+ logger.warn(`handleCardAction: ${inflightKey} 已有同操作在处理中(疑似用户重复点击),本次忽略。`);
88
+ return { ok: false, action, error: `重复点击:${inflightKey} 正在处理中,已忽略` };
89
+ }
90
+ const pending = handleCardActionInner(event, ports, taskId);
91
+ cardActionInflight.set(inflightKey, pending);
92
+ try {
93
+ return await pending;
94
+ } finally {
95
+ cardActionInflight.delete(inflightKey);
96
+ }
97
+ }
98
+ async function handleCardActionInner(event, ports, taskId) {
99
+ const { action } = event.actionValue;
100
+ if (!ports.getTask) {
101
+ return { ok: false, action, error: "ports.getTask not injected" };
102
+ }
103
+ const task = await ports.getTask(taskId);
104
+ if (!task) {
105
+ return { ok: false, action, error: `Task #${taskId} not found` };
106
+ }
107
+ const existingChatId = extractPerTaskChatId(task.context);
108
+ if (action === "create_group") {
109
+ return await handleCreateGroup(event, ports, task, existingChatId);
110
+ } else {
111
+ return await handleDisbandGroup(event, ports, task, existingChatId);
112
+ }
113
+ }
114
+ function buildCardAfterGroupChange(event, ports, task, perTaskChatId, perTaskChatName) {
115
+ const meta = buildTaskMetaFromTask(task, perTaskChatId, perTaskChatName);
116
+ const preserved = ports.notifier?.updateMetaAndBuildCard?.(event.messageId, meta, { clearPerTaskChat: !perTaskChatId });
117
+ if (preserved) {
118
+ logger.debug(`buildCardAfterGroupChange: 复用 notifier 累积状态(里程碑历史保留)messageId=${event.messageId}`);
119
+ return preserved;
120
+ }
121
+ logger.warn(`buildCardAfterGroupChange: notifier 无 messageId=${event.messageId} 的状态,` + `fallback 重建卡片(该卡片的历史里程碑可能丢失)`);
122
+ return buildTaskCard({
123
+ status: "running",
124
+ meta,
125
+ milestones: [
126
+ { title: "Task 创建", timestamp: new Date().toISOString(), description: task.current_status }
127
+ ]
128
+ });
129
+ }
130
+ async function handleCreateGroup(event, ports, task, existingChatId) {
131
+ if (existingChatId) {
132
+ const existingName = extractPerTaskChatName(task.context);
133
+ logger.info(`handleCreateGroup: Task #${task.id} 已有专属群 ${existingChatId}(幂等命中,不重复建群)`);
134
+ return {
135
+ ok: true,
136
+ action: "create_group",
137
+ newChatId: existingChatId,
138
+ cardUpdate: buildCardAfterGroupChange(event, ports, task, existingChatId, existingName)
139
+ };
140
+ }
141
+ if (!ports.createGroupChat) {
142
+ return { ok: false, action: "create_group", error: "ports.createGroupChat not injected" };
143
+ }
144
+ try {
145
+ const renderedName = truncateText(`Task #${task.id} - ${task.title ?? "(无标题)"}`, 60);
146
+ const description = truncateText(`roy-agent task #${task.id} - ${task.project_path ?? ""}`, 100);
147
+ const operatorOpenId = extractOperatorOpenId(event.operatorId);
148
+ const initialUserIds = operatorOpenId ? [operatorOpenId] : undefined;
149
+ const chatId = await ports.createGroupChat({
150
+ name: renderedName,
151
+ description,
152
+ profile: event.profile,
153
+ initialUserIds
154
+ });
155
+ let invitedOpenIds = [];
156
+ if (operatorOpenId) {
157
+ if (initialUserIds) {
158
+ invitedOpenIds = [operatorOpenId];
159
+ logger.debug(`handleCreateGroup: ${operatorOpenId} 已在建群时邀请(initialUserIds 路径)`);
160
+ } else if (ports.inviteUser) {
161
+ try {
162
+ await ports.inviteUser(chatId, operatorOpenId, event.profile);
163
+ invitedOpenIds = [operatorOpenId];
164
+ logger.debug(`handleCreateGroup: 走 inviteUser 端口邀请 ${operatorOpenId} 进 ${chatId}`);
165
+ } catch (err) {
166
+ logger.warn(`handleCreateGroup: inviteUser(${chatId}, ${operatorOpenId}) 失败(不阻断主流程): ${err.message}`);
167
+ }
168
+ } else {
169
+ logger.warn(`handleCreateGroup: createGroupChat 不支持 initialUserIds 且 inviteUser 未注入,` + `${operatorOpenId} 未被拉进群 ${chatId}。` + `需升级 caller(bridge/real impl)使用 ports.inviteUser 或实现 createGroupChat.initialUserIds 参数。`);
170
+ }
171
+ }
172
+ const newContext = patchContext(task.context ?? "{}", {
173
+ [CTX_FIELD_CHAT_ID]: chatId,
174
+ [CTX_FIELD_CHAT_NAME]: renderedName,
175
+ [CTX_FIELD_CHAT_CREATED_AT]: new Date().toISOString(),
176
+ [CTX_FIELD_CHAT_TASK_ID]: task.id,
177
+ [CTX_FIELD_CHAT_INVITEES]: invitedOpenIds.length > 0 ? invitedOpenIds : undefined
178
+ });
179
+ if (ports.updateTaskContext) {
180
+ await ports.updateTaskContext(task.id, newContext);
181
+ }
182
+ const cardUpdate = buildCardAfterGroupChange(event, ports, task, chatId, renderedName);
183
+ return { ok: true, action: "create_group", newChatId: chatId, cardUpdate };
184
+ } catch (err) {
185
+ logger.error(`handleCardAction.create_group failed: ${err.message}`);
186
+ return { ok: false, action: "create_group", error: err.message };
187
+ }
188
+ }
189
+ function extractOperatorOpenId(raw) {
190
+ if (!raw)
191
+ return;
192
+ if (typeof raw === "string")
193
+ return raw;
194
+ if (typeof raw === "object" && typeof raw.open_id === "string")
195
+ return raw.open_id;
196
+ return;
197
+ }
198
+ async function handleDisbandGroup(event, ports, task, existingChatId) {
199
+ if (!existingChatId) {
200
+ return {
201
+ ok: false,
202
+ action: "disband_group",
203
+ error: `Task #${task.id} 无专属群(context.larkPerTaskChatId 空),无需解散`
204
+ };
205
+ }
206
+ if (!ports.deleteGroupChat) {
207
+ return { ok: false, action: "disband_group", error: "ports.deleteGroupChat not injected" };
208
+ }
209
+ try {
210
+ await ports.deleteGroupChat(existingChatId, event.profile);
211
+ const newContext = patchContext(task.context ?? "{}", {
212
+ [CTX_FIELD_CHAT_ID]: undefined,
213
+ [CTX_FIELD_CHAT_NAME]: undefined,
214
+ [CTX_FIELD_CHAT_CREATED_AT]: undefined,
215
+ [CTX_FIELD_CHAT_TASK_ID]: undefined
216
+ });
217
+ if (ports.updateTaskContext) {
218
+ await ports.updateTaskContext(task.id, newContext);
219
+ }
220
+ const cardUpdate = buildCardAfterGroupChange(event, ports, task, undefined, undefined);
221
+ return { ok: true, action: "disband_group", cardUpdate };
222
+ } catch (err) {
223
+ logger.error(`handleCardAction.disband_group failed: ${err.message}`);
224
+ return { ok: false, action: "disband_group", error: err.message };
225
+ }
226
+ }
227
+ function patchContext(contextStr, changes) {
228
+ let obj = {};
229
+ try {
230
+ const parsed = JSON.parse(contextStr);
231
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
232
+ obj = parsed;
233
+ }
234
+ } catch {
235
+ obj = {};
236
+ }
237
+ for (const [k, v] of Object.entries(changes)) {
238
+ if (v === undefined) {
239
+ delete obj[k];
240
+ } else {
241
+ obj[k] = v;
242
+ }
243
+ }
244
+ return JSON.stringify(obj);
245
+ }
246
+ function buildTaskMetaFromTask(task, perTaskChatId, perTaskChatName) {
247
+ return {
248
+ id: task.id,
249
+ title: task.title,
250
+ description: task.description,
251
+ goals: task.goals,
252
+ parentTaskId: typeof task.parent_task_id === "number" && task.parent_task_id > 0 ? task.parent_task_id : undefined,
253
+ priority: task.priority,
254
+ type: task.type,
255
+ projectPath: task.project_path,
256
+ context: task.context,
257
+ currentStatus: task.current_status,
258
+ perTaskChatId,
259
+ perTaskChatName
260
+ };
261
+ }
262
+ async function deleteGroupChatViaLarkCli(chatId, profile) {
263
+ const profileFlag = profile ? `--profile ${profile} ` : "";
264
+ try {
265
+ const { stdout: authStdout } = await execAsync(`lark-cli ${profileFlag}auth status --json`, { timeout: 15000 });
266
+ const appId = JSON.parse(authStdout).appId;
267
+ if (!appId) {
268
+ throw new Error(`lark-cli auth status 未返回 appId: ${authStdout.slice(0, 200)}`);
269
+ }
270
+ const cmd = `lark-cli ${profileFlag}api DELETE /open-apis/im/v1/chats/${chatId}/members ` + `--params '{"member_id_type":"app_id"}' ` + `--data ${shellQuote(JSON.stringify({ id_list: [appId] }))} ` + `--as bot`;
271
+ const { stdout, stderr } = await execAsync(cmd, { timeout: 30000 });
272
+ logger.debug(`deleteGroupChatViaLarkCli(${chatId}) bot 退群 ok: ` + `stdout=${stdout?.slice(0, 300)} stderr=${stderr?.slice(0, 300)}`);
273
+ } catch (err) {
274
+ logger.warn(`deleteGroupChatViaLarkCli(${chatId}) bot 退群失败(task.context 仍会清掉,` + `飞书侧群会保留):${err.message}`);
275
+ }
276
+ }
277
+ function shellQuote(s) {
278
+ return `'${s.replace(/'/g, `'\\''`)}'`;
279
+ }
280
+ function truncateText(text, maxLen) {
281
+ if (!text)
282
+ return "";
283
+ if (text.length <= maxLen)
284
+ return text;
285
+ return text.substring(0, Math.max(0, maxLen - 3)) + "...";
286
+ }
287
+ async function createGroupChatViaLarkCli(opts) {
288
+ const profileFlag = opts.profile ? `--profile ${opts.profile} ` : "";
289
+ const usersFlag = opts.initialUserIds && opts.initialUserIds.length > 0 ? `--users ${shellQuote(opts.initialUserIds.join(","))} ` : "";
290
+ const cmd = `lark-cli ${profileFlag}im +chat-create --name ${shellQuote(truncateText(opts.name, 60))} ` + usersFlag + `--description ${shellQuote(truncateText(opts.description, 100))} --as bot`;
291
+ const { stdout } = await execAsync(cmd, { timeout: 60000 });
292
+ const m = stdout.match(/"chat_id"\s*:\s*"(oc_[a-f0-9]+)"/);
293
+ if (!m) {
294
+ throw new Error(`lark-cli +chat-create 返回无法解析: ${stdout.slice(0, 300)}`);
295
+ }
296
+ return m[1];
297
+ }
298
+
57
299
  // src/env/event-source/timer-handler.ts
58
300
  init_decorator();
59
301
  var DEFAULT_TIMER_INTERVAL_MS = 10 * 60 * 1000;
@@ -566,290 +808,48 @@ class BountyIMInstance {
566
808
  if (evt.event === "message") {
567
809
  const msg = evt.data || {};
568
810
  const from = msg.from || "unknown";
569
- let content = "未知内容";
570
- if (msg.content?.type === "text") {
571
- content = String(msg.content?.body || "");
572
- }
573
- return `[${from}] ${content}`;
574
- }
575
- return `事件: ${evt.event || "unknown"}`;
576
- }
577
- }
578
- var bountyIMHandler = {
579
- type: "bounty-im",
580
- validateConfig(config) {
581
- const errors = [];
582
- if (!config.id)
583
- errors.push("EventSource ID is required");
584
- if (!config.name)
585
- errors.push("EventSource name is required");
586
- try {
587
- assertNoLegacyAddressField(config);
588
- } catch (err) {
589
- errors.push(err instanceof Error ? err.message : String(err));
590
- }
591
- const { imServerUrl, email } = readBountyIMConfig(config);
592
- if (!email) {
593
- errors.push("Bounty IM email is required (v0.14 strict email-only; top-level email or options.email)");
594
- }
595
- if (email !== undefined && email !== "") {
596
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
597
- errors.push("Bounty IM email format invalid (expected: user@domain.tld)");
598
- }
599
- }
600
- if (!imServerUrl) {
601
- errors.push("Bounty IM imServerUrl is required (top-level imServerUrl or options.imServerUrl)");
602
- } else if (!imServerUrl.startsWith("ws://") && !imServerUrl.startsWith("wss://")) {
603
- errors.push("Bounty IM imServerUrl must start with ws:// or wss://");
604
- }
605
- return errors;
606
- },
607
- createInstance(config) {
608
- return new BountyIMInstance(config);
609
- }
610
- };
611
-
612
- // src/env/event-source/event-source-handlers.ts
613
- import { spawn as spawn3, exec as execSync } from "child_process";
614
- import { promisify as promisify2 } from "node:util";
615
- init_global_hook_manager();
616
- init_context();
617
-
618
- // src/env/task/plugins/lark-card-action-handler.ts
619
- init_logger();
620
- import { exec } from "node:child_process";
621
- import { promisify } from "node:util";
622
- var logger = createLogger("lark-card-action-handler");
623
- var execAsync = promisify(exec);
624
- var CTX_FIELD_CHAT_ID = "larkPerTaskChatId";
625
- var CTX_FIELD_CHAT_NAME = "larkPerTaskChatName";
626
- var CTX_FIELD_CHAT_CREATED_AT = "larkPerTaskChatCreatedAt";
627
- var CTX_FIELD_CHAT_TASK_ID = "larkPerTaskChatTaskId";
628
- var CTX_FIELD_CHAT_INVITEES = "larkPerTaskChatInvitees";
629
- var cardActionInflight = new Map;
630
- async function handleCardAction(event, ports) {
631
- const { action, taskId: taskIdRaw } = event.actionValue;
632
- const taskId = typeof taskIdRaw === "string" ? parseInt(taskIdRaw, 10) : taskIdRaw;
633
- if (!taskId || Number.isNaN(taskId)) {
634
- return { ok: false, action, error: `Invalid taskId: ${taskIdRaw}` };
635
- }
636
- if (action !== "create_group" && action !== "disband_group") {
637
- return { ok: false, action, error: `Unknown action: ${action}` };
638
- }
639
- const inflightKey = `${event.profile ?? "-"}:${event.messageId || String(taskId)}:${action}`;
640
- const inflight = cardActionInflight.get(inflightKey);
641
- if (inflight) {
642
- logger.warn(`handleCardAction: ${inflightKey} 已有同操作在处理中(疑似用户重复点击),本次忽略。`);
643
- return { ok: false, action, error: `重复点击:${inflightKey} 正在处理中,已忽略` };
644
- }
645
- const pending = handleCardActionInner(event, ports, taskId);
646
- cardActionInflight.set(inflightKey, pending);
647
- try {
648
- return await pending;
649
- } finally {
650
- cardActionInflight.delete(inflightKey);
651
- }
652
- }
653
- async function handleCardActionInner(event, ports, taskId) {
654
- const { action } = event.actionValue;
655
- if (!ports.getTask) {
656
- return { ok: false, action, error: "ports.getTask not injected" };
657
- }
658
- const task = await ports.getTask(taskId);
659
- if (!task) {
660
- return { ok: false, action, error: `Task #${taskId} not found` };
661
- }
662
- const existingChatId = extractPerTaskChatId(task.context);
663
- if (action === "create_group") {
664
- return await handleCreateGroup(event, ports, task, existingChatId);
665
- } else {
666
- return await handleDisbandGroup(event, ports, task, existingChatId);
667
- }
668
- }
669
- function buildCardAfterGroupChange(event, ports, task, perTaskChatId, perTaskChatName) {
670
- const meta = buildTaskMetaFromTask(task, perTaskChatId, perTaskChatName);
671
- const preserved = ports.notifier?.updateMetaAndBuildCard?.(event.messageId, meta, { clearPerTaskChat: !perTaskChatId });
672
- if (preserved) {
673
- logger.debug(`buildCardAfterGroupChange: 复用 notifier 累积状态(里程碑历史保留)messageId=${event.messageId}`);
674
- return preserved;
675
- }
676
- logger.warn(`buildCardAfterGroupChange: notifier 无 messageId=${event.messageId} 的状态,` + `fallback 重建卡片(该卡片的历史里程碑可能丢失)`);
677
- return buildTaskCard({
678
- status: "running",
679
- meta,
680
- milestones: [
681
- { title: "Task 创建", timestamp: new Date().toISOString(), description: task.current_status }
682
- ]
683
- });
684
- }
685
- async function handleCreateGroup(event, ports, task, existingChatId) {
686
- if (existingChatId) {
687
- const existingName = extractPerTaskChatName(task.context);
688
- logger.info(`handleCreateGroup: Task #${task.id} 已有专属群 ${existingChatId}(幂等命中,不重复建群)`);
689
- return {
690
- ok: true,
691
- action: "create_group",
692
- newChatId: existingChatId,
693
- cardUpdate: buildCardAfterGroupChange(event, ports, task, existingChatId, existingName)
694
- };
695
- }
696
- if (!ports.createGroupChat) {
697
- return { ok: false, action: "create_group", error: "ports.createGroupChat not injected" };
698
- }
699
- try {
700
- const renderedName = truncateText(`Task #${task.id} - ${task.title ?? "(无标题)"}`, 60);
701
- const description = truncateText(`roy-agent task #${task.id} - ${task.project_path ?? ""}`, 100);
702
- const operatorOpenId = extractOperatorOpenId(event.operatorId);
703
- const initialUserIds = operatorOpenId ? [operatorOpenId] : undefined;
704
- const chatId = await ports.createGroupChat({
705
- name: renderedName,
706
- description,
707
- profile: event.profile,
708
- initialUserIds
709
- });
710
- let invitedOpenIds = [];
711
- if (operatorOpenId) {
712
- if (initialUserIds) {
713
- invitedOpenIds = [operatorOpenId];
714
- logger.debug(`handleCreateGroup: ${operatorOpenId} 已在建群时邀请(initialUserIds 路径)`);
715
- } else if (ports.inviteUser) {
716
- try {
717
- await ports.inviteUser(chatId, operatorOpenId, event.profile);
718
- invitedOpenIds = [operatorOpenId];
719
- logger.debug(`handleCreateGroup: 走 inviteUser 端口邀请 ${operatorOpenId} 进 ${chatId}`);
720
- } catch (err) {
721
- logger.warn(`handleCreateGroup: inviteUser(${chatId}, ${operatorOpenId}) 失败(不阻断主流程): ${err.message}`);
722
- }
723
- } else {
724
- logger.warn(`handleCreateGroup: createGroupChat 不支持 initialUserIds 且 inviteUser 未注入,` + `${operatorOpenId} 未被拉进群 ${chatId}。` + `需升级 caller(bridge/real impl)使用 ports.inviteUser 或实现 createGroupChat.initialUserIds 参数。`);
725
- }
726
- }
727
- const newContext = patchContext(task.context ?? "{}", {
728
- [CTX_FIELD_CHAT_ID]: chatId,
729
- [CTX_FIELD_CHAT_NAME]: renderedName,
730
- [CTX_FIELD_CHAT_CREATED_AT]: new Date().toISOString(),
731
- [CTX_FIELD_CHAT_TASK_ID]: task.id,
732
- [CTX_FIELD_CHAT_INVITEES]: invitedOpenIds.length > 0 ? invitedOpenIds : undefined
733
- });
734
- if (ports.updateTaskContext) {
735
- await ports.updateTaskContext(task.id, newContext);
736
- }
737
- const cardUpdate = buildCardAfterGroupChange(event, ports, task, chatId, renderedName);
738
- return { ok: true, action: "create_group", newChatId: chatId, cardUpdate };
739
- } catch (err) {
740
- logger.error(`handleCardAction.create_group failed: ${err.message}`);
741
- return { ok: false, action: "create_group", error: err.message };
742
- }
743
- }
744
- function extractOperatorOpenId(raw) {
745
- if (!raw)
746
- return;
747
- if (typeof raw === "string")
748
- return raw;
749
- if (typeof raw === "object" && typeof raw.open_id === "string")
750
- return raw.open_id;
751
- return;
752
- }
753
- async function handleDisbandGroup(event, ports, task, existingChatId) {
754
- if (!existingChatId) {
755
- return {
756
- ok: false,
757
- action: "disband_group",
758
- error: `Task #${task.id} 无专属群(context.larkPerTaskChatId 空),无需解散`
759
- };
760
- }
761
- if (!ports.deleteGroupChat) {
762
- return { ok: false, action: "disband_group", error: "ports.deleteGroupChat not injected" };
763
- }
764
- try {
765
- await ports.deleteGroupChat(existingChatId, event.profile);
766
- const newContext = patchContext(task.context ?? "{}", {
767
- [CTX_FIELD_CHAT_ID]: undefined,
768
- [CTX_FIELD_CHAT_NAME]: undefined,
769
- [CTX_FIELD_CHAT_CREATED_AT]: undefined,
770
- [CTX_FIELD_CHAT_TASK_ID]: undefined
771
- });
772
- if (ports.updateTaskContext) {
773
- await ports.updateTaskContext(task.id, newContext);
774
- }
775
- const cardUpdate = buildCardAfterGroupChange(event, ports, task, undefined, undefined);
776
- return { ok: true, action: "disband_group", cardUpdate };
777
- } catch (err) {
778
- logger.error(`handleCardAction.disband_group failed: ${err.message}`);
779
- return { ok: false, action: "disband_group", error: err.message };
780
- }
781
- }
782
- function patchContext(contextStr, changes) {
783
- let obj = {};
784
- try {
785
- const parsed = JSON.parse(contextStr);
786
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
787
- obj = parsed;
788
- }
789
- } catch {
790
- obj = {};
791
- }
792
- for (const [k, v] of Object.entries(changes)) {
793
- if (v === undefined) {
794
- delete obj[k];
795
- } else {
796
- obj[k] = v;
797
- }
798
- }
799
- return JSON.stringify(obj);
800
- }
801
- function buildTaskMetaFromTask(task, perTaskChatId, perTaskChatName) {
802
- return {
803
- id: task.id,
804
- title: task.title,
805
- description: task.description,
806
- goals: task.goals,
807
- parentTaskId: typeof task.parent_task_id === "number" && task.parent_task_id > 0 ? task.parent_task_id : undefined,
808
- priority: task.priority,
809
- type: task.type,
810
- projectPath: task.project_path,
811
- context: task.context,
812
- currentStatus: task.current_status,
813
- perTaskChatId,
814
- perTaskChatName
815
- };
816
- }
817
- async function deleteGroupChatViaLarkCli(chatId, profile) {
818
- const profileFlag = profile ? `--profile ${profile} ` : "";
819
- try {
820
- const { stdout: authStdout } = await execAsync(`lark-cli ${profileFlag}auth status --json`, { timeout: 15000 });
821
- const appId = JSON.parse(authStdout).appId;
822
- if (!appId) {
823
- throw new Error(`lark-cli auth status 未返回 appId: ${authStdout.slice(0, 200)}`);
824
- }
825
- const cmd = `lark-cli ${profileFlag}api DELETE /open-apis/im/v1/chats/${chatId}/members ` + `--params '{"member_id_type":"app_id"}' ` + `--data ${shellQuote(JSON.stringify({ id_list: [appId] }))} ` + `--as bot`;
826
- const { stdout, stderr } = await execAsync(cmd, { timeout: 30000 });
827
- logger.debug(`deleteGroupChatViaLarkCli(${chatId}) bot 退群 ok: ` + `stdout=${stdout?.slice(0, 300)} stderr=${stderr?.slice(0, 300)}`);
828
- } catch (err) {
829
- logger.warn(`deleteGroupChatViaLarkCli(${chatId}) bot 退群失败(task.context 仍会清掉,` + `飞书侧群会保留):${err.message}`);
830
- }
831
- }
832
- function shellQuote(s) {
833
- return `'${s.replace(/'/g, `'\\''`)}'`;
834
- }
835
- function truncateText(text, maxLen) {
836
- if (!text)
837
- return "";
838
- if (text.length <= maxLen)
839
- return text;
840
- return text.substring(0, Math.max(0, maxLen - 3)) + "...";
841
- }
842
- async function createGroupChatViaLarkCli(opts) {
843
- const profileFlag = opts.profile ? `--profile ${opts.profile} ` : "";
844
- const usersFlag = opts.initialUserIds && opts.initialUserIds.length > 0 ? `--users ${shellQuote(opts.initialUserIds.join(","))} ` : "";
845
- const cmd = `lark-cli ${profileFlag}im +chat-create --name ${shellQuote(truncateText(opts.name, 60))} ` + usersFlag + `--description ${shellQuote(truncateText(opts.description, 100))} --as bot`;
846
- const { stdout } = await execAsync(cmd, { timeout: 60000 });
847
- const m = stdout.match(/"chat_id"\s*:\s*"(oc_[a-f0-9]+)"/);
848
- if (!m) {
849
- throw new Error(`lark-cli +chat-create 返回无法解析: ${stdout.slice(0, 300)}`);
811
+ let content = "未知内容";
812
+ if (msg.content?.type === "text") {
813
+ content = String(msg.content?.body || "");
814
+ }
815
+ return `[${from}] ${content}`;
816
+ }
817
+ return `事件: ${evt.event || "unknown"}`;
850
818
  }
851
- return m[1];
852
819
  }
820
+ var bountyIMHandler = {
821
+ type: "bounty-im",
822
+ validateConfig(config) {
823
+ const errors = [];
824
+ if (!config.id)
825
+ errors.push("EventSource ID is required");
826
+ if (!config.name)
827
+ errors.push("EventSource name is required");
828
+ try {
829
+ assertNoLegacyAddressField(config);
830
+ } catch (err) {
831
+ errors.push(err instanceof Error ? err.message : String(err));
832
+ }
833
+ const { imServerUrl, email } = readBountyIMConfig(config);
834
+ if (!email) {
835
+ errors.push("Bounty IM email is required (v0.14 strict email-only; top-level email or options.email)");
836
+ }
837
+ if (email !== undefined && email !== "") {
838
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
839
+ errors.push("Bounty IM email format invalid (expected: user@domain.tld)");
840
+ }
841
+ }
842
+ if (!imServerUrl) {
843
+ errors.push("Bounty IM imServerUrl is required (top-level imServerUrl or options.imServerUrl)");
844
+ } else if (!imServerUrl.startsWith("ws://") && !imServerUrl.startsWith("wss://")) {
845
+ errors.push("Bounty IM imServerUrl must start with ws:// or wss://");
846
+ }
847
+ return errors;
848
+ },
849
+ createInstance(config) {
850
+ return new BountyIMInstance(config);
851
+ }
852
+ };
853
853
 
854
854
  // src/env/event-source/bounty-cli-handler.ts
855
855
  import { spawn } from "child_process";
@@ -1085,409 +1085,8 @@ var bountyCliHandler = {
1085
1085
 
1086
1086
  // src/env/event-source/event-source-handlers.ts
1087
1087
  init_logger();
1088
-
1089
- // src/env/error-reply.ts
1090
- init_logger();
1091
- import { spawn as spawn2 } from "node:child_process";
1092
- var logger2 = createLogger("env:error-reply");
1093
- var UPSTREAM_RETRY_PATTERNS = [
1094
- /failed after \d+ attempts/i,
1095
- /endpoint is unavailable/i,
1096
- /upstream request failed/i,
1097
- /rate.?limit/i,
1098
- /\b429\b/,
1099
- /\b50[0234]\b/,
1100
- /service (is )?(temporarily )?unavailable/i,
1101
- /\beconn(reset|refused|aborted)\b/i,
1102
- /socket hang up/i,
1103
- /fetch failed/i,
1104
- /network error/i,
1105
- /overloaded/i
1106
- ];
1107
- var TIMEOUT_PATTERNS = [
1108
- /timeout/i,
1109
- /timed out/i,
1110
- /deadline exceeded/i,
1111
- /etimedout/i,
1112
- /aborted due to timeout/i
1113
- ];
1114
- var TRANSPORT_ABORT_PATTERNS = [
1115
- /requestabortederror/i,
1116
- /econnaborted/i,
1117
- /connection (was )?(aborted|reset|closed)/i,
1118
- /premature close/i
1119
- ];
1120
- var ABORT_PATTERNS = [
1121
- /\babort(?:ed|ing)?\b/i,
1122
- /operation was cancelled/i,
1123
- /operation was canceled/i,
1124
- /sigint/i,
1125
- /\binterrupted\b/i,
1126
- /exiting due to (signal|shutdown)/i
1127
- ];
1128
- var CONTEXT_PATTERNS = [
1129
- /context threshold/i,
1130
- /context (window|length|limit)/i,
1131
- /token limit/i,
1132
- /maximum context/i,
1133
- /ctrieve\b/,
1134
- /CTX_001/
1135
- ];
1136
- var ASK_USER_PATTERNS = [/__ASK_USER_ERROR__/];
1137
- function collectErrorText(error, depth = 0) {
1138
- const parts = [];
1139
- const push = (v) => {
1140
- if (typeof v === "string" && v.length > 0)
1141
- parts.push(v);
1142
- };
1143
- if (error === null || error === undefined)
1144
- return "";
1145
- if (typeof error === "string") {
1146
- push(error);
1147
- return parts.join(`
1148
- `);
1149
- }
1150
- if (typeof error !== "object") {
1151
- push(String(error));
1152
- return parts.join(`
1153
- `);
1154
- }
1155
- const e = error;
1156
- push(e.name);
1157
- push(e.message);
1158
- for (const key of ["statusCode", "status", "code"]) {
1159
- const v = e[key];
1160
- if (typeof v === "number" || typeof v === "string")
1161
- push(String(v));
1162
- }
1163
- if (depth < 3) {
1164
- const nested = collectErrorText(e.lastError, depth + 1);
1165
- if (nested)
1166
- parts.push(nested);
1167
- if (Array.isArray(e.errors)) {
1168
- for (const inner of e.errors.slice(-3)) {
1169
- const s = collectErrorText(inner, depth + 1);
1170
- if (s)
1171
- parts.push(s);
1172
- }
1173
- }
1174
- const cause = collectErrorText(e.cause, depth + 1);
1175
- if (cause)
1176
- parts.push(cause);
1177
- }
1178
- return parts.join(`
1179
- `);
1180
- }
1181
- function truncate(text, max) {
1182
- if (text.length <= max)
1183
- return text;
1184
- return text.slice(0, max) + "…";
1185
- }
1186
- var FAILURE_RULES = [
1187
- {
1188
- id: "ask_user",
1189
- kind: "ask_user",
1190
- names: ["AskUserError"],
1191
- patterns: ASK_USER_PATTERNS,
1192
- notify: false,
1193
- title: "等待用户回答",
1194
- reason: "agent 正在等待用户回答,不是失败。",
1195
- retryable: false
1196
- },
1197
- {
1198
- id: "context_overflow",
1199
- kind: "context_overflow",
1200
- names: ["ContextError"],
1201
- patterns: CONTEXT_PATTERNS,
1202
- notify: true,
1203
- title: "上下文超出限制",
1204
- reason: "这次对话的上下文超出模型窗口,自动压缩也未能恢复。建议新开一个会话继续,或先让我压缩当前会话。",
1205
- retryable: false
1206
- },
1207
- {
1208
- id: "timeout",
1209
- kind: "timeout",
1210
- names: ["TimeoutError"],
1211
- patterns: TIMEOUT_PATTERNS,
1212
- notify: true,
1213
- title: "执行超时",
1214
- reason: "本次执行等待响应超时(上游长时间未返回或网络卡住)。建议稍后重试,或把任务拆小一些。",
1215
- retryable: true
1216
- },
1217
- {
1218
- id: "upstream_retry",
1219
- kind: "upstream_retry",
1220
- names: ["AI_RetryError", "RetryError", "APICallError", "AI_APICallError"],
1221
- patterns: UPSTREAM_RETRY_PATTERNS,
1222
- notify: true,
1223
- title: "模型服务暂时不可用(重试已用尽)",
1224
- reason: "调用模型时上游持续返回错误(如 429 限流 / 503 不可用),自动重试多次后仍未成功。" + "这不是你的操作问题,也不是仓库代码的问题 —— 稍后重发一次即可。",
1225
- retryable: true
1226
- },
1227
- {
1228
- id: "upstream_aborted",
1229
- kind: "upstream_aborted",
1230
- names: ["RequestAbortedError"],
1231
- patterns: TRANSPORT_ABORT_PATTERNS,
1232
- unless: TIMEOUT_PATTERNS,
1233
- notify: true,
1234
- title: "与模型服务的连接中断",
1235
- reason: "请求在传输过程中被中断(连接被重置 / 代理提前关闭),不是你的操作问题。稍后重发一次即可。",
1236
- retryable: true
1237
- },
1238
- {
1239
- id: "aborted",
1240
- kind: "aborted",
1241
- names: ["AbortError", "AbortSignal"],
1242
- patterns: ABORT_PATTERNS,
1243
- unless: [...TIMEOUT_PATTERNS, ...TRANSPORT_ABORT_PATTERNS],
1244
- notify: true,
1245
- title: "执行被中断",
1246
- reason: "本次执行在完成前被中断(可能你手动取消了,或进程收到了停止信号)。你可以直接让我重新执行。",
1247
- retryable: true
1248
- }
1249
- ];
1250
- var UNKNOWN_RULE = {
1251
- id: "unknown",
1252
- kind: "unknown",
1253
- notify: true,
1254
- title: "执行异常失败",
1255
- reason: "本次执行遇到了未预期的异常,已中止。你可以重试;如果持续失败,请把这条消息里的技术细节发我。",
1256
- retryable: true
1257
- };
1258
- function ruleMatches(rule, name, text) {
1259
- const lowered = name.toLowerCase();
1260
- const nameHit = rule.names?.some((n) => n.toLowerCase() === lowered) ?? false;
1261
- const patternHit = rule.patterns?.some((p) => p.test(text)) ?? false;
1262
- if (!nameHit && !patternHit)
1263
- return false;
1264
- if (rule.unless?.some((p) => p.test(text)))
1265
- return false;
1266
- return true;
1267
- }
1268
- function classifyReactFailure(error) {
1269
- const text = collectErrorText(error);
1270
- const name = error && typeof error === "object" ? String(error.name ?? "") : "";
1271
- const technical = text ? truncate(text.replace(/\s*\n\s*/g, " | "), 400) : undefined;
1272
- const rule = FAILURE_RULES.find((r) => ruleMatches(r, name, text)) ?? UNKNOWN_RULE;
1273
- return {
1274
- kind: rule.kind,
1275
- ruleId: rule.id,
1276
- title: rule.title,
1277
- reason: rule.reason,
1278
- retryable: rule.retryable,
1279
- notify: rule.notify,
1280
- technical
1281
- };
1282
- }
1283
- var MAX_QUERY_PREVIEW = 200;
1284
- function buildFailureReplyMarkdown(info, opts) {
1285
- const lines = [];
1286
- lines.push(`❌ **${info.title}**`);
1287
- lines.push("");
1288
- lines.push(info.reason);
1289
- const query = opts?.query?.trim();
1290
- if (query) {
1291
- lines.push("");
1292
- lines.push(`> 原始请求:${truncate(query.replace(/\s+/g, " "), MAX_QUERY_PREVIEW)}`);
1293
- }
1294
- if (info.retryable) {
1295
- lines.push("");
1296
- lines.push("**你可以:** 直接再发一次(重发即可,无需额外操作)。");
1297
- } else {
1298
- lines.push("");
1299
- lines.push("**你可以:** 新开一个会话,或先让我压缩当前会话。");
1300
- }
1301
- const technical = info.technical;
1302
- if (technical) {
1303
- lines.push("");
1304
- lines.push(`> 技术细节:${truncate(technical, 300)}`);
1305
- }
1306
- return lines.join(`
1307
- `);
1308
- }
1309
- function extractReplyChannelFromEvent(envEvent) {
1310
- if (!envEvent || typeof envEvent !== "object")
1311
- return;
1312
- const e = envEvent;
1313
- const candidates = [
1314
- e.metadata?.replyChannel,
1315
- e.payload?.replyChannel
1316
- ];
1317
- for (const c of candidates) {
1318
- if (c && typeof c === "object") {
1319
- const ch = c;
1320
- if (ch.chatId || ch.messageId)
1321
- return ch;
1322
- }
1323
- }
1324
- return;
1325
- }
1326
- function isUsableChannel(ch) {
1327
- if (!ch)
1328
- return false;
1329
- if (!ch.chatId && !ch.messageId)
1330
- return false;
1331
- if (ch.type && !ch.type.toLowerCase().includes("lark"))
1332
- return false;
1333
- return true;
1334
- }
1335
- var repliedTriggers = new Map;
1336
- var CHAT_DEDUP_WINDOW_MS = 5 * 60000;
1337
- var MAX_DEDUP_ENTRIES = 1000;
1338
- function makeDedupKey(channel, info, explicit, now = Date.now()) {
1339
- if (explicit)
1340
- return explicit;
1341
- if (channel.messageId)
1342
- return `msg:${channel.messageId}`;
1343
- if (channel.chatId) {
1344
- const bucket = Math.floor(now / CHAT_DEDUP_WINDOW_MS);
1345
- return `chat:${channel.chatId}:${info.kind}:${bucket}`;
1346
- }
1347
- return "unknown";
1348
- }
1349
- function isDuplicate(key, now = Date.now()) {
1350
- const at = repliedTriggers.get(key);
1351
- if (at === undefined)
1352
- return false;
1353
- if (key.startsWith("chat:") && now - at >= CHAT_DEDUP_WINDOW_MS) {
1354
- repliedTriggers.delete(key);
1355
- return false;
1356
- }
1357
- return true;
1358
- }
1359
- function rememberTrigger(key, now = Date.now()) {
1360
- if (repliedTriggers.size >= MAX_DEDUP_ENTRIES) {
1361
- const oldest = repliedTriggers.keys().next().value;
1362
- if (oldest !== undefined)
1363
- repliedTriggers.delete(oldest);
1364
- }
1365
- repliedTriggers.set(key, now);
1366
- }
1367
- var DEFAULT_REPLY_TIMEOUT_MS = 5000;
1368
- function spawnLarkReply(options) {
1369
- return new Promise((resolve, reject) => {
1370
- const { chatId, messageId, content, profile } = options;
1371
- const timeoutMs = options.timeoutMs ?? DEFAULT_REPLY_TIMEOUT_MS;
1372
- let settled = false;
1373
- let timer;
1374
- const finish = (err) => {
1375
- if (settled)
1376
- return;
1377
- settled = true;
1378
- if (timer)
1379
- clearTimeout(timer);
1380
- if (err)
1381
- reject(err);
1382
- else
1383
- resolve();
1384
- };
1385
- const normalizedContent = normalizeLarkAtMentions(content);
1386
- let args;
1387
- if (messageId) {
1388
- args = [
1389
- "im",
1390
- "+messages-reply",
1391
- "--message-id",
1392
- messageId,
1393
- "--markdown",
1394
- normalizedContent,
1395
- "--as",
1396
- "bot"
1397
- ];
1398
- } else if (chatId) {
1399
- args = [
1400
- "im",
1401
- "+messages-send",
1402
- "--chat-id",
1403
- chatId,
1404
- "--markdown",
1405
- normalizedContent,
1406
- "--as",
1407
- "bot"
1408
- ];
1409
- } else {
1410
- finish(new Error("No target specified for failure reply"));
1411
- return;
1412
- }
1413
- if (profile) {
1414
- args.unshift("--profile", profile);
1415
- }
1416
- let proc;
1417
- try {
1418
- proc = spawn2("lark-cli", args, {
1419
- shell: false,
1420
- stdio: ["pipe", "pipe", "pipe"]
1421
- });
1422
- } catch (err) {
1423
- finish(err instanceof Error ? err : new Error(String(err)));
1424
- return;
1425
- }
1426
- timer = setTimeout(() => {
1427
- try {
1428
- proc.kill("SIGKILL");
1429
- } catch {}
1430
- finish(new Error(`lark-cli timed out after ${timeoutMs}ms`));
1431
- }, timeoutMs);
1432
- timer.unref?.();
1433
- let stderr = "";
1434
- proc.stdout?.on("data", () => {});
1435
- proc.stderr?.on("data", (data) => {
1436
- stderr += data.toString();
1437
- });
1438
- proc.on("close", (code) => {
1439
- if (code === 0)
1440
- finish();
1441
- else
1442
- finish(new Error(`lark-cli exited with code ${code}: ${stderr}`));
1443
- });
1444
- proc.on("error", (err) => finish(err));
1445
- });
1446
- }
1447
- async function notifyReactFailure(options) {
1448
- const info = classifyReactFailure(options.error);
1449
- if (!info.notify) {
1450
- logger2.debug(`[#4418] 命中规则 ${info.ruleId}(非失败),不发失败说明` + (options.sessionId ? ` (session=${options.sessionId})` : ""));
1451
- return { sent: false, kind: info.kind, info, skipped: "not_a_failure" };
1452
- }
1453
- const channel = (isUsableChannel(options.replyChannel) ? options.replyChannel : undefined) ?? extractReplyChannelFromEvent(options.envEvent);
1454
- if (!isUsableChannel(channel)) {
1455
- const hasTrigger = Boolean(options.envEvent);
1456
- const noChannelMsg = `[#4418] React 中断(${info.kind}/${info.ruleId})无法定位 replyChannel,` + `飞书端收不到失败说明` + (hasTrigger ? " —— triggerEvent 存在但缺少 metadata.replyChannel" : "(本地执行,无 triggerEvent)") + (options.sessionId ? ` (session=${options.sessionId})` : "");
1457
- if (hasTrigger)
1458
- logger2.warn(noChannelMsg);
1459
- else
1460
- logger2.debug(noChannelMsg);
1461
- return { sent: false, kind: info.kind, info, skipped: "no_channel" };
1462
- }
1463
- const dedupKey = makeDedupKey(channel, info, options.dedupKey);
1464
- if (isDuplicate(dedupKey)) {
1465
- logger2.info(`[#4418] React 中断(${info.kind})已回复过 ${dedupKey},跳过`);
1466
- return { sent: false, kind: info.kind, info, skipped: "duplicate" };
1467
- }
1468
- rememberTrigger(dedupKey);
1469
- const content = buildFailureReplyMarkdown(info, { query: options.query });
1470
- try {
1471
- await spawnLarkReply({
1472
- chatId: channel.chatId,
1473
- messageId: channel.messageId,
1474
- content,
1475
- profile: channel.profile,
1476
- timeoutMs: options.replyTimeoutMs
1477
- });
1478
- logger2.info(`[#4418] React 中断(${info.kind}/${info.ruleId})已回飞书 ` + `(${channel.messageId ?? channel.chatId})`);
1479
- return { sent: true, kind: info.kind, info };
1480
- } catch (err) {
1481
- const errorMsg = err instanceof Error ? err.message : String(err);
1482
- repliedTriggers.delete(dedupKey);
1483
- logger2.warn(`[#4418] React 中断(${info.kind}/${info.ruleId})回飞书失败(已忽略): ${errorMsg}`);
1484
- return { sent: false, kind: info.kind, info, error: errorMsg };
1485
- }
1486
- }
1487
-
1488
- // src/env/event-source/event-source-handlers.ts
1489
1088
  var execAsync2 = promisify2(execSync);
1490
- var logger3 = createLogger("lark-cli:event-source");
1089
+ var logger2 = createLogger("lark-cli:event-source");
1491
1090
  var CHILD_READY_TIMEOUT_MS = 5000;
1492
1091
  var GRACEFUL_STOP_TIMEOUT_MS = 5000;
1493
1092
  var CARD_ACTION_EVENT_TYPE = "card.action.trigger";
@@ -1716,8 +1315,8 @@ class LarkCliInstance {
1716
1315
  cardActionPorts;
1717
1316
  setCardActionPorts(ports) {
1718
1317
  this.cardActionPorts = ports;
1719
- if (typeof logger3 !== "undefined" && logger3?.debug) {
1720
- logger3.debug(`[LarkCliInstance] CardActionPorts injected: ` + `getTask=${typeof ports.getTask}, updateTaskContext=${typeof ports.updateTaskContext}, ` + `createGroupChat=${typeof ports.createGroupChat}, deleteGroupChat=${typeof ports.deleteGroupChat}, ` + `notifier=${typeof ports.notifier}`);
1318
+ if (typeof logger2 !== "undefined" && logger2?.debug) {
1319
+ logger2.debug(`[LarkCliInstance] CardActionPorts injected: ` + `getTask=${typeof ports.getTask}, updateTaskContext=${typeof ports.updateTaskContext}, ` + `createGroupChat=${typeof ports.createGroupChat}, deleteGroupChat=${typeof ports.deleteGroupChat}, ` + `notifier=${typeof ports.notifier}`);
1721
1320
  }
1722
1321
  }
1723
1322
  hasCardActionPorts() {
@@ -1744,7 +1343,7 @@ class LarkCliInstance {
1744
1343
  if (this.status === "running")
1745
1344
  return;
1746
1345
  if (this.starting) {
1747
- logger3.warn(`[LarkCliInstance] start() 已在执行中,忽略重复调用`);
1346
+ logger2.warn(`[LarkCliInstance] start() 已在执行中,忽略重复调用`);
1748
1347
  return;
1749
1348
  }
1750
1349
  this.starting = true;
@@ -1774,12 +1373,12 @@ class LarkCliInstance {
1774
1373
  if (!consumesCardAction)
1775
1374
  return;
1776
1375
  if (this.config.eventTypes?.length && !matchEventType(CARD_ACTION_EVENT_TYPE, this.config.eventTypes)) {
1777
- logger3.warn(`[LarkCliInstance] eventKeys 含 ${CARD_ACTION_EVENT_TYPE},但 eventTypes=` + `${JSON.stringify(this.config.eventTypes)} 不含它 → 卡片点击会被**静默丢弃**。` + `请把 ${CARD_ACTION_EVENT_TYPE} 加进 eventTypes,或清空 eventTypes。`);
1376
+ logger2.warn(`[LarkCliInstance] eventKeys 含 ${CARD_ACTION_EVENT_TYPE},但 eventTypes=` + `${JSON.stringify(this.config.eventTypes)} 不含它 → 卡片点击会被**静默丢弃**。` + `请把 ${CARD_ACTION_EVENT_TYPE} 加进 eventTypes,或清空 eventTypes。`);
1778
1377
  }
1779
- logger3.info(`[LarkCliInstance] 已监听 ${CARD_ACTION_EVENT_TYPE}。` + `⚠️ 若点击卡片无反应,先确认飞书开发者后台「事件与回调 → 回调配置」已开启该事件。`);
1378
+ logger2.info(`[LarkCliInstance] 已监听 ${CARD_ACTION_EVENT_TYPE}。` + `⚠️ 若点击卡片无反应,先确认飞书开发者后台「事件与回调 → 回调配置」已开启该事件。`);
1780
1379
  }
1781
1380
  spawnConsumeChild(command) {
1782
- return spawn3("exec " + command, [], {
1381
+ return spawn2("exec " + command, [], {
1783
1382
  shell: true,
1784
1383
  stdio: ["pipe", "pipe", "pipe"],
1785
1384
  windowsHide: true
@@ -1816,7 +1415,7 @@ class LarkCliInstance {
1816
1415
  const conflicts = keys.filter((k) => busy.has(k));
1817
1416
  if (conflicts.length > 0) {
1818
1417
  const profile = this.config.profile;
1819
- logger3.warn(`[LarkCliInstance] eventKey 已被其它 consumer 占用(lark-cli 一个 key 只允许一个 consumer):` + `${conflicts.join(", ")}。本 event-source 启动后可能 exit 2。` + `用 \`lark-cli${profile ? ` --profile ${profile}` : ""} event status\` 查看,必要时 \`event stop\`。`);
1418
+ logger2.warn(`[LarkCliInstance] eventKey 已被其它 consumer 占用(lark-cli 一个 key 只允许一个 consumer):` + `${conflicts.join(", ")}。本 event-source 启动后可能 exit 2。` + `用 \`lark-cli${profile ? ` --profile ${profile}` : ""} event status\` 查看,必要时 \`event stop\`。`);
1820
1419
  }
1821
1420
  }
1822
1421
  async probeBusyEventKeys() {
@@ -1867,16 +1466,16 @@ class LarkCliInstance {
1867
1466
  });
1868
1467
  const handleExit = (code, source) => {
1869
1468
  if (code !== 0 && code !== null) {
1870
- logger3.warn(`[LarkCliInstance] consume 子进程异常退出 code=${code} (${source}) cmd="${command}"`);
1469
+ logger2.warn(`[LarkCliInstance] consume 子进程异常退出 code=${code} (${source}) cmd="${command}"`);
1871
1470
  this.status = "error";
1872
1471
  } else {
1873
- logger3.info(`[LarkCliInstance] consume 子进程已退出 code=${code} (${source}) cmd="${command}"`);
1472
+ logger2.info(`[LarkCliInstance] consume 子进程已退出 code=${code} (${source}) cmd="${command}"`);
1874
1473
  }
1875
1474
  settle();
1876
1475
  queueMicrotask(() => {
1877
1476
  if (this.children.length > 0 && this.children.every((c) => !isChildAlive(c))) {
1878
1477
  if (this.status !== "error") {
1879
- logger3.warn(`[LarkCliInstance] 所有 consume 子进程都已退出,状态从 running 改为 stopped`);
1478
+ logger2.warn(`[LarkCliInstance] 所有 consume 子进程都已退出,状态从 running 改为 stopped`);
1880
1479
  this.status = "stopped";
1881
1480
  }
1882
1481
  }
@@ -1885,12 +1484,12 @@ class LarkCliInstance {
1885
1484
  child.on("exit", (code) => handleExit(code, "exit"));
1886
1485
  child.on("close", (code) => handleExit(code, "close"));
1887
1486
  child.on("error", (error) => {
1888
- logger3.error(`[LarkCliInstance] consume 子进程 error: ${error.message}`);
1487
+ logger2.error(`[LarkCliInstance] consume 子进程 error: ${error.message}`);
1889
1488
  this.status = "error";
1890
1489
  settle();
1891
1490
  });
1892
1491
  const timer = setTimeout(() => {
1893
- logger3.warn(`[LarkCliInstance] consume 子进程 ${CHILD_READY_TIMEOUT_MS}ms 内未见 ready marker: cmd="${command}"`);
1492
+ logger2.warn(`[LarkCliInstance] consume 子进程 ${CHILD_READY_TIMEOUT_MS}ms 内未见 ready marker: cmd="${command}"`);
1894
1493
  settle();
1895
1494
  }, CHILD_READY_TIMEOUT_MS);
1896
1495
  ready.then(() => clearTimeout(timer));
@@ -1913,7 +1512,7 @@ class LarkCliInstance {
1913
1512
  try {
1914
1513
  child.kill("SIGTERM");
1915
1514
  } catch (error) {
1916
- logger3.warn(`[LarkCliInstance] Error sending SIGTERM to ${child.pid}: ${error}`);
1515
+ logger2.warn(`[LarkCliInstance] Error sending SIGTERM to ${child.pid}: ${error}`);
1917
1516
  }
1918
1517
  }
1919
1518
  const allExited = Promise.all(children.map((child) => new Promise((resolve) => {
@@ -1968,12 +1567,12 @@ class LarkCliInstance {
1968
1567
  }
1969
1568
  wireCardActionPorts() {
1970
1569
  if (this.cardActionPorts) {
1971
- logger3.debug("[LarkCliInstance] cardActionPorts 已由外部注入,跳过默认 cross-wire");
1570
+ logger2.debug("[LarkCliInstance] cardActionPorts 已由外部注入,跳过默认 cross-wire");
1972
1571
  return;
1973
1572
  }
1974
1573
  const taskComponent = this.environment?.getComponent?.("task");
1975
1574
  if (!taskComponent?.getTask || !taskComponent?.updateTask) {
1976
- logger3.debug(`[LarkCliInstance] card.action.trigger 端口未注入:taskComponent 不可用` + `(getTask=${typeof taskComponent?.getTask}, updateTask=${typeof taskComponent?.updateTask})。` + `卡片按钮点击会被跳过。`);
1575
+ logger2.debug(`[LarkCliInstance] card.action.trigger 端口未注入:taskComponent 不可用` + `(getTask=${typeof taskComponent?.getTask}, updateTask=${typeof taskComponent?.updateTask})。` + `卡片按钮点击会被跳过。`);
1977
1576
  return;
1978
1577
  }
1979
1578
  const sharedNotifier = this.pluginInstances.get("LarkCliTaskNotifyPlugin")?.cardNotifier ?? this.pluginInstances.get("PerTaskGroupChatPlugin")?.cardNotifier;
@@ -2002,7 +1601,7 @@ class LarkCliInstance {
2002
1601
  deleteGroupChat: (chatId, profile) => deleteGroupChatViaLarkCli(chatId, profile),
2003
1602
  notifier: sharedNotifier ?? new LarkCardPatchNotifier
2004
1603
  });
2005
- logger3.info(`[LarkCliInstance] card.action.trigger 端口已注入` + `(notifier ${sharedNotifier ? "复用插件共享实例" : "新建实例"})`);
1604
+ logger2.info(`[LarkCliInstance] card.action.trigger 端口已注入` + `(notifier ${sharedNotifier ? "复用插件共享实例" : "新建实例"})`);
2006
1605
  }
2007
1606
  getPluginHookPoints(plugin) {
2008
1607
  if (Array.isArray(plugin.hooks)) {
@@ -2200,7 +1799,7 @@ class LarkCliInstance {
2200
1799
  }
2201
1800
  return null;
2202
1801
  } catch (err) {
2203
- logger3.warn(`[LarkCliInstance] resolveChatTaskBinding failed for chatId=${chatId}: ${err}. ` + `群消息将不会注入 parentTaskId。`);
1802
+ logger2.warn(`[LarkCliInstance] resolveChatTaskBinding failed for chatId=${chatId}: ${err}. ` + `群消息将不会注入 parentTaskId。`);
2204
1803
  return null;
2205
1804
  }
2206
1805
  }
@@ -2222,7 +1821,7 @@ class LarkCliInstance {
2222
1821
  processStreamWith(data, buffer, opts = {}) {
2223
1822
  buffer.value += data;
2224
1823
  if (buffer.value.length > 2 * 1024 * 1024) {
2225
- logger3.warn(`[LarkCliInstance] stream 行缓冲超过 2MB 仍无换行,丢弃(疑似非 NDJSON 输出)`);
1824
+ logger2.warn(`[LarkCliInstance] stream 行缓冲超过 2MB 仍无换行,丢弃(疑似非 NDJSON 输出)`);
2226
1825
  buffer.value = "";
2227
1826
  return;
2228
1827
  }
@@ -2258,12 +1857,12 @@ class LarkCliInstance {
2258
1857
  const now = Date.now();
2259
1858
  const lastShared = LarkCliInstance.SHARED_SEEN.get(dedupKey);
2260
1859
  if (lastShared !== undefined && now - lastShared < LarkCliInstance.SHARED_MSG_TTL_MS) {
2261
- logger3.warn(`[LarkCliInstance] duplicate lark-cli event suppressed across instances (event_id=${dedupKey}, ` + `lastSeen=${now - lastShared}ms ago). ` + `Task #4137: SHARED_SEEN 跨实例去重。`);
1860
+ logger2.warn(`[LarkCliInstance] duplicate lark-cli event suppressed across instances (event_id=${dedupKey}, ` + `lastSeen=${now - lastShared}ms ago). ` + `Task #4137: SHARED_SEEN 跨实例去重。`);
2262
1861
  return;
2263
1862
  }
2264
1863
  const last = this.recentEventIds.get(dedupKey);
2265
1864
  if (last !== undefined && now - last < this.DEDUP_WINDOW_MS) {
2266
- logger3.warn(`[LarkCliInstance] duplicate lark-cli event suppressed (event_id=${dedupKey}, ` + `lastSeen=${now - last}ms ago). ` + `Task #3977/3978: 防止同一飞书事件触发两次任务创建。`);
1865
+ logger2.warn(`[LarkCliInstance] duplicate lark-cli event suppressed (event_id=${dedupKey}, ` + `lastSeen=${now - last}ms ago). ` + `Task #3977/3978: 防止同一飞书事件触发两次任务创建。`);
2267
1866
  return;
2268
1867
  }
2269
1868
  LarkCliInstance.SHARED_SEEN.set(dedupKey, now);
@@ -2443,11 +2042,11 @@ class LarkCliInstance {
2443
2042
  const chatId = event.chat_id || "";
2444
2043
  const operatorId = event.operator_id?.open_id ?? event.operator_id ?? undefined;
2445
2044
  if (!token || !messageId || !chatId) {
2446
- logger3.warn(`[LarkCliInstance] handleCardActionEvent: missing token/messageId/chatId, skip`);
2045
+ logger2.warn(`[LarkCliInstance] handleCardActionEvent: missing token/messageId/chatId, skip`);
2447
2046
  return;
2448
2047
  }
2449
2048
  if (!this.cardActionPorts) {
2450
- logger3.warn(`[LarkCliInstance] handleCardActionEvent: cardActionPorts 未注入,` + `card.action.trigger 事件被跳过。` + `调 instance.setCardActionPorts({getTask, updateTaskContext, createGroupChat, deleteGroupChat, notifier}) 注入。`);
2049
+ logger2.warn(`[LarkCliInstance] handleCardActionEvent: cardActionPorts 未注入,` + `card.action.trigger 事件被跳过。` + `调 instance.setCardActionPorts({getTask, updateTaskContext, createGroupChat, deleteGroupChat, notifier}) 注入。`);
2451
2050
  return;
2452
2051
  }
2453
2052
  const result = await handleCardAction({
@@ -2462,10 +2061,10 @@ class LarkCliInstance {
2462
2061
  const patch = this.cardActionPorts.patchByToken ?? patchCardByLarkCli;
2463
2062
  await patch(token, result.cardUpdate, profile);
2464
2063
  } else {
2465
- logger3.warn(`[LarkCliInstance] handleCardActionEvent failed: ${result.error ?? "unknown"}`);
2064
+ logger2.warn(`[LarkCliInstance] handleCardActionEvent failed: ${result.error ?? "unknown"}`);
2466
2065
  }
2467
2066
  } catch (err) {
2468
- logger3.error(`[LarkCliInstance] handleCardActionEvent error: ${err.message}`);
2067
+ logger2.error(`[LarkCliInstance] handleCardActionEvent error: ${err.message}`);
2469
2068
  }
2470
2069
  }
2471
2070
  async patchCardByToken(token, card, profile) {
@@ -2553,7 +2152,7 @@ class LarkCliInstance {
2553
2152
  if (profile) {
2554
2153
  args.unshift("--profile", profile);
2555
2154
  }
2556
- const proc = spawn3("lark-cli", args, {
2155
+ const proc = spawn2("lark-cli", args, {
2557
2156
  shell: false,
2558
2157
  stdio: ["pipe", "pipe", "pipe"]
2559
2158
  });
@@ -2650,7 +2249,7 @@ var larkCliHandler = {
2650
2249
  },
2651
2250
  async emitTriggerEvent(payload, store) {
2652
2251
  const eventId = await store.insertTriggerEvent(payload, "lark-cli");
2653
- logger3.info(`[larkCliHandler] emitTriggerEvent: id=${eventId}`, {
2252
+ logger2.info(`[larkCliHandler] emitTriggerEvent: id=${eventId}`, {
2654
2253
  chatId: payload.metadata?.chatId,
2655
2254
  senderId: payload.senderId
2656
2255
  });
@@ -2665,7 +2264,7 @@ var larkCliHandler = {
2665
2264
  try {
2666
2265
  const result = await runner.run(command);
2667
2266
  if (result.code !== 0) {
2668
- logger3.error(`[larkCliHandler] replyMessage non-zero exit`, {
2267
+ logger2.error(`[larkCliHandler] replyMessage non-zero exit`, {
2669
2268
  code: result.code,
2670
2269
  stderr: result.stderr
2671
2270
  });
@@ -2679,7 +2278,7 @@ var larkCliHandler = {
2679
2278
  return { success: true, messageId: replyMessageId };
2680
2279
  } catch (err) {
2681
2280
  const errMsg = err instanceof Error ? err.message : String(err);
2682
- logger3.error(`[larkCliHandler] replyMessage spawn error`, { error: errMsg });
2281
+ logger2.error(`[larkCliHandler] replyMessage spawn error`, { error: errMsg });
2683
2282
  return { success: false, error: errMsg };
2684
2283
  }
2685
2284
  },
@@ -2786,469 +2385,20 @@ async function patchCardByLarkCli(token, card, profile) {
2786
2385
  const cmd = `lark-cli ${profileFlag}api POST /open-apis/interactive/v1/card/update ` + `--data '${JSON.stringify({ token, card }).replace(/'/g, "'\\''")}' --as bot`;
2787
2386
  try {
2788
2387
  const { stdout } = await execAsync2(cmd, { timeout: 30000 });
2789
- logger3.debug(`patchCardByLarkCli ok: ${stdout?.slice(0, 200)}`);
2388
+ logger2.debug(`patchCardByLarkCli ok: ${stdout?.slice(0, 200)}`);
2790
2389
  } catch (err) {
2791
- logger3.error(`patchCardByLarkCli failed: ${err.message}`);
2390
+ logger2.error(`patchCardByLarkCli failed: ${err.message}`);
2792
2391
  }
2793
2392
  }
2794
2393
  var builtInHandlers = [
2795
2394
  larkCliHandler,
2796
2395
  timerHandler,
2797
2396
  bountyIMHandler,
2798
- bountyCliHandler
2397
+ bountyCliHandler,
2398
+ cliCommandHandler
2799
2399
  ];
2800
2400
  function getBuiltInHandler(type) {
2801
2401
  return builtInHandlers.find((h) => h.type === type);
2802
2402
  }
2803
2403
 
2804
- // src/env/event-source/event-source-component.ts
2805
- import { join } from "path";
2806
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2807
- init_logger();
2808
- init_decorator();
2809
-
2810
- // src/env/event-source/event-source-config-registration.ts
2811
- var EVENT_SOURCE_DEFAULTS = {
2812
- "event-source.enabled": true,
2813
- "event-source.persistenceEnabled": true
2814
- };
2815
- var EVENT_SOURCE_CONFIG_REGISTRATION = {
2816
- name: "event-source",
2817
- sources: [
2818
- { type: "env", envPrefix: "EVENT_SOURCE", priority: 20, watch: false }
2819
- ],
2820
- keys: [
2821
- { key: "event-source.enabled", sources: ["env", "file"] },
2822
- { key: "event-source.persistenceEnabled", sources: ["env", "file"] },
2823
- { key: "event-source.configPath", sources: ["env", "file"] }
2824
- ]
2825
- };
2826
-
2827
- // src/env/event-source/event-source-component.ts
2828
- var logger4 = createLogger("event-source");
2829
-
2830
- class EventSourceComponent extends BaseComponent {
2831
- name = "event-source";
2832
- version = "1.0.0";
2833
- sources = new Map;
2834
- statuses = new Map;
2835
- handlers = new Map;
2836
- instances = new Map;
2837
- eventHandlers = new Map;
2838
- buffers = new Map;
2839
- configPath = "";
2840
- persistenceEnabled = true;
2841
- configComponent;
2842
- configWatcher;
2843
- async onInit() {
2844
- await this.executeInitHooks();
2845
- await this.loadConfig();
2846
- }
2847
- async init(options) {
2848
- if (options?.env) {
2849
- this.env = options.env;
2850
- }
2851
- this.setStatus("initializing");
2852
- if (options?.name)
2853
- Object.defineProperty(this, "name", { value: options.name, writable: false });
2854
- if (options?.version)
2855
- Object.defineProperty(this, "version", { value: options.version, writable: false });
2856
- if (options?.enabled !== undefined)
2857
- this._enabled = options.enabled;
2858
- const opts = options?.options;
2859
- if (opts?.configComponent) {
2860
- this.configComponent = opts.configComponent;
2861
- await this.registerConfig(opts);
2862
- if (opts.registerBuiltInHandlers !== false) {
2863
- this.registerBuiltInHandlers();
2864
- }
2865
- } else {
2866
- throw new Error("ConfigComponent is required for EventSourceComponent initialization");
2867
- }
2868
- await this.onInit();
2869
- this.setStatus("running");
2870
- }
2871
- async onStart() {}
2872
- async onStop() {
2873
- this.configWatcher?.();
2874
- this.configWatcher = undefined;
2875
- const runningSources = Array.from(this.statuses.entries()).filter(([_, status]) => status === "running").map(([id]) => id);
2876
- for (const id of runningSources) {
2877
- await this.stopSource(id);
2878
- }
2879
- this.sources.clear();
2880
- this.statuses.clear();
2881
- this.instances.clear();
2882
- this.eventHandlers.clear();
2883
- this.handlers.clear();
2884
- this.buffers.clear();
2885
- }
2886
- createDefaultEventHandler(sourceId, sourceType) {
2887
- return (event) => {
2888
- this.getEnv()?.pushEnvEvent(event);
2889
- };
2890
- }
2891
- registerBuiltInHandlers() {
2892
- for (const handler of builtInHandlers) {
2893
- if (!this.handlers.has(handler.type)) {
2894
- this.handlers.set(handler.type, handler);
2895
- logger4.debug(`Registered built-in handler: ${handler.type}`);
2896
- }
2897
- }
2898
- }
2899
- async executeInitHooks() {
2900
- const { EventSourceInitHooks } = await import("./roy-agent-core-x6c45yqd.js");
2901
- await EventSourceInitHooks.execute(this);
2902
- }
2903
- registerHandler(handler) {
2904
- if (this.handlers.has(handler.type)) {
2905
- logger4.warn(`Handler already registered for type: ${handler.type}, overwriting`);
2906
- }
2907
- this.handlers.set(handler.type, handler);
2908
- logger4.debug(`Handler registered: ${handler.type}`);
2909
- }
2910
- unregisterHandler(type) {
2911
- const deleted = this.handlers.delete(type);
2912
- if (deleted) {
2913
- logger4.debug(`Handler unregistered: ${type}`);
2914
- }
2915
- return deleted;
2916
- }
2917
- getHandler(type) {
2918
- return this.handlers.get(type);
2919
- }
2920
- listHandlers() {
2921
- return Array.from(this.handlers.values());
2922
- }
2923
- async registerConfig(options) {
2924
- const configComponent = options.configComponent;
2925
- if (!configComponent)
2926
- return;
2927
- const { configPath, config } = options;
2928
- const envPrefix = "EVENT_SOURCE";
2929
- configComponent.registerComponent(EVENT_SOURCE_CONFIG_REGISTRATION);
2930
- if (configPath) {
2931
- configComponent.registerSource({
2932
- type: "file",
2933
- relativePath: configPath,
2934
- optional: true,
2935
- watch: false
2936
- });
2937
- }
2938
- configComponent.registerSource({
2939
- type: "env",
2940
- envPrefix,
2941
- priority: 20,
2942
- watch: false
2943
- });
2944
- await configComponent.load("event-source");
2945
- for (const envKey of Object.keys(process.env)) {
2946
- const configKey = envKeyToConfigKey(envKey, envPrefix, "event-source");
2947
- if (!configKey)
2948
- continue;
2949
- const value = process.env[envKey];
2950
- if (value !== undefined) {
2951
- await configComponent.set(configKey, value);
2952
- }
2953
- }
2954
- for (const [key, value] of Object.entries(EVENT_SOURCE_DEFAULTS)) {
2955
- if (configComponent.get(key) === undefined) {
2956
- await configComponent.set(key, value);
2957
- }
2958
- }
2959
- if (configComponent.get("event-source.configPath") === undefined) {
2960
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
2961
- const dataDir = join(home, ".roy-agent");
2962
- await configComponent.set("event-source.configPath", join(dataDir, "event-sources.json"));
2963
- }
2964
- if (config) {
2965
- const flatConfig = this.flattenConfig(config);
2966
- for (const [key, value] of Object.entries(flatConfig)) {
2967
- await configComponent.set(key, value);
2968
- }
2969
- }
2970
- this.registerConfigWatcher(configComponent);
2971
- }
2972
- buildConfig() {
2973
- const configComponent = this.configComponent;
2974
- if (!configComponent) {
2975
- return { enabled: true, persistenceEnabled: true, configPath: "" };
2976
- }
2977
- return {
2978
- enabled: configComponent.get("event-source.enabled") ?? true,
2979
- persistenceEnabled: configComponent.get("event-source.persistenceEnabled") ?? true,
2980
- configPath: configComponent.get("event-source.configPath") ?? ""
2981
- };
2982
- }
2983
- flattenConfig(obj, prefix = "event-source") {
2984
- const result = {};
2985
- for (const [key, value] of Object.entries(obj)) {
2986
- const fullKey = `${prefix}.${key}`;
2987
- if (value && typeof value === "object" && !Array.isArray(value)) {
2988
- Object.assign(result, this.flattenConfig(value, fullKey));
2989
- } else {
2990
- result[fullKey] = value;
2991
- }
2992
- }
2993
- return result;
2994
- }
2995
- registerConfigWatcher(configComponent) {
2996
- if (typeof configComponent.watch !== "function")
2997
- return;
2998
- this.configWatcher = configComponent.watch("event-source.*", (event) => {
2999
- this.onConfigChange(event);
3000
- });
3001
- }
3002
- onConfigChange(event) {
3003
- logger4.info(`EventSource config changed: ${event.key}`, {
3004
- oldValue: event.oldValue,
3005
- newValue: event.newValue
3006
- });
3007
- }
3008
- register(config) {
3009
- if (this.sources.has(config.id)) {
3010
- throw new Error(`EventSource already exists: ${config.id}`);
3011
- }
3012
- const handler = this.handlers.get(config.type);
3013
- if (!handler) {
3014
- throw new Error(`No handler registered for event source type: ${config.type}`);
3015
- }
3016
- const errors = handler.validateConfig(config);
3017
- if (errors.length > 0) {
3018
- throw new Error(`Invalid config: ${errors.join(", ")}`);
3019
- }
3020
- this.sources.set(config.id, config);
3021
- this.statuses.set(config.id, "created");
3022
- logger4.debug(`EventSource registered: ${config.id} (${config.type})`);
3023
- this.saveConfig().catch((err) => {
3024
- logger4.error(`Failed to save config after registering ${config.id}:`, err);
3025
- });
3026
- }
3027
- unregister(id) {
3028
- const status = this.statuses.get(id);
3029
- if (status === "running") {
3030
- this.stopSource(id);
3031
- }
3032
- const existed = this.sources.has(id);
3033
- this.sources.delete(id);
3034
- this.statuses.delete(id);
3035
- this.instances.delete(id);
3036
- this.eventHandlers.delete(id);
3037
- this.buffers.delete(id);
3038
- if (existed) {
3039
- logger4.debug(`EventSource unregistered: ${id}`);
3040
- this.saveConfig().catch((err) => {
3041
- logger4.error(`Failed to save config after unregistering ${id}:`, err);
3042
- });
3043
- }
3044
- return existed;
3045
- }
3046
- async update(id, partial) {
3047
- if (!partial || Object.keys(partial).length === 0) {
3048
- throw new Error("update() partial must not be empty");
3049
- }
3050
- const existing = this.sources.get(id);
3051
- if (!existing) {
3052
- throw new Error(`EventSource not found: ${id}`);
3053
- }
3054
- if (Object.prototype.hasOwnProperty.call(partial, "type")) {
3055
- if (partial.type !== existing.type) {
3056
- throw new Error(`Cannot update event source type: ${existing.type} -> ${partial.type} (use unregister + register instead)`);
3057
- }
3058
- }
3059
- const wasRunning = this.statuses.get(id) === "running";
3060
- let stopped = false;
3061
- if (wasRunning) {
3062
- await this.stopSource(id);
3063
- stopped = true;
3064
- }
3065
- const updated = {
3066
- ...existing,
3067
- ...partial,
3068
- id: existing.id,
3069
- type: existing.type
3070
- };
3071
- const handler = this.handlers.get(existing.type);
3072
- if (handler) {
3073
- const errors = handler.validateConfig(updated);
3074
- if (errors.length > 0) {
3075
- throw new Error(`Invalid config after update: ${errors.join(", ")}`);
3076
- }
3077
- }
3078
- this.sources.set(id, updated);
3079
- logger4.info(`EventSource updated: ${id}`, {
3080
- fields: Object.keys(partial)
3081
- });
3082
- try {
3083
- await this.saveConfig();
3084
- } catch (err) {
3085
- logger4.error(`Failed to save config after updating ${id}:`, err);
3086
- throw err;
3087
- }
3088
- return {
3089
- id,
3090
- updated,
3091
- wasRunning,
3092
- stopped,
3093
- restarted: false,
3094
- fields: Object.keys(partial)
3095
- };
3096
- }
3097
- get(id) {
3098
- return this.sources.get(id);
3099
- }
3100
- list() {
3101
- return Array.from(this.sources.values());
3102
- }
3103
- getStatus(id) {
3104
- if (id === undefined) {
3105
- return this._status;
3106
- }
3107
- return this.statuses.get(id);
3108
- }
3109
- getEventSourceStatus(id) {
3110
- return this.getStatus(id);
3111
- }
3112
- onEvent(id, handler) {
3113
- this.eventHandlers.set(id, handler);
3114
- const instance = this.instances.get(id);
3115
- if (instance) {
3116
- instance.onEvent(handler);
3117
- }
3118
- }
3119
- offEvent(id) {
3120
- this.eventHandlers.delete(id);
3121
- const instance = this.instances.get(id);
3122
- if (instance) {
3123
- instance.offEvent();
3124
- }
3125
- }
3126
- async startSource(id) {
3127
- const config = this.sources.get(id);
3128
- if (!config) {
3129
- throw new Error(`EventSource not found: ${id}`);
3130
- }
3131
- const currentStatus = this.statuses.get(id);
3132
- if (currentStatus === "running") {
3133
- return;
3134
- }
3135
- this.statuses.set(id, "starting");
3136
- try {
3137
- const handler = this.handlers.get(config.type);
3138
- if (!handler) {
3139
- throw new Error(`No handler registered for event source type: ${config.type}`);
3140
- }
3141
- const instance = handler.createInstance(config);
3142
- this.instances.set(id, instance);
3143
- if (typeof instance.setEnvironment === "function") {
3144
- instance.setEnvironment(this.getEnv());
3145
- }
3146
- const eventHandler = this.eventHandlers.get(id) ?? this.createDefaultEventHandler(id, config.type);
3147
- instance.onEvent(eventHandler);
3148
- await instance.start();
3149
- this.statuses.set(id, "running");
3150
- this.getEnv()?.pushEnvEvent({
3151
- type: "event-source.started",
3152
- payload: { sourceId: id, sourceType: config.type }
3153
- });
3154
- logger4.info(`EventSource started: ${id} (${config.type})`);
3155
- } catch (error) {
3156
- this.statuses.set(id, "error");
3157
- logger4.error(`EventSource failed to start: ${id}`, error);
3158
- throw error;
3159
- }
3160
- }
3161
- async stopSource(id) {
3162
- const status = this.statuses.get(id);
3163
- logger4.info(`[EventSource ${id}] stopSource called, current status: ${status}`);
3164
- if (status === "stopped" || status === "created") {
3165
- logger4.info(`[EventSource ${id}] already stopped/created, skipping`);
3166
- return;
3167
- }
3168
- this.statuses.set(id, "stopping");
3169
- try {
3170
- const instance = this.instances.get(id);
3171
- if (instance) {
3172
- await instance.stop();
3173
- this.instances.delete(id);
3174
- }
3175
- const config = this.sources.get(id);
3176
- this.statuses.set(id, "stopped");
3177
- this.getEnv()?.pushEnvEvent({
3178
- type: "event-source.stopped",
3179
- payload: { sourceId: id, sourceType: config?.type }
3180
- });
3181
- logger4.info(`EventSource stopped: ${id}`);
3182
- } catch (error) {
3183
- this.statuses.set(id, "error");
3184
- logger4.error(`EventSource failed to stop: ${id}`, error);
3185
- throw error;
3186
- }
3187
- }
3188
- getConfigFilePath() {
3189
- if (this.configPath) {
3190
- return this.configPath;
3191
- }
3192
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
3193
- const dataDir = join(home, ".roy-agent");
3194
- if (!existsSync(dataDir)) {
3195
- mkdirSync(dataDir, { recursive: true });
3196
- }
3197
- return join(dataDir, "event-sources.json");
3198
- }
3199
- async saveConfig() {
3200
- if (!this.persistenceEnabled)
3201
- return;
3202
- try {
3203
- const configPath = this.getConfigFilePath();
3204
- const config = {
3205
- version: "1.0.0",
3206
- sources: Array.from(this.sources.values())
3207
- };
3208
- writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
3209
- logger4.debug(`Saved ${this.sources.size} event source configurations`);
3210
- } catch (error) {
3211
- logger4.error("Failed to save event source configurations:", error);
3212
- throw error;
3213
- }
3214
- }
3215
- async loadConfig() {
3216
- if (!this.persistenceEnabled)
3217
- return;
3218
- try {
3219
- const configPath = this.getConfigFilePath();
3220
- if (!existsSync(configPath)) {
3221
- logger4.debug(`No event source config file found at ${configPath}`);
3222
- return;
3223
- }
3224
- const content = readFileSync(configPath, "utf-8");
3225
- const config = JSON.parse(content);
3226
- if (!config.sources || !Array.isArray(config.sources)) {
3227
- logger4.warn("Invalid event source config format, skipping load");
3228
- return;
3229
- }
3230
- let loadedCount = 0;
3231
- for (const source of config.sources) {
3232
- if (!this.sources.has(source.id)) {
3233
- this.sources.set(source.id, source);
3234
- this.statuses.set(source.id, "created");
3235
- loadedCount++;
3236
- }
3237
- }
3238
- logger4.info(`Loaded ${loadedCount} event source configurations`);
3239
- } catch (error) {
3240
- logger4.error("Failed to load event source configurations:", error);
3241
- }
3242
- }
3243
- }
3244
- __legacyDecorateClassTS([
3245
- TracedAs("event-source.update", { recordParams: false, log: false })
3246
- ], EventSourceComponent.prototype, "update", null);
3247
- __legacyDecorateClassTS([
3248
- TracedAs("event_source.start", { recordParams: true, recordResult: false })
3249
- ], EventSourceComponent.prototype, "startSource", null);
3250
- __legacyDecorateClassTS([
3251
- TracedAs("event_source.stop", { recordParams: true, recordResult: false })
3252
- ], EventSourceComponent.prototype, "stopSource", null);
3253
-
3254
- export { TimerInstance, timerHandler, buildDefaultBountyIMSystemPrompt, resolveBountyIMSystemPrompt, BountyIMInstance, bountyIMHandler, extractMetadata, larkCliHandler, builtInHandlers, getBuiltInHandler, EventSourceComponent };
2404
+ export { TimerInstance, timerHandler, buildDefaultBountyIMSystemPrompt, resolveBountyIMSystemPrompt, BountyIMInstance, bountyIMHandler, bountyCliHandler, buildLarkRecommendedAction, extractMetadata, LarkCliInstance, renderRuleNoticeSection, larkCliHandler, patchCardByLarkCli, builtInHandlers, getBuiltInHandler };