@kafca/agentdock 0.1.43 → 0.1.45

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 (119) hide show
  1. package/README.md +77 -11
  2. package/bin/agentdock.mjs +5 -5
  3. package/dist/renderer/assets/{Badge-CbG6yRSm.js → Badge-BIojwD6s.js} +1 -1
  4. package/dist/renderer/assets/{Chat-BvNNWGGX.js → Chat-wjBR3XEX.js} +1 -1
  5. package/dist/renderer/assets/{ChatMarkdown-Ct-PvJB8.js → ChatMarkdown-DqszsPB_.js} +1 -1
  6. package/dist/renderer/assets/Config-BDCHs5A2.js +21 -0
  7. package/dist/renderer/assets/{CronList-Dj_3muVG.js → CronList-CEWQYTov.js} +1 -1
  8. package/dist/renderer/assets/Dashboard-DrWftfk3.js +26 -0
  9. package/dist/renderer/assets/{EmptyState-Bn2Qh14U.js → EmptyState-BqCx1oWr.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeDetail-Bsz6Ou41.js → KnowledgeDetail-BwK8Gpfa.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-Cgj4XFXn.js → KnowledgeHome-hhDTZMDO.js} +3 -3
  12. package/dist/renderer/assets/{Logs-Dp-NF6GN.js → Logs-C9xPEhFT.js} +1 -1
  13. package/dist/renderer/assets/{Modal-B6YPPBN6.js → Modal-D2U4r2V0.js} +1 -1
  14. package/dist/renderer/assets/{MonitorList-xEZWg460.js → MonitorList-CayKbfwJ.js} +1 -1
  15. package/dist/renderer/assets/{Page-Bn7RjGOS.js → Page-urf5GcT_.js} +1 -1
  16. package/dist/renderer/assets/ProjectDetail-B1GyAr7a.js +11 -0
  17. package/dist/renderer/assets/{ProjectList-BDk5_gqY.js → ProjectList-BoipQypE.js} +1 -1
  18. package/dist/renderer/assets/{Select-xshfMIEQ.js → Select-CAscWpy5.js} +1 -1
  19. package/dist/renderer/assets/{SessionChat-BkHy90z3.js → SessionChat-BAVy5221.js} +1 -1
  20. package/dist/renderer/assets/{SessionList-BZyXT92L.js → SessionList-BZpuMvh0.js} +1 -1
  21. package/dist/renderer/assets/{ThreadChat-DUOIyXrS.js → ThreadChat-JX7m9biG.js} +1 -1
  22. package/dist/renderer/assets/Workspace-CFW8otjU.js +14 -0
  23. package/dist/renderer/assets/{arrow-left-C54ZI-AS.js → arrow-left-7HrNuS-V.js} +1 -1
  24. package/dist/renderer/assets/{book-open-Dl7GO0zn.js → book-open-BDoAu82s.js} +1 -1
  25. package/dist/renderer/assets/{check-CiqgtrOL.js → check-DGlyq4xX.js} +1 -1
  26. package/dist/renderer/assets/{chevron-down-DTL2OuVh.js → chevron-down-Bb_3EHq9.js} +1 -1
  27. package/dist/renderer/assets/{circle-DaVKfa3P.js → circle-DIpqZnYw.js} +1 -1
  28. package/dist/renderer/assets/desktop-Ci1fnRDR.js +1 -0
  29. package/dist/renderer/assets/{desktop-C6q6wBae.js → desktop-Do_UrC-o.js} +5 -5
  30. package/dist/renderer/assets/en-CmAr_0e6.js +1 -0
  31. package/dist/renderer/assets/es-Cs9x52ca.js +1 -0
  32. package/dist/renderer/assets/{funnel-CrmnLMJI.js → funnel-Bbf0ERLP.js} +1 -1
  33. package/dist/renderer/assets/{heart-BMfQI7y_.js → heart-CGqU-qfw.js} +1 -1
  34. package/dist/renderer/assets/{index-nreiKY1f.js → index-Df-Trovt.js} +2 -2
  35. package/dist/renderer/assets/{index-HPNb1zfx.js → index-DwhTjLA1.js} +36 -36
  36. package/dist/renderer/assets/index-RaTga2BC.css +11 -0
  37. package/dist/renderer/assets/ja-DtvtBRTW.js +1 -0
  38. package/dist/renderer/assets/{pencil-wTQ4l465.js → pencil-CHiy1MvK.js} +1 -1
  39. package/dist/renderer/assets/{play-BK--MXmw.js → play-CGYnmC4Q.js} +1 -1
  40. package/dist/renderer/assets/{plug-BIx9fjip.js → plug-Mexu4gyV.js} +1 -1
  41. package/dist/renderer/assets/{plus-Dn7JFWQ8.js → plus-B_Q5-Oj7.js} +1 -1
  42. package/dist/renderer/assets/projects-C6bbkC-O.js +1 -0
  43. package/dist/renderer/assets/{save-CC3zOSWb.js → save-CJ_QFPw0.js} +1 -1
  44. package/dist/renderer/assets/{search-CDTy9Czu.js → search-D8Dkhsyq.js} +1 -1
  45. package/dist/renderer/assets/{server-DtQk3t2a.js → server-Cd96R7WL.js} +1 -1
  46. package/dist/renderer/assets/{session-utils-4ep5D66T.js → session-utils-BNUbQBfF.js} +1 -1
  47. package/dist/renderer/assets/{sessions-Dor1LteH.js → sessions-BACfV8s1.js} +1 -1
  48. package/dist/renderer/assets/{shield-check-Cz2LpU6r.js → shield-check-Cnn-yQUA.js} +1 -1
  49. package/dist/renderer/assets/{trash-2-C2EmWFZV.js → trash-2-oWCxwQ9D.js} +1 -1
  50. package/dist/renderer/assets/{user-I8B-cs5A.js → user-BzE9BwsY.js} +1 -1
  51. package/dist/renderer/assets/{wifi-off-CPevTQJn.js → wifi-off-DHxnNkdY.js} +1 -1
  52. package/dist/renderer/assets/zh-CcJ9vBZj.js +1 -0
  53. package/dist/renderer/assets/zh-TW-elI72AC1.js +1 -0
  54. package/dist/renderer/index.html +2 -2
  55. package/dist-electron/electron/main.js +26 -1
  56. package/dist-electron/packages/core-sdk/src/index.js +28 -0
  57. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +111 -62
  58. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +80 -7
  59. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +78 -5
  60. package/dist-electron/services/local-ai-core/src/acp/store/external-store.js +98 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +33 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/model-provider-store.js +88 -0
  63. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +43 -0
  64. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +2 -119
  65. package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +148 -0
  66. package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -0
  67. package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +114 -0
  68. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +117 -75
  69. package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +4 -2
  70. package/dist-electron/services/local-ai-core/src/channel/shared/thread-routing.js +34 -0
  71. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +151 -47
  72. package/dist-electron/services/local-ai-core/src/execution/agent-execution-backend.js +56 -0
  73. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +18 -57
  74. package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +255 -0
  75. package/dist-electron/services/local-ai-core/src/plugins/builtin/catalog.js +78 -0
  76. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +3 -1
  77. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +64 -9
  78. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -2
  79. package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +152 -0
  80. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +175 -0
  81. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +330 -3
  82. package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +11 -2
  83. package/dist-electron/services/local-ai-core/src/runtime/provider-config-migration.js +32 -0
  84. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +76 -8
  85. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +62 -0
  86. package/dist-electron/services/local-ai-core/src/runtime/server.js +708 -4
  87. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +13 -3
  88. package/dist-electron/services/local-ai-core/src/sandbox/opensandbox-client.js +113 -0
  89. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +273 -0
  90. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-manager.js +215 -0
  91. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-stdio-proxy.js +188 -0
  92. package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +3 -0
  93. package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +32 -0
  94. package/dist-electron/services/local-ai-core/src/thread/thread-slash-command-dispatcher.js +71 -0
  95. package/dist-electron/shared/desktop.js +85 -1
  96. package/dist-electron/tests/contracts/architecture-docs.test.js +83 -0
  97. package/dist-electron/tests/electron/plugin-kernel.test.js +225 -18
  98. package/dist-electron/tests/electron/runtime-detection-service.test.js +57 -5
  99. package/dist-electron/tests/electron/sandbox-config.test.js +541 -0
  100. package/dist-electron/tests/electron/workspace-task-store.test.js +257 -0
  101. package/dist-electron/tests/integration/channel-gateways.test.js +32 -0
  102. package/dist-electron/tests/integration/lark-gateway.test.js +1977 -0
  103. package/dist-electron/tests/integration/local-core-acp-progress.test.js +1772 -0
  104. package/dist-electron/tests/integration/local-core-refactor.test.js +775 -5156
  105. package/dist-electron/tests/integration/local-core-routes.test.js +238 -0
  106. package/dist-electron/tests/integration/weixin-gateway.test.js +927 -0
  107. package/package.json +2 -3
  108. package/dist/renderer/assets/Config-lQX2qVVV.js +0 -16
  109. package/dist/renderer/assets/Dashboard-eh_RhGYb.js +0 -26
  110. package/dist/renderer/assets/ProjectDetail-Cv_jIE61.js +0 -11
  111. package/dist/renderer/assets/Workspace-Dl80fNEC.js +0 -14
  112. package/dist/renderer/assets/desktop-jaAiayNB.js +0 -1
  113. package/dist/renderer/assets/en-D2SkCrhG.js +0 -1
  114. package/dist/renderer/assets/es-C8UBPhxM.js +0 -1
  115. package/dist/renderer/assets/index-CaQZSRbg.css +0 -11
  116. package/dist/renderer/assets/ja-ChF4vbBL.js +0 -1
  117. package/dist/renderer/assets/projects-brJZgwEJ.js +0 -1
  118. package/dist/renderer/assets/zh-DIcdHycM.js +0 -1
  119. package/dist/renderer/assets/zh-TW-BtRwreY_.js +0 -1
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeLarkInboundMessageEvent = normalizeLarkInboundMessageEvent;
4
+ exports.isLarkBotMentioned = isLarkBotMentioned;
5
+ exports.stripLarkMentions = stripLarkMentions;
6
+ exports.summarizeLarkInboundPayload = summarizeLarkInboundPayload;
7
+ const node_crypto_1 = require("node:crypto");
8
+ function normalizeLarkInboundMessageEvent(data, options = {}) {
9
+ const payload = (data?.event && typeof data.event === 'object')
10
+ ? data.event
11
+ : data;
12
+ const message = payload?.message;
13
+ const sender = payload?.sender;
14
+ if (!message || !sender) {
15
+ return { ok: false, reason: 'missing-message-or-sender', detail: JSON.stringify(Object.keys(data || {})) };
16
+ }
17
+ let parsedContent = {};
18
+ try {
19
+ parsedContent = JSON.parse(String(message.content || '{}'));
20
+ }
21
+ catch {
22
+ parsedContent = {};
23
+ }
24
+ const messageType = String(message.message_type || '').trim().toLowerCase();
25
+ const chatType = String(message.chat_type || '').trim().toLowerCase();
26
+ const mentions = Array.isArray(message.mentions) ? message.mentions : [];
27
+ const botOpenId = String(options.botOpenId || '').trim();
28
+ if (chatType === 'group' && !options.groupReplyAll && botOpenId && !isLarkBotMentioned(mentions, botOpenId)) {
29
+ return {
30
+ ok: false,
31
+ reason: 'group-message-without-bot-mention',
32
+ detail: `chat=${String(message.chat_id || '')} message=${String(message.message_id || '')}`,
33
+ };
34
+ }
35
+ const text = stripLarkMentions(String(parsedContent.text || '').trim(), mentions, botOpenId);
36
+ const platformUserId = String(sender.sender_id?.user_id || sender.sender_id?.open_id || '').trim();
37
+ const chatId = String(message.chat_id || platformUserId).trim();
38
+ if (!platformUserId || !chatId) {
39
+ return {
40
+ ok: false,
41
+ reason: 'missing-sender-or-chat',
42
+ detail: `senderKeys=${JSON.stringify(Object.keys(sender?.sender_id || {}))} chat=${String(message.chat_id || '')}`,
43
+ };
44
+ }
45
+ return {
46
+ ok: true,
47
+ message: {
48
+ payload,
49
+ message,
50
+ sender,
51
+ parsedContent,
52
+ messageType,
53
+ chatType,
54
+ mentions,
55
+ text,
56
+ platformUserId,
57
+ chatId,
58
+ displayName: String(sender.sender_id?.user_id ||
59
+ sender.sender_id?.open_id ||
60
+ `Lark ${platformUserId.slice(-6)}`),
61
+ messageId: String(message.message_id || (0, node_crypto_1.randomUUID)()),
62
+ },
63
+ };
64
+ }
65
+ function isLarkBotMentioned(mentions, botOpenId) {
66
+ if (!botOpenId) {
67
+ return false;
68
+ }
69
+ return mentions.some((mention) => {
70
+ const item = mention && typeof mention === 'object' ? mention : {};
71
+ return getMentionOpenId(item) === botOpenId;
72
+ });
73
+ }
74
+ function stripLarkMentions(text, mentions, botOpenId) {
75
+ let next = String(text || '');
76
+ for (const mention of mentions) {
77
+ const item = mention && typeof mention === 'object' ? mention : {};
78
+ const key = String(item.key || '').trim();
79
+ if (!key) {
80
+ continue;
81
+ }
82
+ const openId = getMentionOpenId(item);
83
+ const name = String(item.name || item.display_name || item.displayName || '').trim();
84
+ if (botOpenId && openId === botOpenId) {
85
+ next = next.split(key).join('');
86
+ continue;
87
+ }
88
+ next = next.split(key).join(name ? `@${name}` : '');
89
+ }
90
+ return next.trim();
91
+ }
92
+ function summarizeLarkInboundPayload(payload) {
93
+ const eventPayload = (payload?.event && typeof payload.event === 'object')
94
+ ? payload.event
95
+ : payload;
96
+ const message = eventPayload?.message || {};
97
+ const sender = eventPayload?.sender || {};
98
+ const senderId = sender?.sender_id || {};
99
+ const content = typeof message.content === 'string' ? message.content : '';
100
+ return [
101
+ `message=${String(message.message_id || '') || 'missing'}`,
102
+ `type=${String(message.message_type || '') || 'missing'}`,
103
+ `chat=${String(message.chat_id || '') || 'missing'}`,
104
+ `chatType=${String(message.chat_type || '') || 'missing'}`,
105
+ `sender=${String(senderId.user_id || senderId.open_id || '') || 'missing'}`,
106
+ `mentions=${Array.isArray(message.mentions) ? message.mentions.length : 0}`,
107
+ `contentBytes=${Buffer.byteLength(content, 'utf8')}`,
108
+ `keys=${JSON.stringify(Object.keys(eventPayload || {}))}`,
109
+ ].join(' ');
110
+ }
111
+ function getMentionOpenId(item) {
112
+ const id = item.id || item.user_id || item.userId || {};
113
+ return String(id.open_id || id.openId || item.open_id || item.openId || '').trim();
114
+ }
@@ -38,16 +38,19 @@ const node_events_1 = require("node:events");
38
38
  const node_crypto_1 = require("node:crypto");
