@kafca/agentdock 0.1.45 → 0.1.47

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 (106) hide show
  1. package/README.md +11 -0
  2. package/dist/renderer/assets/{Badge-BIojwD6s.js → Badge-BYREM3t3.js} +1 -1
  3. package/dist/renderer/assets/Chat-Dtb5X7sB.js +2 -0
  4. package/dist/renderer/assets/{ChatMarkdown-DqszsPB_.js → ChatMarkdown-_slLloCh.js} +1 -1
  5. package/dist/renderer/assets/Config-pHichs7H.js +21 -0
  6. package/dist/renderer/assets/CronList-CJQMeCjz.js +1 -0
  7. package/dist/renderer/assets/Dashboard-CY77Imde.js +26 -0
  8. package/dist/renderer/assets/{EmptyState-BqCx1oWr.js → EmptyState-DCqmct2y.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-BwK8Gpfa.js → KnowledgeDetail-DFrxa-pv.js} +1 -1
  10. package/dist/renderer/assets/KnowledgeHome-DL-vAfrH.js +11 -0
  11. package/dist/renderer/assets/Logs-jw9Uv590.js +1 -0
  12. package/dist/renderer/assets/{Modal-D2U4r2V0.js → Modal-ChSm7tk6.js} +1 -1
  13. package/dist/renderer/assets/MonitorList-DrEwyS71.js +1 -0
  14. package/dist/renderer/assets/{Page-urf5GcT_.js → Page-DhD-zgMU.js} +1 -1
  15. package/dist/renderer/assets/ProjectDetail-BVSjpfpL.js +11 -0
  16. package/dist/renderer/assets/ProjectList-CHGbTJjk.js +1 -0
  17. package/dist/renderer/assets/{Select-CAscWpy5.js → Select-rHs9CSam.js} +1 -1
  18. package/dist/renderer/assets/SessionChat-CDc2FNMA.js +1 -0
  19. package/dist/renderer/assets/SessionList-Mr1uAnRW.js +1 -0
  20. package/dist/renderer/assets/ThreadChat-Detu5UfN.js +23 -0
  21. package/dist/renderer/assets/Workspace-MRRg8ndJ.js +19 -0
  22. package/dist/renderer/assets/{arrow-left-7HrNuS-V.js → arrow-left-BU2NB2LA.js} +1 -1
  23. package/dist/renderer/assets/{book-open-BDoAu82s.js → book-open-D-TGvWwa.js} +1 -1
  24. package/dist/renderer/assets/bot-IYNh8tH5.js +6 -0
  25. package/dist/renderer/assets/{check-DGlyq4xX.js → check-CCZ0JO_S.js} +1 -1
  26. package/dist/renderer/assets/{chevron-down-Bb_3EHq9.js → chevron-down-00bRZi15.js} +1 -1
  27. package/dist/renderer/assets/{circle-DIpqZnYw.js → circle-CpQ8x4k_.js} +1 -1
  28. package/dist/renderer/assets/{desktop-Ci1fnRDR.js → desktop-D0k2aGSj.js} +1 -1
  29. package/dist/renderer/assets/{desktop-Do_UrC-o.js → desktop-JQkhNOF4.js} +1 -1
  30. package/dist/renderer/assets/{funnel-Bbf0ERLP.js → funnel-UbcrCBCp.js} +1 -1
  31. package/dist/renderer/assets/{heart-CGqU-qfw.js → heart-DvLsV7tL.js} +1 -1
  32. package/dist/renderer/assets/{index-Df-Trovt.js → index-B2L4G-b_.js} +1 -1
  33. package/dist/renderer/assets/index-CO4fGqmv.css +11 -0
  34. package/dist/renderer/assets/{index-DwhTjLA1.js → index-dy-g2Bh4.js} +3 -3
  35. package/dist/renderer/assets/{pencil-CHiy1MvK.js → pencil-qBYOgW5M.js} +1 -1
  36. package/dist/renderer/assets/{play-CGYnmC4Q.js → play-Dn6b4AGj.js} +1 -1
  37. package/dist/renderer/assets/{plus-B_Q5-Oj7.js → plus-CaApUwEm.js} +1 -1
  38. package/dist/renderer/assets/projects-BwF5RlNV.js +1 -0
  39. package/dist/renderer/assets/save-CN6yvTfD.js +11 -0
  40. package/dist/renderer/assets/{search-D8Dkhsyq.js → search-Dn2MxYiO.js} +1 -1
  41. package/dist/renderer/assets/{server-Cd96R7WL.js → server-DpcVLHeh.js} +1 -1
  42. package/dist/renderer/assets/{session-utils-BNUbQBfF.js → session-utils-DnD2Q_y1.js} +1 -1
  43. package/dist/renderer/assets/{sessions-BACfV8s1.js → sessions-eK5D4FLt.js} +1 -1
  44. package/dist/renderer/assets/{shield-check-Cnn-yQUA.js → shield-check-DSSJkacw.js} +1 -1
  45. package/dist/renderer/assets/{trash-2-oWCxwQ9D.js → trash-2-DmYJlEvO.js} +1 -1
  46. package/dist/renderer/assets/user-Cvf_uiyQ.js +6 -0
  47. package/dist/renderer/assets/{wifi-off-DHxnNkdY.js → wifi-off-CCTloj-V.js} +1 -1
  48. package/dist/renderer/index.html +2 -2
  49. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +2 -1
  50. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +1 -1
  51. package/dist-electron/services/local-ai-core/src/agents/shared/launch-utils.js +22 -0
  52. package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +55 -1
  53. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +132 -348
  54. package/dist-electron/services/local-ai-core/src/channel/shared/base-channel-gateway.js +303 -0
  55. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +131 -382
  56. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +2 -1
  57. package/dist-electron/services/local-ai-core/src/runtime/channel-service.js +150 -0
  58. package/dist-electron/services/local-ai-core/src/runtime/env-utils.js +12 -0
  59. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +234 -0
  60. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +34 -0
  61. package/dist-electron/services/local-ai-core/src/runtime/handlers/capabilities-handler.js +12 -0
  62. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +65 -0
  63. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +17 -0
  64. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +65 -0
  65. package/dist-electron/services/local-ai-core/src/runtime/handlers/openai-handler.js +496 -0
  66. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +24 -0
  67. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +68 -0
  68. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtimes-handler.js +37 -0
  69. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +34 -0
  70. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +49 -0
  71. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +27 -0
  72. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +42 -0
  73. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +29 -0
  74. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +40 -592
  75. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +96 -0
  76. package/dist-electron/services/local-ai-core/src/runtime/server.js +107 -1084
  77. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +13 -1
  78. package/dist-electron/src/pages/Projects/project-provider-config.js +75 -0
  79. package/dist-electron/tests/contracts/architecture-docs.test.js +1 -0
  80. package/dist-electron/tests/electron/agent-runtime-detector.test.js +18 -0
  81. package/dist-electron/tests/electron/knowledge-skill-script.test.js +15 -5
  82. package/dist-electron/tests/electron/lac-cli.test.js +591 -688
  83. package/dist-electron/tests/electron/plugin-kernel.test.js +47 -31
  84. package/dist-electron/tests/electron/project-provider-config.test.js +71 -0
  85. package/dist-electron/tests/electron/workspace-task-store.test.js +19 -9
  86. package/dist-electron/tests/integration/lark-gateway.test.js +80 -0
  87. package/dist-electron/tests/integration/local-core-cors.test.js +22 -0
  88. package/package.json +1 -1
  89. package/dist/renderer/assets/Chat-wjBR3XEX.js +0 -2
  90. package/dist/renderer/assets/Config-BDCHs5A2.js +0 -21
  91. package/dist/renderer/assets/CronList-CEWQYTov.js +0 -1
  92. package/dist/renderer/assets/Dashboard-DrWftfk3.js +0 -26
  93. package/dist/renderer/assets/KnowledgeHome-hhDTZMDO.js +0 -11
  94. package/dist/renderer/assets/Logs-C9xPEhFT.js +0 -1
  95. package/dist/renderer/assets/MonitorList-CayKbfwJ.js +0 -1
  96. package/dist/renderer/assets/ProjectDetail-B1GyAr7a.js +0 -11
  97. package/dist/renderer/assets/ProjectList-BoipQypE.js +0 -1
  98. package/dist/renderer/assets/SessionChat-BAVy5221.js +0 -1
  99. package/dist/renderer/assets/SessionList-BZpuMvh0.js +0 -1
  100. package/dist/renderer/assets/ThreadChat-JX7m9biG.js +0 -23
  101. package/dist/renderer/assets/Workspace-CFW8otjU.js +0 -14
  102. package/dist/renderer/assets/index-RaTga2BC.css +0 -11
  103. package/dist/renderer/assets/plug-Mexu4gyV.js +0 -6
  104. package/dist/renderer/assets/projects-C6bbkC-O.js +0 -1
  105. package/dist/renderer/assets/save-CJ_QFPw0.js +0 -6
  106. package/dist/renderer/assets/user-BzE9BwsY.js +0 -11
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.LocalCoreLarkGateway = void 0;
37
- const node_events_1 = require("node:events");
38
37
  const node_crypto_1 = require("node:crypto");
