@kafca/agentdock 0.1.22 → 0.1.23
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.
- package/README.md +3 -0
- package/dist/renderer/assets/{Badge-B_rgzxYO.js → Badge-C2K5apfV.js} +1 -1
- package/dist/renderer/assets/{Chat-CYtp6m7T.js → Chat-DI2YeVKb.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DOBMwa9d.js → ChatMarkdown-DMAr15Oi.js} +1 -1
- package/dist/renderer/assets/{Config-DppMSPHF.js → Config-7rP3EuUf.js} +1 -1
- package/dist/renderer/assets/{CronList-BDtB1SuA.js → CronList-81QslYE8.js} +1 -1
- package/dist/renderer/assets/{Dashboard-iFlRnd7Y.js → Dashboard-Db2T7rSZ.js} +2 -2
- package/dist/renderer/assets/{EmptyState-bKDt_T88.js → EmptyState-BBJ3cTvB.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-CKPhKPIg.js → KnowledgeDetail-Dz_6flG3.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-CFeJre6i.js → KnowledgeHome-DIh046mN.js} +3 -3
- package/dist/renderer/assets/{Logs-CyxSVOFK.js → Logs-BXBtHJLf.js} +1 -1
- package/dist/renderer/assets/{Modal-CxPnk1Ey.js → Modal-BB2Av_Xs.js} +1 -1
- package/dist/renderer/assets/{Page-kU9vubzj.js → Page-DPSdvMgU.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D9FY9NWZ.js → ProjectDetail-C6EWGvGg.js} +1 -1
- package/dist/renderer/assets/{ProjectList-DIwr2TXg.js → ProjectList-BBo5ygnS.js} +1 -1
- package/dist/renderer/assets/{Select-BaWoz5Dn.js → Select-CNX-Tx_O.js} +1 -1
- package/dist/renderer/assets/{SessionChat-Cm9CW8Zx.js → SessionChat-BIn46jqZ.js} +1 -1
- package/dist/renderer/assets/{SessionList-UPnWlXXO.js → SessionList-CZt6f1Rd.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-YvVsACW3.js → ThreadChat-BotD0gKQ.js} +1 -1
- package/dist/renderer/assets/Workspace-C_4tdpjX.js +14 -0
- package/dist/renderer/assets/{arrow-left-BmZAVGV7.js → arrow-left-cHr5wkpq.js} +1 -1
- package/dist/renderer/assets/{book-open-DZ3GXFgI.js → book-open-4nx5C8T-.js} +1 -1
- package/dist/renderer/assets/{check-CeVSvDCv.js → check-exTS-R-x.js} +1 -1
- package/dist/renderer/assets/{chevron-down-yryuMoQ-.js → chevron-down-DSvxXQa0.js} +1 -1
- package/dist/renderer/assets/{circle-eASsFISH.js → circle-DyvEovdw.js} +1 -1
- package/dist/renderer/assets/desktop-B-KVT10D.js +1 -0
- package/dist/renderer/assets/{desktop-Che1cbpE.js → desktop-CVibRyAw.js} +3 -3
- package/dist/renderer/assets/{funnel-pwAe2Ixp.js → funnel-DA9qVdTy.js} +1 -1
- package/dist/renderer/assets/{heart-B2Sp-bCm.js → heart-DuEV0ZRJ.js} +1 -1
- package/dist/renderer/assets/{index-Cse2Br64.js → index-BgflqkCN.js} +3 -3
- package/dist/renderer/assets/{index-BC3MWbS1.js → index-Biz-aexG.js} +39 -39
- package/dist/renderer/assets/{pencil-BfEunUF3.js → pencil-DBDxeNmO.js} +1 -1
- package/dist/renderer/assets/{play-Dcs9Lj_Z.js → play-IzlP83_7.js} +1 -1
- package/dist/renderer/assets/{plug-B_YschQe.js → plug-CuT-qFnW.js} +1 -1
- package/dist/renderer/assets/{plus-Pqo-cXHQ.js → plus-DEqgkn63.js} +1 -1
- package/dist/renderer/assets/projects-DDtDN1rc.js +1 -0
- package/dist/renderer/assets/{save-BKM5yi1A.js → save-D4sRo07y.js} +1 -1
- package/dist/renderer/assets/{search-BU42h10M.js → search-DbPZLuV8.js} +1 -1
- package/dist/renderer/assets/{server-DA5t3Rtr.js → server-D1jUQmwN.js} +1 -1
- package/dist/renderer/assets/{session-utils-Cr9VhNSq.js → session-utils-Aife8ep2.js} +1 -1
- package/dist/renderer/assets/{sessions-bvV8ZMfX.js → sessions-DaH3H7gC.js} +1 -1
- package/dist/renderer/assets/{shield-check-BeOJKur_.js → shield-check-BGwUFWNr.js} +1 -1
- package/dist/renderer/assets/{trash-2-CQ7HKO3q.js → trash-2-CIFBioBa.js} +1 -1
- package/dist/renderer/assets/{user-CtFjY9SV.js → user-CnKcvHdo.js} +1 -1
- package/dist/renderer/assets/{wifi-off-Ci5m0ysf.js → wifi-off-ClO53WGa.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/local-core-refactor.test.js +505 -0
- package/dist-electron/electron/plugin-kernel.test.js +74 -14
- package/dist-electron/packages/core-sdk/src/index.js +40 -20
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +5 -1
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +55 -3
- package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +210 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +54 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +212 -471
- package/dist-electron/services/local-ai-core/src/channel/lark/registration.js +50 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +191 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/types.js +2 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/plugin.js +31 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +125 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +141 -324
- package/dist-electron/services/local-ai-core/src/channel/weixin/transport.js +169 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/types.js +2 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +5 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +18 -39
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +18 -39
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +55 -44
- package/dist-electron/services/local-ai-core/src/runtime/server.js +10 -8
- package/dist-electron/shared/desktop.js +10 -0
- package/package.json +1 -1
- package/dist/renderer/assets/Workspace-ST7V8u6T.js +0 -14
- package/dist/renderer/assets/desktop-DkrP_s-b.js +0 -1
- package/dist/renderer/assets/projects-BCj0k_Gy.js +0 -1
|
@@ -40,15 +40,10 @@ const node_fs_1 = require("node:fs");
|
|
|
40
40
|
const node_path_1 = require("node:path");
|
|
41
41
|
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
42
42
|
const file_utils_js_1 = require("../shared/file-utils.js");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const parts = normalized.split(' - ');
|
|
48
|
-
if (parts.length <= 2)
|
|
49
|
-
return normalized;
|
|
50
|
-
return parts.slice(0, 2).join(' - ');
|
|
51
|
-
}
|
|
43
|
+
const cards_js_1 = require("./cards.js");
|
|
44
|
+
const config_js_1 = require("./config.js");
|
|
45
|
+
const registration_js_1 = require("./registration.js");
|
|
46
|
+
const runtime_state_js_1 = require("./runtime-state.js");
|
|
52
47
|
const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
|
|
53
48
|
const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
|
|
54
49
|
class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
@@ -73,25 +68,30 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
73
68
|
async refreshBindings() {
|
|
74
69
|
const config = await this.options.readConfig();
|
|
75
70
|
const bindings = this.collectBindings(config);
|
|
76
|
-
const
|
|
77
|
-
for (const
|
|
78
|
-
if (!
|
|
79
|
-
await this.
|
|
71
|
+
const nextKeys = new Set(bindings.map((binding) => (0, config_js_1.runtimeKey)(binding.workspaceId, binding.instanceId)));
|
|
72
|
+
for (const key of [...this.runtime.keys()]) {
|
|
73
|
+
if (!nextKeys.has(key)) {
|
|
74
|
+
await this.stopWorkspaceKey(key);
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
77
|
for (const binding of bindings) {
|
|
83
|
-
const
|
|
78
|
+
const key = (0, config_js_1.runtimeKey)(binding.workspaceId, binding.instanceId);
|
|
79
|
+
const current = this.runtime.get(key);
|
|
84
80
|
if (!binding.enabled) {
|
|
85
81
|
if (current) {
|
|
86
|
-
await this.
|
|
82
|
+
await this.stopWorkspaceKey(key);
|
|
87
83
|
}
|
|
88
84
|
else {
|
|
89
|
-
this.runtime.set(
|
|
85
|
+
this.runtime.set(key, {
|
|
90
86
|
workspaceId: binding.workspaceId,
|
|
87
|
+
instanceId: binding.instanceId,
|
|
88
|
+
displayName: binding.displayName,
|
|
89
|
+
platformKey: binding.platformKey,
|
|
91
90
|
enabled: false,
|
|
92
91
|
status: 'disabled',
|
|
93
92
|
connected: false,
|
|
94
93
|
appId: binding.appId,
|
|
94
|
+
autoApprove: binding.autoApprove,
|
|
95
95
|
cardActionsEnabled: binding.cardActionsEnabled,
|
|
96
96
|
});
|
|
97
97
|
}
|
|
@@ -104,23 +104,70 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
104
104
|
}
|
|
105
105
|
this.notifyRuntimeStateChanged();
|
|
106
106
|
}
|
|
107
|
-
async testConnection(workspaceId) {
|
|
108
|
-
const binding = await this.getBinding(workspaceId);
|
|
107
|
+
async testConnection(workspaceId, instanceId) {
|
|
108
|
+
const binding = await this.getBinding(workspaceId, instanceId);
|
|
109
109
|
const result = await this.createSdkClientResult(binding);
|
|
110
110
|
return {
|
|
111
111
|
...result,
|
|
112
112
|
platform: 'lark',
|
|
113
113
|
workspaceId,
|
|
114
|
+
instanceId: binding.instanceId,
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
|
-
async enable(workspaceId) {
|
|
117
|
-
const binding = await this.getBinding(workspaceId);
|
|
117
|
+
async enable(workspaceId, instanceId) {
|
|
118
|
+
const binding = await this.getBinding(workspaceId, instanceId);
|
|
118
119
|
await this.startWorkspace(binding);
|
|
119
|
-
return this.getStatus(workspaceId);
|
|
120
|
+
return this.getStatus(workspaceId, binding.instanceId);
|
|
121
|
+
}
|
|
122
|
+
async disable(workspaceId, instanceId) {
|
|
123
|
+
await this.stopWorkspace(workspaceId, instanceId);
|
|
124
|
+
return this.getStatus(workspaceId, instanceId);
|
|
120
125
|
}
|
|
121
|
-
async
|
|
122
|
-
await this.
|
|
123
|
-
|
|
126
|
+
async getQrCode(workspaceId, instanceId) {
|
|
127
|
+
const binding = await this.getBinding(workspaceId, instanceId);
|
|
128
|
+
const data = await (0, registration_js_1.requestAppRegistration)(binding);
|
|
129
|
+
const ticket = String(data.device_code || '').trim();
|
|
130
|
+
const userCode = String(data.user_code || '').trim();
|
|
131
|
+
if (!ticket || !userCode) {
|
|
132
|
+
throw new Error('Lark app registration did not return a device code and user code.');
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
ticket,
|
|
136
|
+
expiresIn: Number(data.expires_in || registration_js_1.DEFAULT_LARK_QR_EXPIRES_IN) || registration_js_1.DEFAULT_LARK_QR_EXPIRES_IN,
|
|
137
|
+
interval: Number(data.interval || 5) || 5,
|
|
138
|
+
qrCodeUrl: `${(0, registration_js_1.getLarkOpenBase)(binding)}${registration_js_1.LARK_APP_REGISTRATION_SETUP_PATH}?user_code=${encodeURIComponent(userCode)}&from=openclaw`,
|
|
139
|
+
instanceId: binding.instanceId,
|
|
140
|
+
displayName: binding.displayName,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async checkQrCodeStatus(workspaceId, ticket, instanceId) {
|
|
144
|
+
const binding = await this.getBinding(workspaceId, instanceId);
|
|
145
|
+
const data = await (0, registration_js_1.pollAppRegistration)(binding, ticket);
|
|
146
|
+
const error = String(data.error || '').trim();
|
|
147
|
+
if (error === 'authorization_pending' || error === 'slow_down') {
|
|
148
|
+
return { status: 'wait' };
|
|
149
|
+
}
|
|
150
|
+
if (error === 'expired_token' || error === 'invalid_grant') {
|
|
151
|
+
return { status: 'expired' };
|
|
152
|
+
}
|
|
153
|
+
if (error === 'access_denied') {
|
|
154
|
+
throw new Error('Lark app registration was rejected.');
|
|
155
|
+
}
|
|
156
|
+
if (error) {
|
|
157
|
+
throw new Error(`Lark app registration failed: ${String(data.error_description || error)}`);
|
|
158
|
+
}
|
|
159
|
+
const appId = String(data.client_id || '').trim();
|
|
160
|
+
const appSecret = String(data.client_secret || '').trim();
|
|
161
|
+
if (!appId || !appSecret) {
|
|
162
|
+
return { status: 'wait' };
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
status: 'confirmed',
|
|
166
|
+
credentials: {
|
|
167
|
+
appId,
|
|
168
|
+
appSecret,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
124
171
|
}
|
|
125
172
|
async sendScheduledCard(workspaceId, chatId, text) {
|
|
126
173
|
return this.sendImmediateCard(workspaceId, chatId, text);
|
|
@@ -129,7 +176,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
129
176
|
return this.sendScheduledCard(workspaceId, route.channelId, text);
|
|
130
177
|
}
|
|
131
178
|
async sendOutboundMessage(workspaceId, input) {
|
|
132
|
-
const state = this.
|
|
179
|
+
const state = this.resolveRuntimeState(workspaceId, input.route?.instanceId).state;
|
|
133
180
|
if (!state?.client || !state.connected) {
|
|
134
181
|
throw new Error(`Lark workspace is not connected: ${workspaceId}`);
|
|
135
182
|
}
|
|
@@ -245,15 +292,19 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
245
292
|
}
|
|
246
293
|
this.mutedThreadBridgeCounts.set(threadId, current - 1);
|
|
247
294
|
}
|
|
248
|
-
getStatus(workspaceId) {
|
|
295
|
+
getStatus(workspaceId, instanceId) {
|
|
249
296
|
this.options.store.expirePendingPairings();
|
|
250
|
-
const
|
|
297
|
+
const resolved = this.resolveRuntimeState(workspaceId, instanceId);
|
|
298
|
+
const binding = resolved.state;
|
|
299
|
+
const platformKey = binding?.platformKey || (0, config_js_1.channelPlatformKey)('lark', resolved.instanceId);
|
|
251
300
|
const pairings = this.options.store.listPendingPairings(workspaceId)
|
|
252
|
-
.filter((row) => row.platform ===
|
|
253
|
-
const users = this.options.store.listAuthorizedUsers(workspaceId,
|
|
301
|
+
.filter((row) => row.platform === platformKey && row.expires_at >= new Date().toISOString());
|
|
302
|
+
const users = this.options.store.listAuthorizedUsers(workspaceId, platformKey);
|
|
254
303
|
return {
|
|
255
304
|
workspaceId,
|
|
256
305
|
platform: 'lark',
|
|
306
|
+
instanceId: resolved.instanceId,
|
|
307
|
+
displayName: binding?.displayName,
|
|
257
308
|
enabled: Boolean(binding?.enabled),
|
|
258
309
|
connected: Boolean(binding?.connected),
|
|
259
310
|
status: binding?.status || 'disabled',
|
|
@@ -265,16 +316,20 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
265
316
|
};
|
|
266
317
|
}
|
|
267
318
|
listStatuses() {
|
|
268
|
-
return [...this.runtime.
|
|
319
|
+
return [...this.runtime.values()]
|
|
320
|
+
.sort((a, b) => `${a.workspaceId}:${a.instanceId}`.localeCompare(`${b.workspaceId}:${b.instanceId}`))
|
|
321
|
+
.map((state) => this.getStatus(state.workspaceId, state.instanceId));
|
|
269
322
|
}
|
|
270
323
|
listPendingPairings(workspaceId) {
|
|
271
324
|
this.options.store.expirePendingPairings();
|
|
272
325
|
return this.options.store
|
|
273
|
-
.listPairingRequests(workspaceId
|
|
326
|
+
.listPairingRequests(workspaceId)
|
|
327
|
+
.filter((item) => item.platform === 'lark' || item.platform.startsWith('lark:'))
|
|
274
328
|
.filter((item) => item.status === 'pending' && item.expiresAt >= new Date().toISOString());
|
|
275
329
|
}
|
|
276
330
|
listAuthorizedUsers(workspaceId) {
|
|
277
|
-
return this.options.store.listAuthorizedUsers(workspaceId
|
|
331
|
+
return this.options.store.listAuthorizedUsers(workspaceId)
|
|
332
|
+
.filter((item) => item.platform === 'lark' || item.platform.startsWith('lark:'));
|
|
278
333
|
}
|
|
279
334
|
async start() {
|
|
280
335
|
await this.refreshBindings();
|
|
@@ -288,7 +343,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
288
343
|
if (!pairing) {
|
|
289
344
|
throw new Error(`Pairing code not found: ${code}`);
|
|
290
345
|
}
|
|
291
|
-
if (pairing.platform !== 'lark') {
|
|
346
|
+
if (pairing.platform !== 'lark' && !pairing.platform.startsWith('lark:')) {
|
|
292
347
|
throw new Error(`Pairing code ${code} is not a Lark pairing`);
|
|
293
348
|
}
|
|
294
349
|
if (pairing.status !== 'pending') {
|
|
@@ -298,12 +353,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
298
353
|
this.options.store.updatePairingStatus(code, 'expired');
|
|
299
354
|
throw new Error(`Pairing code ${code} has expired`);
|
|
300
355
|
}
|
|
301
|
-
const existing = this.options.store.getAuthorizedUser(pairing.workspace_id, pairing.platform_user_id);
|
|
356
|
+
const existing = this.options.store.getAuthorizedUser(pairing.workspace_id, pairing.platform_user_id, pairing.platform);
|
|
302
357
|
const userId = existing?.id || `lark-user-${(0, node_crypto_1.randomUUID)()}`;
|
|
303
358
|
const authorizedAt = new Date().toISOString();
|
|
304
359
|
this.options.store.createAuthorizedUser({
|
|
305
360
|
id: userId,
|
|
306
361
|
workspace_id: pairing.workspace_id,
|
|
362
|
+
platform: pairing.platform,
|
|
307
363
|
platform_user_id: pairing.platform_user_id,
|
|
308
364
|
chat_id: pairing.chat_id,
|
|
309
365
|
display_name: pairing.display_name,
|
|
@@ -312,7 +368,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
312
368
|
});
|
|
313
369
|
this.options.store.updatePairingStatus(code, 'approved');
|
|
314
370
|
this.notifyRuntimeStateChanged();
|
|
315
|
-
const user = this.options.store.listAuthorizedUsers(pairing.workspace_id,
|
|
371
|
+
const user = this.options.store.listAuthorizedUsers(pairing.workspace_id, pairing.platform).find((entry) => entry.id === userId);
|
|
316
372
|
if (!user) {
|
|
317
373
|
throw new Error('Authorized user lookup failed after approval');
|
|
318
374
|
}
|
|
@@ -338,12 +394,14 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
338
394
|
this.options.log?.(`localcore-lark bridge route miss for sessionKey=${sessionKey} type=${event.type}`);
|
|
339
395
|
return;
|
|
340
396
|
}
|
|
341
|
-
const
|
|
397
|
+
const routeInstanceId = route.instanceId || 'default';
|
|
398
|
+
const routePlatformKey = route.platformKey || (0, config_js_1.channelPlatformKey)('lark', routeInstanceId);
|
|
399
|
+
const state = this.runtime.get((0, config_js_1.runtimeKey)(route.workspaceId, routeInstanceId)) || this.runtime.get(route.workspaceId);
|
|
342
400
|
if (!state?.client || !state.connected) {
|
|
343
401
|
this.options.log?.(`localcore-lark bridge event ignored because workspace is not connected: ${route.workspaceId}`);
|
|
344
402
|
return;
|
|
345
403
|
}
|
|
346
|
-
const initialBinding = this.options.store.getPlatformThreadBinding(route.workspaceId, route.chatId, route.platformUserId);
|
|
404
|
+
const initialBinding = this.options.store.getPlatformThreadBinding(route.workspaceId, route.chatId, route.platformUserId, routePlatformKey);
|
|
347
405
|
if (!initialBinding) {
|
|
348
406
|
this.options.log?.(`localcore-lark bridge binding miss for workspace=${route.workspaceId} chat=${route.chatId} user=${route.platformUserId}`);
|
|
349
407
|
return;
|
|
@@ -362,7 +420,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
362
420
|
const current = previous
|
|
363
421
|
.catch(() => undefined)
|
|
364
422
|
.then(async () => {
|
|
365
|
-
const binding = this.options.store.getPlatformThreadBinding(route.workspaceId, route.chatId, route.platformUserId);
|
|
423
|
+
const binding = this.options.store.getPlatformThreadBinding(route.workspaceId, route.chatId, route.platformUserId, routePlatformKey);
|
|
366
424
|
if (!binding) {
|
|
367
425
|
this.options.log?.(`localcore-lark bridge binding disappeared for sessionKey=${sessionKey}`);
|
|
368
426
|
return;
|
|
@@ -391,7 +449,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
391
449
|
this.options.store.clearPlatformThreadMessageId(route.workspaceId, route.chatId, route.platformUserId);
|
|
392
450
|
}
|
|
393
451
|
if (event.type === 'buttons') {
|
|
394
|
-
const permissionCard =
|
|
452
|
+
const permissionCard = (0, cards_js_1.renderPermissionCard)(turn, event, Boolean(state.cardActionsEnabled));
|
|
395
453
|
if (permissionCard.text || permissionCard.buttonRows.length > 0) {
|
|
396
454
|
if (!turn.permissionMessageId) {
|
|
397
455
|
const createdId = await this.sendTextAsCard(state, route.chatId, permissionCard.text, permissionCard.buttonRows, sessionKey, binding.thread_id);
|
|
@@ -409,12 +467,12 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
409
467
|
return;
|
|
410
468
|
}
|
|
411
469
|
this.consumeBridgeEvent(turn, event);
|
|
412
|
-
const rendered =
|
|
470
|
+
const rendered = (0, runtime_state_js_1.renderLarkBridgeEventMessage)(turn, event);
|
|
413
471
|
if (!rendered.text && rendered.buttonRows.length === 0) {
|
|
414
472
|
this.options.log?.(`localcore-lark bridge event produced empty render for sessionKey=${sessionKey} type=${event.type}`);
|
|
415
473
|
return;
|
|
416
474
|
}
|
|
417
|
-
const existingMessageId =
|
|
475
|
+
const existingMessageId = (0, runtime_state_js_1.getLarkRenderedMessageId)(turn, rendered);
|
|
418
476
|
const shouldThrottle = event.type === 'update_message' &&
|
|
419
477
|
rendered.isFinal &&
|
|
420
478
|
existingMessageId &&
|
|
@@ -426,9 +484,9 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
426
484
|
if (!existingMessageId) {
|
|
427
485
|
const createdId = await this.sendTextAsCard(state, route.chatId, rendered.text, rendered.buttonRows, sessionKey, binding.thread_id);
|
|
428
486
|
if (createdId) {
|
|
429
|
-
|
|
487
|
+
(0, runtime_state_js_1.setLarkRenderedMessageId)(turn, rendered, createdId);
|
|
430
488
|
if (rendered.isFinal) {
|
|
431
|
-
this.options.store.updatePlatformThreadMessageId(route.workspaceId, route.chatId, route.platformUserId, createdId);
|
|
489
|
+
this.options.store.updatePlatformThreadMessageId(route.workspaceId, route.chatId, route.platformUserId, createdId, routePlatformKey);
|
|
432
490
|
}
|
|
433
491
|
this.options.log?.(`localcore-lark sent new card message ${createdId} for sessionKey=${sessionKey}`);
|
|
434
492
|
}
|
|
@@ -452,6 +510,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
452
510
|
await current;
|
|
453
511
|
}
|
|
454
512
|
async handleInboundMessage(input) {
|
|
513
|
+
const instanceId = input.instanceId || 'default';
|
|
514
|
+
const platformKey = input.platformKey || (0, config_js_1.channelPlatformKey)('lark', instanceId);
|
|
455
515
|
this.options.eventBus.emit({
|
|
456
516
|
type: 'platform.message.received',
|
|
457
517
|
payload: {
|
|
@@ -465,27 +525,38 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
465
525
|
},
|
|
466
526
|
});
|
|
467
527
|
this.options.store.expirePendingPairings();
|
|
468
|
-
const
|
|
469
|
-
let
|
|
528
|
+
const runtimeState = this.resolveRuntimeState(input.workspaceId, instanceId).state;
|
|
529
|
+
let binding;
|
|
530
|
+
try {
|
|
531
|
+
binding = await this.getBinding(input.workspaceId, instanceId);
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
if (!runtimeState) {
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
this.options.log?.(`localcore-lark using active runtime binding snapshot for ${input.workspaceId}/${instanceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
538
|
+
}
|
|
539
|
+
let authorized = this.options.store.getAuthorizedUser(input.workspaceId, input.platformUserId, platformKey);
|
|
470
540
|
if (!authorized) {
|
|
471
|
-
if (binding
|
|
541
|
+
if (binding?.autoApprove || runtimeState?.autoApprove) {
|
|
472
542
|
const authorizedAt = new Date().toISOString();
|
|
473
543
|
this.options.store.createAuthorizedUser({
|
|
474
544
|
id: `lark-user-${(0, node_crypto_1.randomUUID)()}`,
|
|
475
545
|
workspace_id: input.workspaceId,
|
|
546
|
+
platform: platformKey,
|
|
476
547
|
platform_user_id: input.platformUserId,
|
|
477
548
|
chat_id: input.chatId,
|
|
478
549
|
display_name: input.displayName,
|
|
479
550
|
thread_id: null,
|
|
480
551
|
authorized_at: authorizedAt,
|
|
481
552
|
});
|
|
482
|
-
authorized = this.options.store.getAuthorizedUser(input.workspaceId, input.platformUserId);
|
|
553
|
+
authorized = this.options.store.getAuthorizedUser(input.workspaceId, input.platformUserId, platformKey);
|
|
483
554
|
this.options.log?.(`localcore-lark auto-approved user for ${input.workspaceId}: ${input.platformUserId}`);
|
|
484
555
|
this.notifyRuntimeStateChanged();
|
|
485
556
|
}
|
|
486
557
|
}
|
|
487
558
|
if (!authorized) {
|
|
488
|
-
const existingPending = this.options.store.listPendingPairings(input.workspaceId).find((item) => item.platform ===
|
|
559
|
+
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');
|
|
489
560
|
let pairingCode = existingPending?.code || '';
|
|
490
561
|
if (!existingPending) {
|
|
491
562
|
const now = new Date();
|
|
@@ -493,6 +564,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
493
564
|
this.options.store.createPairingRequest({
|
|
494
565
|
code: pairingCode,
|
|
495
566
|
workspace_id: input.workspaceId,
|
|
567
|
+
platform: platformKey,
|
|
496
568
|
platform_user_id: input.platformUserId,
|
|
497
569
|
chat_id: input.chatId,
|
|
498
570
|
display_name: input.displayName,
|
|
@@ -502,19 +574,20 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
502
574
|
});
|
|
503
575
|
this.notifyRuntimeStateChanged();
|
|
504
576
|
}
|
|
505
|
-
await this.sendImmediateCard(input.workspaceId, input.chatId,
|
|
577
|
+
await this.sendImmediateCard(input.workspaceId, input.chatId, (0, cards_js_1.renderPendingPairingCard)(pairingCode), instanceId);
|
|
506
578
|
return { paired: false };
|
|
507
579
|
}
|
|
508
580
|
const router = this.options.getWorkspaceRouter();
|
|
509
|
-
const threadBinding = this.options.store.getPlatformThreadBinding(input.workspaceId, input.chatId, input.platformUserId);
|
|
581
|
+
const threadBinding = this.options.store.getPlatformThreadBinding(input.workspaceId, input.chatId, input.platformUserId, platformKey);
|
|
510
582
|
let threadId = threadBinding?.thread_id || authorized.thread_id || '';
|
|
511
583
|
if (!threadId) {
|
|
512
584
|
const thread = await router.createThread(input.workspaceId, input.displayName || `Lark ${input.chatId}`);
|
|
513
585
|
threadId = thread.id;
|
|
514
|
-
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, threadId);
|
|
586
|
+
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, threadId, platformKey);
|
|
515
587
|
const now = new Date().toISOString();
|
|
516
588
|
this.options.store.upsertPlatformThreadBinding({
|
|
517
589
|
workspace_id: input.workspaceId,
|
|
590
|
+
platform: platformKey,
|
|
518
591
|
chat_id: input.chatId,
|
|
519
592
|
platform_user_id: input.platformUserId,
|
|
520
593
|
thread_id: threadId,
|
|
@@ -534,20 +607,23 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
534
607
|
const effectiveSessionKey = this.options.getWorkspaceRouter().getThreadSessionKey(threadId);
|
|
535
608
|
this.threadRouting.set(effectiveSessionKey, {
|
|
536
609
|
workspaceId: input.workspaceId,
|
|
610
|
+
instanceId,
|
|
611
|
+
platformKey,
|
|
537
612
|
platformUserId: input.platformUserId,
|
|
538
613
|
chatId: input.chatId,
|
|
539
614
|
threadId,
|
|
540
615
|
});
|
|
541
616
|
const acknowledgement = this.createTurnState(effectiveSessionKey, input.messageId);
|
|
542
|
-
await this.addAcknowledgementReaction(input.workspaceId, input.messageId, acknowledgement);
|
|
617
|
+
await this.addAcknowledgementReaction(input.workspaceId, input.messageId, acknowledgement, instanceId);
|
|
543
618
|
const slashCommand = this.parseSlashCommand(input.text);
|
|
544
619
|
if (slashCommand?.name === 'new') {
|
|
545
620
|
const title = slashCommand.args.join(' ').trim() || `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`;
|
|
546
621
|
const nextThread = await router.createThread(input.workspaceId, title);
|
|
547
622
|
const now = new Date().toISOString();
|
|
548
|
-
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id);
|
|
623
|
+
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id, platformKey);
|
|
549
624
|
this.options.store.upsertPlatformThreadBinding({
|
|
550
625
|
workspace_id: input.workspaceId,
|
|
626
|
+
platform: platformKey,
|
|
551
627
|
chat_id: input.chatId,
|
|
552
628
|
platform_user_id: input.platformUserId,
|
|
553
629
|
thread_id: nextThread.id,
|
|
@@ -557,11 +633,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
557
633
|
});
|
|
558
634
|
this.threadRouting.set(this.options.getWorkspaceRouter().getThreadSessionKey(nextThread.id), {
|
|
559
635
|
workspaceId: input.workspaceId,
|
|
636
|
+
instanceId,
|
|
637
|
+
platformKey,
|
|
560
638
|
platformUserId: input.platformUserId,
|
|
561
639
|
chatId: input.chatId,
|
|
562
640
|
threadId: nextThread.id,
|
|
563
641
|
});
|
|
564
|
-
await this.sendImmediateCard(input.workspaceId, input.chatId, '**已开始新会话**');
|
|
642
|
+
await this.sendImmediateCard(input.workspaceId, input.chatId, '**已开始新会话**', instanceId);
|
|
565
643
|
return { paired: true, threadId: nextThread.id };
|
|
566
644
|
}
|
|
567
645
|
const latestRun = this.options.store.getLatestRunForThread(threadId);
|
|
@@ -576,13 +654,25 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
576
654
|
return { paired: true, threadId };
|
|
577
655
|
}
|
|
578
656
|
close() {
|
|
579
|
-
return Promise.all([...this.runtime.keys()].map((
|
|
657
|
+
return Promise.all([...this.runtime.keys()].map((key) => this.stopWorkspaceKey(key))).then(() => undefined);
|
|
658
|
+
}
|
|
659
|
+
resolveRuntimeState(workspaceId, instanceId) {
|
|
660
|
+
if (instanceId) {
|
|
661
|
+
const state = this.runtime.get((0, config_js_1.runtimeKey)(workspaceId, instanceId)) || (instanceId === 'default' ? this.runtime.get(workspaceId) : undefined);
|
|
662
|
+
return { instanceId, state };
|
|
663
|
+
}
|
|
664
|
+
const states = [...this.runtime.values()].filter((entry) => entry.workspaceId === workspaceId);
|
|
665
|
+
const state = states.find((entry) => entry.instanceId === 'default') || states[0];
|
|
666
|
+
return { instanceId: state?.instanceId || 'default', state: state || this.runtime.get(workspaceId) };
|
|
580
667
|
}
|
|
581
|
-
async getBinding(workspaceId) {
|
|
668
|
+
async getBinding(workspaceId, instanceId) {
|
|
582
669
|
const config = await this.options.readConfig();
|
|
583
|
-
const
|
|
670
|
+
const bindings = this.collectBindings(config).filter((entry) => entry.workspaceId === workspaceId);
|
|
671
|
+
const binding = instanceId
|
|
672
|
+
? bindings.find((entry) => entry.instanceId === instanceId)
|
|
673
|
+
: bindings.find((entry) => entry.instanceId === 'default') || bindings[0];
|
|
584
674
|
if (!binding) {
|
|
585
|
-
throw new Error(`No Lark binding configured for workspace "${workspaceId}"`);
|
|
675
|
+
throw new Error(`No Lark binding configured for workspace "${workspaceId}"${instanceId ? ` instance "${instanceId}"` : ''}`);
|
|
586
676
|
}
|
|
587
677
|
return binding;
|
|
588
678
|
}
|
|
@@ -600,6 +690,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
600
690
|
success: true,
|
|
601
691
|
platform: 'lark',
|
|
602
692
|
workspaceId: binding.workspaceId,
|
|
693
|
+
instanceId: binding.instanceId,
|
|
603
694
|
appId: binding.appId,
|
|
604
695
|
};
|
|
605
696
|
}
|
|
@@ -608,22 +699,28 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
608
699
|
success: false,
|
|
609
700
|
platform: 'lark',
|
|
610
701
|
workspaceId: binding.workspaceId,
|
|
702
|
+
instanceId: binding.instanceId,
|
|
611
703
|
appId: binding.appId,
|
|
612
704
|
error: error instanceof Error ? error.message : String(error),
|
|
613
705
|
};
|
|
614
706
|
}
|
|
615
707
|
}
|
|
616
708
|
async startWorkspace(binding) {
|
|
617
|
-
|
|
709
|
+
const key = (0, config_js_1.runtimeKey)(binding.workspaceId, binding.instanceId);
|
|
710
|
+
await this.stopWorkspaceKey(key);
|
|
618
711
|
const status = {
|
|
619
712
|
workspaceId: binding.workspaceId,
|
|
713
|
+
instanceId: binding.instanceId,
|
|
714
|
+
displayName: binding.displayName,
|
|
715
|
+
platformKey: binding.platformKey,
|
|
620
716
|
enabled: true,
|
|
621
717
|
status: 'starting',
|
|
622
718
|
connected: false,
|
|
623
719
|
appId: binding.appId,
|
|
720
|
+
autoApprove: binding.autoApprove,
|
|
624
721
|
cardActionsEnabled: binding.cardActionsEnabled,
|
|
625
722
|
};
|
|
626
|
-
this.runtime.set(
|
|
723
|
+
this.runtime.set(key, status);
|
|
627
724
|
this.notifyRuntimeStateChanged();
|
|
628
725
|
try {
|
|
629
726
|
this.options.log?.(`localcore-lark starting workspace=${binding.workspaceId} app=${this.maskLarkAppId(binding.appId)} cardActions=${binding.cardActionsEnabled}`);
|
|
@@ -641,15 +738,15 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
641
738
|
});
|
|
642
739
|
status.eventDispatcher.register({
|
|
643
740
|
'im.message.receive_v1': async (data) => {
|
|
644
|
-
this.options.log?.(`localcore-lark received im.message.receive_v1 for ${binding.workspaceId}: ${this.summarizeLarkEvent(data)}`);
|
|
645
|
-
void this.handleMessageEvent(binding.workspaceId, data).catch((error) => {
|
|
741
|
+
this.options.log?.(`localcore-lark received im.message.receive_v1 for ${binding.workspaceId}/${binding.instanceId}: ${this.summarizeLarkEvent(data)}`);
|
|
742
|
+
void this.handleMessageEvent(binding.workspaceId, binding.instanceId, binding.platformKey, data).catch((error) => {
|
|
646
743
|
this.options.log?.(`localcore-lark inbound message failed for ${binding.workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
647
744
|
});
|
|
648
745
|
return {};
|
|
649
746
|
},
|
|
650
747
|
'card.action.trigger': async (data) => {
|
|
651
|
-
this.options.log?.(`localcore-lark received card.action.trigger for ${binding.workspaceId}`);
|
|
652
|
-
void this.handleCardActionEvent(binding.workspaceId, data);
|
|
748
|
+
this.options.log?.(`localcore-lark received card.action.trigger for ${binding.workspaceId}/${binding.instanceId}`);
|
|
749
|
+
void this.handleCardActionEvent(binding.workspaceId, binding.instanceId, data);
|
|
653
750
|
return {};
|
|
654
751
|
},
|
|
655
752
|
});
|
|
@@ -679,26 +776,34 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
679
776
|
}
|
|
680
777
|
this.notifyRuntimeStateChanged();
|
|
681
778
|
}
|
|
682
|
-
async stopWorkspace(workspaceId) {
|
|
683
|
-
const
|
|
779
|
+
async stopWorkspace(workspaceId, instanceId) {
|
|
780
|
+
const resolved = this.resolveRuntimeState(workspaceId, instanceId);
|
|
781
|
+
await this.stopWorkspaceKey((0, config_js_1.runtimeKey)(workspaceId, resolved.instanceId));
|
|
782
|
+
}
|
|
783
|
+
async stopWorkspaceKey(key) {
|
|
784
|
+
const state = this.runtime.get(key);
|
|
684
785
|
if (!state) {
|
|
685
786
|
return;
|
|
686
787
|
}
|
|
687
|
-
this.options.log?.(`localcore-lark stopping workspace=${workspaceId} status=${state.status}`);
|
|
788
|
+
this.options.log?.(`localcore-lark stopping workspace=${state.workspaceId}/${state.instanceId} status=${state.status}`);
|
|
688
789
|
try {
|
|
689
790
|
await state.wsClient?.stop?.();
|
|
690
|
-
this.options.log?.(`localcore-lark stopped workspace=${workspaceId}`);
|
|
791
|
+
this.options.log?.(`localcore-lark stopped workspace=${state.workspaceId}/${state.instanceId}`);
|
|
691
792
|
}
|
|
692
793
|
catch (error) {
|
|
693
|
-
this.options.log?.(`localcore-lark stop failed for ${workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
794
|
+
this.options.log?.(`localcore-lark stop failed for ${state.workspaceId}/${state.instanceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
694
795
|
// Best effort: current SDK versions may not implement stop().
|
|
695
796
|
}
|
|
696
|
-
this.runtime.set(
|
|
697
|
-
workspaceId,
|
|
797
|
+
this.runtime.set(key, {
|
|
798
|
+
workspaceId: state.workspaceId,
|
|
799
|
+
instanceId: state.instanceId,
|
|
800
|
+
displayName: state.displayName,
|
|
801
|
+
platformKey: state.platformKey,
|
|
698
802
|
enabled: false,
|
|
699
803
|
status: 'stopped',
|
|
700
804
|
connected: false,
|
|
701
805
|
appId: state.appId,
|
|
806
|
+
autoApprove: state.autoApprove,
|
|
702
807
|
cardActionsEnabled: state.cardActionsEnabled,
|
|
703
808
|
});
|
|
704
809
|
this.notifyRuntimeStateChanged();
|
|
@@ -711,7 +816,11 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
711
816
|
},
|
|
712
817
|
});
|
|
713
818
|
}
|
|
714
|
-
async handleMessageEvent(workspaceId,
|
|
819
|
+
async handleMessageEvent(workspaceId, instanceIdOrData, platformKeyOrData, maybeData) {
|
|
820
|
+
const legacyCall = typeof instanceIdOrData === 'object';
|
|
821
|
+
const instanceId = legacyCall ? 'default' : instanceIdOrData;
|
|
822
|
+
const platformKey = legacyCall ? 'lark' : String(platformKeyOrData || (0, config_js_1.channelPlatformKey)('lark', instanceId));
|
|
823
|
+
const data = (legacyCall ? instanceIdOrData : maybeData) || {};
|
|
715
824
|
const payload = (data?.event && typeof data.event === 'object')
|
|
716
825
|
? data.event
|
|
717
826
|
: data;
|
|
@@ -739,7 +848,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
739
848
|
const imageKey = String(parsedContent.image_key || parsedContent.file_key || '').trim();
|
|
740
849
|
if (imageKey) {
|
|
741
850
|
try {
|
|
742
|
-
contentParts.push(await this.downloadMessageImage(workspaceId, String(message.message_id || ''), imageKey));
|
|
851
|
+
contentParts.push(await this.downloadMessageImage(workspaceId, String(message.message_id || ''), imageKey, instanceId));
|
|
743
852
|
}
|
|
744
853
|
catch (error) {
|
|
745
854
|
const errorText = `[Image download failed: ${error instanceof Error ? error.message : String(error)}]`;
|
|
@@ -766,6 +875,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
766
875
|
this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} type=${messageType || 'unknown'} text=${JSON.stringify(displayText.slice(0, 120))}`);
|
|
767
876
|
await this.handleInboundMessage({
|
|
768
877
|
workspaceId,
|
|
878
|
+
instanceId,
|
|
879
|
+
platformKey,
|
|
769
880
|
platformUserId,
|
|
770
881
|
chatId,
|
|
771
882
|
displayName: String(payload?.sender?.sender_id?.user_id ||
|
|
@@ -795,8 +906,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
795
906
|
contentParts: this.createWrappedContentParts(wrappedText, parts),
|
|
796
907
|
};
|
|
797
908
|
}
|
|
798
|
-
async downloadMessageImage(workspaceId, messageId, imageKey) {
|
|
799
|
-
const state = this.
|
|
909
|
+
async downloadMessageImage(workspaceId, messageId, imageKey, instanceId) {
|
|
910
|
+
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
800
911
|
if (!state?.client) {
|
|
801
912
|
throw new Error('Lark client is not connected');
|
|
802
913
|
}
|
|
@@ -930,32 +1041,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
930
1041
|
return `${value.slice(0, 6)}...${value.slice(-4)}`;
|
|
931
1042
|
}
|
|
932
1043
|
collectBindings(config) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
const platforms = Array.isArray(project.platforms) ? project.platforms : [];
|
|
936
|
-
return platforms
|
|
937
|
-
.map((platform) => ({
|
|
938
|
-
platformType: (0, desktop_js_1.normalizeDesktopPlatformType)(platform?.type),
|
|
939
|
-
options: platform?.options && typeof platform.options === 'object'
|
|
940
|
-
? platform.options
|
|
941
|
-
: {},
|
|
942
|
-
}))
|
|
943
|
-
.filter((platform) => platform.platformType === 'lark')
|
|
944
|
-
.map((platform) => ({
|
|
945
|
-
workspaceId: project.name,
|
|
946
|
-
appId: String(platform.options.app_id || '').trim(),
|
|
947
|
-
appSecret: String(platform.options.app_secret || '').trim(),
|
|
948
|
-
encryptKey: String(platform.options.encrypt_key || '').trim(),
|
|
949
|
-
verificationToken: String(platform.options.verification_token || '').trim(),
|
|
950
|
-
autoApprove: String(platform.options.auto_approve || '').trim().toLowerCase() === 'true'
|
|
951
|
-
|| platform.options.auto_approve === true,
|
|
952
|
-
cardActionsEnabled: String(platform.options.card_actions || platform.options.enable_card_actions || '').trim().toLowerCase() === 'true'
|
|
953
|
-
|| platform.options.card_actions === true
|
|
954
|
-
|| platform.options.enable_card_actions === true
|
|
955
|
-
|| this.defaultCardActionsEnabled,
|
|
956
|
-
enabled: Boolean(String(platform.options.app_id || '').trim() && String(platform.options.app_secret || '').trim()),
|
|
957
|
-
project,
|
|
958
|
-
}));
|
|
1044
|
+
return (0, config_js_1.collectLarkWorkspaceBindings)(config, {
|
|
1045
|
+
defaultCardActionsEnabled: this.defaultCardActionsEnabled,
|
|
959
1046
|
});
|
|
960
1047
|
}
|
|
961
1048
|
async getLarkModule() {
|
|
@@ -964,40 +1051,6 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
964
1051
|
}
|
|
965
1052
|
return this.larkModulePromise;
|
|
966
1053
|
}
|
|
967
|
-
buildInteractiveCard(text, buttonRows = [], sessionKey, threadId) {
|
|
968
|
-
const elements = [];
|
|
969
|
-
if (text) {
|
|
970
|
-
elements.push({ tag: 'markdown', content: text });
|
|
971
|
-
}
|
|
972
|
-
for (const row of buttonRows) {
|
|
973
|
-
const actions = row
|
|
974
|
-
.filter((button) => button.text && button.data)
|
|
975
|
-
.map((button, index) => ({
|
|
976
|
-
tag: 'button',
|
|
977
|
-
text: {
|
|
978
|
-
tag: 'plain_text',
|
|
979
|
-
content: this.formatPermissionButtonLabel(button),
|
|
980
|
-
},
|
|
981
|
-
type: this.resolveLarkButtonType(button, index),
|
|
982
|
-
value: {
|
|
983
|
-
action: 'permission_response',
|
|
984
|
-
response: (0, desktop_js_1.normalizePermissionResponse)(button.data) || button.data,
|
|
985
|
-
session_key: sessionKey || '',
|
|
986
|
-
thread_id: threadId || '',
|
|
987
|
-
},
|
|
988
|
-
}));
|
|
989
|
-
if (actions.length) {
|
|
990
|
-
elements.push({
|
|
991
|
-
tag: 'action',
|
|
992
|
-
actions,
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
return {
|
|
997
|
-
config: { wide_screen_mode: true },
|
|
998
|
-
elements,
|
|
999
|
-
};
|
|
1000
|
-
}
|
|
1001
1054
|
async sendTextAsCard(state, chatId, text, buttonRows = [], sessionKey, threadId) {
|
|
1002
1055
|
const response = await state.client.im.message.create({
|
|
1003
1056
|
params: {
|
|
@@ -1006,7 +1059,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1006
1059
|
data: {
|
|
1007
1060
|
receive_id: chatId,
|
|
1008
1061
|
msg_type: 'interactive',
|
|
1009
|
-
content: JSON.stringify(
|
|
1062
|
+
content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
|
|
1010
1063
|
},
|
|
1011
1064
|
});
|
|
1012
1065
|
return String(response?.data?.message_id || '').trim();
|
|
@@ -1044,7 +1097,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1044
1097
|
message_id: messageId,
|
|
1045
1098
|
},
|
|
1046
1099
|
data: {
|
|
1047
|
-
content: JSON.stringify(
|
|
1100
|
+
content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
|
|
1048
1101
|
},
|
|
1049
1102
|
});
|
|
1050
1103
|
}
|
|
@@ -1080,21 +1133,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1080
1133
|
};
|
|
1081
1134
|
}
|
|
1082
1135
|
createTurnState(sessionKey, sourceMessageId) {
|
|
1083
|
-
const turn =
|
|
1084
|
-
sessionKey,
|
|
1085
|
-
sourceMessageId,
|
|
1086
|
-
awaitingPermission: false,
|
|
1087
|
-
processing: false,
|
|
1088
|
-
previewText: '',
|
|
1089
|
-
finalText: '',
|
|
1090
|
-
progressMessageIds: {},
|
|
1091
|
-
thinkingSteps: [],
|
|
1092
|
-
toolCalls: [],
|
|
1093
|
-
statusLines: [],
|
|
1094
|
-
buttonRows: [],
|
|
1095
|
-
lastPatchedAt: 0,
|
|
1096
|
-
lastPatchedAtByMessageId: {},
|
|
1097
|
-
};
|
|
1136
|
+
const turn = (0, runtime_state_js_1.createLarkTurnState)(sessionKey, sourceMessageId);
|
|
1098
1137
|
this.outboundTurns.set(sessionKey, turn);
|
|
1099
1138
|
return turn;
|
|
1100
1139
|
}
|
|
@@ -1115,209 +1154,36 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1115
1154
|
return turn;
|
|
1116
1155
|
}
|
|
1117
1156
|
consumeBridgeEvent(turn, event) {
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
// This keeps Feishu message order aligned with user-visible timeline.
|
|
1122
|
-
turn.messageId = undefined;
|
|
1123
|
-
turn.finalMessageId = undefined;
|
|
1124
|
-
turn.progressMessageIds = {};
|
|
1125
|
-
turn.processing = true;
|
|
1126
|
-
turn.permissionMessageId = undefined;
|
|
1127
|
-
turn.previewText = '';
|
|
1128
|
-
turn.finalText = '';
|
|
1129
|
-
turn.thinkingSteps = [];
|
|
1130
|
-
turn.toolCalls = [];
|
|
1131
|
-
turn.buttonRows = [];
|
|
1132
|
-
turn.statusLines = [];
|
|
1133
|
-
turn.lastPatchedAtByMessageId = {};
|
|
1134
|
-
return;
|
|
1135
|
-
}
|
|
1136
|
-
if (event.type === 'typing_stop') {
|
|
1137
|
-
turn.processing = false;
|
|
1138
|
-
return;
|
|
1139
|
-
}
|
|
1140
|
-
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
1141
|
-
turn.previewText = content;
|
|
1142
|
-
return;
|
|
1143
|
-
}
|
|
1144
|
-
if (event.type === 'status') {
|
|
1145
|
-
if (content) {
|
|
1146
|
-
this.pushUnique(turn.statusLines, content);
|
|
1147
|
-
}
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
if (event.type === 'buttons') {
|
|
1151
|
-
turn.awaitingPermission = true;
|
|
1152
|
-
turn.buttonRows = [];
|
|
1153
|
-
if (this.mirrorPermissionStateInMainCard && content) {
|
|
1154
|
-
this.pushUnique(turn.statusLines, `等待确认: ${content}`);
|
|
1155
|
-
}
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
if (!content) {
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
if (content.startsWith('💭 ')) {
|
|
1162
|
-
this.pushUnique(turn.thinkingSteps, content.slice(3).trim());
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
if (content.startsWith('🔧 ')) {
|
|
1166
|
-
this.pushUnique(turn.toolCalls, content.slice(3).trim());
|
|
1167
|
-
return;
|
|
1168
|
-
}
|
|
1169
|
-
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
1170
|
-
this.pushUnique(turn.statusLines, content.slice(3).trim());
|
|
1171
|
-
return;
|
|
1172
|
-
}
|
|
1173
|
-
turn.finalText = content;
|
|
1174
|
-
turn.previewText = content;
|
|
1175
|
-
}
|
|
1176
|
-
renderBridgeEventMessage(turn, event) {
|
|
1177
|
-
const content = foldToolResultForLark(String(event.content || '').trim());
|
|
1178
|
-
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
1179
|
-
if (content.startsWith('💭 ')) {
|
|
1180
|
-
return this.renderProgressMessage(event.previewHandle || 'thinking-preview', content);
|
|
1181
|
-
}
|
|
1182
|
-
if (content.startsWith('🔧 ')) {
|
|
1183
|
-
return this.renderProgressMessage(this.progressKey('tool', event), content);
|
|
1184
|
-
}
|
|
1185
|
-
return {
|
|
1186
|
-
key: 'final',
|
|
1187
|
-
text: content,
|
|
1188
|
-
buttonRows: turn.buttonRows,
|
|
1189
|
-
isFinal: true,
|
|
1190
|
-
};
|
|
1191
|
-
}
|
|
1192
|
-
if (event.type === 'status') {
|
|
1193
|
-
return this.renderProgressMessage(this.progressKey('status', event), content.startsWith('⏳ ') ? content : `⏳ ${content}`);
|
|
1194
|
-
}
|
|
1195
|
-
if (event.type === 'reply') {
|
|
1196
|
-
if (content.startsWith('💭 ')) {
|
|
1197
|
-
return this.renderProgressMessage(this.progressKey('thinking', event), content);
|
|
1198
|
-
}
|
|
1199
|
-
if (content.startsWith('🔧 ')) {
|
|
1200
|
-
return this.renderProgressMessage(this.progressKey('tool', event), content);
|
|
1201
|
-
}
|
|
1202
|
-
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
1203
|
-
return this.renderProgressMessage(this.progressKey('status', event), content);
|
|
1204
|
-
}
|
|
1205
|
-
return {
|
|
1206
|
-
key: 'final',
|
|
1207
|
-
text: content,
|
|
1208
|
-
buttonRows: turn.buttonRows,
|
|
1209
|
-
isFinal: true,
|
|
1210
|
-
};
|
|
1211
|
-
}
|
|
1212
|
-
if (event.type === 'typing_start' || event.type === 'typing_stop') {
|
|
1213
|
-
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
1214
|
-
}
|
|
1215
|
-
return {
|
|
1216
|
-
key: 'noop',
|
|
1217
|
-
text: '',
|
|
1218
|
-
buttonRows: [],
|
|
1219
|
-
isFinal: false,
|
|
1220
|
-
};
|
|
1221
|
-
}
|
|
1222
|
-
renderProgressMessage(key, text) {
|
|
1223
|
-
return {
|
|
1224
|
-
key,
|
|
1225
|
-
text,
|
|
1226
|
-
buttonRows: [],
|
|
1227
|
-
isFinal: false,
|
|
1228
|
-
};
|
|
1229
|
-
}
|
|
1230
|
-
progressKey(prefix, event) {
|
|
1231
|
-
const stableId = String(event.messageId || event.previewHandle || '').trim();
|
|
1232
|
-
if (stableId) {
|
|
1233
|
-
return `${prefix}:${stableId}`;
|
|
1234
|
-
}
|
|
1235
|
-
const content = String(event.content || '').trim().replace(/\s+/g, ' ');
|
|
1236
|
-
return `${prefix}:${content.slice(0, 120)}`;
|
|
1237
|
-
}
|
|
1238
|
-
getRenderedMessageId(turn, rendered) {
|
|
1239
|
-
if (rendered.isFinal) {
|
|
1240
|
-
return turn.finalMessageId || turn.messageId;
|
|
1241
|
-
}
|
|
1242
|
-
return turn.progressMessageIds[rendered.key];
|
|
1243
|
-
}
|
|
1244
|
-
setRenderedMessageId(turn, rendered, messageId) {
|
|
1245
|
-
if (rendered.isFinal) {
|
|
1246
|
-
turn.finalMessageId = messageId;
|
|
1247
|
-
turn.messageId = messageId;
|
|
1248
|
-
return;
|
|
1249
|
-
}
|
|
1250
|
-
turn.progressMessageIds[rendered.key] = messageId;
|
|
1251
|
-
}
|
|
1252
|
-
renderPermissionCard(turn, event, cardActionsEnabled) {
|
|
1253
|
-
const summary = this.buildPermissionSummary(turn, String(event.content || '').trim());
|
|
1254
|
-
const sections = [
|
|
1255
|
-
'**需要工具确认**',
|
|
1256
|
-
summary.command ? `\`${summary.command}\`` : '',
|
|
1257
|
-
summary.reason || '',
|
|
1258
|
-
cardActionsEnabled
|
|
1259
|
-
? '也可以直接回复:`allow` / `allow all` / `deny`'
|
|
1260
|
-
: '请直接回复:`allow` / `allow all` / `deny`',
|
|
1261
|
-
].filter(Boolean);
|
|
1262
|
-
const buttonRows = cardActionsEnabled && Array.isArray(event.buttonRows)
|
|
1263
|
-
? event.buttonRows
|
|
1264
|
-
.map((row) => Array.isArray(row)
|
|
1265
|
-
? row
|
|
1266
|
-
.filter((button) => Boolean(button?.text && button?.data))
|
|
1267
|
-
.map((button) => ({
|
|
1268
|
-
text: this.formatPermissionButtonLabel(button),
|
|
1269
|
-
data: (0, desktop_js_1.normalizePermissionResponse)(button.data) || button.data,
|
|
1270
|
-
}))
|
|
1271
|
-
: [])
|
|
1272
|
-
.filter((row) => row.length > 0)
|
|
1273
|
-
: [];
|
|
1274
|
-
return {
|
|
1275
|
-
text: sections.join('\n\n').trim(),
|
|
1276
|
-
buttonRows,
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
|
-
renderPendingPairingCard(code) {
|
|
1280
|
-
const lines = [
|
|
1281
|
-
'**已收到消息**',
|
|
1282
|
-
'当前账号还未授权接入这个工作区。',
|
|
1283
|
-
'请在桌面端完成审批后再次发送消息。',
|
|
1284
|
-
];
|
|
1285
|
-
if (code) {
|
|
1286
|
-
lines.push(`配对码:\`${code}\``);
|
|
1287
|
-
}
|
|
1288
|
-
return lines.join('\n\n');
|
|
1157
|
+
(0, runtime_state_js_1.consumeLarkBridgeEvent)(turn, event, {
|
|
1158
|
+
mirrorPermissionStateInMainCard: this.mirrorPermissionStateInMainCard,
|
|
1159
|
+
});
|
|
1289
1160
|
}
|
|
1290
|
-
async handleCardActionEvent(workspaceId,
|
|
1161
|
+
async handleCardActionEvent(workspaceId, instanceIdOrData, maybeData) {
|
|
1162
|
+
const legacyCall = typeof instanceIdOrData === 'object';
|
|
1163
|
+
const instanceId = legacyCall ? 'default' : instanceIdOrData;
|
|
1164
|
+
const data = (legacyCall ? instanceIdOrData : maybeData) || {};
|
|
1291
1165
|
try {
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
: data;
|
|
1295
|
-
const value = payload?.action?.value;
|
|
1296
|
-
if (!value || value.action !== 'permission_response') {
|
|
1297
|
-
return;
|
|
1298
|
-
}
|
|
1299
|
-
const response = (0, desktop_js_1.normalizePermissionResponse)(String(value.response || '').trim()) || String(value.response || '').trim();
|
|
1300
|
-
const threadId = String(value.thread_id || '').trim();
|
|
1301
|
-
if (!response || !threadId) {
|
|
1166
|
+
const action = (0, cards_js_1.extractCardActionValue)(data);
|
|
1167
|
+
if (!action) {
|
|
1302
1168
|
return;
|
|
1303
1169
|
}
|
|
1304
1170
|
const router = this.options.getWorkspaceRouter();
|
|
1305
|
-
await
|
|
1306
|
-
await
|
|
1307
|
-
this.options.log?.(`localcore-lark processed card action for ${workspaceId}: ${response}`);
|
|
1171
|
+
await this.markPermissionCardActionHandled(workspaceId, instanceId, data, action.event, action.value, action.response, action.threadId);
|
|
1172
|
+
await router.sendThreadAction(action.threadId, action.response);
|
|
1173
|
+
this.options.log?.(`localcore-lark processed card action for ${workspaceId}/${instanceId}: ${action.response}`);
|
|
1308
1174
|
}
|
|
1309
1175
|
catch (error) {
|
|
1310
|
-
this.options.log?.(`localcore-lark card action failed for ${workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1176
|
+
this.options.log?.(`localcore-lark card action failed for ${workspaceId}/${instanceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1311
1177
|
}
|
|
1312
1178
|
}
|
|
1313
|
-
async markPermissionCardActionHandled(workspaceId, rootPayload, payload, value, response, threadId) {
|
|
1314
|
-
const state = this.
|
|
1179
|
+
async markPermissionCardActionHandled(workspaceId, instanceId, rootPayload, payload, value, response, threadId) {
|
|
1180
|
+
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
1315
1181
|
if (!state?.client) {
|
|
1316
1182
|
return;
|
|
1317
1183
|
}
|
|
1318
1184
|
const sessionKey = String(value.session_key || '').trim();
|
|
1319
1185
|
const turn = sessionKey ? this.outboundTurns.get(sessionKey) : undefined;
|
|
1320
|
-
const messageId =
|
|
1186
|
+
const messageId = (0, cards_js_1.extractCardActionMessageId)(rootPayload, payload, value) || turn?.permissionMessageId;
|
|
1321
1187
|
if (!messageId) {
|
|
1322
1188
|
this.options.log?.(`localcore-lark could not find permission card message id for workspace=${workspaceId} sessionKey=${sessionKey || 'missing'}`);
|
|
1323
1189
|
return;
|
|
@@ -1325,7 +1191,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1325
1191
|
try {
|
|
1326
1192
|
await this.patchTextCard(state, messageId, [
|
|
1327
1193
|
'**工具确认已处理**',
|
|
1328
|
-
`已选择:${
|
|
1194
|
+
`已选择:${(0, cards_js_1.formatPermissionResponseLabel)(response)}`,
|
|
1329
1195
|
'等待代理继续执行...',
|
|
1330
1196
|
].join('\n\n'), [], sessionKey || undefined, threadId);
|
|
1331
1197
|
if (turn) {
|
|
@@ -1337,133 +1203,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1337
1203
|
this.options.log?.(`localcore-lark failed to patch handled permission card ${messageId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1338
1204
|
}
|
|
1339
1205
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
const messageId = this.extractKnownCardActionMessageId(payload);
|
|
1343
|
-
if (messageId) {
|
|
1344
|
-
return messageId;
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
for (const payload of payloads) {
|
|
1348
|
-
const messageId = this.findNestedCardActionMessageId(payload);
|
|
1349
|
-
if (messageId) {
|
|
1350
|
-
return messageId;
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
return '';
|
|
1354
|
-
}
|
|
1355
|
-
extractKnownCardActionMessageId(payload) {
|
|
1356
|
-
const source = payload;
|
|
1357
|
-
if (!source || typeof source !== 'object') {
|
|
1358
|
-
return '';
|
|
1359
|
-
}
|
|
1360
|
-
const candidates = [
|
|
1361
|
-
source?.permission_message_id,
|
|
1362
|
-
source?.action_message_id,
|
|
1363
|
-
source?.context?.open_message_id,
|
|
1364
|
-
source?.context?.message_id,
|
|
1365
|
-
source?.event?.context?.open_message_id,
|
|
1366
|
-
source?.event?.context?.message_id,
|
|
1367
|
-
source?.event_context?.open_message_id,
|
|
1368
|
-
source?.event_context?.message_id,
|
|
1369
|
-
source?.message?.message_id,
|
|
1370
|
-
source?.message?.open_message_id,
|
|
1371
|
-
source?.event?.message?.message_id,
|
|
1372
|
-
source?.event?.message?.open_message_id,
|
|
1373
|
-
source?.message_id,
|
|
1374
|
-
source?.open_message_id,
|
|
1375
|
-
];
|
|
1376
|
-
return candidates
|
|
1377
|
-
.map((candidate) => String(candidate || '').trim())
|
|
1378
|
-
.find(Boolean) || '';
|
|
1379
|
-
}
|
|
1380
|
-
findNestedCardActionMessageId(payload, seen = new Set()) {
|
|
1381
|
-
if (!payload || typeof payload !== 'object' || seen.has(payload)) {
|
|
1382
|
-
return '';
|
|
1383
|
-
}
|
|
1384
|
-
seen.add(payload);
|
|
1385
|
-
if (Array.isArray(payload)) {
|
|
1386
|
-
for (const item of payload) {
|
|
1387
|
-
const nested = this.findNestedCardActionMessageId(item, seen);
|
|
1388
|
-
if (nested)
|
|
1389
|
-
return nested;
|
|
1390
|
-
}
|
|
1391
|
-
return '';
|
|
1392
|
-
}
|
|
1393
|
-
const source = payload;
|
|
1394
|
-
for (const key of ['open_message_id', 'message_id', 'permission_message_id', 'action_message_id']) {
|
|
1395
|
-
const value = source[key];
|
|
1396
|
-
if (typeof value === 'string' && value.trim()) {
|
|
1397
|
-
return value.trim();
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
for (const value of Object.values(source)) {
|
|
1401
|
-
const nested = this.findNestedCardActionMessageId(value, seen);
|
|
1402
|
-
if (nested)
|
|
1403
|
-
return nested;
|
|
1404
|
-
}
|
|
1405
|
-
return '';
|
|
1406
|
-
}
|
|
1407
|
-
pushUnique(target, value) {
|
|
1408
|
-
const normalized = value.trim();
|
|
1409
|
-
if (!normalized) {
|
|
1410
|
-
return;
|
|
1411
|
-
}
|
|
1412
|
-
if (target[target.length - 1] === normalized) {
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
|
-
target.push(normalized);
|
|
1416
|
-
if (target.length > 6) {
|
|
1417
|
-
target.splice(0, target.length - 6);
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
formatPermissionButtonLabel(button) {
|
|
1421
|
-
return this.formatPermissionResponseLabel(button.data || button.text);
|
|
1422
|
-
}
|
|
1423
|
-
formatPermissionResponseLabel(response) {
|
|
1424
|
-
switch ((0, desktop_js_1.normalizePermissionResponse)(response) || response) {
|
|
1425
|
-
case 'allow':
|
|
1426
|
-
return '允许一次';
|
|
1427
|
-
case 'allow all':
|
|
1428
|
-
return '始终允许';
|
|
1429
|
-
case 'deny':
|
|
1430
|
-
return '拒绝';
|
|
1431
|
-
default:
|
|
1432
|
-
return response;
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
resolveLarkButtonType(button, index) {
|
|
1436
|
-
const response = (0, desktop_js_1.normalizePermissionResponse)(button.data) || (0, desktop_js_1.normalizePermissionResponse)(button.text);
|
|
1437
|
-
if (response === 'deny') {
|
|
1438
|
-
return 'danger';
|
|
1439
|
-
}
|
|
1440
|
-
if (response === 'allow') {
|
|
1441
|
-
return 'primary';
|
|
1442
|
-
}
|
|
1443
|
-
return index === 0 ? 'primary' : 'default';
|
|
1444
|
-
}
|
|
1445
|
-
buildPermissionSummary(turn, rawContent) {
|
|
1446
|
-
const lastTool = turn.toolCalls[turn.toolCalls.length - 1] || '';
|
|
1447
|
-
const [commandPart = '', reasonPart = ''] = lastTool.split(/\s+-\s+/, 2);
|
|
1448
|
-
const compactContent = rawContent
|
|
1449
|
-
.replace(/\s+/g, ' ')
|
|
1450
|
-
.replace(/请选择一个选项继续执行。?/g, '')
|
|
1451
|
-
.replace(/若按钮没有显示,请直接回复:?\s*allow all \/ allow \/ deny/gi, '')
|
|
1452
|
-
.replace(/等待工具确认/gi, '')
|
|
1453
|
-
.trim();
|
|
1454
|
-
return {
|
|
1455
|
-
command: commandPart.trim(),
|
|
1456
|
-
reason: reasonPart.trim() || compactContent,
|
|
1457
|
-
};
|
|
1458
|
-
}
|
|
1459
|
-
formatCompactToolLines(toolCalls) {
|
|
1460
|
-
return toolCalls.slice(-2).map((line) => {
|
|
1461
|
-
const compact = line.replace(/\s+/g, ' ').trim();
|
|
1462
|
-
return compact.startsWith('Terminal') ? '• Terminal' : `• ${compact}`;
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
async sendImmediateCard(workspaceId, chatId, text) {
|
|
1466
|
-
const state = this.runtime.get(workspaceId);
|
|
1206
|
+
async sendImmediateCard(workspaceId, chatId, text, instanceId) {
|
|
1207
|
+
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
1467
1208
|
if (!state?.client || !state.connected) {
|
|
1468
1209
|
this.options.log?.(`localcore-lark immediate card skipped because workspace is not connected: ${workspaceId}`);
|
|
1469
1210
|
return '';
|
|
@@ -1476,8 +1217,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1476
1217
|
return '';
|
|
1477
1218
|
}
|
|
1478
1219
|
}
|
|
1479
|
-
async addAcknowledgementReaction(workspaceId, messageId, turn) {
|
|
1480
|
-
const state = this.
|
|
1220
|
+
async addAcknowledgementReaction(workspaceId, messageId, turn, instanceId) {
|
|
1221
|
+
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
1481
1222
|
if (!state?.client || !state.connected || !messageId) {
|
|
1482
1223
|
return;
|
|
1483
1224
|
}
|