39
39
  const node_fs_1 = require("node:fs");
40
40
  const node_path_1 = require("node:path");
41
+ const local_core_errors_js_1 = require("../../kernel/local-core-errors.js");
41
42
  const desktop_js_1 = require("../../../../../shared/desktop.js");
42
43
  const content_js_1 = require("../shared/content.js");
43
44
  const file_utils_js_1 = require("../shared/file-utils.js");
44
45
  const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
46
+ const thread_routing_js_1 = require("../shared/thread-routing.js");
45
47
  const cards_js_1 = require("./cards.js");
46
48
  const config_js_1 = require("./config.js");
47
49
  const registration_js_1 = require("./registration.js");
48
50
  const messages_js_1 = require("./rendering/messages.js");
51
+ const inbound_js_1 = require("./inbound.js");
49
52
  const runtime_state_js_1 = require("./runtime-state.js");
50
- const session_command_service_js_1 = require("../../thread/session-command-service.js");
53
+ const thread_slash_command_dispatcher_js_1 = require("../../thread/thread-slash-command-dispatcher.js");
51
54
  const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
52
55
  const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
53
56
  const LARK_FINAL_PATCH_INTERVAL_MS = 900;
@@ -71,15 +74,29 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
71
74
  constructor(options) {
72
75
  super();
73
76
  this.options = options;
74
- const sessionCommandService = new session_command_service_js_1.SessionCommandService({
75
- listThreads: (workspaceId) => this.options.getWorkspaceRouter().listThreads(workspaceId),
76
- getThread: (threadId) => this.options.getWorkspaceRouter().getThread(threadId),
77
- createThread: (workspaceId, title) => this.options.getWorkspaceRouter().createThread(workspaceId, title),
78
- renameThread: (threadId, title) => this.options.getWorkspaceRouter().renameThread(threadId, title),
79
- deleteThread: (threadId) => this.options.getWorkspaceRouter().deleteThread(threadId),
77
+ const slashCommands = new thread_slash_command_dispatcher_js_1.ThreadSlashCommandDispatcher({
78
+ session: {
79
+ listThreads: (workspaceId) => this.options.getWorkspaceRouter().listThreads(workspaceId),
80
+ getThread: (threadId) => this.options.getWorkspaceRouter().getThread(threadId),
81
+ createThread: (workspaceId, title) => this.options.getWorkspaceRouter().createThread(workspaceId, title),
82
+ renameThread: (threadId, title) => this.options.getWorkspaceRouter().renameThread(threadId, title),
83
+ deleteThread: (threadId) => this.options.getWorkspaceRouter().deleteThread(threadId),
84
+ },
85
+ thread: {
86
+ getThreadRow: (threadId) => this.options.store.getThreadRow(threadId),
87
+ updateThreadAgentMode: (threadId, mode) => this.options.store.updateThreadAgentMode(threadId, mode),
88
+ updateThreadAgentType: (threadId, agentType) => this.options.store.updateThreadAgentType(threadId, agentType),
89
+ getLatestRunForThread: (threadId) => this.options.store.getLatestRunForThread(threadId),
90
+ createAuditEvent: (input) => this.options.store.createAuditEvent(input),
91
+ getAgentTypes: () => this.options.getWorkspaceRouter().getAgentTypes(),
92
+ setThreadMode: (threadId, mode) => this.options.getWorkspaceRouter().setThreadMode(threadId, mode),
93
+ closeThreadSession: (threadId) => this.options.getWorkspaceRouter().closeThreadSession(threadId),
94
+ interruptRun: (runId) => this.options.getWorkspaceRouter().interruptRun(runId),
95
+ log: this.options.log,
96
+ },
80
97
  });
81
98
  this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
82
- service: sessionCommandService,
99
+ dispatcher: slashCommands,
83
100
  store: this.options.store,
84
101
  getThreadSessionKey: (threadId) => this.options.getWorkspaceRouter().getThreadSessionKey(threadId),
85
102
  setThreadRoute: (sessionKey, route) => {
@@ -124,6 +141,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
124
141
  appId: binding.appId,
125
142
  autoApprove: binding.autoApprove,
126
143
  cardActionsEnabled: binding.cardActionsEnabled,
144
+ groupReplyAll: binding.groupReplyAll,
145
+ botOpenId: binding.botOpenId,
127
146
  });
128
147
  }
129
148
  continue;
@@ -378,6 +397,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
378
397
  status: binding?.status || 'disabled',
379
398
  appId: binding?.appId || '',
380
399
  lastError: binding?.lastError,
400
+ lastErrorInfo: binding?.lastErrorInfo,
401
+ lastErrorAt: binding?.lastErrorAt,
381
402
  connectedAt: binding?.connectedAt,
382
403
  pendingPairings: pairings.length,
383
404
  authorizedUsers: users.length,
@@ -659,25 +680,17 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
659
680
  return { paired: false };
660
681
  }
