@kafca/agentdock 0.1.55 → 0.1.57

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 (185) hide show
  1. package/README.md +14 -0
  2. package/dist/renderer/assets/{Badge-Bg_nNvBL.js → Badge-CDTbmw1h.js} +1 -1
  3. package/dist/renderer/assets/Card-DayUo35w.js +1 -0
  4. package/dist/renderer/assets/Config-ByGMQuzR.js +21 -0
  5. package/dist/renderer/assets/CronList-XqHdVlgu.js +1 -0
  6. package/dist/renderer/assets/Dashboard-CZj-oANw.js +41 -0
  7. package/dist/renderer/assets/{EmptyState-C60g3RMj.js → EmptyState-EFMkOjZO.js} +1 -1
  8. package/dist/renderer/assets/HighlightedMarkdown-DyvF3DHK.js +12 -0
  9. package/dist/renderer/assets/Input-DxoWVc9d.js +1 -0
  10. package/dist/renderer/assets/{KnowledgeDetail-CC5C7JYe.js → KnowledgeDetail-CbUb2tG7.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-3rlvxgWf.js → KnowledgeHome-BWV1gz4f.js} +3 -3
  12. package/dist/renderer/assets/Logs-DqnanQTc.js +6 -0
  13. package/dist/renderer/assets/{Modal-BQUW9LSf.js → Modal-yY7TzR0x.js} +3 -3
  14. package/dist/renderer/assets/MonitorList-CIjGQkFs.js +1 -0
  15. package/dist/renderer/assets/Page-vwHNUdoj.js +1 -0
  16. package/dist/renderer/assets/{Select-CfRkos3z.js → Select-CmbK36pN.js} +2 -2
  17. package/dist/renderer/assets/ThreadChat-4OceMgM4.js +86 -0
  18. package/dist/renderer/assets/Workspace-DplPJOjJ.js +19 -0
  19. package/dist/renderer/assets/{arrow-left-D1DbXrLA.js → arrow-left-C8HfBt2K.js} +1 -1
  20. package/dist/renderer/assets/{book-open-BxC1z1C1.js → book-open-BCdZWncQ.js} +1 -1
  21. package/dist/renderer/assets/channels-hgO3cAIx.js +6 -0
  22. package/dist/renderer/assets/chevron-down-BPk77tqY.js +11 -0
  23. package/dist/renderer/assets/index-BIKL3fTP.css +11 -0
  24. package/dist/renderer/assets/index-BlA4xPdd.js +41 -0
  25. package/dist/renderer/assets/index-wYpjqVqC.js +167 -0
  26. package/dist/renderer/assets/knowledge-7pl06KuH.js +1 -0
  27. package/dist/renderer/assets/{pencil-X44UaxwR.js → pencil-CB1SWZ9A.js} +1 -1
  28. package/dist/renderer/assets/{play-ujo-De38.js → play-BvsoXUrM.js} +1 -1
  29. package/dist/renderer/assets/{plus-BHgVdG_A.js → plus-CokBDnaL.js} +1 -1
  30. package/dist/renderer/assets/{save-Cz6giKrE.js → save-D-w4kATO.js} +1 -1
  31. package/dist/renderer/assets/{search-DKWvTqi5.js → search-Cnsn6i4Q.js} +1 -1
  32. package/dist/renderer/assets/{shield-check-V82O8AC1.js → shield-check-Cjja2Gh6.js} +1 -1
  33. package/dist/renderer/assets/threads-BCm6j4eI.js +1 -0
  34. package/dist/renderer/assets/{trash-2-_Fgwk8mc.js → trash-2-CIxz9qYY.js} +1 -1
  35. package/dist/renderer/index.html +2 -2
  36. package/dist-electron/packages/contracts/src/automation.js +2 -0
  37. package/dist-electron/packages/contracts/src/channels.js +2 -0
  38. package/dist-electron/packages/contracts/src/knowledge.js +2 -0
  39. package/dist-electron/packages/contracts/src/local-core.js +15 -0
  40. package/dist-electron/packages/contracts/src/runtime.js +2 -0
  41. package/dist-electron/packages/contracts/src/scheduler.js +2 -0
  42. package/dist-electron/packages/contracts/src/threads.js +2 -0
  43. package/dist-electron/packages/core-sdk/src/automation.js +32 -0
  44. package/dist-electron/packages/core-sdk/src/channels.js +121 -0
  45. package/dist-electron/packages/core-sdk/src/client.js +455 -0
  46. package/dist-electron/packages/core-sdk/src/index.js +43 -607
  47. package/dist-electron/packages/core-sdk/src/knowledge.js +85 -0
  48. package/dist-electron/packages/core-sdk/src/request.js +22 -0
  49. package/dist-electron/packages/core-sdk/src/runtime.js +214 -0
  50. package/dist-electron/packages/core-sdk/src/scheduler.js +32 -0
  51. package/dist-electron/packages/core-sdk/src/threads.js +67 -0
  52. package/dist-electron/packages/plugin-sdk/src/agents.js +2 -0
  53. package/dist-electron/packages/plugin-sdk/src/automation.js +2 -0
  54. package/dist-electron/packages/plugin-sdk/src/channels.js +2 -0
  55. package/dist-electron/packages/plugin-sdk/src/index.js +21 -0
  56. package/dist-electron/packages/plugin-sdk/src/knowledge.js +2 -0
  57. package/dist-electron/packages/plugin-sdk/src/runtime.js +2 -0
  58. package/dist-electron/packages/plugin-sdk/src/scheduler.js +2 -0
  59. package/dist-electron/packages/plugin-sdk/src/threads.js +2 -0
  60. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +6 -9
  61. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +2 -2
  62. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +3 -3
  63. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +5 -5
  64. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +12 -12
  65. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +2 -2
  66. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +11 -11
  67. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +3 -3
  68. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +7 -7
  69. package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +2 -2
  70. package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +3 -3
  71. package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +3 -3
  72. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +2 -2
  73. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +4 -4
  74. package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +2 -2
  75. package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +2 -2
  76. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +3 -3
  77. package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +1 -1
  78. package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +4 -4
  79. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +33 -18
  80. package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -2
  81. package/dist-electron/services/local-ai-core/src/channel/lark/gateway-utils.js +91 -0
  82. package/dist-electron/services/local-ai-core/src/channel/lark/inbound-handler.js +180 -0
  83. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +52 -456
  84. package/dist-electron/services/local-ai-core/src/channel/lark/outbound-transport.js +124 -0
  85. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-attachment-store.js +93 -0
  86. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-authorization.js +54 -0
  87. package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +2 -2
  88. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-media.js +21 -0
  89. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +167 -0
  90. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +98 -483
  91. package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +156 -0
  92. package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +100 -0
  93. package/dist-electron/services/local-ai-core/src/cli/lac.js +6 -6
  94. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +2 -2
  95. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +28 -70
  96. package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +33 -5
  97. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +2 -2
  98. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +2 -2
  99. package/dist-electron/services/local-ai-core/src/router/workspace-bridge-event-stream.js +29 -0
  100. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +5 -5
  101. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +47 -60
  102. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -5
  103. package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +6 -6
  104. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +3 -3
  105. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +3 -1
  106. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +11 -2
  107. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +12 -6
  108. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +10 -2
  109. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +18 -6
  110. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +7 -2
  111. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +28 -3
  112. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +10 -2
  113. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +18 -5
  114. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +14 -2
  115. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +18 -15
  116. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +13 -2
  117. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +35 -8
  118. package/dist-electron/services/local-ai-core/src/runtime/request-validation.js +79 -0
  119. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +9 -9
  120. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +10 -1
  121. package/dist-electron/services/local-ai-core/src/runtime/server.js +2 -1
  122. package/dist-electron/services/local-ai-core/src/runtime/workspace-project-registry.js +76 -0
  123. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +8 -8
  124. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +75 -0
  125. package/dist-electron/shared/desktop.js +1 -64
  126. package/dist-electron/src/components/chat/chat-controller-state.js +60 -0
  127. package/dist-electron/src/components/chat/chat-event-gate.js +146 -0
  128. package/dist-electron/src/components/chat/markdown-code-block.js +8 -0
  129. package/dist-electron/src/pages/Desktop/workspace-model.js +212 -0
  130. package/dist-electron/src/pages/Threads/thread-chat-model.js +50 -51
  131. package/dist-electron/tests/contracts/agent-message-policy.test.js +21 -0
  132. package/dist-electron/tests/contracts/architecture-docs.test.js +56 -33
  133. package/dist-electron/tests/contracts/chat-event-gate.test.js +114 -0
  134. package/dist-electron/tests/contracts/chat-markdown.test.js +16 -0
  135. package/dist-electron/tests/contracts/thread-task-state.test.js +32 -0
  136. package/dist-electron/tests/contracts/workspace-identity.test.js +23 -0
  137. package/dist-electron/tests/electron/core-client.test.js +284 -0
  138. package/dist-electron/tests/electron/plugin-kernel.test.js +54 -0
  139. package/dist-electron/tests/electron/renderer-packaging.test.js +9 -0
  140. package/dist-electron/tests/electron/workspace-task-store.test.js +31 -0
  141. package/dist-electron/tests/integration/channel-inbound-attachment-store.test.js +117 -0
  142. package/dist-electron/tests/integration/channel-inbound-authorization.test.js +80 -0
  143. package/dist-electron/tests/integration/lark-gateway-utils.test.js +13 -0
  144. package/dist-electron/tests/integration/lark-gateway.test.js +58 -4
  145. package/dist-electron/tests/integration/local-core-errors.test.js +41 -0
  146. package/dist-electron/tests/integration/weixin-gateway.test.js +36 -0
  147. package/dist-electron/tests/integration/weixin-runtime-state.test.js +32 -0
  148. package/dist-electron/tests/integration/weixin-text-utils.test.js +15 -0
  149. package/package.json +9 -4
  150. package/dist/renderer/assets/Chat-BJveQQKu.js +0 -2
  151. package/dist/renderer/assets/ChatMarkdown-Bqn2HJ6f.js +0 -45
  152. package/dist/renderer/assets/Config-CMtZDRAE.js +0 -21
  153. package/dist/renderer/assets/CronList-C-ILB_Ae.js +0 -1
  154. package/dist/renderer/assets/Dashboard-CsKBSQIe.js +0 -26
  155. package/dist/renderer/assets/Logs-CktemGN0.js +0 -1
  156. package/dist/renderer/assets/MonitorList-B0hxjuOZ.js +0 -1
  157. package/dist/renderer/assets/Page-DL_Nv2i5.js +0 -1
  158. package/dist/renderer/assets/ProjectDetail-Djr9-MyT.js +0 -11
  159. package/dist/renderer/assets/ProjectList-BKl4eW7q.js +0 -1
  160. package/dist/renderer/assets/SessionChat-Dxv8D5DW.js +0 -1
  161. package/dist/renderer/assets/SessionList-BJ2GjXvR.js +0 -1
  162. package/dist/renderer/assets/ThreadChat-CAsIl9qf.js +0 -28
  163. package/dist/renderer/assets/Workspace-CaUhiGBX.js +0 -19
  164. package/dist/renderer/assets/bot-Fw3IzhJA.js +0 -6
  165. package/dist/renderer/assets/check-5zCTgp3A.js +0 -6
  166. package/dist/renderer/assets/chevron-down-N3PxTNxH.js +0 -6
  167. package/dist/renderer/assets/circle-C_chUflo.js +0 -6
  168. package/dist/renderer/assets/desktop-DkQTZNhe.js +0 -1
  169. package/dist/renderer/assets/desktop-JQkhNOF4.js +0 -5
  170. package/dist/renderer/assets/funnel-B8ZAv6I7.js +0 -6
  171. package/dist/renderer/assets/heart-M9A3E4Ed.js +0 -6
  172. package/dist/renderer/assets/index-Bwv855ID.js +0 -41
  173. package/dist/renderer/assets/index-CjCuR6DI.css +0 -11
  174. package/dist/renderer/assets/index-DJ8w4e0l.js +0 -182
  175. package/dist/renderer/assets/projects-DB1FLZ3A.js +0 -1
  176. package/dist/renderer/assets/server-BsuHcYl4.js +0 -11
  177. package/dist/renderer/assets/session-utils-DnAWL3eo.js +0 -6
  178. package/dist/renderer/assets/sessions-DptxO_BE.js +0 -1
  179. package/dist/renderer/assets/user-DQKTaUcR.js +0 -6
  180. package/dist/renderer/assets/wifi-off-vjH-MD2w.js +0 -11
  181. package/dist-electron/src/api/client.js +0 -73
  182. package/dist-electron/src/api/sessions.js +0 -21
  183. package/dist-electron/src/lib/session-utils.js +0 -51
  184. package/dist-electron/src/pages/Projects/project-provider-config.js +0 -75
  185. package/dist-electron/tests/electron/project-provider-config.test.js +0 -71