39
38
  const node_fs_1 = require("node:fs");
40
39
  const node_path_1 = require("node:path");
@@ -42,118 +41,30 @@ const local_core_errors_js_1 = require("../../kernel/local-core-errors.js");
42
41
  const desktop_js_1 = require("../../../../../shared/desktop.js");
43
42
  const content_js_1 = require("../shared/content.js");
44
43
  const file_utils_js_1 = require("../shared/file-utils.js");
45
- const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
46
44
  const thread_routing_js_1 = require("../shared/thread-routing.js");
45
+ const base_channel_gateway_js_1 = require("../shared/base-channel-gateway.js");
47
46
  const cards_js_1 = require("./cards.js");
48
47
  const config_js_1 = require("./config.js");
49
48
  const registration_js_1 = require("./registration.js");
50
49
  const messages_js_1 = require("./rendering/messages.js");
51
50
  const inbound_js_1 = require("./inbound.js");
52
51
  const runtime_state_js_1 = require("./runtime-state.js");
53
- const thread_slash_command_dispatcher_js_1 = require("../../thread/thread-slash-command-dispatcher.js");
54
52
  const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
55
53
  const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
56
54
  const LARK_FINAL_PATCH_INTERVAL_MS = 900;
57
55
  const LARK_PROGRESS_PATCH_INTERVAL_MS = 3000;