661
682
  const router = this.options.getWorkspaceRouter();
662
- const threadBinding = this.options.store.getPlatformThreadBinding(input.workspaceId, input.chatId, input.platformUserId, platformKey);
663
- let threadId = threadBinding?.thread_id || authorized.thread_id || '';
664
- if (!threadId) {
665
- const thread = await router.createThread(input.workspaceId, input.displayName || `Lark ${input.chatId}`);
666
- threadId = thread.id;
667
- this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, threadId, platformKey);
668
- const now = new Date().toISOString();
669
- this.options.store.upsertPlatformThreadBinding({
670
- workspace_id: input.workspaceId,
671
- platform: platformKey,
672
- chat_id: input.chatId,
673
- platform_user_id: input.platformUserId,
674
- thread_id: threadId,
675
- last_platform_message_id: null,
676
- created_at: now,
677
- updated_at: now,
678
- });
679
- }
680
- const sessionKey = this.options.getWorkspaceRouter().getThreadSessionKey(threadId);
683
+ let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
684
+ store: this.options.store,
685
+ router,
686
+ workspaceId: input.workspaceId,
687
+ platformKey,
688
+ chatId: input.chatId,
689
+ platformUserId: input.platformUserId,
690
+ displayName: input.displayName,
691
+ fallbackTitlePrefix: 'Lark',
692
+ authorized,
693
+ });
681
694
  const normalizedText = String(input.text || '').trim().toLowerCase();