@@ -35,25 +35,20 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.LocalCoreLarkGateway = void 0;
37
37
  const node_crypto_1 = require("node:crypto");
38
- const node_fs_1 = require("node:fs");
39
- const promises_1 = require("node:fs/promises");
40
- const node_path_1 = require("node:path");
41
- const promises_2 = require("node:stream/promises");
42
38
  const local_core_errors_js_1 = require("../../kernel/local-core-errors.js");
43
- const desktop_js_1 = require("../../../../../shared/desktop.js");
44
39
  const content_js_1 = require("../shared/content.js");
45
- const file_utils_js_1 = require("../shared/file-utils.js");
46
40
  const thread_routing_js_1 = require("../shared/thread-routing.js");
47
41
  const base_channel_gateway_js_1 = require("../shared/base-channel-gateway.js");
42
+ const inbound_authorization_js_1 = require("../shared/inbound-authorization.js");
48
43
  const cards_js_1 = require("./cards.js");
49
44
  const channel_keys_js_1 = require("../shared/channel-keys.js");
50
45
  const config_js_1 = require("./config.js");
51
46
  const registration_js_1 = require("./registration.js");
52
- const messages_js_1 = require("./rendering/messages.js");
53
47
  const inbound_js_1 = require("./inbound.js");
48
+ const inbound_handler_js_1 = require("./inbound-handler.js");
49
+ const outbound_transport_js_1 = require("./outbound-transport.js");
54
50
  const runtime_state_js_1 = require("./runtime-state.js");