58
- class LocalCoreLarkGateway extends node_events_1.EventEmitter {
59
- options;
56
+ class LocalCoreLarkGateway extends base_channel_gateway_js_1.BaseChannelGateway {
60
57
  // Lark returns 200340 when card action events are not enabled in the app's
61
58
  // event subscription. Keep card actions opt-in so text approval always works.
62
59
  defaultCardActionsEnabled = false;
63
60
  // Keep permission state in a dedicated card to avoid mixing order in the main reply card.
64
61
  mirrorPermissionStateInMainCard = false;
65
- runtime = new Map();
66
- threadRouting = new Map();
67
- outboundEventChains = new Map();
68
- outboundTurns = new Map();
69
- mutedThreadBridgeCounts = new Map();
70
- sessionCommandRuntime;
71
62
  larkModulePromise = null;
72
63
  platform = 'lark';
73
- routeType = 'channel.chat';
74
64
  constructor(options) {
75
- super();
76
- this.options = options;
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
- },
97
- });
98
- this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
99
- dispatcher: slashCommands,
100
- store: this.options.store,
101
- getThreadSessionKey: (threadId) => this.options.getWorkspaceRouter().getThreadSessionKey(threadId),
102
- setThreadRoute: (sessionKey, route) => {
103
- this.threadRouting.set(sessionKey, route);
104
- },
105
- createRoute: (input, threadId) => ({
106
- workspaceId: input.workspaceId,
107
- instanceId: input.instanceId,
108
- platformKey: input.platformKey,
109
- platformUserId: input.platformUserId,
110
- chatId: input.chatId,
111
- threadId,
112
- }),
113
- sendResult: (input, result) => this.sendSessionCommandResult(input, result),
114
- });
115
- }
116
- async refreshBindings() {
117
- const config = await this.options.readConfig();
118
- const bindings = this.collectBindings(config);
119
- const nextKeys = new Set(bindings.map((binding) => (0, config_js_1.runtimeKey)(binding.workspaceId, binding.instanceId)));
120
- for (const key of [...this.runtime.keys()]) {
121
- if (!nextKeys.has(key)) {
122
- await this.stopWorkspaceKey(key);
123
- }
124
- }
125
- for (const binding of bindings) {
126
- const key = (0, config_js_1.runtimeKey)(binding.workspaceId, binding.instanceId);
127
- const current = this.runtime.get(key);
128
- if (!binding.enabled) {
129
- if (current) {
130
- await this.stopWorkspaceKey(key);
131
- }
132
- else {
133
- this.runtime.set(key, {
134
- workspaceId: binding.workspaceId,
135
- instanceId: binding.instanceId,
136
- displayName: binding.displayName,
137
- platformKey: binding.platformKey,
138
- enabled: false,
139
- status: 'disabled',
140
- connected: false,
141
- appId: binding.appId,
142
- autoApprove: binding.autoApprove,
143
- cardActionsEnabled: binding.cardActionsEnabled,
144
- groupReplyAll: binding.groupReplyAll,
145
- botOpenId: binding.botOpenId,
146
- });
147
- }
148
- continue;
149
- }
150
- if (current?.status === 'running' && current.appId === binding.appId) {
151
- continue;
152
- }
153
- await this.startWorkspace(binding);
154
- }
155
- this.notifyRuntimeStateChanged();
65
+ super(options);
156
66
  }
67
+ // ==================== Lifecycle (platform-specific) ====================
157
68
  async testConnection(workspaceId, instanceId) {
158
69
  const binding = await this.getBinding(workspaceId, instanceId);
159
70
  const result = await this.createSdkClientResult(binding);
@@ -164,15 +75,6 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
164
75
  instanceId: binding.instanceId,
165
76
  };
166
77
  }