682
695
  const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
683
696
  ? this.findAwaitingPermissionThreadId(input.workspaceId, input.chatId, input.platformUserId)
@@ -702,6 +715,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
702
715
  currentThreadId: threadId,
703
716
  text: input.text,
704
717
  defaultTitle: `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`,
718
+ defaultAgentType: slashCommand ? await this.resolveDefaultAgentType(input.workspaceId, threadId) : '',
705
719
  chatId: input.chatId,
706
720
  platformUserId: input.platformUserId,
707
721
  platformKey,
@@ -789,6 +803,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
789
803
  appId: binding.appId,
790
804
  autoApprove: binding.autoApprove,
791
805
  cardActionsEnabled: binding.cardActionsEnabled,
806
+ groupReplyAll: binding.groupReplyAll,
807
+ botOpenId: binding.botOpenId,
792
808
  };
793
809
  this.runtime.set(key, status);
794
810
  this.notifyRuntimeStateChanged();
@@ -801,6 +817,14 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
801
817
  appType: mod.AppType.SelfBuild,
802
818
  domain: mod.Domain.Feishu,
803
819
  });
820
+ try {
821
+ status.botOpenId = await this.fetchBotOpenId(status);
822
+ binding.botOpenId = status.botOpenId;
823
+ this.options.log?.(`localcore-lark bot identified for ${binding.workspaceId}/${binding.instanceId}: ${status.botOpenId}`);
824
+ }
825
+ catch (error) {
826
+ this.options.log?.(`localcore-lark bot identity lookup failed for ${binding.workspaceId}/${binding.instanceId}; group mention filtering may be limited: ${error instanceof Error ? error.message : String(error)}`);
827
+ }
804
828
  status.eventDispatcher = new mod.EventDispatcher({
805
829
  encryptKey: binding.encryptKey || '',
806
830
  verificationToken: binding.verificationToken || '',
@@ -835,13 +859,20 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
835
859
  status.status = 'running';
836
860
  status.connected = true;
837
861
  status.connectedAt = new Date().toISOString();
838
- status.lastError = undefined;
862
+ this.clearRuntimeError(status);
839
863
  this.options.log?.(`localcore-lark ws ready for ${binding.workspaceId}`);
840
864
  }
841
865
  catch (error) {
842
866
  status.status = 'error';
843
867
  status.connected = false;
844
- status.lastError = error instanceof Error ? error.message : String(error);
868
+ const errorInfo = (0, local_core_errors_js_1.toLocalCoreErrorInfo)(error instanceof local_core_errors_js_1.LocalCoreError
869
+ ? error
870
+ : new local_core_errors_js_1.LocalCoreError('channel_auth_failed', error instanceof Error ? error.message : String(error), {
871
+ userMessage: 'Lark is not connected.',
872
+ suggestedAction: 'Check app credentials and restart the Lark gateway.',
873
+ details: { workspaceId: binding.workspaceId, instanceId: binding.instanceId },
874
+ }), 'channel_auth_failed');
875
+ this.setRuntimeError(status, errorInfo);
845
876
  this.options.log?.(`localcore-lark start failed for ${binding.workspaceId}: ${status.lastError}`);
846
877
  }
847
878
  this.notifyRuntimeStateChanged();
@@ -875,6 +906,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
875
906
  appId: state.appId,
876
907
  autoApprove: state.autoApprove,
877
908
  cardActionsEnabled: state.cardActionsEnabled,
909
+ groupReplyAll: state.groupReplyAll,
910
+ botOpenId: state.botOpenId,
878
911
  });