55
- const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
56
- const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
51
+ const gateway_utils_js_1 = require("./gateway-utils.js");
57
52
  const LARK_FINAL_PATCH_INTERVAL_MS = 900;
58
53
  const LARK_PROGRESS_PATCH_INTERVAL_MS = 3000;
59
54
  const LARK_EMPTY_RENDER_LOG_WINDOW_MS = 5 * 60 * 1000;
@@ -65,9 +60,20 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
65
60
  mirrorPermissionStateInMainCard = false;
66
61
  larkModulePromise = null;
67
62
  emptyRenderLogWindows = new Map();
63
+ inboundHandler;
64
+ outboundTransport;
68
65
  platform = 'lark';
69
66
  constructor(options) {
70
67
  super(options);
68
+ this.inboundHandler = new inbound_handler_js_1.LarkInboundHandler({
69
+ store: options.store,
70
+ getWorkspaceRouter: options.getWorkspaceRouter,
71
+ getRuntimeState: (workspaceId, instanceId) => this.resolveRuntimeState(workspaceId, instanceId).state,
72
+ getBinding: (workspaceId, instanceId) => this.getBinding(workspaceId, instanceId),
73
+ dispatchInboundMessage: (message) => this.handleInboundMessage(message),
74
+ log: options.log,
75
+ });
76
+ this.outboundTransport = new outbound_transport_js_1.LarkOutboundTransport(options.log);
71
77
  }
72
78
  // ==================== Lifecycle (platform-specific) ====================