167
- async enable(workspaceId, instanceId) {
168
- const binding = await this.getBinding(workspaceId, instanceId);
169
- await this.startWorkspace(binding);
170
- return this.getStatus(workspaceId, binding.instanceId);
171
- }
172
- async disable(workspaceId, instanceId) {
173
- await this.stopWorkspace(workspaceId, instanceId);
174
- return this.getStatus(workspaceId, instanceId);
175
- }
176
78
  async getQrCode(workspaceId, instanceId) {
177
79
  const binding = await this.getBinding(workspaceId, instanceId);
178
80
  const data = await (0, registration_js_1.requestAppRegistration)(binding);
@@ -250,9 +152,6 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
250
152
  }
251
153
  };
252
154
  }
253
- async executeSessionCommand(input) {
254
- return this.sessionCommandRuntime.execute(input);
255
- }
256
155
  async sendSessionCommandResult(input, result) {
257
156
  const state = this.resolveRuntimeState(input.workspaceId, input.instanceId).state;
258
157
  if (state?.client && state.connected && result.card?.actions?.length && state.cardActionsEnabled) {
@@ -367,111 +266,6 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
367
266
  file,
368
267
  };
369
268
  }
370
- muteThreadBridge(threadId) {
371
- const current = this.mutedThreadBridgeCounts.get(threadId) || 0;
372
- this.mutedThreadBridgeCounts.set(threadId, current + 1);
373
- }
374
- unmuteThreadBridge(threadId) {
375
- const current = this.mutedThreadBridgeCounts.get(threadId) || 0;
376
- if (current <= 1) {
377
- this.mutedThreadBridgeCounts.delete(threadId);
378
- return;
379
- }
380
- this.mutedThreadBridgeCounts.set(threadId, current - 1);
381
- }
382
- getStatus(workspaceId, instanceId) {
383
- this.options.store.expirePendingPairings();
384
- const resolved = this.resolveRuntimeState(workspaceId, instanceId);
385
- const binding = resolved.state;
386
- const platformKey = binding?.platformKey || (0, config_js_1.channelPlatformKey)('lark', resolved.instanceId);
387
- const pairings = this.options.store.listPendingPairings(workspaceId)
388
- .filter((row) => row.platform === platformKey && row.expires_at >= new Date().toISOString());
389
- const users = this.options.store.listAuthorizedUsers(workspaceId, platformKey);
390
- return {
391
- workspaceId,
392
- platform: 'lark',
393
- instanceId: resolved.instanceId,
394
- displayName: binding?.displayName,
395
- enabled: Boolean(binding?.enabled),
396
- connected: Boolean(binding?.connected),
397
- status: binding?.status || 'disabled',
398
- appId: binding?.appId || '',
399
- lastError: binding?.lastError,
400
- lastErrorInfo: binding?.lastErrorInfo,
401
- lastErrorAt: binding?.lastErrorAt,
402
- connectedAt: binding?.connectedAt,
403
- pendingPairings: pairings.length,
404
- authorizedUsers: users.length,
405
- };
406
- }
407
- listStatuses() {
408
- return [...this.runtime.values()]
409
- .sort((a, b) => `${a.workspaceId}:${a.instanceId}`.localeCompare(`${b.workspaceId}:${b.instanceId}`))
410
- .map((state) => this.getStatus(state.workspaceId, state.instanceId));
411
- }
412
- listPendingPairings(workspaceId) {
413
- this.options.store.expirePendingPairings();
414
- return this.options.store
415
- .listPairingRequests(workspaceId)
416
- .filter((item) => item.platform === 'lark' || item.platform.startsWith('lark:'))
417
- .filter((item) => item.status === 'pending' && item.expiresAt >= new Date().toISOString());
418
- }
419
- listAuthorizedUsers(workspaceId) {
420
- return this.options.store.listAuthorizedUsers(workspaceId)
421
- .filter((item) => item.platform === 'lark' || item.platform.startsWith('lark:'));
422
- }
423
- async start() {
424
- await this.refreshBindings();
425
- }
426
- async stop() {
427
- this.close();
428
- }
429
- approvePairing(code) {
430
- this.options.store.expirePendingPairings();
431
- const pairing = this.options.store.getPairingRequest(code);
432
- if (!pairing) {
433
- throw new Error(`Pairing code not found: ${code}`);
434
- }
435
- if (pairing.platform !== 'lark' && !pairing.platform.startsWith('lark:')) {
436
- throw new Error(`Pairing code ${code} is not a Lark pairing`);
437
- }
438
- if (pairing.status !== 'pending') {
439
- throw new Error(`Pairing code ${code} is already ${pairing.status}`);
440
- }
441
- if (pairing.expires_at < new Date().toISOString()) {
442
- this.options.store.updatePairingStatus(code, 'expired');
443
- throw new Error(`Pairing code ${code} has expired`);
444
- }
445
- const existing = this.options.store.getAuthorizedUser(pairing.workspace_id, pairing.platform_user_id, pairing.platform);
446
- const userId = existing?.id || `lark-user-${(0, node_crypto_1.randomUUID)()}`;
447
- const authorizedAt = new Date().toISOString();
448
- this.options.store.createAuthorizedUser({
449
- id: userId,
450
- workspace_id: pairing.workspace_id,
451
- platform: pairing.platform,
452
- platform_user_id: pairing.platform_user_id,
453
- chat_id: pairing.chat_id,
454
- display_name: pairing.display_name,
455
- thread_id: existing?.thread_id || null,
456
- authorized_at: authorizedAt,
457
- });
458
- this.options.store.updatePairingStatus(code, 'approved');
459
- this.notifyRuntimeStateChanged();
460
- const user = this.options.store.listAuthorizedUsers(pairing.workspace_id, pairing.platform).find((entry) => entry.id === userId);
461
- if (!user) {
462
- throw new Error('Authorized user lookup failed after approval');
463
- }
464
- return user;
465
- }
466
- rejectPairing(code) {
467
- const pairing = this.options.store.getPairingRequest(code);
468
- if (!pairing) {
469
- throw new Error(`Pairing code not found: ${code}`);
470
- }
471
- this.options.store.updatePairingStatus(code, 'rejected');
472
- this.notifyRuntimeStateChanged();
473
- return { rejected: true };
474
- }
475
269
  async onBridgeEvent(event) {
476
270
  if (!event.sessionKey) {
477
271
  this.options.log?.(`localcore-lark bridge event ignored without sessionKey: ${event.type}`);
@@ -612,153 +406,131 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
612
406
  await current;
613
407
  }
614
408
  async handleInboundMessage(input) {
615
- const instanceId = input.instanceId || 'default';
616
- const platformKey = input.platformKey || (0, config_js_1.channelPlatformKey)('lark', instanceId);
409
+ const msg = input;
410
+ const instanceId = msg.instanceId || 'default';
411
+ const platformKey = msg.platformKey || (0, config_js_1.channelPlatformKey)('lark', instanceId);
617
412
  this.options.eventBus.emit({
618
413
  type: 'platform.message.received',
619
414
  payload: {
620
415
  platform: this.platform,
621
- workspaceId: input.workspaceId,
622
- participantId: input.platformUserId,
623
- channelId: input.chatId,
624
- displayName: input.displayName,
625
- text: input.text,
626
- messageId: input.messageId,
416
+ workspaceId: msg.workspaceId,
417
+ participantId: msg.platformUserId,
418
+ channelId: msg.chatId,
419
+ displayName: msg.displayName,
420
+ text: msg.text,
421
+ messageId: msg.messageId,
627
422
  },
628
423
  });
629
424
  this.options.store.expirePendingPairings();
630
- const runtimeState = this.resolveRuntimeState(input.workspaceId, instanceId).state;
425
+ const runtimeState = this.resolveRuntimeState(msg.workspaceId, instanceId).state;
631
426
  let binding;
632
427
  try {
633
- binding = await this.getBinding(input.workspaceId, instanceId);
428
+ binding = await this.getBinding(msg.workspaceId, instanceId);
634
429
  }
635
430
  catch (error) {
636
431
  if (!runtimeState) {
637
432
  throw error;
638
433
  }
639
- this.options.log?.(`localcore-lark using active runtime binding snapshot for ${input.workspaceId}/${instanceId}: ${error instanceof Error ? error.message : String(error)}`);
434
+ this.options.log?.(`localcore-lark using active runtime binding snapshot for ${msg.workspaceId}/${instanceId}: ${error instanceof Error ? error.message : String(error)}`);
640
435
  }
641
- let authorized = this.options.store.getAuthorizedUser(input.workspaceId, input.platformUserId, platformKey);
436
+ let authorized = this.options.store.getAuthorizedUser(msg.workspaceId, msg.platformUserId, platformKey);
642
437
  if (!authorized) {
643
438
  if (binding?.autoApprove || runtimeState?.autoApprove) {
644
439
  const authorizedAt = new Date().toISOString();
645
440
  this.options.store.createAuthorizedUser({
646
441
  id: `lark-user-${(0, node_crypto_1.randomUUID)()}`,
647
- workspace_id: input.workspaceId,
442
+ workspace_id: msg.workspaceId,
648
443
  platform: platformKey,
649
- platform_user_id: input.platformUserId,
650
- chat_id: input.chatId,
651
- display_name: input.displayName,
444
+ platform_user_id: msg.platformUserId,
445
+ chat_id: msg.chatId,
446
+ display_name: msg.displayName,
652
447
  thread_id: null,
653
448
  authorized_at: authorizedAt,
654
449
  });
655
- authorized = this.options.store.getAuthorizedUser(input.workspaceId, input.platformUserId, platformKey);
656
- this.options.log?.(`localcore-lark auto-approved user for ${input.workspaceId}: ${input.platformUserId}`);
450
+ authorized = this.options.store.getAuthorizedUser(msg.workspaceId, msg.platformUserId, platformKey);
451
+ this.options.log?.(`localcore-lark auto-approved user for ${msg.workspaceId}: ${msg.platformUserId}`);
657
452
  this.notifyRuntimeStateChanged();
658
453
  }
659
454
  }
660
455
  if (!authorized) {
661
- const existingPending = this.options.store.listPendingPairings(input.workspaceId).find((item) => item.platform === platformKey && item.platform_user_id === input.platformUserId && item.chat_id === input.chatId && item.status === 'pending');
456
+ 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');
662
457
  let pairingCode = existingPending?.code || '';
663
458
  if (!existingPending) {
664
459
  const now = new Date();
665
460
  pairingCode = this.generatePairingCode();
666
461
  this.options.store.createPairingRequest({
667
462
  code: pairingCode,
668
- workspace_id: input.workspaceId,
463
+ workspace_id: msg.workspaceId,
669
464
  platform: platformKey,
670
- platform_user_id: input.platformUserId,
671
- chat_id: input.chatId,
672
- display_name: input.displayName,
465
+ platform_user_id: msg.platformUserId,
466
+ chat_id: msg.chatId,
467
+ display_name: msg.displayName,
673
468
  requested_at: now.toISOString(),
674
469
  expires_at: new Date(now.getTime() + PAIRING_EXPIRY_MS).toISOString(),
675
470
  status: 'pending',
676
471
  });
677
472
  this.notifyRuntimeStateChanged();
678
473
  }
679
- await this.sendImmediateCard(input.workspaceId, input.chatId, (0, cards_js_1.renderPendingPairingCard)(pairingCode), instanceId);
680
- return { paired: false };
474
+ await this.sendImmediateCard(msg.workspaceId, msg.chatId, (0, cards_js_1.renderPendingPairingCard)(pairingCode), instanceId);
475
+ return; // { paired: false };
681
476
  }
682
477
  const router = this.options.getWorkspaceRouter();
683
478
  let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
684
479
  store: this.options.store,
685
480
  router,
686
- workspaceId: input.workspaceId,
481
+ workspaceId: msg.workspaceId,
687
482
  platformKey,
688
- chatId: input.chatId,
689
- platformUserId: input.platformUserId,
690
- displayName: input.displayName,
483
+ chatId: msg.chatId,
484
+ platformUserId: msg.platformUserId,
485
+ displayName: msg.displayName,
691
486
  fallbackTitlePrefix: 'Lark',
692
487
  authorized,
693
488
  });