879
912
  this.notifyRuntimeStateChanged();
880
913
  }
@@ -886,30 +919,44 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
886
919
  },
887
920
  });
888
921
  }
922
+ clearRuntimeError(state) {
923
+ state.lastError = undefined;
924
+ state.lastErrorInfo = undefined;
925
+ state.lastErrorAt = undefined;
926
+ }
927
+ setRuntimeError(state, errorInfo) {
928
+ state.lastError = errorInfo.message;
929
+ state.lastErrorInfo = errorInfo;
930
+ state.lastErrorAt = new Date().toISOString();
931
+ this.options.eventBus.emit({
932
+ type: 'localcore.error',
933
+ payload: {
934
+ scope: 'channel.lark',
935
+ errorInfo,
936
+ context: {
937
+ workspaceId: state.workspaceId,
938
+ instanceId: state.instanceId,
939
+ platform: 'lark',
940
+ },
941
+ },
942
+ });
943
+ }
889
944
  async handleMessageEvent(workspaceId, instanceIdOrData, platformKeyOrData, maybeData) {
890
945
  const legacyCall = typeof instanceIdOrData === 'object';
891
946
  const instanceId = legacyCall ? 'default' : instanceIdOrData;
892
947
  const platformKey = legacyCall ? 'lark' : String(platformKeyOrData || (0, config_js_1.channelPlatformKey)('lark', instanceId));
893
948
  const data = (legacyCall ? instanceIdOrData : maybeData) || {};
894
- const payload = (data?.event && typeof data.event === 'object')
895
- ? data.event
896
- : data;
897
- const message = payload?.message;
898
- const sender = payload?.sender;
899
- this.options.log?.(`localcore-lark handling message event for ${workspaceId}: ${this.summarizeLarkPayload(payload)}`);
900
- if (!message || !sender) {
901
- this.options.log?.(`localcore-lark ignored event without message/sender for ${workspaceId}: ${JSON.stringify(Object.keys(data || {}))}`);
949
+ const runtimeState = this.resolveRuntimeState(workspaceId, instanceId).state;
950
+ const normalized = (0, inbound_js_1.normalizeLarkInboundMessageEvent)(data, {
951
+ botOpenId: runtimeState?.botOpenId,
952
+ groupReplyAll: runtimeState?.groupReplyAll,
953
+ });
954
+ this.options.log?.(`localcore-lark handling message event for ${workspaceId}: ${(0, inbound_js_1.summarizeLarkInboundPayload)(data)}`);
955
+ if (!normalized.ok) {
956
+ this.options.log?.(`localcore-lark ignored message event for ${workspaceId}: reason=${normalized.reason}${normalized.detail ? ` ${normalized.detail}` : ''}`);
902
957
  return;
903
958
  }
904
- let parsedContent = {};
905
- try {
906
- parsedContent = JSON.parse(String(message.content || '{}'));
907
- }
908
- catch {
909
- parsedContent = {};
910
- }
911
- const messageType = String(message.message_type || '').trim().toLowerCase();
912
- const text = String(parsedContent.text || '').trim();
959
+ const { message, parsedContent, messageType, chatType, mentions, text, platformUserId, chatId, displayName, messageId, } = normalized.message;
913
960
  const contentParts = [];
914
961
  if (text) {
915
962
  contentParts.push({ type: 'text', text });
@@ -945,24 +992,16 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
945
992
  return;
946
993
  }
947
994
  const displayText = text || this.summarizeInboundContentParts(contentParts);
948
- const platformUserId = String(sender.sender_id?.user_id || sender.sender_id?.open_id || '').trim();
949
- const chatId = String(message.chat_id || platformUserId).trim();
950
- if (!platformUserId || !chatId) {
951
- this.options.log?.(`localcore-lark ignored message without sender/chat for ${workspaceId}: senderKeys=${JSON.stringify(Object.keys(sender?.sender_id || {}))} chat=${String(message.chat_id || '')}`);
952
- return;
953
- }
954
- this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} type=${messageType || 'unknown'} text=${JSON.stringify(displayText.slice(0, 120))}`);
995
+ 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))}`);
955
996
  await this.handleInboundMessage({
956
997
  workspaceId,
957
998
  instanceId,
958
999
  platformKey,
959
1000
  platformUserId,
960
1001
  chatId,
961
- displayName: String(payload?.sender?.sender_id?.user_id ||
962
- payload?.sender?.sender_id?.open_id ||
963
- `Lark ${platformUserId.slice(-6)}`),
1002
+ displayName,
964
1003
  text: displayText,
965
- messageId: String(message.message_id || (0, node_crypto_1.randomUUID)()),
1004
+ messageId,
966
1005
  contentParts,
967
1006
  });