73
79
  async testConnection(workspaceId, instanceId) {
@@ -160,7 +166,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
160
166
  async sendSessionCommandResult(input, result) {
161
167
  const state = this.resolveRuntimeState(input.workspaceId, input.instanceId).state;
162
168
  if (state?.client && state.connected && result.card?.actions?.length && state.cardActionsEnabled) {
163
- await this.sendSessionCommandCard(state, input.chatId, result.displayText, result.card.actions, this.options.getWorkspaceRouter().getThreadSessionKey(input.currentThreadId), input.currentThreadId);
169
+ await this.outboundTransport.sendSessionCommandCard(state, input.chatId, result.displayText, result.card.actions, this.options.getWorkspaceRouter().getThreadSessionKey(input.currentThreadId), input.currentThreadId);
164
170
  return;
165
171
  }
166
172
  await this.sendImmediateCard(input.workspaceId, input.chatId, result.displayText, input.instanceId);
@@ -185,7 +191,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
185
191
  continue;
186
192
  }
187
193
  if (part.type === 'file') {
188
- const sent = await this.sendFilePart(state, channelId, part);
194
+ const sent = await this.outboundTransport.sendFilePart(state, channelId, part);
189
195
  messageIds.push(sent.messageId);
190
196
  attachments.push({
191
197
  kind: 'file',
@@ -231,46 +237,6 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
231
237
  fileSize: attachment?.fileSize || 0,
232
238
  };
233
239
  }
234
- async sendFilePart(state, channelId, part) {
235
- const file = await (0, file_utils_js_1.prepareChannelFile)({
236
- path: part.path,
237
- fileName: part.fileName,
238
- workspacePath: typeof part.metadata?.workspacePath === 'string' ? part.metadata.workspacePath : undefined,
239
- maxBytes: LARK_MAX_UPLOAD_FILE_SIZE,
240
- platformLabel: 'Lark',
241
- });
242
- const upload = await state.client.im.file.create({
243
- data: {
244
- file_type: this.resolveLarkUploadFileType(file.fileName),
245
- file_name: file.fileName,
246
- file: (0, node_fs_1.createReadStream)(file.path),
247
- },
248
- });
249
- const fileKey = String(upload?.file_key || upload?.data?.file_key || '').trim();
250
- if (!fileKey) {
251
- throw new Error('Lark file upload did not return a file key');
252
- }
253
- const response = await state.client.im.message.create({
254
- params: {
255
- receive_id_type: this.resolveReceiveIdType(channelId),
256
- },
257
- data: {
258
- receive_id: channelId,
259
- msg_type: 'file',
260
- content: JSON.stringify({ file_key: fileKey }),
261
- },
262
- });
263
- const messageId = String(response?.data?.message_id || '').trim();
264
- if (!messageId) {
265
- throw new Error('Lark file message did not return a message id');
266
- }
267
- this.options.log?.(`localcore-lark sent file ${file.fileName} (${file.fileSize} bytes) to ${channelId}`);
268
- return {
269
- messageId,
270
- fileKey,
271
- file,
272
- };
273
- }
274
240
  async onBridgeEvent(event) {
275
241
  if (!event.sessionKey) {
276
242
  this.options.log?.(`localcore-lark bridge event ignored without sessionKey: ${event.type}`);
@@ -327,7 +293,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
327
293
  }
328
294
  if (event.type === 'typing_start' && (turn.permissionMessageId || turn.awaitingPermission)) {
329
295
  if (turn.permissionMessageId) {
330
- await this.patchTextCard(state, turn.permissionMessageId, '**工具确认已处理**\n\n继续生成中...', [], sessionKey, bridgeThreadId);
296
+ await this.outboundTransport.patchTextCard(state, turn.permissionMessageId, '**工具确认已处理**\n\n继续生成中...', [], sessionKey, bridgeThreadId);
331
297
  }
332
298
  turn.permissionMessageId = undefined;
333
299
  turn.awaitingPermission = false;
@@ -340,14 +306,14 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
340
306
  const permissionCard = (0, cards_js_1.renderPermissionCard)(turn, event, Boolean(state.cardActionsEnabled));
341
307
  if (permissionCard.text || permissionCard.buttonRows.length > 0) {
342
308
  if (!turn.permissionMessageId) {
343
- const createdId = await this.sendTextAsCard(state, route.chatId, permissionCard.text, permissionCard.buttonRows, sessionKey, bridgeThreadId);
309
+ const createdId = await this.outboundTransport.sendTextAsCard(state, route.chatId, permissionCard.text, permissionCard.buttonRows, sessionKey, bridgeThreadId);
344
310
  if (createdId) {
345
311
  turn.permissionMessageId = createdId;
346
312
  this.options.log?.(`localcore-lark sent permission card ${createdId} for sessionKey=${sessionKey}`);
347
313
  }
348
314
  }
349
315
  else {
350
- await this.patchTextCard(state, turn.permissionMessageId, permissionCard.text, permissionCard.buttonRows, sessionKey, bridgeThreadId);
316
+ await this.outboundTransport.patchTextCard(state, turn.permissionMessageId, permissionCard.text, permissionCard.buttonRows, sessionKey, bridgeThreadId);
351
317
  this.options.log?.(`localcore-lark patched permission card ${turn.permissionMessageId} for sessionKey=${sessionKey}`);
352
318
  }
353
319
  }
@@ -376,7 +342,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
376
342
  const sentMessage = sendAsPlainMessage
377
343
  ? await this.sendTextAsMessage(state, route.chatId, renderedMessage.text)
378
344
  : {
379
- messageId: await this.sendTextAsCard(state, route.chatId, renderedMessage.text, renderedMessage.buttonRows, sessionKey, bridgeThreadId),
345
+ messageId: await this.outboundTransport.sendTextAsCard(state, route.chatId, renderedMessage.text, renderedMessage.buttonRows, sessionKey, bridgeThreadId),
380
346
  renderKind: 'card',
381
347
  };
382
348
  const createdId = sentMessage.messageId;
@@ -392,7 +358,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
392
358
  if (renderedMessage.delivery === 'message') {
393
359
  continue;
394
360
  }
395
- await this.patchTextCard(state, existingMessageId, renderedMessage.text, renderedMessage.buttonRows, sessionKey, bridgeThreadId);
361
+ await this.outboundTransport.patchTextCard(state, existingMessageId, renderedMessage.text, renderedMessage.buttonRows, sessionKey, bridgeThreadId);
396
362
  turn.lastPatchedAt = Date.now();
397
363
  turn.lastPatchedAtByMessageId[existingMessageId] = turn.lastPatchedAt;
398
364
  this.options.log?.(`localcore-lark patched card message ${existingMessageId} for sessionKey=${sessionKey}`);
@@ -426,7 +392,6 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
426
392
  messageId: msg.messageId,
427
393
  },
428
394
  });
429
- this.options.store.expirePendingPairings();
430
395
  const runtimeState = this.resolveRuntimeState(msg.workspaceId, instanceId).state;
431
396
  let binding;
432
397
  try {
@@ -438,47 +403,28 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
438
403
  }
439
404
  this.options.log?.(`localcore-lark using active runtime binding snapshot for ${msg.workspaceId}/${instanceId}: ${error instanceof Error ? error.message : String(error)}`);
440
405
  }