694
- const normalizedText = String(input.text || '').trim().toLowerCase();
489
+ const normalizedText = String(msg.text || '').trim().toLowerCase();
695
490
  const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
696
- ? this.findAwaitingPermissionThreadId(input.workspaceId, input.chatId, input.platformUserId)
491
+ ? this.findAwaitingPermissionThreadId(msg.workspaceId, msg.chatId, msg.platformUserId)
697
492
  : '';
698
493
  if (permissionThreadId && permissionThreadId !== threadId) {
699
494
  threadId = permissionThreadId;
700
495
  }
701
496
  const effectiveSessionKey = this.options.getWorkspaceRouter().getThreadSessionKey(threadId);
702
497
  this.threadRouting.set(effectiveSessionKey, {
703
- workspaceId: input.workspaceId,
498
+ workspaceId: msg.workspaceId,
704
499
  instanceId,
705
500
  platformKey,
706
- platformUserId: input.platformUserId,
707
- chatId: input.chatId,
501
+ platformUserId: msg.platformUserId,
502
+ chatId: msg.chatId,
708
503
  threadId,
709
504
  });
710
- const acknowledgement = this.createTurnState(effectiveSessionKey, input.messageId);
711
- await this.addAcknowledgementReaction(input.workspaceId, input.messageId, acknowledgement, instanceId);
712
- const slashCommand = this.parseSlashCommand(input.text);
505
+ const acknowledgement = this.createTurnState(effectiveSessionKey, msg.messageId);
506
+ await this.addAcknowledgementReaction(msg.workspaceId, msg.messageId, acknowledgement, instanceId);
507
+ const slashCommand = this.parseSlashCommand(msg.text);
713
508
  const sessionCommand = await this.executeSessionCommand({
714
- workspaceId: input.workspaceId,
509
+ workspaceId: msg.workspaceId,
715
510
  currentThreadId: threadId,
716
- text: input.text,
717
- defaultTitle: `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`,
718
- defaultAgentType: slashCommand ? await this.resolveDefaultAgentType(input.workspaceId, threadId) : '',
719
- chatId: input.chatId,
720
- platformUserId: input.platformUserId,
511
+ text: msg.text,
512
+ defaultTitle: `${msg.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`,
513
+ defaultAgentType: slashCommand ? await this.resolveDefaultAgentType(msg.workspaceId, threadId) : '',
514
+ chatId: msg.chatId,
515
+ platformUserId: msg.platformUserId,
721
516
  platformKey,
722
517
  instanceId,
723
518
  });
