@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
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseChannelGateway = void 0;
4
+ const node_events_1 = require("node:events");
5
+ const node_crypto_1 = require("node:crypto");
6
+ const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
7
+ const thread_slash_command_dispatcher_js_1 = require("../../thread/thread-slash-command-dispatcher.js");
8
+ function resolveRuntimeKey(workspaceId, instanceId) {
9
+ return instanceId ? `${workspaceId}::${instanceId}` : workspaceId;
10
+ }
11
+ class BaseChannelGateway extends node_events_1.EventEmitter {
12
+ options;
13
+ routeType = 'channel.chat';
14
+ runtime = new Map();
15
+ threadRouting = new Map();
16
+ outboundEventChains = new Map();
17
+ outboundTurns = new Map();
18
+ mutedThreadBridgeCounts = new Map();
19
+ sessionCommandRuntime;
20
+ constructor(options) {
21
+ super();
22
+ this.options = options;
23
+ const slashCommands = new thread_slash_command_dispatcher_js_1.ThreadSlashCommandDispatcher({
24
+ session: {
25
+ listThreads: (workspaceId) => options.getWorkspaceRouter().listThreads(workspaceId),
26
+ getThread: (threadId) => options.getWorkspaceRouter().getThread(threadId),
27
+ createThread: (workspaceId, title) => options.getWorkspaceRouter().createThread(workspaceId, title),
28
+ renameThread: (threadId, title) => options.getWorkspaceRouter().renameThread(threadId, title),
29
+ deleteThread: (threadId) => options.getWorkspaceRouter().deleteThread(threadId),
30
+ },
31
+ thread: {
32
+ getThreadRow: (threadId) => options.store.getThreadRow(threadId),
33
+ updateThreadAgentMode: (threadId, mode) => options.store.updateThreadAgentMode(threadId, mode),
34
+ updateThreadAgentType: (threadId, agentType) => options.store.updateThreadAgentType(threadId, agentType),
35
+ getLatestRunForThread: (threadId) => options.store.getLatestRunForThread(threadId),
36
+ createAuditEvent: (input) => options.store.createAuditEvent(input),
37
+ getAgentTypes: () => options.getWorkspaceRouter().getAgentTypes(),
38
+ setThreadMode: (threadId, mode) => options.getWorkspaceRouter().setThreadMode(threadId, mode),
39
+ closeThreadSession: (threadId) => options.getWorkspaceRouter().closeThreadSession(threadId),
40
+ interruptRun: (runId) => options.getWorkspaceRouter().interruptRun(runId),
41
+ log: options.log,
42
+ },
43
+ });
44
+ this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
45
+ dispatcher: slashCommands,
46
+ store: options.store,
47
+ getThreadSessionKey: (threadId) => options.getWorkspaceRouter().getThreadSessionKey(threadId),
48
+ setThreadRoute: (sessionKey, route) => {
49
+ this.threadRouting.set(sessionKey, route);
50
+ },
51
+ createRoute: (input, threadId) => this.makeThreadRoute(input, threadId),
52
+ sendResult: (input, result) => this.sendSessionCommandResult(input, result),
53
+ });
54
+ }
55
+ // ==================== Lifecycle ====================
56
+ async refreshBindings() {
57
+ const config = await this.options.readConfig();
58
+ const bindings = this.collectBindings(config);
59
+ const nextKeys = new Set(bindings.map((b) => resolveRuntimeKey(b.workspaceId, b.instanceId)));
60
+ for (const key of [...this.runtime.keys()]) {
61
+ if (!nextKeys.has(key)) {
62
+ await this.stopWorkspaceKey(key);
63
+ }
64
+ }
65
+ for (const binding of bindings) {
66
+ const key = resolveRuntimeKey(binding.workspaceId, binding.instanceId);
67
+ const current = this.runtime.get(key);
68
+ if (!binding.enabled) {
69
+ if (current) {
70
+ await this.stopWorkspaceKey(key);
71
+ }
72
+ else {
73
+ this.runtime.set(key, this.createDisabledState(binding));
74
+ }
75
+ continue;
76
+ }
77
+ if (current?.status === 'running' && this.isSameIdentity(current, binding)) {
78
+ continue;
79
+ }
80
+ await this.startWorkspace(binding);
81
+ }
82
+ this.notifyRuntimeStateChanged();
83
+ }
84
+ /** Returns true if the current runtime state belongs to the same identity as the binding (skip restart). */
85
+ isSameIdentity(_state, _binding) {
86
+ return false;
87
+ }
88
+ async enable(workspaceId, instanceId) {
89
+ const binding = await this.getBinding(workspaceId, instanceId);
90
+ await this.startWorkspace(binding);
91
+ return this.getStatus(workspaceId, binding.instanceId);
92
+ }
93
+ async disable(workspaceId, instanceId) {
94
+ await this.stopWorkspace(workspaceId, instanceId);
95
+ return this.getStatus(workspaceId, instanceId);
96
+ }
97
+ async start() {
98
+ await this.refreshBindings();
99
+ }
100
+ async stop() {
101
+ await this.close();
102
+ }
103
+ close() {
104
+ return Promise.all([...this.runtime.keys()].map((key) => this.stopWorkspaceKey(key))).then(() => undefined);
105
+ }
106
+ // ==================== Status ====================
107
+ getStatus(workspaceId, instanceId) {
108
+ this.options.store.expirePendingPairings();
109
+ const resolved = this.resolveRuntimeState(workspaceId, instanceId);
110
+ return this.buildStatusObject(resolved.state, resolved);
111
+ }
112
+ listStatuses() {
113
+ return [...this.runtime.values()]
114
+ .sort((a, b) => `${a.workspaceId}:${a.instanceId}`.localeCompare(`${b.workspaceId}:${b.instanceId}`))
115
+ .map((state) => this.getStatus(state.workspaceId, state.instanceId));
116
+ }
117
+ listPendingPairings(workspaceId) {
118
+ this.options.store.expirePendingPairings();
119
+ return this.options.store
120
+ .listPairingRequests(workspaceId)
121
+ .filter((item) => item.platform === this.platform || item.platform.startsWith(`${this.platform}:`))
122
+ .filter((item) => item.status === 'pending' && item.expiresAt >= new Date().toISOString());
123
+ }
124
+ listAuthorizedUsers(workspaceId) {
125
+ return this.options.store.listAuthorizedUsers(workspaceId)
126
+ .filter((item) => item.platform === this.platform || item.platform.startsWith(`${this.platform}:`));
127
+ }
128
+ // ==================== Pairing ====================
129
+ approvePairing(code) {
130
+ this.options.store.expirePendingPairings();
131
+ const pairing = this.options.store.getPairingRequest(code);
132
+ if (!pairing)
133
+ throw new Error(`Pairing code not found: ${code}`);
134
+ if (pairing.platform !== this.platform && !pairing.platform.startsWith(`${this.platform}:`))
135
+ throw new Error(`Pairing code ${code} is not a ${this.platform} pairing`);
136
+ if (pairing.status !== 'pending')
137
+ throw new Error(`Pairing code ${code} is already ${pairing.status}`);
138
+ if (pairing.expires_at < new Date().toISOString()) {
139
+ this.options.store.updatePairingStatus(code, 'expired');
140
+ throw new Error(`Pairing code ${code} has expired`);
141
+ }
142
+ const existing = this.options.store.getAuthorizedUser(pairing.workspace_id, pairing.platform_user_id, pairing.platform);
143
+ const userId = existing?.id || `${this.platform}-user-${(0, node_crypto_1.randomUUID)()}`;
144
+ const authorizedAt = new Date().toISOString();
145
+ this.options.store.createAuthorizedUser({
146
+ id: userId,
147
+ workspace_id: pairing.workspace_id,
148
+ platform: pairing.platform,
149
+ platform_user_id: pairing.platform_user_id,
150
+ chat_id: pairing.chat_id,
151
+ display_name: pairing.display_name,
152
+ thread_id: existing?.thread_id || null,
153
+ authorized_at: authorizedAt,
154
+ });
155
+ this.options.store.updatePairingStatus(code, 'approved');
156
+ this.notifyRuntimeStateChanged();
157
+ const user = this.options.store.listAuthorizedUsers(pairing.workspace_id, pairing.platform).find((e) => e.id === userId);
158
+ if (!user)
159
+ throw new Error('Authorized user lookup failed after approval');
160
+ return user;
161
+ }
162
+ rejectPairing(code) {
163
+ const pairing = this.options.store.getPairingRequest(code);
164
+ if (!pairing)
165
+ throw new Error(`Pairing code not found: ${code}`);
166
+ if (pairing.platform !== this.platform && !pairing.platform.startsWith(`${this.platform}:`))
167
+ throw new Error(`Pairing code ${code} is not a ${this.platform} pairing`);
168
+ this.options.store.updatePairingStatus(code, 'rejected');
169
+ this.notifyRuntimeStateChanged();
170
+ return { rejected: true };
171
+ }
172
+ // ==================== Bridge Event Throttling ====================
173
+ muteThreadBridge(threadId) {
174
+ const current = this.mutedThreadBridgeCounts.get(threadId) || 0;
175
+ this.mutedThreadBridgeCounts.set(threadId, current + 1);
176
+ }
177
+ unmuteThreadBridge(threadId) {
178
+ const current = this.mutedThreadBridgeCounts.get(threadId) || 0;
179
+ if (current <= 1) {
180
+ this.mutedThreadBridgeCounts.delete(threadId);
181
+ return;
182
+ }
183
+ this.mutedThreadBridgeCounts.set(threadId, current - 1);
184
+ }
185
+ // ==================== Scheduling ====================
186
+ async sendScheduledCard(workspaceId, chatId, text) {
187
+ return this.sendScheduledMessage(workspaceId, { type: 'channel.chat', channelId: chatId }, text);
188
+ }
189
+ async sendScheduledMessage(workspaceId, route, text) {
190
+ const state = this.resolveRuntimeState(workspaceId, route.instanceId).state;
191
+ if (!state?.connected) {
192
+ this.options.log?.(`[${this.platform}] scheduled message skipped: workspace not connected: ${workspaceId}`);
193
+ return '';
194
+ }
195
+ try {
196
+ await this.sendOutboundMessage(workspaceId, {
197
+ route: { type: 'channel.chat', channelId: route.channelId, participantId: route.participantId },
198
+ parts: [{ type: 'text', text }],
199
+ });
200
+ return `${this.platform}_sched_${(0, node_crypto_1.randomUUID)()}`;
201
+ }
202
+ catch (error) {
203
+ this.options.log?.(`[${this.platform}] scheduled message failed for ${workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
204
+ return '';
205
+ }
206
+ }
207
+ registerScheduledThreadBridge(input) {
208
+ const instanceId = input.route.instanceId || 'default';
209
+ const route = {
210
+ workspaceId: input.workspaceId,
211
+ instanceId,
212
+ platformKey: `${this.platform}${instanceId !== 'default' ? `:${instanceId}` : ''}`,
213
+ platformUserId: input.route.participantId || '',
214
+ chatId: input.route.channelId,
215
+ threadId: input.threadId,
216
+ };
217
+ const previousRoute = this.threadRouting.get(input.sessionKey);
218
+ this.threadRouting.set(input.sessionKey, route);
219
+ return () => {
220
+ if (previousRoute) {
221
+ this.threadRouting.set(input.sessionKey, previousRoute);
222
+ }
223
+ else {
224
+ this.threadRouting.delete(input.sessionKey);
225
+ }
226
+ };
227
+ }
228
+ // ==================== Session Commands ====================
229
+ async executeSessionCommand(input) {
230
+ return this.sessionCommandRuntime.execute(input);
231
+ }
232
+ // ==================== Runtime Management ====================
233
+ resolveRuntimeState(workspaceId, instanceId) {
234
+ const key = resolveRuntimeKey(workspaceId, instanceId);
235
+ if (instanceId) {
236
+ const state = this.runtime.get(key) || (instanceId === 'default' ? this.runtime.get(workspaceId) : undefined);
237
+ return { instanceId, state };
238
+ }
239
+ const states = [...this.runtime.values()].filter((entry) => entry.workspaceId === workspaceId);
240
+ const state = states.find((entry) => entry.instanceId === 'default') || states[0];
241
+ return { instanceId: state?.instanceId || 'default', state: state || this.runtime.get(workspaceId) };
242
+ }
243
+ async getBinding(workspaceId, instanceId) {
244
+ const config = await this.options.readConfig();
245
+ const bindings = this.collectBindings(config).filter((entry) => entry.workspaceId === workspaceId);
246
+ const binding = instanceId
247
+ ? bindings.find((entry) => entry.instanceId === instanceId)
248
+ : bindings.find((entry) => entry.instanceId === 'default') || bindings[0];
249
+ if (!binding) {
250
+ throw new Error(`No ${this.platform} binding configured for workspace "${workspaceId}"${instanceId ? ` instance "${instanceId}"` : ''}`);
251
+ }
252
+ return binding;
253
+ }
254
+ async stopWorkspace(workspaceId, instanceId) {
255
+ const resolved = this.resolveRuntimeState(workspaceId, instanceId);
256
+ await this.stopWorkspaceKey(resolveRuntimeKey(workspaceId, resolved.instanceId));
257
+ }
258
+ async stopWorkspaceKey(key) {
259
+ const state = this.runtime.get(key);
260
+ if (!state)
261
+ return;
262
+ try {
263
+ await this.stopWorkspaceTransport(state);
264
+ }
265
+ catch (error) {
266
+ this.options.log?.(`[${this.platform}] stop transport failed for ${state.workspaceId}/${state.instanceId}: ${error instanceof Error ? error.message : String(error)}`);
267
+ }
268
+ this.resetStateToStopped(state, key);
269
+ this.notifyRuntimeStateChanged();
270
+ }
271
+ // ==================== Error Management ====================
272
+ notifyRuntimeStateChanged() {
273
+ this.options.eventBus.emit({
274
+ type: 'runtime.state.changed',
275
+ payload: {
276
+ reason: 'channel-bindings',
277
+ },
278
+ });
279
+ }
280
+ clearRuntimeError(state) {
281
+ state.lastError = undefined;
282
+ state.lastErrorInfo = undefined;
283
+ state.lastErrorAt = undefined;
284
+ }
285
+ setRuntimeError(state, errorInfo) {
286
+ state.lastError = errorInfo.message;
287
+ state.lastErrorInfo = errorInfo;
288
+ state.lastErrorAt = new Date().toISOString();
289
+ this.options.eventBus.emit({
290
+ type: 'localcore.error',
291
+ payload: {
292
+ scope: `channel.${this.platform}`,
293
+ errorInfo,
294
+ context: {
295
+ workspaceId: state.workspaceId,
296
+ instanceId: state.instanceId,
297
+ platform: this.platform,
298
+ },
299
+ },
300
+ });
301
+ }
302
+ }
303
+ exports.BaseChannelGateway = BaseChannelGateway;