441
- let authorized = this.options.store.getAuthorizedUser(msg.workspaceId, msg.platformUserId, platformKey);
442
- if (!authorized) {
443
- if (binding?.autoApprove || runtimeState?.autoApprove) {
444
- const authorizedAt = new Date().toISOString();
445
- this.options.store.createAuthorizedUser({
446
- id: `lark-user-${(0, node_crypto_1.randomUUID)()}`,
447
- workspace_id: msg.workspaceId,
448
- platform: platformKey,
449
- platform_user_id: msg.platformUserId,
450
- chat_id: msg.chatId,
451
- display_name: msg.displayName,
452
- thread_id: null,
453
- authorized_at: authorizedAt,
454
- });
455
- authorized = this.options.store.getAuthorizedUser(msg.workspaceId, msg.platformUserId, platformKey);
456
- this.options.log?.(`localcore-lark auto-approved user for ${msg.workspaceId}: ${msg.platformUserId}`);
457
- this.notifyRuntimeStateChanged();
458
- }
459
- }
460
- if (!authorized) {
461
- const existingPending = this.options.store.listPendingPairings(msg.workspaceId).find((item) => item.platform === platformKey && item.platform_user_id === msg.platformUserId && item.chat_id === msg.chatId && item.status === 'pending');
462
- let pairingCode = existingPending?.code || '';
463
- if (!existingPending) {
464
- const now = new Date();
465
- pairingCode = this.generatePairingCode();
466
- this.options.store.createPairingRequest({
467
- code: pairingCode,
468
- workspace_id: msg.workspaceId,
469
- platform: platformKey,
470
- platform_user_id: msg.platformUserId,
471
- chat_id: msg.chatId,
472
- display_name: msg.displayName,
473
- requested_at: now.toISOString(),
474
- expires_at: new Date(now.getTime() + PAIRING_EXPIRY_MS).toISOString(),
475
- status: 'pending',
476
- });
477
- this.notifyRuntimeStateChanged();
478
- }
479
- await this.sendImmediateCard(msg.workspaceId, msg.chatId, (0, cards_js_1.renderPendingPairingCard)(pairingCode), instanceId);
406
+ const authorization = (0, inbound_authorization_js_1.resolveInboundChannelAuthorization)({
407
+ store: this.options.store,
408
+ identity: {
409
+ workspaceId: msg.workspaceId,
410
+ platformKey,
411
+ platformUserId: msg.platformUserId,
412
+ chatId: msg.chatId,
413
+ displayName: msg.displayName,
414
+ },
415
+ autoApprove: Boolean(binding?.autoApprove || runtimeState?.autoApprove),
416
+ authorizedUserIdPrefix: 'lark-user',
417
+ generatePairingCode: () => this.generatePairingCode(),
418
+ onStateChanged: () => this.notifyRuntimeStateChanged(),
419
+ });
420
+ if (authorization.status === 'pending') {
421
+ await this.sendImmediateCard(msg.workspaceId, msg.chatId, (0, cards_js_1.renderPendingPairingCard)(authorization.pairingCode), instanceId);
480
422
  return; // { paired: false };
481
423
  }
424
+ if (authorization.autoApproved) {
425
+ this.options.log?.(`localcore-lark auto-approved user for ${msg.workspaceId}: ${msg.platformUserId}`);
426
+ }
427
+ const authorized = authorization.authorized;
482
428
  const router = this.options.getWorkspaceRouter();
483
429
  let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
484
430
  store: this.options.store,
@@ -531,10 +477,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
531
477
  return; // { paired: true, threadId };
532
478
  }
533
479
  this.options.store.clearPlatformThreadMessageId(msg.workspaceId, msg.chatId, msg.platformUserId);
534
- const wrappedText = slashCommand
535
- ? msg.text
536
- : (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(msg.text);
537
- await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, msg.contentParts));
480
+ await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(msg.text, msg.contentParts));
538
481
  return; // { paired: true, threadId };
539
482
  }