724
519
  if (sessionCommand.handled) {
725
- return { paired: true, threadId: sessionCommand.threadId || threadId };
520
+ return; // { paired: true, threadId: sessionCommand.threadId || threadId };
726
521
  }
727
522
  const latestRun = this.options.store.getLatestRunForThread(threadId);
728
523
  if ((normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
729
524
  && latestRun?.status === 'awaiting_input') {
730
- await router.sendThreadAction(threadId, input.text);
731
- return { paired: true, threadId };
525
+ await router.sendThreadAction(threadId, msg.text);
526
+ return; // { paired: true, threadId };
732
527
  }
733
- this.options.store.clearPlatformThreadMessageId(input.workspaceId, input.chatId, input.platformUserId);
528
+ this.options.store.clearPlatformThreadMessageId(msg.workspaceId, msg.chatId, msg.platformUserId);
734
529
  const wrappedText = slashCommand
735
- ? input.text
736
- : (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(input.text);
737
- await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, input.contentParts));
738
- return { paired: true, threadId };
739
- }
740
- close() {
741
- return Promise.all([...this.runtime.keys()].map((key) => this.stopWorkspaceKey(key))).then(() => undefined);
742
- }
743
- resolveRuntimeState(workspaceId, instanceId) {
744
- if (instanceId) {
745
- const state = this.runtime.get((0, config_js_1.runtimeKey)(workspaceId, instanceId)) || (instanceId === 'default' ? this.runtime.get(workspaceId) : undefined);
746
- return { instanceId, state };
747
- }
748
- const states = [...this.runtime.values()].filter((entry) => entry.workspaceId === workspaceId);
749
- const state = states.find((entry) => entry.instanceId === 'default') || states[0];
750
- return { instanceId: state?.instanceId || 'default', state: state || this.runtime.get(workspaceId) };
751
- }
752
- async getBinding(workspaceId, instanceId) {
753
- const config = await this.options.readConfig();
754
- const bindings = this.collectBindings(config).filter((entry) => entry.workspaceId === workspaceId);
755
- const binding = instanceId
756
- ? bindings.find((entry) => entry.instanceId === instanceId)
757
- : bindings.find((entry) => entry.instanceId === 'default') || bindings[0];
758
- if (!binding) {
759
- throw new Error(`No Lark binding configured for workspace "${workspaceId}"${instanceId ? ` instance "${instanceId}"` : ''}`);
760
- }
761
- return binding;
530
+ ? msg.text
531
+ : (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(msg.text);
532
+ await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, msg.contentParts));
533
+ return; // { paired: true, threadId };
762
534
  }