968
1007
  }
@@ -1109,24 +1148,19 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1109
1148
  }
1110
1149
  }
1111
1150
  summarizeLarkEvent(data) {
1112
- const payload = (data?.event && typeof data.event === 'object')
1113
- ? data.event
1114
- : data;
1115
- return this.summarizeLarkPayload(payload);
1116
- }
1117
- summarizeLarkPayload(payload) {
1118
- const message = payload?.message || {};
1119
- const sender = payload?.sender || {};
1120
- const senderId = sender?.sender_id || {};
1121
- const content = typeof message.content === 'string' ? message.content : '';
1122
- return [
1123
- `message=${String(message.message_id || '') || 'missing'}`,
1124
- `type=${String(message.message_type || '') || 'missing'}`,
1125
- `chat=${String(message.chat_id || '') || 'missing'}`,
1126
- `sender=${String(senderId.user_id || senderId.open_id || '') || 'missing'}`,
1127
- `contentBytes=${Buffer.byteLength(content, 'utf8')}`,
1128
- `keys=${JSON.stringify(Object.keys(payload || {}))}`,
1129
- ].join(' ');
1151
+ return (0, inbound_js_1.summarizeLarkInboundPayload)(data);
1152
+ }
1153
+ async fetchBotOpenId(state) {
1154
+ const response = await state.client.request({
1155
+ url: '/open-apis/bot/v3/info',
1156
+ method: 'GET',
1157
+ });
1158
+ const bot = response?.bot || response?.data?.bot;
1159
+ const openId = String(bot?.open_id || bot?.openId || '').trim();
1160
+ if (!openId) {
1161
+ throw new Error('Lark bot info response did not include bot.open_id');
1162
+ }
1163
+ return openId;
1130
1164
  }
