@xmanrui/dsh-im 4.11.0 → 4.13.0
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/PROACTIVE_DELIVERY.en.md +4 -0
- package/PROACTIVE_DELIVERY.md +4 -0
- package/README.en.md +12 -2
- package/README.md +12 -2
- package/assets/dingtalk-menu-template.json +6 -0
- package/lib/client.js +1211 -1034
- package/lib/index.js +270 -264
- package/package.json +1 -1
- package/plugin-src/client/channels/dingtalk/index.js +16 -5
- package/plugin-src/client/channels/feishu/index.js +45 -36
- package/plugin-src/client/channels/qq/index.js +16 -5
- package/plugin-src/client/channels/shared/collapsible-account.js +80 -0
- package/plugin-src/client/channels/shared/token-channel.js +39 -28
- package/plugin-src/client/channels/wecom/index.js +16 -5
- package/plugin-src/client/channels/weixin/index.js +16 -5
- package/plugin-src/client/channels/whatsapp/index.js +16 -5
- package/plugin-src/client/i18n.js +2 -0
- package/plugin-src/client/styles.js +14 -1
- package/plugin-src/host/harness-command-executor.mjs +13 -6
- package/src/channels/dingtalk/dingtalk-api.mjs +33 -0
- package/src/channels/dingtalk/dingtalk-bridge.mjs +136 -2
- package/src/channels/dingtalk/dingtalk-menu.mjs +91 -0
- package/src/channels/dingtalk/dingtalk-runtime.mjs +17 -0
- package/src/channels/dingtalk/state-store.mjs +8 -0
- package/src/channels/feishu/bridge.mjs +74 -3
- package/src/channels/feishu/state-store.mjs +11 -0
- package/src/channels/qq/qq-bridge.mjs +121 -1
- package/src/channels/qq/qq-menu.mjs +205 -0
- package/src/channels/qq/state-store.mjs +16 -0
- package/src/channels/shared/bot-workspace-store.mjs +3 -0
- package/src/channels/shared/control-command.mjs +8 -0
- package/src/channels/shared/conversation-state-store.mjs +8 -0
- package/src/channels/shared/deferred-delivery-coordinator.mjs +241 -0
- package/src/channels/shared/deferred-delivery.mjs +161 -0
- package/src/channels/shared/deferred-state.mjs +53 -0
- package/src/channels/shared/harness-client.mjs +21 -1
- package/src/channels/shared/i18n-en/dingtalk.mjs +5 -0
- package/src/channels/shared/i18n-en/feishu.mjs +6 -0
- package/src/channels/shared/i18n-en/qq.mjs +39 -0
- package/src/channels/shared/i18n-en/wecom.mjs +24 -0
- package/src/channels/shared/i18n-en/weixin.mjs +2 -0
- package/src/channels/shared/text-harness-bridge.mjs +15 -0
- package/src/channels/shared/workspace-session.mjs +16 -1
- package/src/channels/wecom/state-store.mjs +8 -0
- package/src/channels/wecom/wecom-bridge.mjs +294 -6
- package/src/channels/wecom/wecom-cards.mjs +101 -0
- package/src/channels/wecom/wecom-runtime.mjs +2 -0
- package/src/channels/weixin/state-store.mjs +64 -1
- package/src/channels/weixin/weixin-bridge.mjs +31 -5
- package/src/channels/weixin/weixin-runtime.mjs +33 -8
- package/src/channels/whatsapp/whatsapp-runtime.mjs +78 -26
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
4
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
4
5
|
import { h } from '../../i18n.js';
|
|
5
6
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
6
7
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -256,13 +257,20 @@ export function AccountCard({
|
|
|
256
257
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
257
258
|
return h('article', { className: 'ddt-card dim-botCard', tabIndex: -1, 'data-bot-id': account.botId },
|
|
258
259
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
259
|
-
h(
|
|
260
|
+
h(CollapsibleAccountSection, {
|
|
261
|
+
id: `ddt-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
262
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
260
263
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
261
264
|
h('div', { className: 'ddt-avatar dim-botAvatar', 'aria-hidden': 'true' }, h(DingtalkIcon, { size: 29 })),
|
|
262
265
|
h('div', { className: 'dim-botName' },
|
|
263
266
|
h('h3', { title: account.bot.name }, account.bot.name),
|
|
264
267
|
h('p', { title: account.bot.clientIdMasked }, account.bot.clientIdMasked))),
|
|
265
|
-
h('div', {
|
|
268
|
+
h('div', {
|
|
269
|
+
className: 'dim-botCardTools',
|
|
270
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
271
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
272
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
273
|
+
},
|
|
266
274
|
h(BotStatusMeta, {
|
|
267
275
|
className: 'ddt-health',
|
|
268
276
|
dotClassName: 'ddt-dot',
|
|
@@ -277,8 +285,9 @@ export function AccountCard({
|
|
|
277
285
|
botName: account.bot.name,
|
|
278
286
|
connected: account.connected,
|
|
279
287
|
accessPolicy: account.accessPolicy,
|
|
280
|
-
})))
|
|
281
|
-
|
|
288
|
+
})))
|
|
289
|
+
},
|
|
290
|
+
h(WorkspaceEditor, {
|
|
282
291
|
workspace: account.workspace,
|
|
283
292
|
disabled: Boolean(busy),
|
|
284
293
|
onSave: onWorkspaceSave,
|
|
@@ -314,7 +323,9 @@ export function AccountCard({
|
|
|
314
323
|
feedback ? h('div', {
|
|
315
324
|
className: 'ddt-summary dim-cardFeedback',
|
|
316
325
|
role: 'status',
|
|
317
|
-
}, feedback) : null))
|
|
326
|
+
}, feedback) : null)),
|
|
327
|
+
),
|
|
328
|
+
),
|
|
318
329
|
removing ? h(RemoveConfirmation, {
|
|
319
330
|
account,
|
|
320
331
|
busy: busy === 'delete',
|
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
import { FeishuLogoGlyph } from "../../channel-logos.js";
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from "../../credential-binding.js";
|
|
5
|
+
import { CollapsibleAccountSection } from "../shared/collapsible-account.js";
|
|
5
6
|
import { h } from "../../i18n.js";
|
|
6
7
|
import {
|
|
7
8
|
FEISHU_ENDPOINTS,
|
|
@@ -506,42 +507,49 @@ export function BotCard({
|
|
|
506
507
|
ref: cardRef,
|
|
507
508
|
},
|
|
508
509
|
h("div", { className: "bxf-cardBody dim-botCardBody" },
|
|
509
|
-
h(
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
h("
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
510
|
+
h(CollapsibleAccountSection, {
|
|
511
|
+
id: `bxf-settings-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
|
|
512
|
+
header: h("div", { className: "bxf-connectedTop dim-botCardTop" },
|
|
513
|
+
h("div", { className: "bxf-botIdentity dim-botIdentity" },
|
|
514
|
+
h("div", { className: "bxf-avatar dim-botAvatar", "aria-hidden": "true" },
|
|
515
|
+
h(FeishuLogoGlyph, { size: 34 })),
|
|
516
|
+
h("div", { className: "bxf-botName dim-botName" },
|
|
517
|
+
h("h3", { id: titleId, title: bot.name }, bot.name),
|
|
518
|
+
h("p", { title: bot.appIdMasked }, bot.appIdMasked ?? "应用标识已安全保存")),
|
|
519
|
+
),
|
|
520
|
+
h("div", {
|
|
521
|
+
className: "dim-botCardTools",
|
|
522
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
523
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
524
|
+
onKeyDown: (event) => { if (event.key === "Enter" || event.key === " ") event.stopPropagation(); },
|
|
525
|
+
},
|
|
526
|
+
h(BotStatusMeta, {
|
|
527
|
+
className: "bxf-healthPill",
|
|
528
|
+
dotClassName: "bxf-dot",
|
|
529
|
+
tone,
|
|
530
|
+
stateLabel: HEALTH_LABELS[stateForDisplay] ?? "状态未知",
|
|
531
|
+
lastCheckedAt: health.lastCheckedAt,
|
|
532
|
+
formatCheckedTime,
|
|
533
|
+
healthState: stateForDisplay,
|
|
534
|
+
}),
|
|
535
|
+
h(BotSettingsButton, {
|
|
536
|
+
channel: "feishu",
|
|
537
|
+
botId: connection.botId,
|
|
538
|
+
botName: bot.name,
|
|
539
|
+
connected,
|
|
540
|
+
accessPolicy: connection.accessPolicy,
|
|
541
|
+
channelSettings: {
|
|
542
|
+
groupResponseMode: connection.groupResponseMode,
|
|
543
|
+
groupTopicReply: connection.groupTopicReply,
|
|
544
|
+
groupMessagePermissionGranted: connection.groupMessagePermissionGranted,
|
|
545
|
+
},
|
|
546
|
+
}))),
|
|
547
|
+
},
|
|
548
|
+
h(WorkspaceEditor, {
|
|
549
|
+
workspace: connection.workspace,
|
|
550
|
+
disabled: Boolean(busy),
|
|
551
|
+
onSave: onWorkspaceSave,
|
|
552
|
+
}),
|
|
545
553
|
h(ModelEditor, {
|
|
546
554
|
model: connection.model,
|
|
547
555
|
disabled: Boolean(busy),
|
|
@@ -605,6 +613,7 @@ export function BotCard({
|
|
|
605
613
|
className: "bxf-healthSummary dim-cardFeedback",
|
|
606
614
|
role: "status",
|
|
607
615
|
}, testNotice) : null),
|
|
616
|
+
),
|
|
608
617
|
),
|
|
609
618
|
),
|
|
610
619
|
removing
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { QqLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
8
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -184,12 +185,19 @@ export function AccountCard({
|
|
|
184
185
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
185
186
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
186
187
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
187
|
-
h(
|
|
188
|
+
h(CollapsibleAccountSection, {
|
|
189
|
+
id: `qq-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
190
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
188
191
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
189
192
|
h('div', { className: 'ddt-avatar dim-botAvatar dqq-avatar', 'aria-hidden': 'true' }, h(QqLogoGlyph, { size: 29 })),
|
|
190
193
|
h('div', { className: 'dim-botName' },
|
|
191
194
|
h('h3', null, account.bot.name), h('p', null, account.bot.appIdMasked))),
|
|
192
|
-
h('div', {
|
|
195
|
+
h('div', {
|
|
196
|
+
className: 'dim-botCardTools',
|
|
197
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
198
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
199
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
200
|
+
},
|
|
193
201
|
h(BotStatusMeta, {
|
|
194
202
|
className: 'ddt-health',
|
|
195
203
|
dotClassName: 'ddt-dot',
|
|
@@ -204,8 +212,9 @@ export function AccountCard({
|
|
|
204
212
|
botName: account.bot.name,
|
|
205
213
|
connected: account.connected,
|
|
206
214
|
accessPolicy: account.accessPolicy,
|
|
207
|
-
})))
|
|
208
|
-
|
|
215
|
+
})))
|
|
216
|
+
},
|
|
217
|
+
h(WorkspaceEditor, {
|
|
209
218
|
workspace: account.workspace,
|
|
210
219
|
disabled: Boolean(busy),
|
|
211
220
|
onSave: onWorkspaceSave,
|
|
@@ -239,7 +248,9 @@ export function AccountCard({
|
|
|
239
248
|
className: 'ddt-summary dim-cardFeedback',
|
|
240
249
|
role: 'status',
|
|
241
250
|
'aria-live': 'polite',
|
|
242
|
-
}, feedback) : null))
|
|
251
|
+
}, feedback) : null)),
|
|
252
|
+
),
|
|
253
|
+
),
|
|
243
254
|
removing ? h(RemoveConfirmation, {
|
|
244
255
|
account, busy: busy === 'delete', onConfirm: onConfirmRemove, onCancel: onCancelRemove,
|
|
245
256
|
}) : null);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapsible per-account card, shared by every IM channel.
|
|
3
|
+
*
|
|
4
|
+
* When several accounts are connected, each account's workspace / preset /
|
|
5
|
+
* context-enhancement editors make the list extremely long. This component
|
|
6
|
+
* renders the account header as the toggle itself: collapsed, the card shows
|
|
7
|
+
* only the header line; clicking the header expands the settings details.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - The whole header is the toggle (click + keyboard). Buttons rendered inside
|
|
11
|
+
* the header must call stopPropagation so they keep their own behaviour.
|
|
12
|
+
* - A chevron sits at the end of the header line as the affordance.
|
|
13
|
+
* - Height animation uses grid-template-rows: 0fr -> 1fr (pure CSS).
|
|
14
|
+
* - Full a11y: the header is a button-like region with aria-expanded /
|
|
15
|
+
* aria-controls; the details region keeps native semantics.
|
|
16
|
+
* - Honors prefers-reduced-motion.
|
|
17
|
+
* - Styles are managed by the IM settings plugin, not individual accounts.
|
|
18
|
+
*/
|
|
19
|
+
import * as React from 'react';
|
|
20
|
+
import { h } from '../../i18n.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Collapsible account card.
|
|
24
|
+
*
|
|
25
|
+
* `header` renders the always-visible header line; clicking it toggles.
|
|
26
|
+
* Any interactive control inside the header should stop the click event so it
|
|
27
|
+
* does not toggle the section (e.g. the bot settings button).
|
|
28
|
+
* `children` is the collapsed details region.
|
|
29
|
+
*/
|
|
30
|
+
export function CollapsibleAccountSection({
|
|
31
|
+
header,
|
|
32
|
+
defaultOpen = false,
|
|
33
|
+
open: controlledOpen,
|
|
34
|
+
onToggle,
|
|
35
|
+
id,
|
|
36
|
+
className = '',
|
|
37
|
+
children,
|
|
38
|
+
}) {
|
|
39
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
40
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
41
|
+
const contentId = id ? `${id}-content` : undefined;
|
|
42
|
+
|
|
43
|
+
const toggle = () => {
|
|
44
|
+
if (controlledOpen === undefined) setUncontrolledOpen((value) => !value);
|
|
45
|
+
onToggle?.(!open);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const onKeyDown = (event) => {
|
|
49
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar') {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
toggle();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return h('div', {
|
|
56
|
+
className: `dim-collapsibleAccount ${open ? 'is-open' : ''} ${className}`.trim(),
|
|
57
|
+
'data-open': open ? 'true' : 'false',
|
|
58
|
+
},
|
|
59
|
+
h('div', {
|
|
60
|
+
className: 'dim-collapsibleHead',
|
|
61
|
+
role: 'button',
|
|
62
|
+
tabIndex: 0,
|
|
63
|
+
onClick: toggle,
|
|
64
|
+
onKeyDown,
|
|
65
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
66
|
+
'aria-controls': contentId,
|
|
67
|
+
'aria-label': open ? '收起该账号的设置' : '展开该账号的设置',
|
|
68
|
+
},
|
|
69
|
+
h('div', { className: 'dim-collapsibleHeaderContent' }, header),
|
|
70
|
+
h('span', { className: 'dim-collapsibleChevron', 'aria-hidden': 'true' }),
|
|
71
|
+
),
|
|
72
|
+
h('div', {
|
|
73
|
+
id: contentId,
|
|
74
|
+
className: 'dim-collapsibleBody',
|
|
75
|
+
role: 'region',
|
|
76
|
+
},
|
|
77
|
+
h('div', { className: 'dim-collapsibleBodyInner' }, children),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { CredentialActionIcon, CredentialBindingPanel } from '../../credential-binding.js';
|
|
4
|
+
import { CollapsibleAccountSection } from './collapsible-account.js';
|
|
4
5
|
import { h } from '../../i18n.js';
|
|
5
6
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
@@ -88,33 +89,41 @@ export function createTokenChannelSettings(definition) {
|
|
|
88
89
|
const identity = account.bot.username ? `@${account.bot.username}` : account.bot.idMasked;
|
|
89
90
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
90
91
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
91
|
-
h(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
92
|
+
h(CollapsibleAccountSection, {
|
|
93
|
+
id: `tok-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
94
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
95
|
+
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
96
|
+
h('div', { className: `ddt-avatar dim-botAvatar ${avatarClass}`, 'aria-hidden': 'true' },
|
|
97
|
+
h(LogoGlyph, { size: 29 })),
|
|
98
|
+
h('div', { className: 'dim-botName' },
|
|
99
|
+
h('h3', null, account.bot.name), h('p', null, identity))),
|
|
100
|
+
h('div', {
|
|
101
|
+
className: 'dim-botCardTools',
|
|
102
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
103
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
104
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
105
|
+
},
|
|
106
|
+
h(BotStatusMeta, {
|
|
107
|
+
className: 'ddt-health',
|
|
108
|
+
dotClassName: 'ddt-dot',
|
|
109
|
+
tone,
|
|
110
|
+
stateLabel,
|
|
111
|
+
lastCheckedAt: account.health.lastCheckedAt,
|
|
112
|
+
formatCheckedTime: checkedTime,
|
|
113
|
+
}),
|
|
114
|
+
h(BotSettingsButton, {
|
|
115
|
+
channel: channel.toLowerCase(),
|
|
116
|
+
botId: account.botId,
|
|
117
|
+
botName: account.bot.name,
|
|
118
|
+
connected: account.connected,
|
|
119
|
+
accessPolicy: account.accessPolicy,
|
|
120
|
+
}))),
|
|
121
|
+
},
|
|
122
|
+
h(WorkspaceEditor, {
|
|
123
|
+
workspace: account.workspace,
|
|
124
|
+
disabled: Boolean(busy),
|
|
125
|
+
onSave: onWorkspaceSave,
|
|
126
|
+
}),
|
|
118
127
|
h(ModelEditor, {
|
|
119
128
|
model: account.model,
|
|
120
129
|
disabled: Boolean(busy),
|
|
@@ -157,7 +166,9 @@ export function createTokenChannelSettings(definition) {
|
|
|
157
166
|
testNotice ? h('div', {
|
|
158
167
|
className: 'ddt-summary dim-cardFeedback',
|
|
159
168
|
role: 'status',
|
|
160
|
-
}, testNotice) : null))
|
|
169
|
+
}, testNotice) : null)),
|
|
170
|
+
),
|
|
171
|
+
),
|
|
161
172
|
removing ? h('div', { className: 'ddt-confirm dim-confirm', role: 'alertdialog' },
|
|
162
173
|
h('strong', null, `从 DeepSeek Harness 移除“${account.bot.name}”?`),
|
|
163
174
|
h('p', null, `这会停止消息连接,并删除本机保存的 ${credentialNoun}、机器人配置及会话映射。${platformLabel}中的机器人不会被自动删除。`),
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { WecomLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
8
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -183,12 +184,19 @@ export function AccountCard({
|
|
|
183
184
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
184
185
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
185
186
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
186
|
-
h(
|
|
187
|
+
h(CollapsibleAccountSection, {
|
|
188
|
+
id: `wec-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
189
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
187
190
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
188
191
|
h('div', { className: 'ddt-avatar dim-botAvatar dwecom-avatar', 'aria-hidden': 'true' }, h(WecomLogoGlyph, { size: 29 })),
|
|
189
192
|
h('div', { className: 'dim-botName' },
|
|
190
193
|
h('h3', null, account.bot.name), h('p', null, account.bot.appIdMasked))),
|
|
191
|
-
h('div', {
|
|
194
|
+
h('div', {
|
|
195
|
+
className: 'dim-botCardTools',
|
|
196
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
197
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
198
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
199
|
+
},
|
|
192
200
|
h(BotStatusMeta, {
|
|
193
201
|
className: 'ddt-health',
|
|
194
202
|
dotClassName: 'ddt-dot',
|
|
@@ -203,8 +211,9 @@ export function AccountCard({
|
|
|
203
211
|
botName: account.bot.name,
|
|
204
212
|
connected: account.connected,
|
|
205
213
|
accessPolicy: account.accessPolicy,
|
|
206
|
-
})))
|
|
207
|
-
|
|
214
|
+
})))
|
|
215
|
+
},
|
|
216
|
+
h(WorkspaceEditor, {
|
|
208
217
|
workspace: account.workspace,
|
|
209
218
|
disabled: Boolean(busy),
|
|
210
219
|
onSave: onWorkspaceSave,
|
|
@@ -238,7 +247,9 @@ export function AccountCard({
|
|
|
238
247
|
className: 'ddt-summary dim-cardFeedback',
|
|
239
248
|
role: 'status',
|
|
240
249
|
'aria-live': 'polite',
|
|
241
|
-
}, feedback) : null))
|
|
250
|
+
}, feedback) : null)),
|
|
251
|
+
),
|
|
252
|
+
),
|
|
242
253
|
removing ? h(RemoveConfirmation, {
|
|
243
254
|
account, busy: busy === 'delete', onConfirm: onConfirmRemove, onCancel: onCancelRemove,
|
|
244
255
|
}) : null);
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { WeixinLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import {
|
|
7
8
|
WEIXIN_ENDPOINTS,
|
|
@@ -225,11 +226,18 @@ export function AccountCard({
|
|
|
225
226
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
226
227
|
return h('article', { className: 'dxw-card dim-botCard', tabIndex: -1, 'data-bot-id': account.botId },
|
|
227
228
|
h('div', { className: 'dxw-cardBody dim-botCardBody' },
|
|
228
|
-
h(
|
|
229
|
+
h(CollapsibleAccountSection, {
|
|
230
|
+
id: `dxw-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
231
|
+
header: h('div', { className: 'dxw-accountTop dim-botCardTop' },
|
|
229
232
|
h('div', { className: 'dxw-accountIdentity dim-botIdentity' },
|
|
230
233
|
h('div', { className: 'dxw-avatar dim-botAvatar', 'aria-hidden': 'true' }, h(WeixinLogoGlyph, { size: 27 })),
|
|
231
234
|
h('div', { className: 'dim-botName' }, h('h3', null, account.bot.name), h('p', null, account.bot.accountIdMasked))),
|
|
232
|
-
h('div', {
|
|
235
|
+
h('div', {
|
|
236
|
+
className: 'dim-botCardTools',
|
|
237
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
238
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
239
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
240
|
+
},
|
|
233
241
|
h(BotStatusMeta, {
|
|
234
242
|
className: 'dxw-health',
|
|
235
243
|
dotClassName: 'dxw-dot',
|
|
@@ -244,8 +252,9 @@ export function AccountCard({
|
|
|
244
252
|
botName: account.bot.name,
|
|
245
253
|
connected: account.connected,
|
|
246
254
|
accessPolicy: account.accessPolicy,
|
|
247
|
-
})))
|
|
248
|
-
|
|
255
|
+
})))
|
|
256
|
+
},
|
|
257
|
+
h(WorkspaceEditor, {
|
|
249
258
|
workspace: account.workspace,
|
|
250
259
|
disabled: Boolean(busy),
|
|
251
260
|
onSave: onWorkspaceSave,
|
|
@@ -281,7 +290,9 @@ export function AccountCard({
|
|
|
281
290
|
className: 'dxw-summary dim-cardFeedback',
|
|
282
291
|
role: 'status',
|
|
283
292
|
'aria-live': 'polite',
|
|
284
|
-
}, feedback) : null))
|
|
293
|
+
}, feedback) : null)),
|
|
294
|
+
),
|
|
295
|
+
),
|
|
285
296
|
removing ? h('div', { className: 'dxw-confirm dim-confirm', role: 'alertdialog' },
|
|
286
297
|
h('strong', null, '从此 Harness 移除这个微信账号?'),
|
|
287
298
|
h('p', null, '这会停止消息连接,并删除本机保存的 bot_token、账号配置和会话映射。其他微信账号不受影响。'),
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { WhatsappLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
8
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -203,7 +204,9 @@ export function WhatsappAccountCard({
|
|
|
203
204
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
204
205
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
205
206
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
206
|
-
h(
|
|
207
|
+
h(CollapsibleAccountSection, {
|
|
208
|
+
id: `wsp-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
209
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
207
210
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
208
211
|
h('div', {
|
|
209
212
|
className: 'ddt-avatar dim-botAvatar dwa-avatar',
|
|
@@ -211,7 +214,12 @@ export function WhatsappAccountCard({
|
|
|
211
214
|
}, h(WhatsappLogoGlyph, { size: 29 })),
|
|
212
215
|
h('div', { className: 'dim-botName' },
|
|
213
216
|
h('h3', null, account.bot.name), h('p', null, account.bot.idMasked))),
|
|
214
|
-
h('div', {
|
|
217
|
+
h('div', {
|
|
218
|
+
className: 'dim-botCardTools',
|
|
219
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
220
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
221
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
222
|
+
},
|
|
215
223
|
h(BotStatusMeta, {
|
|
216
224
|
className: 'ddt-health',
|
|
217
225
|
dotClassName: 'ddt-dot',
|
|
@@ -226,8 +234,9 @@ export function WhatsappAccountCard({
|
|
|
226
234
|
botName: account.bot.name,
|
|
227
235
|
connected: account.connected,
|
|
228
236
|
accessPolicy: account.accessPolicy,
|
|
229
|
-
})))
|
|
230
|
-
|
|
237
|
+
})))
|
|
238
|
+
},
|
|
239
|
+
h(WorkspaceEditor, {
|
|
231
240
|
workspace: account.workspace,
|
|
232
241
|
disabled: Boolean(busy),
|
|
233
242
|
onSave: onWorkspaceSave,
|
|
@@ -264,7 +273,9 @@ export function WhatsappAccountCard({
|
|
|
264
273
|
testNotice ? h('div', {
|
|
265
274
|
className: 'ddt-summary dim-cardFeedback',
|
|
266
275
|
role: 'status',
|
|
267
|
-
}, testNotice) : null))
|
|
276
|
+
}, testNotice) : null)),
|
|
277
|
+
),
|
|
278
|
+
),
|
|
268
279
|
removing ? h(RemoveConfirmation, {
|
|
269
280
|
account,
|
|
270
281
|
busy: busy === 'delete',
|
|
@@ -227,6 +227,8 @@ const EN = Object.freeze({
|
|
|
227
227
|
'手动接入': 'Manual setup',
|
|
228
228
|
'收起凭据': 'Hide credentials',
|
|
229
229
|
'收起接入': 'Hide setup',
|
|
230
|
+
'展开该账号的设置': "Expand this account's settings",
|
|
231
|
+
'收起该账号的设置': "Collapse this account's settings",
|
|
230
232
|
'接入机器人': 'Connect bot',
|
|
231
233
|
'开始接入': 'Start setup',
|
|
232
234
|
'在线': 'online',
|
|
@@ -355,9 +355,21 @@ const CSS = String.raw`
|
|
|
355
355
|
.dim-panel .dim-cardActions .dim-cardAction { flex: none; min-height: 32px; padding: 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; font-weight: 560; line-height: normal; white-space: nowrap; }
|
|
356
356
|
.dim-panel .dim-cardActions .dim-cardAction:hover:not(:disabled) { border-color: #aeb3bb; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
357
357
|
.dim-panel .dim-cardActions .dim-cardAction[data-kind="danger"] { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
358
|
-
|
|
358
|
+
/* Header tooltips may extend beyond the card; the collapsible body clips its own content. */
|
|
359
|
+
.dim-panel .dim-botCard { position: relative; min-width: 0; width: 100%; max-width: 100%; overflow: visible; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 14px; background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 1px 2px rgb(31 35 41 / 3%); }
|
|
359
360
|
.dim-panel .dim-botCard::before { display: none; }
|
|
360
361
|
.dim-panel .dim-botCardBody { position: relative; min-width: 0; width: 100%; max-width: 100%; padding: 12px; }
|
|
362
|
+
.dim-collapsibleAccount { min-width: 0; display: flex; flex-direction: column; }
|
|
363
|
+
.dim-collapsibleHead { min-width: 0; display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; -webkit-user-select: none; }
|
|
364
|
+
.dim-collapsibleHead:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; border-radius: 8px; }
|
|
365
|
+
.dim-collapsibleHeaderContent { min-width: 0; flex: 1 1 auto; display: flex; align-items: center; }
|
|
366
|
+
.dim-collapsibleChevron { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 9px; height: 9px; border-right: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); border-bottom: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); transform: rotate(-45deg); transition: transform .22s cubic-bezier(.4, 0, .2, 1); transform-origin: 50% 50%; }
|
|
367
|
+
.dim-collapsibleAccount.is-open .dim-collapsibleChevron { transform: rotate(45deg); }
|
|
368
|
+
/* Animate height without measuring content; hide collapsed controls from focus and accessibility. */
|
|
369
|
+
.dim-collapsibleBody { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s cubic-bezier(.4, 0, .2, 1); }
|
|
370
|
+
.dim-collapsibleAccount.is-open > .dim-collapsibleBody { grid-template-rows: 1fr; }
|
|
371
|
+
.dim-collapsibleBodyInner { min-height: 0; overflow: hidden; }
|
|
372
|
+
.dim-collapsibleAccount:not(.is-open) .dim-collapsibleBodyInner { visibility: hidden; }
|
|
361
373
|
.dim-panel .dim-botCardTop { min-width: 0; max-width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
362
374
|
.dim-panel .dim-botIdentity { min-width: 0; flex: 1 1 0; display: flex; align-items: center; gap: 10px; }
|
|
363
375
|
.dim-panel .dim-botAvatar { flex: none; width: 38px; height: 38px; display: grid; place-items: center; overflow: hidden; border-radius: 11px; box-shadow: none; }
|
|
@@ -634,6 +646,7 @@ const CSS = String.raw`
|
|
|
634
646
|
@media (prefers-reduced-motion: reduce) {
|
|
635
647
|
.dim-page * { transition-duration: .01ms !important; }
|
|
636
648
|
.dim-directoryPickerSpinner { animation-duration: 1.8s; }
|
|
649
|
+
.dim-collapsibleBody, .dim-collapsibleChevron { transition: none !important; }
|
|
637
650
|
}
|
|
638
651
|
`;
|
|
639
652
|
|
|
@@ -22,19 +22,26 @@ export function createHarnessCommandExecutor(ctx, provided) {
|
|
|
22
22
|
try {
|
|
23
23
|
return await gateway.invoke(request);
|
|
24
24
|
} catch (error) {
|
|
25
|
-
//
|
|
26
|
-
//
|
|
25
|
+
// Host versions use no attachments, images, or submittedAttachments.
|
|
26
|
+
// Adapt only exact descriptor rejections before command dispatch, so
|
|
27
27
|
// a business failure can never cause compaction to run twice.
|
|
28
28
|
if (error?.name !== 'TypertGatewayError'
|
|
29
|
-
||
|
|
30
|
-
|| error.endpoint !== 'commands/execute'
|
|
31
|
-
|
|
29
|
+
|| !['arguments-invalid', 'gateway/arguments-invalid'].includes(error.code)
|
|
30
|
+
|| error.endpoint !== 'commands/execute') {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
let args;
|
|
34
|
+
if (error.message === 'typert gateway: commands/execute: args fields do not match the descriptor: unexpected "images"') {
|
|
35
|
+
args = { agentId: sessionId, line };
|
|
36
|
+
} else if (error.message === 'typert gateway: commands/execute: args fields do not match the descriptor: missing "submittedAttachments"; unexpected "images"') {
|
|
37
|
+
args = { agentId: sessionId, line, submittedAttachments: [] };
|
|
38
|
+
} else {
|
|
32
39
|
throw error;
|
|
33
40
|
}
|
|
34
41
|
options.signal?.throwIfAborted();
|
|
35
42
|
return gateway.invoke({
|
|
36
43
|
...request,
|
|
37
|
-
args
|
|
44
|
+
args,
|
|
38
45
|
});
|
|
39
46
|
}
|
|
40
47
|
};
|