763
535
  async createSdkClientResult(binding) {
764
536
  try {
@@ -877,70 +649,6 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
877
649
  }
878
650
  this.notifyRuntimeStateChanged();
879
651
  }
880
- async stopWorkspace(workspaceId, instanceId) {
881
- const resolved = this.resolveRuntimeState(workspaceId, instanceId);
882
- await this.stopWorkspaceKey((0, config_js_1.runtimeKey)(workspaceId, resolved.instanceId));
883
- }
884
- async stopWorkspaceKey(key) {
885
- const state = this.runtime.get(key);
886
- if (!state) {
887
- return;
888
- }
889
- this.options.log?.(`localcore-lark stopping workspace=${state.workspaceId}/${state.instanceId} status=${state.status}`);
890
- try {
891
- await state.wsClient?.stop?.();
892
- this.options.log?.(`localcore-lark stopped workspace=${state.workspaceId}/${state.instanceId}`);
893
- }
894
- catch (error) {
895
- this.options.log?.(`localcore-lark stop failed for ${state.workspaceId}/${state.instanceId}: ${error instanceof Error ? error.message : String(error)}`);
896
- // Best effort: current SDK versions may not implement stop().
897
- }
898
- this.runtime.set(key, {
899
- workspaceId: state.workspaceId,
900
- instanceId: state.instanceId,
901
- displayName: state.displayName,
902
- platformKey: state.platformKey,
903
- enabled: false,
904
- status: 'stopped',
905
- connected: false,
906
- appId: state.appId,
907
- autoApprove: state.autoApprove,
908
- cardActionsEnabled: state.cardActionsEnabled,
909
- groupReplyAll: state.groupReplyAll,
910
- botOpenId: state.botOpenId,
911
- });
912
- this.notifyRuntimeStateChanged();
913
- }
914
- notifyRuntimeStateChanged() {
915
- this.options.eventBus.emit({
916
- type: 'runtime.state.changed',
917
- payload: {
918
- reason: 'channel-bindings',
919
- },
920
- });
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
- }
944
652
  async handleMessageEvent(workspaceId, instanceIdOrData, platformKeyOrData, maybeData) {
945
653
  const legacyCall = typeof instanceIdOrData === 'object';
946
654
  const instanceId = legacyCall ? 'default' : instanceIdOrData;
@@ -1186,11 +894,87 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1186
894
  }
