@kafca/agentdock 0.1.18 → 0.1.20
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/dist/renderer/assets/{Badge-BIuWuNsC.js → Badge-C1f8JpRb.js} +1 -1
- package/dist/renderer/assets/Chat-S50iFg3I.js +2 -0
- package/dist/renderer/assets/{ChatMarkdown-C-BlK1yX.js → ChatMarkdown-VWL9Vnpz.js} +4 -4
- package/dist/renderer/assets/{Config-DSqG53SF.js → Config-Yc9ExUI6.js} +1 -1
- package/dist/renderer/assets/{CronList-BP6eOFIl.js → CronList-DTboWazi.js} +1 -1
- package/dist/renderer/assets/{Dashboard-yNvLuZ9h.js → Dashboard-CzXCvZVR.js} +2 -2
- package/dist/renderer/assets/{EmptyState-DrCleE-v.js → EmptyState-9FbY2o6z.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-DTpTUVcH.js → KnowledgeDetail-D_BDc4Zt.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-gN27MIm8.js → KnowledgeHome-DsUA_BCR.js} +1 -1
- package/dist/renderer/assets/{Logs-DSEpn2aP.js → Logs-DDAmR67f.js} +1 -1
- package/dist/renderer/assets/{Modal-DRn2QI8p.js → Modal-Bt5VBC6S.js} +1 -1
- package/dist/renderer/assets/{Page-DFPQdZab.js → Page-Da_Kc6Qm.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-CPAlBCe1.js → ProjectDetail-B4Ps80yv.js} +1 -1
- package/dist/renderer/assets/{ProjectList-D1YqnA_p.js → ProjectList-BWTP9npz.js} +1 -1
- package/dist/renderer/assets/{Select-BOoDNxoe.js → Select-DWs3hVUh.js} +1 -1
- package/dist/renderer/assets/SessionChat-DOhUnOfH.js +1 -0
- package/dist/renderer/assets/{SessionList-EwaQ7I9m.js → SessionList-ChZYFXuo.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-rmnoSpy7.js → ThreadChat-nhnikHnk.js} +5 -5
- package/dist/renderer/assets/Workspace-pq_JYdTN.js +14 -0
- package/dist/renderer/assets/{arrow-left-DLijH4Ma.js → arrow-left-CR39hNvq.js} +1 -1
- package/dist/renderer/assets/{book-open-C39iVsTl.js → book-open-Bot2WKl8.js} +1 -1
- package/dist/renderer/assets/{check-CIzPQt9l.js → check-Drbl2nU3.js} +1 -1
- package/dist/renderer/assets/{circle-C22V7KHC.js → circle-BXFfAwnA.js} +1 -1
- package/dist/renderer/assets/{desktop-SfDg5_P-.js → desktop-5k3W66fH.js} +1 -1
- package/dist/renderer/assets/{funnel-Uqe7wSsV.js → funnel-BNKYan_N.js} +1 -1
- package/dist/renderer/assets/{heart-BAV26w-r.js → heart-wUOSwQE-.js} +1 -1
- package/dist/renderer/assets/index-3CzgyQYB.css +11 -0
- package/dist/renderer/assets/{index-HCsfse2M.js → index-CmOphqrf.js} +1 -1
- package/dist/renderer/assets/{index-bNsLuLje.js → index-DT5la73R.js} +2 -2
- package/dist/renderer/assets/{pencil-DrFGidyy.js → pencil-D7-8ggue.js} +1 -1
- package/dist/renderer/assets/{play-CUr5dfBa.js → play-BCYOAfet.js} +1 -1
- package/dist/renderer/assets/{plug-CLHivmxo.js → plug-Dsik74Yl.js} +1 -1
- package/dist/renderer/assets/{plus-B96DRLtO.js → plus-CKrU26_l.js} +1 -1
- package/dist/renderer/assets/projects-CGDtNb0M.js +1 -0
- package/dist/renderer/assets/{save-BGOA2LdX.js → save-q7M2_eAl.js} +1 -1
- package/dist/renderer/assets/{search-bWm0yagY.js → search-BptY4_MT.js} +1 -1
- package/dist/renderer/assets/{server-wa53brxF.js → server-DSSEF0D8.js} +1 -1
- package/dist/renderer/assets/{session-utils-7J-omgrc.js → session-utils-BFuqPZ5x.js} +1 -1
- package/dist/renderer/assets/{sessions-BIMMb8YC.js → sessions-CrWo3g3u.js} +1 -1
- package/dist/renderer/assets/{shield-check-MBIcswd2.js → shield-check-CCU722RQ.js} +1 -1
- package/dist/renderer/assets/{trash-2-CEov4VLH.js → trash-2-DaeeiV8x.js} +1 -1
- package/dist/renderer/assets/{user-B93Dje9X.js → user-Bkz8J7Yw.js} +1 -1
- package/dist/renderer/assets/{wifi-off-cCUI9WRl.js → wifi-off-P8xdIOHU.js} +1 -1
- package/dist/renderer/index.html +2 -2
- package/dist-electron/electron/local-core-refactor.test.js +426 -0
- package/dist-electron/electron/plugin-kernel.test.js +34 -0
- package/dist-electron/services/local-ai-core/src/gateway/local-core-lark-gateway.js +216 -50
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +34 -0
- package/package.json +1 -1
- package/dist/renderer/assets/Chat-bI6xVd_L.js +0 -2
- package/dist/renderer/assets/SessionChat-BoqnI_Sb.js +0 -1
- package/dist/renderer/assets/Workspace-CIoiGaPJ.js +0 -14
- package/dist/renderer/assets/index-CVrF_DwQ.css +0 -11
- package/dist/renderer/assets/projects-DC4slOOB.js +0 -1
|
@@ -40,9 +40,9 @@ const desktop_js_1 = require("../../../../shared/desktop.js");
|
|
|
40
40
|
const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
|
|
41
41
|
class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
42
42
|
options;
|
|
43
|
-
// Lark card action
|
|
44
|
-
// Keep
|
|
45
|
-
|
|
43
|
+
// Lark returns 200340 when card action events are not enabled in the app's
|
|
44
|
+
// event subscription. Keep card actions opt-in so text approval always works.
|
|
45
|
+
defaultCardActionsEnabled = false;
|
|
46
46
|
// Keep permission state in a dedicated card to avoid mixing order in the main reply card.
|
|
47
47
|
mirrorPermissionStateInMainCard = false;
|
|
48
48
|
runtime = new Map();
|
|
@@ -79,6 +79,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
79
79
|
status: 'disabled',
|
|
80
80
|
connected: false,
|
|
81
81
|
appId: binding.appId,
|
|
82
|
+
cardActionsEnabled: binding.cardActionsEnabled,
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
continue;
|
|
@@ -272,7 +273,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
272
273
|
this.options.store.clearPlatformThreadMessageId(route.workspaceId, route.chatId, route.platformUserId);
|
|
273
274
|
}
|
|
274
275
|
if (event.type === 'buttons') {
|
|
275
|
-
const permissionCard = this.renderPermissionCard(turn, event);
|
|
276
|
+
const permissionCard = this.renderPermissionCard(turn, event, Boolean(state.cardActionsEnabled));
|
|
276
277
|
if (permissionCard.text || permissionCard.buttonRows.length > 0) {
|
|
277
278
|
if (!turn.permissionMessageId) {
|
|
278
279
|
const createdId = await this.sendTextAsCard(state, route.chatId, permissionCard.text, permissionCard.buttonRows, sessionKey, binding.thread_id);
|
|
@@ -290,30 +291,35 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
290
291
|
return;
|
|
291
292
|
}
|
|
292
293
|
this.consumeBridgeEvent(turn, event);
|
|
293
|
-
const rendered = this.
|
|
294
|
+
const rendered = this.renderBridgeEventMessage(turn, event);
|
|
294
295
|
if (!rendered.text && rendered.buttonRows.length === 0) {
|
|
295
296
|
this.options.log?.(`localcore-lark bridge event produced empty render for sessionKey=${sessionKey} type=${event.type}`);
|
|
296
297
|
return;
|
|
297
298
|
}
|
|
299
|
+
const existingMessageId = this.getRenderedMessageId(turn, rendered);
|
|
298
300
|
const shouldThrottle = event.type === 'update_message' &&
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
rendered.isFinal &&
|
|
302
|
+
existingMessageId &&
|
|
303
|
+
Date.now() - (turn.lastPatchedAtByMessageId[existingMessageId] || 0) < 900;
|
|
304
|
+
this.options.log?.(`localcore-lark bridge event type=${event.type} sessionKey=${sessionKey} hasMessageId=${Boolean(existingMessageId)} throttle=${shouldThrottle}`);
|
|
302
305
|
if (shouldThrottle) {
|
|
303
306
|
return;
|
|
304
307
|
}
|
|
305
|
-
if (!
|
|
308
|
+
if (!existingMessageId) {
|
|
306
309
|
const createdId = await this.sendTextAsCard(state, route.chatId, rendered.text, rendered.buttonRows, sessionKey, binding.thread_id);
|
|
307
310
|
if (createdId) {
|
|
308
|
-
turn
|
|
309
|
-
|
|
311
|
+
this.setRenderedMessageId(turn, rendered, createdId);
|
|
312
|
+
if (rendered.isFinal) {
|
|
313
|
+
this.options.store.updatePlatformThreadMessageId(route.workspaceId, route.chatId, route.platformUserId, createdId);
|
|
314
|
+
}
|
|
310
315
|
this.options.log?.(`localcore-lark sent new card message ${createdId} for sessionKey=${sessionKey}`);
|
|
311
316
|
}
|
|
312
317
|
return;
|
|
313
318
|
}
|
|
314
|
-
await this.patchTextCard(state,
|
|
319
|
+
await this.patchTextCard(state, existingMessageId, rendered.text, rendered.buttonRows, sessionKey, binding.thread_id);
|
|
315
320
|
turn.lastPatchedAt = Date.now();
|
|
316
|
-
|
|
321
|
+
turn.lastPatchedAtByMessageId[existingMessageId] = turn.lastPatchedAt;
|
|
322
|
+
this.options.log?.(`localcore-lark patched card message ${existingMessageId} for sessionKey=${sessionKey}`);
|
|
317
323
|
}
|
|
318
324
|
catch (error) {
|
|
319
325
|
this.options.log?.(`localcore-lark bridge send failed for sessionKey=${sessionKey}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -496,10 +502,12 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
496
502
|
status: 'starting',
|
|
497
503
|
connected: false,
|
|
498
504
|
appId: binding.appId,
|
|
505
|
+
cardActionsEnabled: binding.cardActionsEnabled,
|
|
499
506
|
};
|
|
500
507
|
this.runtime.set(binding.workspaceId, status);
|
|
501
508
|
this.notifyRuntimeStateChanged();
|
|
502
509
|
try {
|
|
510
|
+
this.options.log?.(`localcore-lark starting workspace=${binding.workspaceId} app=${this.maskLarkAppId(binding.appId)} cardActions=${binding.cardActionsEnabled}`);
|
|
503
511
|
const mod = await this.getLarkModule();
|
|
504
512
|
status.client = new mod.Client({
|
|
505
513
|
appId: binding.appId,
|
|
@@ -514,8 +522,11 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
514
522
|
});
|
|
515
523
|
status.eventDispatcher.register({
|
|
516
524
|
'im.message.receive_v1': async (data) => {
|
|
517
|
-
this.options.log?.(`localcore-lark received im.message.receive_v1 for ${binding.workspaceId}`);
|
|
518
|
-
|
|
525
|
+
this.options.log?.(`localcore-lark received im.message.receive_v1 for ${binding.workspaceId}: ${this.summarizeLarkEvent(data)}`);
|
|
526
|
+
void this.handleMessageEvent(binding.workspaceId, data).catch((error) => {
|
|
527
|
+
this.options.log?.(`localcore-lark inbound message failed for ${binding.workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
528
|
+
});
|
|
529
|
+
return {};
|
|
519
530
|
},
|
|
520
531
|
'card.action.trigger': async (data) => {
|
|
521
532
|
this.options.log?.(`localcore-lark received card.action.trigger for ${binding.workspaceId}`);
|
|
@@ -523,12 +534,15 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
523
534
|
return {};
|
|
524
535
|
},
|
|
525
536
|
});
|
|
537
|
+
this.options.log?.(`localcore-lark event dispatcher registered for ${binding.workspaceId}`);
|
|
526
538
|
status.wsClient = new mod.WSClient({
|
|
527
539
|
appId: binding.appId,
|
|
528
540
|
appSecret: binding.appSecret,
|
|
529
541
|
domain: mod.Domain.Feishu,
|
|
530
542
|
loggerLevel: mod.LoggerLevel.info,
|
|
531
543
|
});
|
|
544
|
+
this.attachWsDiagnostics(binding.workspaceId, status.wsClient);
|
|
545
|
+
this.options.log?.(`localcore-lark ws starting for ${binding.workspaceId}`);
|
|
532
546
|
await status.wsClient.start({
|
|
533
547
|
eventDispatcher: status.eventDispatcher,
|
|
534
548
|
});
|
|
@@ -536,6 +550,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
536
550
|
status.connected = true;
|
|
537
551
|
status.connectedAt = new Date().toISOString();
|
|
538
552
|
status.lastError = undefined;
|
|
553
|
+
this.options.log?.(`localcore-lark ws ready for ${binding.workspaceId}`);
|
|
539
554
|
}
|
|
540
555
|
catch (error) {
|
|
541
556
|
status.status = 'error';
|
|
@@ -550,10 +565,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
550
565
|
if (!state) {
|
|
551
566
|
return;
|
|
552
567
|
}
|
|
568
|
+
this.options.log?.(`localcore-lark stopping workspace=${workspaceId} status=${state.status}`);
|
|
553
569
|
try {
|
|
554
570
|
await state.wsClient?.stop?.();
|
|
571
|
+
this.options.log?.(`localcore-lark stopped workspace=${workspaceId}`);
|
|
555
572
|
}
|
|
556
|
-
catch {
|
|
573
|
+
catch (error) {
|
|
574
|
+
this.options.log?.(`localcore-lark stop failed for ${workspaceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
557
575
|
// Best effort: current SDK versions may not implement stop().
|
|
558
576
|
}
|
|
559
577
|
this.runtime.set(workspaceId, {
|
|
@@ -562,6 +580,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
562
580
|
status: 'stopped',
|
|
563
581
|
connected: false,
|
|
564
582
|
appId: state.appId,
|
|
583
|
+
cardActionsEnabled: state.cardActionsEnabled,
|
|
565
584
|
});
|
|
566
585
|
this.notifyRuntimeStateChanged();
|
|
567
586
|
}
|
|
@@ -579,6 +598,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
579
598
|
: data;
|
|
580
599
|
const message = payload?.message;
|
|
581
600
|
const sender = payload?.sender;
|
|
601
|
+
this.options.log?.(`localcore-lark handling message event for ${workspaceId}: ${this.summarizeLarkPayload(payload)}`);
|
|
582
602
|
if (!message || !sender) {
|
|
583
603
|
this.options.log?.(`localcore-lark ignored event without message/sender for ${workspaceId}: ${JSON.stringify(Object.keys(data || {}))}`);
|
|
584
604
|
return;
|
|
@@ -592,13 +612,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
592
612
|
}
|
|
593
613
|
const text = String(parsedContent.text || '').trim();
|
|
594
614
|
if (!text) {
|
|
595
|
-
this.options.log?.(`localcore-lark ignored non-text message for ${workspaceId}:
|
|
615
|
+
this.options.log?.(`localcore-lark ignored non-text message for ${workspaceId}: type=${String(message.message_type || 'unknown')} contentKeys=${JSON.stringify(Object.keys(parsedContent))}`);
|
|
596
616
|
return;
|
|
597
617
|
}
|
|
598
618
|
const platformUserId = String(sender.sender_id?.user_id || sender.sender_id?.open_id || '').trim();
|
|
599
619
|
const chatId = String(message.chat_id || platformUserId).trim();
|
|
600
620
|
if (!platformUserId || !chatId) {
|
|
601
|
-
this.options.log?.(`localcore-lark ignored message without sender/chat for ${workspaceId}`);
|
|
621
|
+
this.options.log?.(`localcore-lark ignored message without sender/chat for ${workspaceId}: senderKeys=${JSON.stringify(Object.keys(sender?.sender_id || {}))} chat=${String(message.chat_id || '')}`);
|
|
602
622
|
return;
|
|
603
623
|
}
|
|
604
624
|
this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} text=${JSON.stringify(text.slice(0, 120))}`);
|
|
@@ -613,6 +633,67 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
613
633
|
messageId: String(message.message_id || (0, node_crypto_1.randomUUID)()),
|
|
614
634
|
});
|
|
615
635
|
}
|
|
636
|
+
attachWsDiagnostics(workspaceId, wsClient) {
|
|
637
|
+
const on = typeof wsClient?.on === 'function' ? wsClient.on.bind(wsClient) : null;
|
|
638
|
+
if (!on) {
|
|
639
|
+
this.options.log?.(`localcore-lark ws diagnostics unavailable for ${workspaceId}: client has no on()`);
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
for (const eventName of ['open', 'connect', 'connected', 'ready', 'close', 'closed', 'disconnect', 'error', 'reconnect']) {
|
|
643
|
+
try {
|
|
644
|
+
on(eventName, (...args) => {
|
|
645
|
+
this.options.log?.(`localcore-lark ws event ${eventName} for ${workspaceId}: ${this.summarizeWsArgs(args)}`);
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
catch (error) {
|
|
649
|
+
this.options.log?.(`localcore-lark ws diagnostic hook failed for ${workspaceId} event=${eventName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
summarizeLarkEvent(data) {
|
|
654
|
+
const payload = (data?.event && typeof data.event === 'object')
|
|
655
|
+
? data.event
|
|
656
|
+
: data;
|
|
657
|
+
return this.summarizeLarkPayload(payload);
|
|
658
|
+
}
|
|
659
|
+
summarizeLarkPayload(payload) {
|
|
660
|
+
const message = payload?.message || {};
|
|
661
|
+
const sender = payload?.sender || {};
|
|
662
|
+
const senderId = sender?.sender_id || {};
|
|
663
|
+
const content = typeof message.content === 'string' ? message.content : '';
|
|
664
|
+
return [
|
|
665
|
+
`message=${String(message.message_id || '') || 'missing'}`,
|
|
666
|
+
`type=${String(message.message_type || '') || 'missing'}`,
|
|
667
|
+
`chat=${String(message.chat_id || '') || 'missing'}`,
|
|
668
|
+
`sender=${String(senderId.user_id || senderId.open_id || '') || 'missing'}`,
|
|
669
|
+
`contentBytes=${Buffer.byteLength(content, 'utf8')}`,
|
|
670
|
+
`keys=${JSON.stringify(Object.keys(payload || {}))}`,
|
|
671
|
+
].join(' ');
|
|
672
|
+
}
|
|
673
|
+
summarizeWsArgs(args) {
|
|
674
|
+
if (args.length === 0) {
|
|
675
|
+
return 'no-args';
|
|
676
|
+
}
|
|
677
|
+
return args.map((arg) => {
|
|
678
|
+
if (arg instanceof Error) {
|
|
679
|
+
return `${arg.name}: ${arg.message}`;
|
|
680
|
+
}
|
|
681
|
+
if (typeof arg === 'string') {
|
|
682
|
+
return arg.slice(0, 200);
|
|
683
|
+
}
|
|
684
|
+
if (arg && typeof arg === 'object') {
|
|
685
|
+
return JSON.stringify(Object.keys(arg));
|
|
686
|
+
}
|
|
687
|
+
return String(arg);
|
|
688
|
+
}).join(' ');
|
|
689
|
+
}
|
|
690
|
+
maskLarkAppId(appId) {
|
|
691
|
+
const value = String(appId || '').trim();
|
|
692
|
+
if (value.length <= 8) {
|
|
693
|
+
return value ? '***' : '';
|
|
694
|
+
}
|
|
695
|
+
return `${value.slice(0, 6)}...${value.slice(-4)}`;
|
|
696
|
+
}
|
|
616
697
|
collectBindings(config) {
|
|
617
698
|
const projects = Array.isArray(config?.projects) ? config.projects : [];
|
|
618
699
|
return projects.flatMap((project) => {
|
|
@@ -633,6 +714,10 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
633
714
|
verificationToken: String(platform.options.verification_token || '').trim(),
|
|
634
715
|
autoApprove: String(platform.options.auto_approve || '').trim().toLowerCase() === 'true'
|
|
635
716
|
|| platform.options.auto_approve === true,
|
|
717
|
+
cardActionsEnabled: String(platform.options.card_actions || platform.options.enable_card_actions || '').trim().toLowerCase() === 'true'
|
|
718
|
+
|| platform.options.card_actions === true
|
|
719
|
+
|| platform.options.enable_card_actions === true
|
|
720
|
+
|| this.defaultCardActionsEnabled,
|
|
636
721
|
enabled: Boolean(String(platform.options.app_id || '').trim() && String(platform.options.app_secret || '').trim()),
|
|
637
722
|
project,
|
|
638
723
|
}));
|
|
@@ -656,12 +741,12 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
656
741
|
tag: 'button',
|
|
657
742
|
text: {
|
|
658
743
|
tag: 'plain_text',
|
|
659
|
-
content: button
|
|
744
|
+
content: this.formatPermissionButtonLabel(button),
|
|
660
745
|
},
|
|
661
|
-
type: index
|
|
746
|
+
type: this.resolveLarkButtonType(button, index),
|
|
662
747
|
value: {
|
|
663
748
|
action: 'permission_response',
|
|
664
|
-
response: button.data,
|
|
749
|
+
response: (0, desktop_js_1.normalizePermissionResponse)(button.data) || button.data,
|
|
665
750
|
session_key: sessionKey || '',
|
|
666
751
|
thread_id: threadId || '',
|
|
667
752
|
},
|
|
@@ -741,11 +826,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
741
826
|
processing: false,
|
|
742
827
|
previewText: '',
|
|
743
828
|
finalText: '',
|
|
829
|
+
progressMessageIds: {},
|
|
744
830
|
thinkingSteps: [],
|
|
745
831
|
toolCalls: [],
|
|
746
832
|
statusLines: [],
|
|
747
833
|
buttonRows: [],
|
|
748
834
|
lastPatchedAt: 0,
|
|
835
|
+
lastPatchedAtByMessageId: {},
|
|
749
836
|
};
|
|
750
837
|
this.outboundTurns.set(sessionKey, turn);
|
|
751
838
|
return turn;
|
|
@@ -755,12 +842,14 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
755
842
|
if (existing) {
|
|
756
843
|
if (messageId && !existing.messageId) {
|
|
757
844
|
existing.messageId = messageId;
|
|
845
|
+
existing.finalMessageId = messageId;
|
|
758
846
|
}
|
|
759
847
|
return existing;
|
|
760
848
|
}
|
|
761
849
|
const turn = this.createTurnState(sessionKey);
|
|
762
850
|
if (messageId) {
|
|
763
851
|
turn.messageId = messageId;
|
|
852
|
+
turn.finalMessageId = messageId;
|
|
764
853
|
}
|
|
765
854
|
return turn;
|
|
766
855
|
}
|
|
@@ -770,6 +859,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
770
859
|
// Always start a fresh card for each generation phase.
|
|
771
860
|
// This keeps Feishu message order aligned with user-visible timeline.
|
|
772
861
|
turn.messageId = undefined;
|
|
862
|
+
turn.finalMessageId = undefined;
|
|
863
|
+
turn.progressMessageIds = {};
|
|
773
864
|
turn.processing = true;
|
|
774
865
|
turn.permissionMessageId = undefined;
|
|
775
866
|
turn.previewText = '';
|
|
@@ -778,6 +869,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
778
869
|
turn.toolCalls = [];
|
|
779
870
|
turn.buttonRows = [];
|
|
780
871
|
turn.statusLines = [];
|
|
872
|
+
turn.lastPatchedAtByMessageId = {};
|
|
781
873
|
return;
|
|
782
874
|
}
|
|
783
875
|
if (event.type === 'typing_stop') {
|
|
@@ -796,15 +888,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
796
888
|
}
|
|
797
889
|
if (event.type === 'buttons') {
|
|
798
890
|
turn.awaitingPermission = true;
|
|
799
|
-
turn.buttonRows =
|
|
800
|
-
? event.buttonRows
|
|
801
|
-
.map((row) => Array.isArray(row)
|
|
802
|
-
? row
|
|
803
|
-
.filter((button) => Boolean(button?.text && button?.data))
|
|
804
|
-
.map((button) => ({ text: button.text, data: button.data }))
|
|
805
|
-
: [])
|
|
806
|
-
.filter((row) => row.length > 0)
|
|
807
|
-
: [];
|
|
891
|
+
turn.buttonRows = [];
|
|
808
892
|
if (this.mirrorPermissionStateInMainCard && content) {
|
|
809
893
|
this.pushUnique(turn.statusLines, `等待确认: ${content}`);
|
|
810
894
|
}
|
|
@@ -828,42 +912,101 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
828
912
|
turn.finalText = content;
|
|
829
913
|
turn.previewText = content;
|
|
830
914
|
}
|
|
831
|
-
|
|
832
|
-
const
|
|
833
|
-
if (
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
915
|
+
renderBridgeEventMessage(turn, event) {
|
|
916
|
+
const content = String(event.content || '').trim();
|
|
917
|
+
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
918
|
+
if (content.startsWith('💭 ')) {
|
|
919
|
+
return this.renderProgressMessage(event.previewHandle || 'thinking-preview', content);
|
|
920
|
+
}
|
|
921
|
+
if (content.startsWith('🔧 ')) {
|
|
922
|
+
return this.renderProgressMessage(this.progressKey('tool', event), content);
|
|
923
|
+
}
|
|
924
|
+
return {
|
|
925
|
+
key: 'final',
|
|
926
|
+
text: content,
|
|
927
|
+
buttonRows: turn.buttonRows,
|
|
928
|
+
isFinal: true,
|
|
929
|
+
};
|
|
838
930
|
}
|
|
839
|
-
|
|
840
|
-
|
|
931
|
+
if (event.type === 'status') {
|
|
932
|
+
return this.renderProgressMessage(this.progressKey('status', event), content.startsWith('⏳ ') ? content : `⏳ ${content}`);
|
|
841
933
|
}
|
|
842
|
-
|
|
843
|
-
|
|
934
|
+
if (event.type === 'reply') {
|
|
935
|
+
if (content.startsWith('💭 ')) {
|
|
936
|
+
return this.renderProgressMessage(this.progressKey('thinking', event), content);
|
|
937
|
+
}
|
|
938
|
+
if (content.startsWith('🔧 ')) {
|
|
939
|
+
return this.renderProgressMessage(this.progressKey('tool', event), content);
|
|
940
|
+
}
|
|
941
|
+
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
942
|
+
return this.renderProgressMessage(this.progressKey('status', event), content);
|
|
943
|
+
}
|
|
944
|
+
return {
|
|
945
|
+
key: 'final',
|
|
946
|
+
text: content,
|
|
947
|
+
buttonRows: turn.buttonRows,
|
|
948
|
+
isFinal: true,
|
|
949
|
+
};
|
|
844
950
|
}
|
|
845
|
-
|
|
846
|
-
|
|
951
|
+
if (event.type === 'typing_start' || event.type === 'typing_stop') {
|
|
952
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
847
953
|
}
|
|
848
954
|
return {
|
|
849
|
-
|
|
850
|
-
|
|
955
|
+
key: 'noop',
|
|
956
|
+
text: '',
|
|
957
|
+
buttonRows: [],
|
|
958
|
+
isFinal: false,
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
renderProgressMessage(key, text) {
|
|
962
|
+
return {
|
|
963
|
+
key,
|
|
964
|
+
text,
|
|
965
|
+
buttonRows: [],
|
|
966
|
+
isFinal: false,
|
|
851
967
|
};
|
|
852
968
|
}
|
|
853
|
-
|
|
969
|
+
progressKey(prefix, event) {
|
|
970
|
+
const stableId = String(event.messageId || event.previewHandle || '').trim();
|
|
971
|
+
if (stableId) {
|
|
972
|
+
return `${prefix}:${stableId}`;
|
|
973
|
+
}
|
|
974
|
+
const content = String(event.content || '').trim().replace(/\s+/g, ' ');
|
|
975
|
+
return `${prefix}:${content.slice(0, 120)}`;
|
|
976
|
+
}
|
|
977
|
+
getRenderedMessageId(turn, rendered) {
|
|
978
|
+
if (rendered.isFinal) {
|
|
979
|
+
return turn.finalMessageId || turn.messageId;
|
|
980
|
+
}
|
|
981
|
+
return turn.progressMessageIds[rendered.key];
|
|
982
|
+
}
|
|
983
|
+
setRenderedMessageId(turn, rendered, messageId) {
|
|
984
|
+
if (rendered.isFinal) {
|
|
985
|
+
turn.finalMessageId = messageId;
|
|
986
|
+
turn.messageId = messageId;
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
turn.progressMessageIds[rendered.key] = messageId;
|
|
990
|
+
}
|
|
991
|
+
renderPermissionCard(turn, event, cardActionsEnabled) {
|
|
854
992
|
const summary = this.buildPermissionSummary(turn, String(event.content || '').trim());
|
|
855
993
|
const sections = [
|
|
856
994
|
'**需要工具确认**',
|
|
857
995
|
summary.command ? `\`${summary.command}\`` : '',
|
|
858
996
|
summary.reason || '',
|
|
859
|
-
|
|
997
|
+
cardActionsEnabled
|
|
998
|
+
? '也可以直接回复:`allow` / `allow all` / `deny`'
|
|
999
|
+
: '请直接回复:`allow` / `allow all` / `deny`',
|
|
860
1000
|
].filter(Boolean);
|
|
861
|
-
const buttonRows =
|
|
1001
|
+
const buttonRows = cardActionsEnabled && Array.isArray(event.buttonRows)
|
|
862
1002
|
? event.buttonRows
|
|
863
1003
|
.map((row) => Array.isArray(row)
|
|
864
1004
|
? row
|
|
865
1005
|
.filter((button) => Boolean(button?.text && button?.data))
|
|
866
|
-
.map((button) => ({
|
|
1006
|
+
.map((button) => ({
|
|
1007
|
+
text: this.formatPermissionButtonLabel(button),
|
|
1008
|
+
data: (0, desktop_js_1.normalizePermissionResponse)(button.data) || button.data,
|
|
1009
|
+
}))
|
|
867
1010
|
: [])
|
|
868
1011
|
.filter((row) => row.length > 0)
|
|
869
1012
|
: [];
|
|
@@ -892,7 +1035,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
892
1035
|
if (!value || value.action !== 'permission_response') {
|
|
893
1036
|
return;
|
|
894
1037
|
}
|
|
895
|
-
const response = String(value.response || '').trim();
|
|
1038
|
+
const response = (0, desktop_js_1.normalizePermissionResponse)(String(value.response || '').trim()) || String(value.response || '').trim();
|
|
896
1039
|
const threadId = String(value.thread_id || '').trim();
|
|
897
1040
|
if (!response || !threadId) {
|
|
898
1041
|
return;
|
|
@@ -918,6 +1061,29 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
918
1061
|
target.splice(0, target.length - 6);
|
|
919
1062
|
}
|
|
920
1063
|
}
|
|
1064
|
+
formatPermissionButtonLabel(button) {
|
|
1065
|
+
const response = (0, desktop_js_1.normalizePermissionResponse)(button.data) || (0, desktop_js_1.normalizePermissionResponse)(button.text);
|
|
1066
|
+
switch (response) {
|
|
1067
|
+
case 'allow':
|
|
1068
|
+
return '允许一次';
|
|
1069
|
+
case 'allow all':
|
|
1070
|
+
return '始终允许';
|
|
1071
|
+
case 'deny':
|
|
1072
|
+
return '拒绝';
|
|
1073
|
+
default:
|
|
1074
|
+
return button.text;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
resolveLarkButtonType(button, index) {
|
|
1078
|
+
const response = (0, desktop_js_1.normalizePermissionResponse)(button.data) || (0, desktop_js_1.normalizePermissionResponse)(button.text);
|
|
1079
|
+
if (response === 'deny') {
|
|
1080
|
+
return 'danger';
|
|
1081
|
+
}
|
|
1082
|
+
if (response === 'allow') {
|
|
1083
|
+
return 'primary';
|
|
1084
|
+
}
|
|
1085
|
+
return index === 0 ? 'primary' : 'default';
|
|
1086
|
+
}
|
|
921
1087
|
buildPermissionSummary(turn, rawContent) {
|
|
922
1088
|
const lastTool = turn.toolCalls[turn.toolCalls.length - 1] || '';
|
|
923
1089
|
const [commandPart = '', reasonPart = ''] = lastTool.split(/\s+-\s+/, 2);
|
|
@@ -17,6 +17,8 @@ class LocalCoreController extends node_events_1.EventEmitter {
|
|
|
17
17
|
runtime;
|
|
18
18
|
runtimeDetection;
|
|
19
19
|
busUnsubscribers = [];
|
|
20
|
+
pendingLogs = [];
|
|
21
|
+
handlingLog = false;
|
|
20
22
|
constructor(userDataPath, runtime) {
|
|
21
23
|
super();
|
|
22
24
|
this.userDataPath = userDataPath;
|
|
@@ -38,6 +40,7 @@ class LocalCoreController extends node_events_1.EventEmitter {
|
|
|
38
40
|
log: (message) => this.handleLog(message),
|
|
39
41
|
emit: (event) => this.handleRuntimeDetectionEvent(event),
|
|
40
42
|
});
|
|
43
|
+
this.flushPendingLogs();
|
|
41
44
|
this.busUnsubscribers.push(this.kernel.context.bus.on('platform.bridge.updated', (event) => {
|
|
42
45
|
this.emit('bridge', event);
|
|
43
46
|
}), this.kernel.context.bus.on('scheduler.job.updated', (job) => {
|
|
@@ -382,8 +385,39 @@ class LocalCoreController extends node_events_1.EventEmitter {
|
|
|
382
385
|
this.emit('runtime', await this.getRuntimeStatus());
|
|
383
386
|
}
|
|
384
387
|
handleLog(message) {
|
|
388
|
+
if (this.handlingLog) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const state = this.state;
|
|
392
|
+
if (!state) {
|
|
393
|
+
this.pendingLogs.push(message);
|
|
394
|
+
this.emit('logs', message);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
this.handlingLog = true;
|
|
398
|
+
try {
|
|
399
|
+
state.pushLog?.(message);
|
|
400
|
+
}
|
|
401
|
+
finally {
|
|
402
|
+
this.handlingLog = false;
|
|
403
|
+
}
|
|
385
404
|
this.emit('logs', message);
|
|
386
405
|
}
|
|
406
|
+
flushPendingLogs() {
|
|
407
|
+
if (this.pendingLogs.length === 0) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const logs = this.pendingLogs.splice(0);
|
|
411
|
+
this.handlingLog = true;
|
|
412
|
+
try {
|
|
413
|
+
for (const message of logs) {
|
|
414
|
+
this.state.pushLog?.(message);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
finally {
|
|
418
|
+
this.handlingLog = false;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
387
421
|
resolveChannelRuntime(platform) {
|
|
388
422
|
if (platform === this.channelRuntime.platform) {
|
|
389
423
|
return this.channelRuntime;
|
package/package.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{u as ze,t as Me,r,j as s,C as ye,I as pe,M as K,B as C,w as ee,R as De,T as Le}from"./index-bNsLuLje.js";import{M as je}from"./Modal-DRn2QI8p.js";import{E as U}from"./EmptyState-DrCleE-v.js";import{C as Ae,S as Be}from"./ChatMarkdown-C-BlK1yX.js";import{l as Ke}from"./projects-DC4slOOB.js";import{l as Ue,g as $e,s as qe,a as be,r as Fe,d as Oe}from"./sessions-BIMMb8YC.js";import{s as He,a as ve,b as v,L as $,t as Ve}from"./session-utils-7J-omgrc.js";import{S as We}from"./search-bWm0yagY.js";import{P as Ge}from"./pencil-DrFGidyy.js";import{T as Je}from"./trash-2-CEov4VLH.js";import{B as Qe,U as Xe}from"./user-B93Dje9X.js";import"./index-HCsfse2M.js";import"./check-CIzPQt9l.js";const Ye=1500,Ze=9e4;function es(a){return String(a||"").startsWith("web:")}function ss(a){return(a||[]).map((c,p)=>({id:`${c.timestamp||p}-${c.role}-${p}`,role:c.role==="user"?"user":"assistant",content:c.content,timestamp:c.timestamp,kind:c.kind}))}function ts(a){return a.map(c=>`${c.role}:${c.kind||"final"}:${c.timestamp||""}:${c.content}`).join(`
|
|
2
|
-
`)}function as(a){return a.filter(c=>c.role!=="user").length}function ns(a,c){var p;return(p=a.last_message)!=null&&p.content?a.last_message.content.replace(/\n/g," "):c("sessions.noMessages")}function we(a){return(a instanceof Error?a.message:String(a||"")).trim().toLowerCase().includes("no active session found")}function rs(a,c){return(a instanceof Error?a.message:String(a||"")).trim().toLowerCase()?we(a)?c("sessions.sessionUnavailable"):a instanceof Error?a.message:c("sessions.sendFailed"):c("sessions.sendFailed")}function js(){const{t:a}=ze(),[c,p]=Me(),[se,ke]=r.useState([]),[te,ae]=r.useState({}),[i,G]=r.useState(c.get("project")||""),[j,_]=r.useState([]),[n,h]=r.useState(null),[R,w]=r.useState([]),[J,ne]=r.useState(""),[I,Q]=r.useState(""),[Se,re]=r.useState(!0),[Ne,ie]=r.useState(!1),[Ce,le]=r.useState(!1),[X,oe]=r.useState(!1),[E,P]=r.useState("idle"),[ce,k]=r.useState(""),[T,q]=r.useState(null),[F,Y]=r.useState(""),[z,O]=r.useState(null),[de,H]=r.useState(null),me=r.useRef(null),x=r.useRef({project:"",sessionId:""}),V=r.useRef(null),W=r.useRef(null),b=c.get("project")||"",M=c.get("session")||"",ue=r.useMemo(()=>new Set(Object.values(te)),[te]),S=r.useMemo(()=>{const e=J.trim().toLowerCase();return e?j.filter(t=>He(t,e)):j},[J,j]),D=!!(n&&(n.live||ue.has(n.id))),Ee=!!(i&&D&&I.trim()&&!X&&E!=="sending"&&E!=="activating"&&E!=="polling"),f=r.useCallback((e,t)=>{const l=new URLSearchParams;e&&l.set("project",e),t&&l.set("session",t),p(l,{replace:!0})},[p]),d=r.useCallback((e="idle")=>{V.current&&(window.clearTimeout(V.current),V.current=null),W.current=null,P(e)},[]),xe=r.useCallback(e=>{_(t=>{const l=t.some(o=>o.id===e.id)?t.map(o=>o.id===e.id?{...o,...e}:o):[...t,e];return ve(l)})},[]),fe=r.useCallback(async()=>{re(!0);try{const{projects:e}=await Ke();ke(e||[])}finally{re(!1)}},[]),u=r.useCallback(async e=>{if(!e)return _([]),ae({}),[];ie(!0);try{const{sessions:t,active_keys:l}=await Ue(e),o=ve((t||[]).filter(m=>!es(m.session_key)));return ae(l||{}),x.current.project===e&&_(o),o}finally{ie(!1)}},[]),N=r.useCallback(async(e,t,l)=>{if(!e||!t)return h(null),w([]),null;l!=null&&l.silent||le(!0);try{const o=await $e(e,t,200);return x.current.project!==e||x.current.sessionId!==t||(xe(o),h({id:o.id,project:e,sessionKey:o.session_key,name:o.name||v(o),live:o.live,isDraft:!1,detail:o}),w(ss(o.history)),k("")),o}catch(o){return x.current.project===e&&x.current.sessionId===t&&k(o instanceof Error?o.message:a("sessions.loadFailed")),null}finally{l!=null&&l.silent||le(!1)}},[xe,a]),Z=r.useCallback(e=>{W.current=e,V.current=window.setTimeout(async()=>{const t=W.current;if(!t)return;if(Date.now()-t.startedAt>=Ze){d("timed_out"),k(a("sessions.pollTimeout")),await u(t.project);return}const l=await N(t.project,t.sessionId,{silent:!0});if(!l||!W.current){d(),await u(t.project);return}if(x.current.project!==t.project||x.current.sessionId!==t.sessionId){d();return}const o=ts(l.history),m=as(l.history)>t.assistantCountBefore,g=m&&o===t.lastSignature?t.stableCount+1:0,B={...t,lastSignature:o,stableCount:g};if(m&&g>=2){d(),await u(t.project);return}P("polling"),Z(B)},Ye)},[N,u,d,a]),he=r.useCallback((e,t,l)=>{d(),P("polling"),Z({project:e,sessionId:t,assistantCountBefore:l,stableCount:0,lastSignature:"",startedAt:Date.now()})},[Z,d]),Pe=r.useCallback(async e=>{if(d(),G(e),ne(""),k(""),Q(""),!e){x.current={project:"",sessionId:""},h(null),w([]),_([]),f("");return}x.current={project:e,sessionId:""},h(null),w([]),f(e),await u(e)},[u,d,f]),L=r.useCallback(async e=>{if(e.isDraft||e.live||!e.id)return e;P("activating");try{await qe(e.project,{session_key:e.sessionKey,session_id:e.id}),await u(e.project);const t=await N(e.project,e.id,{silent:!0}),l={...e,live:(t==null?void 0:t.live)??!0,isDraft:!1,detail:t??e.detail,name:(t==null?void 0:t.name)||e.name};return h(l),l}finally{P("idle")}},[N,u]),A=r.useCallback(async(e,t)=>{d(),k(""),x.current={project:e,sessionId:t.id},G(e),f(e,t.id),h({id:t.id,project:e,sessionKey:t.session_key,name:v(t),live:t.live,isDraft:!1,detail:null});const l=await N(e,t.id);l&&!l.live&&await L({id:l.id,project:e,sessionKey:l.session_key,name:l.name||v(l),live:l.live,isDraft:!1,detail:l})},[L,N,d,f]),_e=r.useCallback(async()=>{d(),i&&(await u(i),n!=null&&n.id&&(x.current={project:i,sessionId:n.id},await N(i,n.id)))},[n==null?void 0:n.id,N,u,i,d]),ge=r.useCallback(async()=>{if(!I.trim()||!i)return;if(!D){k(a("sessions.sessionUnavailable"));return}const e=I.trim(),t=`${crypto.randomUUID()}-user`,l={id:t,role:"user",content:e,timestamp:new Date().toISOString()};Q(""),oe(!0),P("sending"),k("");try{const o=n||S[0];if(!o)throw new Error(a("sessions.noAvailableChatTarget"));let m=n&&n.id===o.id?n:{id:o.id,project:i,sessionKey:"session_key"in o?o.session_key:o.sessionKey,name:"session_key"in o?v(o):o.name,live:o.live,isDraft:!1,detail:null};(!n||n.id!==m.id)&&(x.current={project:i,sessionId:m.id},f(i,m.id),h(m)),m=await L(m),w(y=>[...y,l]);try{await be(i,{session_key:m.sessionKey,message:e})}catch(y){if(!we(y)||!m.id)throw y;m=await L({...m,live:!1}),await be(i,{session_key:m.sessionKey,message:e})}const g=m.id;if(!g)throw new Error(a("sessions.createFailed"));const B=R.filter(y=>y.role!=="user").length;x.current={project:i,sessionId:g},h(y=>y&&{...y,id:g,isDraft:!1}),f(i,g),he(i,g,B),await u(i)}catch(o){d(),w(g=>g.filter(B=>B.id!==t));const m=rs(o,a);k(m)}finally{oe(!1)}},[n,D,L,I,S,R,u,i,he,d,a,f]),Re=r.useCallback(async()=>{if(!(!T||!i||!F.trim())){H("rename");try{await Fe(i,T.id,{name:F.trim()});const t=(await u(i)).find(l=>l.id===T.id);t&&(n==null?void 0:n.id)===t.id&&h(l=>l&&{...l,name:v(t)}),q(null),Y("")}finally{H(null)}}},[n==null?void 0:n.id,u,F,T,i]),Ie=r.useCallback(async()=>{if(!(!z||!i)){H("delete");try{await Oe(i,z.id);const e=await u(i);(n==null?void 0:n.id)===z.id&&(d(),x.current={project:i,sessionId:""},h(null),w([]),f(i)),e.length===0&&w([]),O(null)}finally{H(null)}}},[n==null?void 0:n.id,z,u,i,d,f]);r.useEffect(()=>{fe()},[fe]),r.useEffect(()=>{b&&(i&&i===b||G(b))},[b,i]),r.useEffect(()=>{if(!i){_([]);return}x.current.project=i,u(i)},[u,i]),r.useEffect(()=>{!i||M||n!=null&&n.id||S.length===0||A(i,S[0])},[n==null?void 0:n.id,S,A,M,i]),r.useEffect(()=>{if(!b||!M||i!==b)return;const e=j.find(t=>t.id===M);if(!e){j.length>0&&f(b,j[0].id);return}(n==null?void 0:n.id)!==e.id&&A(b,e)},[n==null?void 0:n.id,A,b,M,i,j,f]),r.useEffect(()=>{var e;(e=me.current)==null||e.scrollIntoView({behavior:"smooth"})},[R]),r.useEffect(()=>()=>d(),[d]);const Te=(n==null?void 0:n.name)||a("sessions.activeChat");return s.jsxs("div",{className:"grid min-h-[calc(100vh-8rem)] grid-cols-1 gap-4 xl:grid-cols-[22rem_minmax(0,1fr)] animate-fade-in",children:[s.jsxs(ye,{className:"flex flex-col gap-4 p-4 xl:h-[calc(100vh-8rem)] xl:overflow-hidden",children:[s.jsx("div",{className:"flex items-center gap-3",children:s.jsxs("div",{className:"flex-1",children:[s.jsx("p",{className:"text-xs font-medium uppercase tracking-[0.2em] text-gray-400",children:a("sessions.selectProject")}),s.jsxs("select",{value:i,onChange:e=>void Pe(e.target.value),className:"mt-2 w-full rounded-xl border border-gray-300/90 bg-white/90 px-3 py-2 text-sm text-gray-900 transition-all focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/45 dark:border-white/[0.1] dark:bg-[rgba(0,0,0,0.45)] dark:text-white",children:[s.jsx("option",{value:"",children:a("sessions.allProjects")}),se.map(e=>s.jsx("option",{value:e.name,children:e.name},e.name))]})]})}),s.jsxs("div",{className:"relative",children:[s.jsx(pe,{value:J,onChange:e=>ne(e.target.value),placeholder:a("common.search"),className:"pl-9","aria-label":a("common.search")}),s.jsx(We,{size:16,className:"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"})]}),s.jsxs("div",{className:"flex min-h-0 flex-1 flex-col overflow-hidden",children:[s.jsxs("div",{className:"mb-3 flex items-center justify-between text-xs text-gray-500 dark:text-gray-400",children:[s.jsx("span",{children:a("sessions.historyTitle")}),s.jsx("span",{children:S.length})]}),s.jsx("div",{className:"min-h-0 flex-1 overflow-y-auto space-y-2 pr-1",children:Se?s.jsx("div",{className:"flex h-32 items-center justify-center text-gray-400",children:s.jsx($,{className:"animate-spin",size:18})}):i?Ne&&j.length===0?s.jsx("div",{className:"flex h-32 items-center justify-center text-gray-400",children:s.jsx($,{className:"animate-spin",size:18})}):j.length===0?s.jsx(U,{message:a("sessions.noSessions"),icon:K}):S.length===0?s.jsx(U,{message:a("sessions.noSessions"),icon:K}):S.map(e=>{const t=e.id===(n==null?void 0:n.id);return s.jsxs("div",{className:ee("rounded-2xl border p-3 transition-all",t?"border-accent/45 bg-accent/10 shadow-[0_0_20px_-12px_rgba(139,92,246,0.55)]":"border-gray-200/80 bg-white/70 hover:border-accent/30 dark:border-white/[0.08] dark:bg-white/[0.03]"),children:[s.jsxs("button",{type:"button",onClick:()=>void A(i,e),className:"w-full text-left","data-testid":"web-chat-session-open",children:[s.jsxs("div",{className:"flex items-start justify-between gap-2",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("span",{className:"truncate text-sm font-medium text-gray-900 dark:text-white",children:v(e)}),e.live||ue.has(e.id)?s.jsx("span",{className:"rounded-full bg-violet-50 px-2 py-0.5 text-[10px] text-violet-600 dark:bg-violet-950/20 dark:text-violet-300",children:"live"}):s.jsx("span",{className:"rounded-full bg-gray-100 px-2 py-0.5 text-[10px] text-gray-400 dark:bg-white/[0.06] dark:text-gray-500",children:"history"})]}),s.jsx("p",{className:"mt-1 truncate text-xs text-gray-500 dark:text-gray-400",children:Ve(e.updated_at||e.created_at,a("sessions.justNow"))})]}),s.jsx("span",{className:"shrink-0 text-[10px] text-gray-400",children:e.history_count})]}),s.jsx("p",{className:"mt-2 line-clamp-2 text-xs text-gray-500 dark:text-gray-400",children:ns(e,a)})]}),s.jsxs("div",{className:"mt-3 flex items-center justify-end gap-1",children:[s.jsx(C,{size:"sm",variant:"ghost",onClick:()=>{q({id:e.id,name:v(e)}),Y(v(e))},"data-testid":"web-chat-session-rename",children:s.jsx(Ge,{size:14})}),s.jsx(C,{size:"sm",variant:"ghost",onClick:()=>O({id:e.id,name:v(e)}),"data-testid":"web-chat-session-delete",children:s.jsx(Je,{size:14})})]})]},e.id)}):s.jsx(U,{message:a("sessions.projectRequired"),icon:K})})]})]}),s.jsxs(ye,{className:"flex min-h-[32rem] flex-col p-0 xl:h-[calc(100vh-8rem)]",children:[s.jsxs("div",{className:"flex items-center justify-between gap-3 border-b border-gray-200/80 px-5 py-4 dark:border-white/[0.08]",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsx("div",{className:"flex items-center gap-2",children:s.jsx("h2",{className:"truncate text-lg font-semibold text-gray-900 dark:text-white",children:Te})}),s.jsx("p",{className:"mt-1 truncate text-sm text-gray-500 dark:text-gray-400",children:n?n.project:a("sessions.sendHint")})]}),s.jsxs(C,{size:"sm",variant:"secondary",onClick:()=>void _e(),"data-testid":"web-chat-refresh",children:[s.jsx(De,{size:14})," ",a("common.refresh")]})]}),s.jsx("div",{className:"flex-1 overflow-y-auto px-5 py-5",children:i?Ce?s.jsx("div",{className:"flex h-full items-center justify-center text-gray-400",children:s.jsx($,{className:"animate-spin",size:22})}):R.length===0?s.jsx("div",{className:"flex h-full items-center justify-center",children:s.jsx(U,{message:a(n?"sessions.noMessages":"sessions.sendHint"),icon:K})}):s.jsxs("div",{className:"space-y-5",children:[R.map(e=>{const t=e.role==="user";return s.jsxs("div",{className:ee("flex gap-3",t?"justify-end":"justify-start"),children:[!t&&s.jsx("div",{className:"mt-1 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-accent/10",children:s.jsx(Qe,{size:16,className:"text-accent"})}),s.jsx("div",{className:ee("max-w-[85%] rounded-2xl px-5 py-3.5 text-sm",t?"bg-accent text-white rounded-br-md":"border border-gray-200 bg-white text-gray-900 shadow-sm dark:border-white/[0.08] dark:bg-[rgba(0,0,0,0.42)] dark:text-gray-100 rounded-bl-md"),children:s.jsx(Ae,{content:e.content,isUser:t})}),t&&s.jsx("div",{className:"mt-1 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-200 dark:bg-white/[0.08]",children:s.jsx(Xe,{size:16,className:"text-gray-500 dark:text-gray-300"})})]},e.id)}),s.jsx("div",{ref:me})]}):s.jsx("div",{className:"flex h-full items-center justify-center",children:s.jsx(U,{message:a("sessions.emptySelection"),icon:K})})}),s.jsxs("div",{className:"border-t border-gray-200/80 px-5 py-4 dark:border-white/[0.08]",children:[ce&&s.jsx("div",{className:"mb-3 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-600 dark:border-red-900/40 dark:bg-red-950/20 dark:text-red-300",children:ce}),E==="polling"&&s.jsxs("div",{className:"mb-3 flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400",children:[s.jsx($,{size:14,className:"animate-spin"}),s.jsx("span",{children:a("sessions.waitingForReply")})]}),E==="activating"&&s.jsxs("div",{className:"mb-3 flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400",children:[s.jsx($,{size:14,className:"animate-spin"}),s.jsx("span",{children:a("sessions.preparingChat")})]}),s.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-end",children:[s.jsx("div",{className:"flex-1",children:s.jsx(Le,{value:I,onChange:e=>Q(e.target.value),onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),ge())},rows:3,placeholder:a(i?"sessions.messageInput":"sessions.projectRequired"),disabled:!i||!D||X||E==="polling"||E==="activating","data-testid":"web-chat-input"})}),s.jsxs(C,{onClick:()=>void ge(),disabled:!Ee,loading:X,size:"lg",className:"sm:self-stretch","data-testid":"web-chat-send",children:[s.jsx(Be,{size:16})," ",a("sessions.send")]})]}),!D&&n&&s.jsx("div",{className:"mt-3 rounded-xl border border-gray-200 bg-gray-50 px-4 py-3 text-sm text-gray-500 dark:border-white/[0.08] dark:bg-white/[0.03] dark:text-gray-400",children:a("sessions.notLiveHint")})]})]}),s.jsx(je,{open:!!T,onClose:()=>q(null),title:a("sessions.renameTitle"),children:s.jsxs("div",{className:"space-y-4",children:[s.jsx(pe,{value:F,onChange:e=>Y(e.target.value),placeholder:a("sessions.renamePlaceholder"),"data-testid":"web-chat-rename-input"}),s.jsxs("div",{className:"flex justify-end gap-2",children:[s.jsx(C,{variant:"secondary",onClick:()=>q(null),children:a("common.cancel")}),s.jsx(C,{onClick:()=>void Re(),loading:de==="rename","data-testid":"web-chat-rename-save",children:a("common.save")})]})]})}),s.jsx(je,{open:!!z,onClose:()=>O(null),title:a("sessions.deleteConfirmTitle"),children:s.jsxs("div",{className:"space-y-4",children:[s.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:a("sessions.deleteConfirmBody")}),s.jsxs("div",{className:"flex justify-end gap-2",children:[s.jsx(C,{variant:"secondary",onClick:()=>O(null),children:a("common.cancel")}),s.jsx(C,{variant:"danger",onClick:()=>void Ie(),loading:de==="delete","data-testid":"web-chat-delete-confirm",children:a("common.delete")})]})]})})]})}export{js as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as C,z,r,j as e,L as S,B as j,w as g,I as B}from"./index-bNsLuLje.js";import{B as y}from"./Badge-BIuWuNsC.js";import{g as E,a as I}from"./sessions-BIMMb8YC.js";import{C as L,S as M}from"./ChatMarkdown-C-BlK1yX.js";import{A as R}from"./arrow-left-DLijH4Ma.js";import{C as D}from"./circle-C22V7KHC.js";import{W as v,R as K}from"./wifi-off-cCUI9WRl.js";import{B as U,U as W}from"./user-B93Dje9X.js";import"./check-CIzPQt9l.js";function G(){var h;const{t:a}=C(),{project:n,id:l}=z(),[s,N]=r.useState(null),[o,m]=r.useState(""),[d,x]=r.useState(!1),[b,f]=r.useState(!0),u=r.useRef(null),c=r.useCallback(async()=>{if(!(!n||!l))try{f(!0);const t=await E(n,l,200);N(t)}finally{f(!1)}},[n,l]);r.useEffect(()=>{c()},[c]),r.useEffect(()=>{var t;(t=u.current)==null||t.scrollIntoView({behavior:"smooth"})},[s==null?void 0:s.history]);const p=async()=>{if(!o.trim()||!n||!s)return;const t=o.trim();m(""),x(!0);try{await I(n,{session_key:s.session_key,message:t}),setTimeout(c,1500)}finally{x(!1)}},w=t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),p())};return b&&!s?e.jsx("div",{className:"flex items-center justify-center h-64 text-muted-foreground animate-pulse",children:"Loading..."}):e.jsxs("div",{className:"flex flex-col h-[calc(100vh-8rem)] animate-fade-in",children:[e.jsxs("div",{className:"flex items-center justify-between pb-4 border-b",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(S,{to:"/sessions",className:"p-2 rounded-md hover:bg-accent/10 transition-colors",children:e.jsx(R,{size:18,className:"text-muted-foreground"})}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-lg font-semibold text-foreground",children:(s==null?void 0:s.name)||l}),s!=null&&s.live?e.jsxs("span",{className:"flex items-center gap-1 text-[10px] text-primary bg-primary/10 px-1.5 py-0.5 rounded-full",children:[e.jsx(D,{size:5,className:"fill-current"})," live"]}):e.jsxs("span",{className:"flex items-center gap-1 text-[10px] text-muted-foreground bg-muted px-1.5 py-0.5 rounded-full",children:[e.jsx(v,{size:9})," ",a("sessions.offline")]})]}),e.jsxs("div",{className:"flex items-center gap-2 mt-0.5",children:[e.jsx(y,{children:n}),(s==null?void 0:s.platform)&&e.jsx(y,{variant:"info",children:s.platform}),e.jsx("span",{className:"text-xs text-muted-foreground",children:s==null?void 0:s.session_key})]})]})]}),e.jsxs(j,{size:"sm",variant:"ghost",onClick:c,children:[e.jsx(K,{size:14})," ",a("common.refresh")]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto py-6 space-y-5",children:[(!(s!=null&&s.history)||s.history.length===0)&&e.jsx("p",{className:"text-center text-sm text-muted-foreground py-12",children:a("sessions.noMessages")}),(h=s==null?void 0:s.history)==null?void 0:h.map((t,k)=>{const i=t.role==="user";return e.jsxs("div",{className:g("flex gap-3",i?"justify-end":"justify-start"),children:[!i&&e.jsx("div",{className:"w-8 h-8 rounded-md bg-primary/10 flex items-center justify-center shrink-0 mt-1",children:e.jsx(U,{size:16,className:"text-primary"})}),e.jsx("div",{className:g("rounded-lg px-5 py-3.5 text-sm",i?"max-w-[70%] bg-primary text-primary-foreground rounded-br-md":"max-w-[85%] bg-card border text-card-foreground rounded-bl-md shadow-sm"),children:e.jsx(L,{content:t.content,isUser:i})}),i&&e.jsx("div",{className:"w-8 h-8 rounded-md bg-muted flex items-center justify-center shrink-0 mt-1",children:e.jsx(W,{size:16,className:"text-muted-foreground"})})]},k)}),e.jsx("div",{ref:u})]}),e.jsx("div",{className:"border-t pt-4",children:s!=null&&s.live?e.jsxs("div",{className:"flex gap-3",children:[e.jsx(B,{value:o,onChange:t=>m(t.target.value),onKeyDown:w,placeholder:a("sessions.messageInput"),className:"flex-1",disabled:d}),e.jsx(j,{onClick:p,disabled:d||!o.trim(),size:"icon","aria-label":a("sessions.messageInput"),children:d?e.jsxs("svg",{className:"animate-spin h-4 w-4",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4",fill:"none"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]}):e.jsx(M,{size:18})})]}):e.jsxs("div",{className:"flex items-center gap-2 px-4 py-3 text-sm text-muted-foreground bg-muted rounded-lg",children:[e.jsx(v,{size:14}),e.jsx("span",{children:a("sessions.notLiveHint")})]})})]})}export{G as default};
|