540
483
  async createSdkClientResult(binding) {
@@ -587,7 +530,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
587
530
  this.runtime.set(key, status);
588
531
  this.notifyRuntimeStateChanged();
589
532
  try {
590
- this.options.log?.(`localcore-lark starting workspace=${binding.workspaceId} app=${this.maskLarkAppId(binding.appId)} cardActions=${binding.cardActionsEnabled}`);
533
+ this.options.log?.(`localcore-lark starting workspace=${binding.workspaceId} app=${(0, gateway_utils_js_1.maskLarkAppId)(binding.appId)} cardActions=${binding.cardActionsEnabled}`);
591
534
  const mod = await this.getLarkModule();
592
535
  status.client = new mod.Client({
593
536
  appId: binding.appId,
@@ -610,7 +553,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
610
553
  });
611
554
  status.eventDispatcher.register({
612
555
  'im.message.receive_v1': async (data) => {
613
- this.options.log?.(`localcore-lark received im.message.receive_v1 for ${binding.workspaceId}/${binding.instanceId}: ${this.summarizeLarkEvent(data)}`);
556
+ this.options.log?.(`localcore-lark received im.message.receive_v1 for ${binding.workspaceId}/${binding.instanceId}: ${(0, inbound_js_1.summarizeLarkInboundPayload)(data)}`);
614
557
  void this.handleMessageEvent(binding.workspaceId, binding.instanceId, binding.platformKey, data).catch((error) => {
615
558
  this.options.log?.(`localcore-lark inbound message failed for ${binding.workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
616
559
  });
@@ -629,7 +572,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
629
572
  domain: mod.Domain.Feishu,
630
573
  loggerLevel: mod.LoggerLevel.info,
631
574
  });
632
- this.attachWsDiagnostics(binding.workspaceId, status.wsClient);
575
+ (0, gateway_utils_js_1.attachLarkWsDiagnostics)(binding.workspaceId, status.wsClient, this.options.log);
633
576
  this.options.log?.(`localcore-lark ws starting for ${binding.workspaceId}`);
634
577
  await status.wsClient.start({
635
578
  eventDispatcher: status.eventDispatcher,
@@ -656,249 +599,13 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
656
599
  this.notifyRuntimeStateChanged();
657
600
  }
658
601
  async handleMessageEvent(workspaceId, instanceIdOrData, platformKeyOrData, maybeData) {
659
- const legacyCall = typeof instanceIdOrData === 'object';
660
- const instanceId = legacyCall ? 'default' : instanceIdOrData;
661
- const platformKey = legacyCall ? 'lark' : String(platformKeyOrData || (0, channel_keys_js_1.channelPlatformKey)('lark', instanceId));
662
- const data = (legacyCall ? instanceIdOrData : maybeData) || {};
663
- const runtimeState = this.resolveRuntimeState(workspaceId, instanceId).state;
664
- const normalized = (0, inbound_js_1.normalizeLarkInboundMessageEvent)(data, {
665
- botOpenId: runtimeState?.botOpenId,
666
- groupReplyAll: runtimeState?.groupReplyAll,
667
- });
668
- this.options.log?.(`localcore-lark handling message event for ${workspaceId}: ${(0, inbound_js_1.summarizeLarkInboundPayload)(data)}`);
669
- if (!normalized.ok) {
670
- this.options.log?.(`localcore-lark ignored message event for ${workspaceId}: reason=${normalized.reason}${normalized.detail ? ` ${normalized.detail}` : ''}`);
671
- return;
672
- }
673
- const { message, parsedContent, messageType, chatType, mentions, text, platformUserId, chatId, displayName, messageId, } = normalized.message;
674
- const contentParts = [];
675
- if (text) {
676
- contentParts.push({ type: 'text', text });
677
- }
678
- if (messageType === 'image') {
679
- const imageKey = String(parsedContent.image_key || parsedContent.file_key || '').trim();
680
- if (imageKey) {
681
- try {
682
- contentParts.push(await this.downloadMessageImage(workspaceId, String(message.message_id || ''), imageKey, instanceId));
683
- }
684
- catch (error) {
685
- const errorText = `[Image download failed: ${error instanceof Error ? error.message : String(error)}]`;
686
- contentParts.push({ type: 'text', text: errorText });
687
- this.options.log?.(`localcore-lark image download failed for ${workspaceId}: message=${String(message.message_id || '')} imageKey=${imageKey} error=${error instanceof Error ? error.message : String(error)}`);
688
- }
689
- }
690
- }
691
- if (messageType === 'file') {
692
- const fileKey = String(parsedContent.file_key || '').trim();
693
- if (fileKey) {
694
- try {
695
- contentParts.push(await this.downloadMessageFile(workspaceId, String(message.message_id || ''), fileKey, String(parsedContent.file_name || parsedContent.name || '').trim(), instanceId));
696
- }
697
- catch (error) {
698
- const errorText = `[File download failed: ${error instanceof Error ? error.message : String(error)}]`;
699
- contentParts.push({ type: 'text', text: errorText });
700
- this.options.log?.(`localcore-lark file download failed for ${workspaceId}: message=${String(message.message_id || '')} fileKey=${fileKey} error=${error instanceof Error ? error.message : String(error)}`);
701
- }
702
- }
703
- }
704
- if (contentParts.length === 0) {
705
- this.options.log?.(`localcore-lark ignored unsupported message for ${workspaceId}: type=${String(message.message_type || 'unknown')} contentKeys=${JSON.stringify(Object.keys(parsedContent))}`);
706
- return;
707
- }
708
- const displayText = text || this.summarizeInboundContentParts(contentParts);
709
- this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} chatType=${chatType || 'unknown'} mentions=${mentions.length} type=${messageType || 'unknown'} text=${JSON.stringify(displayText.slice(0, 120))}`);
710
- await this.handleInboundMessage({
711
- workspaceId,
712
- instanceId,
713
- platformKey,
714
- platformUserId,
715
- chatId,
716
- displayName,
717
- text: displayText,
718
- messageId,
719
- contentParts,
720
- });
602
+ await this.inboundHandler.handleMessageEvent(workspaceId, instanceIdOrData, platformKeyOrData, maybeData);
721
603
  }
722
604
  async downloadMessageImage(workspaceId, messageId, imageKey, instanceId) {
723
- const state = this.resolveRuntimeState(workspaceId, instanceId).state;
724
- if (!state?.client) {
725
- throw new Error('Lark client is not connected');
726
- }
727
- if (!messageId) {
728
- throw new Error('Lark image message is missing message_id');
729
- }
730
- const resource = await state.client.im.messageResource.get({
731
- path: {
732
- message_id: messageId,
733
- file_key: imageKey,
734
- },
735
- params: {
736
- type: 'image',
737
- },
738
- });
739
- const buffer = await this.readLarkResourceBuffer(resource);
740
- if (buffer.length === 0) {
741
- throw new Error('Lark image resource is empty');
742
- }
743
- const headerMime = this.extractHeaderMimeType(resource?.headers);
744
- return {
745
- type: 'image',
746
- data: buffer.toString('base64'),
747
- mimeType: headerMime || this.sniffImageMimeType(buffer),
748
- fileName: `${imageKey}.${this.sniffImageExtension(buffer)}`,
749
- };
605
+ return this.inboundHandler.downloadMessageImage(workspaceId, messageId, imageKey, instanceId);
750
606
  }
751
607
  async downloadMessageFile(workspaceId, messageId, fileKey, fileName, instanceId) {
752
- const state = this.resolveRuntimeState(workspaceId, instanceId).state;
753
- if (!state?.client) {
754
- throw new Error('Lark client is not connected');
755
- }
756
- if (!messageId) {
757
- throw new Error('Lark file message is missing message_id');
758
- }
759
- const downloadsDir = await this.resolveInboundDownloadsDir(workspaceId, instanceId, state.downloadsDir);
760
- const storedFileName = `${this.safeInboundFilePart(messageId, 'message')}-${this.safeInboundFilePart(fileName || fileKey, 'file')}`;
761
- const filePath = (0, node_path_1.join)(downloadsDir, storedFileName);
762
- const temporaryPath = `${filePath}.${(0, node_crypto_1.randomUUID)()}.part`;
763
- const resource = await state.client.im.messageResource.get({
764
- path: {
765
- message_id: messageId,
766
- file_key: fileKey,
767
- },
768
- params: {
769
- type: 'file',
770
- },
771
- });
772
- const readable = resource?.getReadableStream?.();
773
- if (!readable || typeof readable.pipe !== 'function') {
774
- throw new Error('Lark file resource did not provide a readable stream');
775
- }
776
- await (0, promises_1.mkdir)(downloadsDir, { recursive: true });
777
- try {
778
- await (0, promises_2.pipeline)(readable, (0, node_fs_1.createWriteStream)(temporaryPath, { flags: 'wx' }));
779
- const temporaryStat = await (0, promises_1.stat)(temporaryPath);
780
- if (temporaryStat.size === 0) {
781
- throw new Error('Lark file resource is empty');
782
- }
783
- await (0, promises_1.rename)(temporaryPath, filePath);
784
- }
785
- catch (error) {
786
- await (0, promises_1.rm)(temporaryPath, { force: true }).catch(() => undefined);
787
- throw error;
788
- }
789
- const fileStat = await (0, promises_1.stat)(filePath);
790
- return {
791
- type: 'file',
792
- path: filePath,
793
- mimeType: this.extractHeaderMimeType(resource?.headers) || 'application/octet-stream',
794
- fileName: fileName || fileKey,
795
- size: fileStat.size,
796
- };
797
- }
798
- async resolveInboundDownloadsDir(workspaceId, instanceId = 'default', runtimeDownloadsDir) {
799
- const binding = runtimeDownloadsDir === undefined
800
- ? await this.getBinding(workspaceId, instanceId)
801
- : undefined;
802
- const configuredDir = String(runtimeDownloadsDir ?? binding?.downloadsDir ?? '').trim();
803
- if (configuredDir && (0, node_path_1.isAbsolute)(configuredDir)) {
804
- return configuredDir;
805
- }
806
- const workspace = await this.options.getWorkspaceRouter().getWorkspaceRegistryEntry(workspaceId);
807
- return configuredDir
808
- ? (0, node_path_1.resolve)(workspace.path, configuredDir)
809
- : (0, node_path_1.join)(workspace.path, '.agentdock', 'channel-uploads', 'lark', instanceId);
810
- }
811
- safeInboundFilePart(value, fallback) {
812
- return String(value || fallback)
813
- .replace(/[^a-zA-Z0-9._-]/g, '_')
814
- .slice(0, 120) || fallback;
815
- }
816
- summarizeInboundContentParts(parts) {
817
- const text = parts
818
- .filter((part) => part.type === 'text')
819
- .map((part) => part.text)
820
- .filter(Boolean)
821
- .join('\n\n')
822
- .trim();
823
- if (text)
824
- return text;
825
- const attachmentSummary = parts
826
- .map((part) => {
827
- if (part.type === 'image') {
828
- return '[Image]';
829
- }
830
- if (part.type === 'file') {
831
- return part.fileName ? `[File: ${part.fileName}]` : '[File]';
832
- }
833
- return '';
834
- })
835
- .filter(Boolean)
836
- .join('\n');
837
- return attachmentSummary;
838
- }
839
- async readLarkResourceBuffer(resource) {
840
- const readable = resource?.getReadableStream?.();
841
- if (!readable || typeof readable.on !== 'function') {
842
- throw new Error('Lark resource did not provide a readable stream');
843
- }
844
- const chunks = [];
845
- await new Promise((resolve, reject) => {
846
- readable.on('data', (chunk) => {
847
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
848
- });
849
- readable.on('error', reject);
850
- readable.on('end', resolve);
851
- });
852
- return Buffer.concat(chunks);
853
- }
854
- extractHeaderMimeType(headers) {
855
- const value = headers && typeof headers === 'object'
856
- ? headers['content-type'] || headers['Content-Type']
857
- : '';
858
- return String(value || '').split(';')[0]?.trim() || '';
859
- }
860
- sniffImageMimeType(buffer) {
861
- if (buffer[0] === 0xff && buffer[1] === 0xd8)
862
- return 'image/jpeg';
863
- if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47)
864
- return 'image/png';
865
- if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46)
866
- return 'image/gif';
867
- if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46)
868
- return 'image/webp';
869
- return 'application/octet-stream';
870
- }
871
- sniffImageExtension(buffer) {
872
- const mimeType = this.sniffImageMimeType(buffer);
873
- if (mimeType === 'image/jpeg')
874
- return 'jpg';
875
- if (mimeType === 'image/png')
876
- return 'png';
877
- if (mimeType === 'image/gif')
878
- return 'gif';
879
- if (mimeType === 'image/webp')
880
- return 'webp';
881
- return 'bin';
882
- }
883
- attachWsDiagnostics(workspaceId, wsClient) {
884
- const on = typeof wsClient?.on === 'function' ? wsClient.on.bind(wsClient) : null;
885
- if (!on) {
886
- this.options.log?.(`localcore-lark ws diagnostics unavailable for ${workspaceId}: client has no on()`);
887
- return;
888
- }
889
- for (const eventName of ['open', 'connect', 'connected', 'ready', 'close', 'closed', 'disconnect', 'error', 'reconnect']) {
890
- try {
891
- on(eventName, (...args) => {
892
- this.options.log?.(`localcore-lark ws event ${eventName} for ${workspaceId}: ${this.summarizeWsArgs(args)}`);
893
- });
894
- }
895
- catch (error) {
896
- this.options.log?.(`localcore-lark ws diagnostic hook failed for ${workspaceId} event=${eventName}: ${error instanceof Error ? error.message : String(error)}`);
897
- }
898
- }
899
- }
900
- summarizeLarkEvent(data) {
901
- return (0, inbound_js_1.summarizeLarkInboundPayload)(data);
608
+ return this.inboundHandler.downloadMessageFile(workspaceId, messageId, fileKey, fileName, instanceId);
902
609
  }
903
610
  async fetchBotOpenId(state) {
904
611
  const response = await state.client.request({
@@ -912,30 +619,6 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
912
619
  }
913
620
  return openId;
914
621
  }
915
- summarizeWsArgs(args) {
916
- if (args.length === 0) {
917
- return 'no-args';
918
- }
919
- return args.map((arg) => {
920
- if (arg instanceof Error) {
921
- return `${arg.name}: ${arg.message}`;
922
- }
923
- if (typeof arg === 'string') {
924
- return arg.slice(0, 200);
925
- }
926
- if (arg && typeof arg === 'object') {
927
- return JSON.stringify(Object.keys(arg));
928
- }
929
- return String(arg);
930
- }).join(' ');
931
- }
932
- maskLarkAppId(appId) {
933
- const value = String(appId || '').trim();
934
- if (value.length <= 8) {
935
- return value ? '***' : '';
936
- }
937
- return `${value.slice(0, 6)}...${value.slice(-4)}`;
938
- }
939
622
  makeThreadRoute(input, threadId) {
940
623
  return {
941
624
  workspaceId: input.workspaceId,
@@ -952,7 +635,6 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
952
635
  });
953
636
  }
954
637
  buildStatusObject(state, _resolved) {
955
- this.options.store.expirePendingPairings();
956
638
  const resolved = this.resolveRuntimeState(state.workspaceId, state.instanceId);
957
639
  const binding = resolved.state;
958
640
  const platformKey = binding?.platformKey || (0, channel_keys_js_1.channelPlatformKey)('lark', resolved.instanceId);
@@ -1024,94 +706,8 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
1024
706
  }
1025
707
  return this.larkModulePromise;
1026
708
  }
1027
- async sendTextAsCard(state, chatId, text, buttonRows = [], sessionKey, threadId) {
1028
- const startedAt = Date.now();
1029
- const response = await state.client.im.message.create({
1030
- params: {
1031
- receive_id_type: this.resolveReceiveIdType(chatId),
1032
- },
1033
- data: {
1034
- receive_id: chatId,
1035
- msg_type: 'interactive',
1036
- content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
1037
- },
1038
- });
1039
- this.options.log?.(`localcore-lark card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
1040
- return String(response?.data?.message_id || '').trim();
1041
- }
1042
- async sendSessionCommandCard(state, chatId, text, actionRows, sessionKey, threadId) {
1043
- const startedAt = Date.now();
1044
- const response = await state.client.im.message.create({
1045
- params: {
1046
- receive_id_type: this.resolveReceiveIdType(chatId),
1047
- },
1048
- data: {
1049
- receive_id: chatId,
1050
- msg_type: 'interactive',
1051
- content: JSON.stringify((0, cards_js_1.buildSessionCommandCard)(text, actionRows, sessionKey, threadId)),
1052
- },
1053
- });
1054
- this.options.log?.(`localcore-lark session card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
1055
- return String(response?.data?.message_id || '').trim();
1056
- }
1057
709
  async sendTextAsMessage(state, chatId, text) {
1058
- const startedAt = Date.now();
1059
- const rendered = (0, messages_js_1.renderLarkTextMessage)(text);
1060
- const response = await state.client.im.message.create({
1061
- params: {
1062
- receive_id_type: this.resolveReceiveIdType(chatId),
1063
- },
1064
- data: {
1065
- receive_id: chatId,
1066
- msg_type: rendered.msgType,
1067
- content: JSON.stringify(rendered.content),
1068
- },
1069
- });
1070
- this.options.log?.(`localcore-lark ${rendered.renderKind} create took ${Date.now() - startedAt}ms msgType=${rendered.msgType} reason=${rendered.reason} tableCount=${rendered.tableCount} textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
1071
- return {
1072
- messageId: String(response?.data?.message_id || '').trim(),
1073
- renderKind: rendered.renderKind,
1074
- msgType: rendered.msgType,
1075
- };
1076
- }
1077
- resolveReceiveIdType(receiveId) {
1078
- return receiveId.startsWith('oc_') ? 'chat_id' : receiveId.startsWith('ou_') ? 'open_id' : 'user_id';
1079
- }
1080
- resolveLarkUploadFileType(fileName) {
1081
- switch ((0, node_path_1.extname)(fileName).toLowerCase()) {
1082
- case '.opus':
1083
- return 'opus';
1084
- case '.mp4':
1085
- case '.mov':
1086
- case '.m4v':
1087
- return 'mp4';
1088
- case '.pdf':
1089
- return 'pdf';
1090
- case '.doc':
1091
- case '.docx':
1092
- return 'doc';
1093
- case '.xls':
1094
- case '.xlsx':
1095
- case '.csv':
1096
- return 'xls';
1097
- case '.ppt':
1098
- case '.pptx':
1099
- return 'ppt';
1100
- default:
1101
- return 'stream';
1102
- }
1103
- }
1104
- async patchTextCard(state, messageId, text, buttonRows = [], sessionKey, threadId) {
1105
- const startedAt = Date.now();
1106
- await state.client.im.message.patch({
1107
- path: {
1108
- message_id: messageId,
1109
- },
1110
- data: {
1111
- content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
1112
- },
1113
- });
1114
- this.options.log?.(`localcore-lark card patch took ${Date.now() - startedAt}ms message=${messageId} textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
710
+ return this.outboundTransport.sendTextAsMessage(state, chatId, text);
1115
711
  }
1116
712
  generatePairingCode() {
1117
713
  return String((0, node_crypto_1.randomInt)(100000, 1000000));
@@ -1239,7 +835,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
1239
835
  return;
1240
836
  }
1241
837
  try {
1242
- await this.patchTextCard(state, messageId, [
838
+ await this.outboundTransport.patchTextCard(state, messageId, [
1243
839
  '**工具确认已处理**',
1244
840
  `已选择:${(0, cards_js_1.formatPermissionResponseLabel)(response)}`,
1245
841
  '等待代理继续执行...',
@@ -1260,7 +856,7 @@ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway
1260
856
  return '';
1261
857
  }
1262
858
  try {
1263
- return await this.sendTextAsCard(state, chatId, text);
859
+ return await this.outboundTransport.sendTextAsCard(state, chatId, text);
1264
860
  }
1265
861
  catch (error) {
1266
862
  this.options.log?.(`localcore-lark immediate card failed for ${workspaceId}: ${error instanceof Error ? error.message : String(error)}`);