1187
895
  return `${value.slice(0, 6)}...${value.slice(-4)}`;
1188
896
  }
897
+ makeThreadRoute(input, threadId) {
898
+ return {
899
+ workspaceId: input.workspaceId,
900
+ instanceId: input.instanceId,
901
+ platformKey: input.platformKey,
902
+ platformUserId: input.platformUserId,
903
+ chatId: input.chatId,
904
+ threadId,
905
+ };
906
+ }
1189
907
  collectBindings(config) {
1190
908
  return (0, config_js_1.collectLarkWorkspaceBindings)(config, {
1191
909
  defaultCardActionsEnabled: this.defaultCardActionsEnabled,
1192
910
  });
1193
911
  }
912
+ buildStatusObject(state, _resolved) {
913
+ this.options.store.expirePendingPairings();
914
+ const resolved = this.resolveRuntimeState(state.workspaceId, state.instanceId);
915
+ const binding = resolved.state;
916
+ const platformKey = binding?.platformKey || (0, config_js_1.channelPlatformKey)('lark', resolved.instanceId);
917
+ const pairings = this.options.store.listPendingPairings(state.workspaceId)
918
+ .filter((row) => row.platform === platformKey && row.expires_at >= new Date().toISOString());
919
+ const users = this.options.store.listAuthorizedUsers(state.workspaceId, platformKey);
920
+ return {
921
+ workspaceId: state.workspaceId,
922
+ platform: 'lark',
923
+ instanceId: resolved.instanceId,
924
+ displayName: binding?.displayName,
925
+ enabled: Boolean(binding?.enabled),
926
+ connected: Boolean(binding?.connected),
927
+ status: binding?.status || 'disabled',
928
+ appId: binding?.appId || '',
929
+ lastError: binding?.lastError,
930
+ lastErrorInfo: binding?.lastErrorInfo,
931
+ lastErrorAt: binding?.lastErrorAt,
932
+ connectedAt: binding?.connectedAt,
933
+ pendingPairings: pairings.length,
934
+ authorizedUsers: users.length,
935
+ };
936
+ }
937
+ createDisabledState(binding) {
938
+ return {
939
+ workspaceId: binding.workspaceId,
940
+ instanceId: binding.instanceId,
941
+ displayName: binding.displayName,
942
+ platformKey: binding.platformKey,
943
+ enabled: false,
944
+ status: 'disabled',
945
+ connected: false,
946
+ appId: binding.appId,
947
+ autoApprove: binding.autoApprove,
948
+ cardActionsEnabled: binding.cardActionsEnabled,
949
+ groupReplyAll: binding.groupReplyAll,
950
+ botOpenId: binding.botOpenId,
951
+ };
952
+ }
953
+ async stopWorkspaceTransport(state) {
954
+ this.options.log?.(`localcore-lark stopping workspace=${state.workspaceId}/${state.instanceId} status=${state.status}`);
955
+ try {
956
+ await state.wsClient?.stop?.();
957
+ this.options.log?.(`localcore-lark stopped workspace=${state.workspaceId}/${state.instanceId}`);
958
+ }
959
+ catch (error) {
960
+ this.options.log?.(`localcore-lark stop failed for ${state.workspaceId}/${state.instanceId}: ${error instanceof Error ? error.message : String(error)}`);
961
+ }
962
+ }
963
+ resetStateToStopped(state, _key) {
964
+ Object.assign(state, {
965
+ enabled: false,
966
+ status: 'stopped',
967
+ connected: false,
968
+ appId: state.appId,
969
+ autoApprove: state.autoApprove,
970
+ cardActionsEnabled: state.cardActionsEnabled,
971
+ groupReplyAll: state.groupReplyAll,
972
+ botOpenId: state.botOpenId,
973
+ });
974
+ }
975
+ isSameIdentity(state, binding) {
976
+ return state.appId === binding.appId;
977
+ }
1194
978
  async getLarkModule() {
1195
979
  if (!this.larkModulePromise) {
1196
980
  this.larkModulePromise = Promise.resolve().then(() => __importStar(require('@larksuiteoapi/node-sdk')));