1131
1165
  summarizeWsArgs(args) {
1132
1166
  if (args.length === 0) {
@@ -1321,6 +1355,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1321
1355
  currentThreadId: sessionAction.threadId,
1322
1356
  text: sessionAction.command,
1323
1357
  defaultTitle: `Lark ${new Date().toLocaleTimeString()}`,
1358
+ defaultAgentType: await this.resolveDefaultAgentType(workspaceId, sessionAction.threadId),
1324
1359
  chatId: route.chatId,
1325
1360
  platformUserId: route.platformUserId,
1326
1361
  platformKey: route.platformKey,
@@ -1357,6 +1392,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1357
1392
  threadId: binding.thread_id,
1358
1393
  };
1359
1394
  }
1395
+ async resolveDefaultAgentType(workspaceId, threadId) {
1396
+ const router = this.options.getWorkspaceRouter();
1397
+ if (typeof router.getWorkspaceDefaultAgentType === 'function') {
1398
+ return router.getWorkspaceDefaultAgentType(workspaceId);
1399
+ }
1400
+ return this.options.store.getThreadRow(threadId)?.agent_type || 'codex';
1401
+ }
1360
1402
  async markPermissionCardActionHandled(workspaceId, instanceId, rootPayload, payload, value, response, threadId) {
1361
1403
  const state = this.resolveRuntimeState(workspaceId, instanceId).state;
1362
1404
  if (!state?.client) {
@@ -7,10 +7,12 @@ class ChannelSessionCommandRuntime {
7
7
  this.options = options;
8
8
  }
9
9
  async execute(input) {
10
- const result = await this.options.service.execute(input.text, {
10
+ const result = await this.options.dispatcher.execute({
11
11
  workspaceId: input.workspaceId,
12
- currentThreadId: input.currentThreadId,
12
+ threadId: input.currentThreadId,
13
+ content: input.text,
13
14
  defaultTitle: input.defaultTitle,
15
+ defaultAgentType: input.defaultAgentType,
14
16
  });
15
17
  if (!result.handled) {
16
18
  return { handled: false, threadId: input.currentThreadId };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveChannelThreadRoute = resolveChannelThreadRoute;
4
+ async function resolveChannelThreadRoute(input) {
5
+ const threadBinding = input.store.getPlatformThreadBinding(input.workspaceId, input.chatId, input.platformUserId, input.platformKey);
6
+ let threadId = threadBinding?.thread_id || (input.authorized.chat_id === input.chatId ? input.authorized.thread_id : '') || '';
7
+ let createdThread = false;
8
+ if (!threadId) {
9
+ const thread = await input.router.createThread(input.workspaceId, input.displayName || `${input.fallbackTitlePrefix} ${input.chatId}`);
10
+ threadId = thread.id;
11
+ createdThread = true;
12
+ input.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, threadId, input.platformKey);
13
+ }
14
+ let createdBinding = false;
15
+ if (!threadBinding) {
16
+ const now = new Date().toISOString();
17
+ input.store.upsertPlatformThreadBinding({
18
+ workspace_id: input.workspaceId,
19
+ platform: input.platformKey,
20
+ chat_id: input.chatId,
21
+ platform_user_id: input.platformUserId,
22
+ thread_id: threadId,
23
+ last_platform_message_id: null,
24
+ created_at: now,
25
+ updated_at: now,
26
+ });
27
+ createdBinding = true;
28
+ }
29
+ return {
30
+ threadId,
31
+ createdThread,
32
+ createdBinding,
33
+ };
34
+ }