@xmanrui/dsh-im 4.24.1 → 4.26.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 +12 -4
- package/PROACTIVE_DELIVERY.md +12 -4
- package/README.en.md +11 -3
- package/README.md +11 -3
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/lib/client.js +654 -311
- package/lib/index.js +298 -289
- package/package.json +7 -8
- package/plugin-src/client/channel-logos.js +11 -0
- package/plugin-src/client/channels/matrix/api.js +11 -0
- package/plugin-src/client/channels/matrix/index.js +151 -0
- package/plugin-src/client/channels/matrix/styles.js +36 -0
- package/plugin-src/client/global-settings.js +26 -14
- package/plugin-src/client/i18n.js +20 -0
- package/plugin-src/client/index.js +20 -0
- package/plugin-src/client/session-channel-logos.js +2 -1
- package/plugin-src/client/styles.js +19 -3
- package/plugin-src/client/update-panel.js +31 -11
- package/plugin-src/host/channels/matrix/index.mjs +31 -0
- package/plugin-src/host/channels/matrix/production.mjs +227 -0
- package/plugin-src/host/channels/matrix/rpc.mjs +228 -0
- package/plugin-src/host/channels/shared/access-policy-production.mjs +1 -1
- package/plugin-src/host/channels/shared/startup-error.mjs +2 -1
- package/plugin-src/host/delivery-adapter.mjs +18 -0
- package/plugin-src/host/delivery-rpc.mjs +7 -2
- package/plugin-src/host/delivery-service.mjs +8 -2
- package/plugin-src/host/delivery-suggestions.mjs +13 -0
- package/plugin-src/host/index.mjs +3 -0
- package/scripts/verify-injected-context.mjs +120 -0
- package/scripts/verify-lan-management.mjs +1 -1
- package/scripts/verify-package.mjs +6 -1
- package/src/channels/feishu/feishu-runtime.mjs +13 -3
- package/src/channels/matrix/matrix-api.mjs +696 -0
- package/src/channels/matrix/matrix-bridge.mjs +20 -0
- package/src/channels/matrix/matrix-config-store.mjs +356 -0
- package/src/channels/matrix/matrix-controller.mjs +404 -0
- package/src/channels/matrix/matrix-crypto-store.mjs +279 -0
- package/src/channels/matrix/matrix-crypto.mjs +1014 -0
- package/src/channels/matrix/matrix-harness-client.mjs +11 -0
- package/src/channels/matrix/matrix-normalize.mjs +357 -0
- package/src/channels/matrix/matrix-rich-text.mjs +313 -0
- package/src/channels/matrix/matrix-runtime.mjs +900 -0
- package/src/channels/shared/command-catalog.mjs +1 -1
- package/src/channels/shared/i18n-en/image-input.mjs +1 -0
- package/src/channels/shared/i18n-en/matrix.mjs +75 -0
- package/src/channels/shared/i18n-en.mjs +2 -0
- package/src/channels/shared/injected-context.mjs +3 -3
- package/src/channels/shared/session-channel-labels.mjs +1 -0
- package/src/channels/shared/text-harness-bridge.mjs +3 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmanrui/dsh-im",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.26.0",
|
|
4
|
+
"description": "把十二种 IM 渠道和公网 AI Office 接入本机 DeepSeek Harness。 Connect twelve IM channels and a public AI Office to a local DeepSeek Harness.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
7
7
|
"dsh",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"discord",
|
|
22
22
|
"whatsapp",
|
|
23
23
|
"imessage",
|
|
24
|
+
"matrix",
|
|
24
25
|
"ai-office"
|
|
25
26
|
],
|
|
26
27
|
"author": "xmanrui (https://github.com/xmanrui)",
|
|
@@ -115,6 +116,7 @@
|
|
|
115
116
|
"lib",
|
|
116
117
|
"plugin-src",
|
|
117
118
|
"scripts/verify-interface-language.mjs",
|
|
119
|
+
"scripts/verify-injected-context.mjs",
|
|
118
120
|
"scripts/verify-lan-management.mjs",
|
|
119
121
|
"scripts/verify-model-setting.mjs",
|
|
120
122
|
"scripts/verify-package.mjs",
|
|
@@ -144,13 +146,9 @@
|
|
|
144
146
|
"platform": "web"
|
|
145
147
|
},
|
|
146
148
|
"compatibility": {
|
|
147
|
-
"dsh": "0.1.
|
|
149
|
+
"dsh": "0.1.7-alpha.1",
|
|
148
150
|
"dshReleases": {
|
|
149
|
-
"0.1.
|
|
150
|
-
"0.1.2-alpha.5": "compatible",
|
|
151
|
-
"0.1.2-rc.1": "compatible",
|
|
152
|
-
"0.1.3-alpha.1": "compatible",
|
|
153
|
-
"0.1.5-alpha.1": "compatible"
|
|
151
|
+
"0.1.7-alpha.1": "compatible"
|
|
154
152
|
},
|
|
155
153
|
"profiles": [
|
|
156
154
|
"web"
|
|
@@ -166,6 +164,7 @@
|
|
|
166
164
|
"node": ">=22.19"
|
|
167
165
|
},
|
|
168
166
|
"dependencies": {
|
|
167
|
+
"@matrix-org/olm": "3.2.15",
|
|
169
168
|
"@tencent-connect/qqbot-connector": "1.2.0",
|
|
170
169
|
"@tencent-connect/qqbot-nodejs": "1.0.4",
|
|
171
170
|
"@wecom/aibot-node-sdk": "1.0.7",
|
|
@@ -155,6 +155,17 @@ export function IMessageLogoGlyph({ size } = {}) {
|
|
|
155
155
|
}));
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
export function MatrixLogoGlyph({ size } = {}) {
|
|
159
|
+
return h('svg', {
|
|
160
|
+
...dimensions(size), viewBox: '0 0 24 24', focusable: 'false',
|
|
161
|
+
'aria-hidden': 'true', 'data-im-channel-logo': 'matrix',
|
|
162
|
+
}, h('path', {
|
|
163
|
+
fill: 'currentColor',
|
|
164
|
+
'fill-rule': 'evenodd',
|
|
165
|
+
d: 'M4 4h16a2.4 2.4 0 0 1 2.4 2.4v8.2A2.4 2.4 0 0 1 20 17h-7.55l-4.2 3.3a.6.6 0 0 1-.98-.47V17H4A2.4 2.4 0 0 1 1.6 14.6V6.4A2.4 2.4 0 0 1 4 4Zm3 4.1a1.45 1.45 0 1 0 0 2.9 1.45 1.45 0 0 0 0-2.9Zm5.6 0a1.45 1.45 0 1 0 0 2.9 1.45 1.45 0 0 0 0-2.9Zm5.6 0a1.45 1.45 0 1 0 0 2.9 1.45 1.45 0 0 0 0-2.9Z',
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
|
|
158
169
|
export function OfficeLogoGlyph({ size } = {}) {
|
|
159
170
|
return h('svg', {
|
|
160
171
|
...dimensions(size),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TOKEN_BOT_ENDPOINTS, createTokenChannelApi } from '../shared/token-api.js';
|
|
2
|
+
|
|
3
|
+
export const MATRIX_RPC_CHANNEL = '/matrix';
|
|
4
|
+
export const MATRIX_ENDPOINTS = TOKEN_BOT_ENDPOINTS;
|
|
5
|
+
|
|
6
|
+
const api = createTokenChannelApi('Matrix', ' CS API 长轮询');
|
|
7
|
+
|
|
8
|
+
export const unwrapRpcResult = api.unwrapRpcResult;
|
|
9
|
+
export const normalizeSnapshot = api.normalizeSnapshot;
|
|
10
|
+
export const presentError = api.presentError;
|
|
11
|
+
export { api as matrixClientApi };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { MatrixLogoGlyph } from '../../channel-logos.js';
|
|
4
|
+
import { h } from '../../i18n.js';
|
|
5
|
+
import { createTokenChannelSettings } from '../shared/token-channel.js';
|
|
6
|
+
import { MATRIX_ENDPOINTS, matrixClientApi } from './api.js';
|
|
7
|
+
import { installMatrixStyles } from './styles.js';
|
|
8
|
+
|
|
9
|
+
const MATRIX_USER_ID_PATTERN = /^@[^:@\s]+:[^:@\s]+(?::\d{1,5})?$/u;
|
|
10
|
+
|
|
11
|
+
function validHomeserver(value) {
|
|
12
|
+
if (!value || value.length > 2_048) return false;
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(value);
|
|
15
|
+
return (url.protocol === 'https:' || url.protocol === 'http:')
|
|
16
|
+
&& !url.username && !url.password && !url.hash;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function MatrixCredentialPanel({ busy, error, onSubmit, onCancel }) {
|
|
23
|
+
const [homeserver, setHomeserver] = React.useState('');
|
|
24
|
+
const [accessToken, setAccessToken] = React.useState('');
|
|
25
|
+
const [userId, setUserId] = React.useState('');
|
|
26
|
+
const [password, setPassword] = React.useState('');
|
|
27
|
+
const headingId = React.useId();
|
|
28
|
+
|
|
29
|
+
const normalizedHomeserver = homeserver.trim();
|
|
30
|
+
const normalizedUserId = userId.trim();
|
|
31
|
+
const tokenMode = Boolean(accessToken.trim());
|
|
32
|
+
const loginMode = Boolean(normalizedUserId) && Boolean(password);
|
|
33
|
+
const canSubmit = validHomeserver(normalizedHomeserver)
|
|
34
|
+
&& (tokenMode
|
|
35
|
+
? (!normalizedUserId && !password && accessToken.trim().length >= 8)
|
|
36
|
+
: (!accessToken.trim() && MATRIX_USER_ID_PATTERN.test(normalizedUserId) && password.length >= 1));
|
|
37
|
+
|
|
38
|
+
const submit = (event) => {
|
|
39
|
+
event.preventDefault();
|
|
40
|
+
if (!canSubmit || busy) return;
|
|
41
|
+
void onSubmit?.(tokenMode
|
|
42
|
+
? { homeserver: normalizedHomeserver, accessToken: accessToken.trim() }
|
|
43
|
+
: {
|
|
44
|
+
homeserver: normalizedHomeserver,
|
|
45
|
+
userId: normalizedUserId,
|
|
46
|
+
password,
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return h('section', {
|
|
51
|
+
className: 'ddt-card dim-surfaceCard dim-credentialPanel dmt-setup',
|
|
52
|
+
'aria-labelledby': headingId,
|
|
53
|
+
},
|
|
54
|
+
h('h3', { id: headingId, className: 'dim-credentialTitle' }, '接入 Matrix 机器人'),
|
|
55
|
+
h('div', { className: 'dmt-guide' },
|
|
56
|
+
h('div', { className: 'dmt-guideCopy' },
|
|
57
|
+
h('strong', null, '连接你的 Matrix homeserver'),
|
|
58
|
+
h('p', null, '填写 homeserver 地址,并提供访问令牌,或者用户 ID 与密码的组合。机器人只访问该 homeserver,不连接第三方服务器。'))),
|
|
59
|
+
h('form', { className: 'dim-credentialForm dim-credentialFormSingle', onSubmit: submit },
|
|
60
|
+
h('div', { className: 'dmt-fields' },
|
|
61
|
+
h('label', { className: 'dim-credentialField dmt-fieldWide' },
|
|
62
|
+
h('span', null, 'Homeserver 地址'),
|
|
63
|
+
h('input', {
|
|
64
|
+
type: 'url',
|
|
65
|
+
value: homeserver,
|
|
66
|
+
onChange: (event) => setHomeserver(event.target.value),
|
|
67
|
+
placeholder: 'https://matrix.example.org',
|
|
68
|
+
maxLength: 2048,
|
|
69
|
+
autoCapitalize: 'none',
|
|
70
|
+
autoCorrect: 'off',
|
|
71
|
+
spellCheck: false,
|
|
72
|
+
disabled: busy,
|
|
73
|
+
required: true,
|
|
74
|
+
})),
|
|
75
|
+
h('label', { className: 'dim-credentialField dmt-fieldWide' },
|
|
76
|
+
h('span', null, '访问令牌(与用户 ID、密码二选一)'),
|
|
77
|
+
h('input', {
|
|
78
|
+
type: 'password',
|
|
79
|
+
value: accessToken,
|
|
80
|
+
onChange: (event) => setAccessToken(event.target.value),
|
|
81
|
+
placeholder: 'syt_…',
|
|
82
|
+
maxLength: 4096,
|
|
83
|
+
autoCapitalize: 'none',
|
|
84
|
+
autoCorrect: 'off',
|
|
85
|
+
spellCheck: false,
|
|
86
|
+
autoComplete: 'new-password',
|
|
87
|
+
disabled: busy,
|
|
88
|
+
})),
|
|
89
|
+
h('label', { className: 'dim-credentialField' },
|
|
90
|
+
h('span', null, '用户 ID(可选)'),
|
|
91
|
+
h('input', {
|
|
92
|
+
type: 'text',
|
|
93
|
+
value: userId,
|
|
94
|
+
onChange: (event) => setUserId(event.target.value),
|
|
95
|
+
placeholder: '@bot:example.org',
|
|
96
|
+
maxLength: 512,
|
|
97
|
+
autoCapitalize: 'none',
|
|
98
|
+
autoCorrect: 'off',
|
|
99
|
+
spellCheck: false,
|
|
100
|
+
disabled: busy,
|
|
101
|
+
})),
|
|
102
|
+
h('label', { className: 'dim-credentialField' },
|
|
103
|
+
h('span', null, '密码(可选)'),
|
|
104
|
+
h('input', {
|
|
105
|
+
type: 'password',
|
|
106
|
+
value: password,
|
|
107
|
+
onChange: (event) => setPassword(event.target.value),
|
|
108
|
+
maxLength: 1024,
|
|
109
|
+
autoComplete: 'new-password',
|
|
110
|
+
disabled: busy,
|
|
111
|
+
})),
|
|
112
|
+
h('p', { className: 'dmt-tokenHint' }, '访问令牌来自 Element 设置 → 帮助 → 编辑设置,或 homeserver 的登录接口;用户 ID 与密码方式会为本安装派生稳定设备会话。')),
|
|
113
|
+
error ? h('p', { className: 'dim-credentialError', role: 'alert' }, error.message ?? String(error)) : null,
|
|
114
|
+
h('div', { className: 'ddt-actions dim-viewActions dim-credentialActions' },
|
|
115
|
+
h('button', {
|
|
116
|
+
type: 'submit',
|
|
117
|
+
className: 'ddt-button',
|
|
118
|
+
'data-kind': 'primary',
|
|
119
|
+
disabled: busy || !canSubmit,
|
|
120
|
+
}, busy ? '正在验证并连接…' : '验证并连接'),
|
|
121
|
+
h('button', {
|
|
122
|
+
type: 'button',
|
|
123
|
+
className: 'ddt-button',
|
|
124
|
+
onClick: onCancel,
|
|
125
|
+
disabled: busy,
|
|
126
|
+
}, '取消'))));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const channel = createTokenChannelSettings({
|
|
130
|
+
channel: 'Matrix',
|
|
131
|
+
endpoints: MATRIX_ENDPOINTS,
|
|
132
|
+
api: matrixClientApi,
|
|
133
|
+
LogoGlyph: MatrixLogoGlyph,
|
|
134
|
+
installStyles: installMatrixStyles,
|
|
135
|
+
pageClass: 'dmt-page',
|
|
136
|
+
avatarClass: 'dmt-avatar',
|
|
137
|
+
connectionLabel: 'CS API 长轮询',
|
|
138
|
+
emptyTitle: '接入 Matrix 机器人',
|
|
139
|
+
emptyDescription: '填写 homeserver 地址与访问令牌,或者用户 ID 与密码,即可让机器人以 CS API 长轮询接收消息并以富文本回复。',
|
|
140
|
+
platformLabel: 'Matrix homeserver',
|
|
141
|
+
CredentialPanel: MatrixCredentialPanel,
|
|
142
|
+
credentialPayload: ({ homeserver, accessToken, userId, password }) => ({ homeserver, accessToken, userId, password }),
|
|
143
|
+
credentialAriaLabel: '使用 homeserver 与凭据接入 Matrix 机器人',
|
|
144
|
+
credentialOpenLabel: '接入机器人',
|
|
145
|
+
credentialCloseLabel: '收起接入',
|
|
146
|
+
credentialNoun: '访问令牌或用户 ID 与密码',
|
|
147
|
+
emptyActionLabel: '开始接入',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
export const MatrixSettingsTab = channel.SettingsTab;
|
|
151
|
+
export const MatrixAccountCard = channel.AccountCard;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const MATRIX_STYLE_ID = 'xmanrui-dsh-im-matrix-settings';
|
|
2
|
+
|
|
3
|
+
const CSS = String.raw`
|
|
4
|
+
.dmt-page { --ddt-accent: #1a8f6f; --ddt-accent-deep: #12654f; --ddt-accent-wash: #eef8f4; }
|
|
5
|
+
.dmt-avatar { background: linear-gradient(145deg, #fff, #f6faf8); border: 1px solid #e2eae7; }
|
|
6
|
+
.dmt-avatar svg { display: block; }
|
|
7
|
+
.dim-logoMatrix { color: white; background: #0dbd8b; }
|
|
8
|
+
.dim-logoMatrix svg { width: 22px; height: 22px; }
|
|
9
|
+
.dmt-setup { display: grid; gap: 18px; }
|
|
10
|
+
.dmt-guide { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 18px; padding: 16px; border: 1px solid color-mix(in srgb, #1a8f6f 18%, var(--dsw-alias-border-l2, #e5e6eb)); border-radius: 11px; background: color-mix(in srgb, #1a8f6f 4%, var(--dsw-alias-bg-layer-1, #fff)); }
|
|
11
|
+
.dmt-guideCopy { min-width: 0; }
|
|
12
|
+
.dmt-guideCopy strong { display: block; margin-bottom: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; }
|
|
13
|
+
.dmt-guideCopy p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 1.6; }
|
|
14
|
+
.dmt-guideActions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
|
|
15
|
+
.dmt-guideActions .ddt-button { white-space: nowrap; }
|
|
16
|
+
.dmt-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
17
|
+
.dmt-fields .dmt-fieldWide { grid-column: 1 / -1; }
|
|
18
|
+
.dmt-tokenHint { grid-column: 1 / -1; margin: -4px 0 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.55; }
|
|
19
|
+
@container (max-width: 680px) {
|
|
20
|
+
.dmt-guide { grid-template-columns: minmax(0, 1fr); }
|
|
21
|
+
.dmt-guideActions { justify-content: flex-start; }
|
|
22
|
+
.dmt-fields { grid-template-columns: minmax(0, 1fr); }
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
export function installMatrixStyles() {
|
|
27
|
+
if (typeof document === 'undefined') return () => {};
|
|
28
|
+
const existing = document.querySelector(`style[data-plugin-css="${MATRIX_STYLE_ID}"]`);
|
|
29
|
+
if (existing) return () => {};
|
|
30
|
+
const style = document.createElement('style');
|
|
31
|
+
style.dataset.plugin = '@xmanrui/dsh-im';
|
|
32
|
+
style.dataset.pluginCss = MATRIX_STYLE_ID;
|
|
33
|
+
style.textContent = CSS;
|
|
34
|
+
document.head.appendChild(style);
|
|
35
|
+
return () => style.remove();
|
|
36
|
+
}
|
|
@@ -118,21 +118,33 @@ export function ImageInputSettings({ rpcCall }) {
|
|
|
118
118
|
['maxTotalMb', '模型图片总量上限 (MB)'],
|
|
119
119
|
['maxImages', '每条消息最多图片数'],
|
|
120
120
|
];
|
|
121
|
-
return h('section', { className: 'dim-globalSection', 'aria-label': '图片输入', 'aria-busy': phase === 'loading' || phase === 'saving' },
|
|
122
|
-
h('
|
|
123
|
-
|
|
121
|
+
return h('section', { className: 'dim-globalSection dim-imageSettings', 'aria-label': '图片输入', 'aria-busy': phase === 'loading' || phase === 'saving' },
|
|
122
|
+
h('div', { className: 'dim-globalHead' },
|
|
123
|
+
h('div', { className: 'dim-globalHeadTitle' },
|
|
124
|
+
h('h3', null, '图片输入'),
|
|
125
|
+
h('div', { className: 'dim-globalTtlHelp' },
|
|
126
|
+
h('button', {
|
|
127
|
+
type: 'button',
|
|
128
|
+
className: 'dim-channelHelpButton dim-globalTtlHelpButton',
|
|
129
|
+
'aria-label': '查看图片输入说明',
|
|
130
|
+
'aria-describedby': `${id}-help`,
|
|
131
|
+
}, h('span', { 'aria-hidden': 'true' }, '?')),
|
|
132
|
+
h('div', { id: `${id}-help`, className: 'dim-globalTtlTooltip dim-imageSettingsTooltip', role: 'tooltip' },
|
|
133
|
+
'适用于支持图片的聊天渠道。原图按附件保留时长保存,发送给模型的副本会自动缩放或压缩;无法直接发送时交给模型按文件处理。')))),
|
|
124
134
|
h('form', { onSubmit: save },
|
|
125
|
-
|
|
126
|
-
h('
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
h('div', { className: 'dim-imageSettingsFields' },
|
|
136
|
+
...fields.map(([key, label]) => h('div', { className: 'dim-imageSettingsField', key },
|
|
137
|
+
h('label', { htmlFor: `${id}-${key}` }, label),
|
|
138
|
+
h('input', { id: `${id}-${key}`, className: 'dim-globalTtlInput', type: 'number', min: 1, step: 1,
|
|
139
|
+
value: values[key], disabled: phase !== 'ready',
|
|
140
|
+
onChange: (event) => { setValues((current) => ({ ...current, [key]: event.target.value })); setSaved(false); setError(null); },
|
|
141
|
+
})))),
|
|
142
|
+
h('div', { className: 'dim-imageSettingsActions' },
|
|
143
|
+
h(GlobalButton, { type: 'submit', kind: 'primary', className: 'dim-globalSaveButton', disabled: phase !== 'ready' }, phase === 'saving' ? '保存中…' : '保存图片设置'),
|
|
144
|
+
phase === 'error' ? h(GlobalButton, { className: 'dim-globalSaveButton', onClick: () => void load() }, '重试') : null)),
|
|
145
|
+
error ? h('p', { className: 'dim-globalInline dim-imageSettingsFeedback', 'data-tone': 'error', role: 'alert' }, error) : null,
|
|
146
|
+
saved ? h('p', { className: 'dim-globalInline dim-imageSettingsFeedback', role: 'status' }, '已保存') : null,
|
|
147
|
+
phase === 'loading' ? h('p', { className: 'dim-globalInline dim-imageSettingsFeedback', role: 'status' }, '正在读取图片设置…') : null);
|
|
136
148
|
}
|
|
137
149
|
|
|
138
150
|
export function GlobalSettingsPanel({ rpcCall }) {
|
|
@@ -108,6 +108,10 @@ const EN = Object.freeze({
|
|
|
108
108
|
'当前版本': 'Current version',
|
|
109
109
|
'DSH-IM 更新': 'DSH-IM update',
|
|
110
110
|
'检查更新': 'Check for updates',
|
|
111
|
+
'DSH 版本兼容说明': 'DSH version compatibility',
|
|
112
|
+
'dsh-im 4.25.0 支持到 DSH v0.1.6-alpha.2。': 'dsh-im 4.25.0 supports DSH up to v0.1.6-alpha.2.',
|
|
113
|
+
'dsh-im 4.26.0 仅支持 DSH v0.1.7-alpha.1。': 'dsh-im 4.26.0 only supports DSH v0.1.7-alpha.1.',
|
|
114
|
+
'升级到 dsh-im 4.26.0 前,请先将 DSH 升级到 v0.1.7-alpha.1;使用旧版 DSH 请保留 dsh-im 4.25.0。': 'Before updating to dsh-im 4.26.0, upgrade DSH to v0.1.7-alpha.1. If you use an older DSH version, stay on dsh-im 4.25.0.',
|
|
111
115
|
'重新检查': 'Check again',
|
|
112
116
|
'刷新状态': 'Refresh status',
|
|
113
117
|
'手工更新': 'Manual update',
|
|
@@ -671,6 +675,22 @@ const EN = Object.freeze({
|
|
|
671
675
|
'Gateway 长连接': 'Gateway persistent connection',
|
|
672
676
|
' Socket Mode 长连接': ' Socket Mode persistent connection',
|
|
673
677
|
'Socket Mode 长连接': 'Socket Mode persistent connection',
|
|
678
|
+
' CS API 长轮询': ' CS API long polling',
|
|
679
|
+
'CS API 长轮询': 'CS API long polling',
|
|
680
|
+
'接入 Matrix 机器人': 'Connect a Matrix bot',
|
|
681
|
+
'连接你的 Matrix homeserver': 'Connect your Matrix homeserver',
|
|
682
|
+
'填写 homeserver 地址,并提供访问令牌,或者用户 ID 与密码的组合。机器人只访问该 homeserver,不连接第三方服务器。':
|
|
683
|
+
'Enter the homeserver URL plus an access token, or a user id with a password. The bot only talks to that homeserver and never to third-party servers.',
|
|
684
|
+
'Homeserver 地址': 'Homeserver URL',
|
|
685
|
+
'访问令牌(与用户 ID、密码二选一)': 'Access token (or user id + password)',
|
|
686
|
+
'用户 ID(可选)': 'User id (optional)',
|
|
687
|
+
'密码(可选)': 'Password (optional)',
|
|
688
|
+
'访问令牌来自 Element 设置 → 帮助 → 编辑设置,或 homeserver 的登录接口;用户 ID 与密码方式会为本安装派生稳定设备会话。':
|
|
689
|
+
'The access token comes from Element settings → Help → Advanced settings, or from the homeserver login API; the user id and password flow derives a stable device session for this installation.',
|
|
690
|
+
'填写 homeserver 地址与访问令牌,或者用户 ID 与密码,即可让机器人以 CS API 长轮询接收消息并以富文本回复。':
|
|
691
|
+
'Enter the homeserver URL with an access token, or a user id with a password, and the bot receives messages over the CS API long poll and replies with rich text.',
|
|
692
|
+
'使用 homeserver 与凭据接入 Matrix 机器人': 'Connect a Matrix bot with the homeserver and credentials',
|
|
693
|
+
'访问令牌或用户 ID 与密码': 'access token or user id with password',
|
|
674
694
|
'接入 Telegram 机器人': 'Connect a Telegram bot',
|
|
675
695
|
'先通过 @BotFather 获取 Bot Token,再在这里完成接入。': 'Get a Bot Token from @BotFather, then connect it here.',
|
|
676
696
|
'填写 @BotFather 生成的 Bot Token': 'Enter the Bot Token from @BotFather',
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
WhatsappLogoGlyph,
|
|
16
16
|
IMessageLogoGlyph,
|
|
17
17
|
EmailLogoGlyph,
|
|
18
|
+
MatrixLogoGlyph,
|
|
18
19
|
} from './channel-logos.js';
|
|
19
20
|
import { DINGTALK_RPC_CHANNEL } from './channels/dingtalk/api.js';
|
|
20
21
|
import { DingtalkSettingsTab } from './channels/dingtalk/index.js';
|
|
@@ -54,6 +55,9 @@ import { IMessageSettingsTab } from './channels/imessage/index.js';
|
|
|
54
55
|
import { EmailSettingsTab, useEmailChannelEnabled } from './channels/email/index.js';
|
|
55
56
|
import { installIMessageStyles } from './channels/imessage/styles.js';
|
|
56
57
|
import { installEmailStyles } from './channels/email/styles.js';
|
|
58
|
+
import { MATRIX_RPC_CHANNEL } from './channels/matrix/api.js';
|
|
59
|
+
import { MatrixSettingsTab } from './channels/matrix/index.js';
|
|
60
|
+
import { installMatrixStyles } from './channels/matrix/styles.js';
|
|
57
61
|
import { en, h, IM_LOCALE_NAMESPACE, setImTranslator, zh } from './i18n.js';
|
|
58
62
|
import {
|
|
59
63
|
HOST_LANGUAGE_RPC_CHANNEL,
|
|
@@ -107,6 +111,7 @@ const CHANNELS = Object.freeze([
|
|
|
107
111
|
{ id: 'wecomApp', label: '企业微信应用', note: '(实验功能)' },
|
|
108
112
|
{ id: 'imessage', label: 'iMessage', note: '(实验功能)' },
|
|
109
113
|
{ id: 'email', label: '邮箱', note: '(实验功能)' },
|
|
114
|
+
{ id: 'matrix', label: 'Matrix', note: '(实验功能)' },
|
|
110
115
|
{ id: 'office', label: 'AI Office', note: '(实验功能)' },
|
|
111
116
|
]);
|
|
112
117
|
|
|
@@ -167,6 +172,11 @@ function EmailLogo() {
|
|
|
167
172
|
h(EmailLogoGlyph));
|
|
168
173
|
}
|
|
169
174
|
|
|
175
|
+
function MatrixLogo() {
|
|
176
|
+
return h('span', { className: 'dim-logo dim-logoMatrix', 'aria-hidden': 'true' },
|
|
177
|
+
h(MatrixLogoGlyph));
|
|
178
|
+
}
|
|
179
|
+
|
|
170
180
|
function OfficeLogo() {
|
|
171
181
|
return h('span', { className: 'dim-logo dim-logoOffice', 'aria-hidden': 'true' },
|
|
172
182
|
h(OfficeLogoGlyph));
|
|
@@ -185,6 +195,7 @@ function ChannelLogo({ channel }) {
|
|
|
185
195
|
if (channel === 'whatsapp') return h(WhatsappLogo);
|
|
186
196
|
if (channel === 'imessage') return h(IMessageLogo);
|
|
187
197
|
if (channel === 'email') return h(EmailLogo);
|
|
198
|
+
if (channel === 'matrix') return h(MatrixLogo);
|
|
188
199
|
return h(OfficeLogo);
|
|
189
200
|
}
|
|
190
201
|
|
|
@@ -210,6 +221,7 @@ export function IMSettingsTab({
|
|
|
210
221
|
feishuRpcCall,
|
|
211
222
|
imessageRpcCall,
|
|
212
223
|
emailRpcCall,
|
|
224
|
+
matrixRpcCall,
|
|
213
225
|
qqRpcCall,
|
|
214
226
|
slackRpcCall,
|
|
215
227
|
telegramRpcCall,
|
|
@@ -275,6 +287,7 @@ export function IMSettingsTab({
|
|
|
275
287
|
globalSettingsRpcCall,
|
|
276
288
|
imessageRpcCall,
|
|
277
289
|
emailRpcCall,
|
|
290
|
+
matrixRpcCall,
|
|
278
291
|
}, {
|
|
279
292
|
location: browserLocation,
|
|
280
293
|
onRecovery: reportLoopbackRecovery,
|
|
@@ -287,6 +300,7 @@ export function IMSettingsTab({
|
|
|
287
300
|
globalSettingsRpcCall,
|
|
288
301
|
imessageRpcCall,
|
|
289
302
|
emailRpcCall,
|
|
303
|
+
matrixRpcCall,
|
|
290
304
|
officeRpcCall,
|
|
291
305
|
qqRpcCall,
|
|
292
306
|
reportLoopbackRecovery,
|
|
@@ -427,6 +441,8 @@ export function IMSettingsTab({
|
|
|
427
441
|
? h(IMessageSettingsTab, { rpcCall: rpcCalls.imessageRpcCall })
|
|
428
442
|
: active.id === 'email'
|
|
429
443
|
? h(EmailSettingsTab, { rpcCall: rpcCalls.emailRpcCall })
|
|
444
|
+
: active.id === 'matrix'
|
|
445
|
+
? h(MatrixSettingsTab, { rpcCall: rpcCalls.matrixRpcCall })
|
|
430
446
|
: h(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall }))),
|
|
431
447
|
),
|
|
432
448
|
));
|
|
@@ -466,6 +482,7 @@ export function apply(ctx) {
|
|
|
466
482
|
installWhatsappStyles(),
|
|
467
483
|
installIMessageStyles(),
|
|
468
484
|
installEmailStyles(),
|
|
485
|
+
installMatrixStyles(),
|
|
469
486
|
installOfficeStyles(),
|
|
470
487
|
installImStyles(),
|
|
471
488
|
];
|
|
@@ -496,6 +513,8 @@ export function apply(ctx) {
|
|
|
496
513
|
callManagementRpc(ctx.connection, IMESSAGE_RPC_CHANNEL, endpoint, payload, signal);
|
|
497
514
|
const emailRpcCall = (endpoint, payload, signal) =>
|
|
498
515
|
callManagementRpc(ctx.connection, EMAIL_RPC_CHANNEL, endpoint, payload, signal);
|
|
516
|
+
const matrixRpcCall = (endpoint, payload, signal) =>
|
|
517
|
+
callManagementRpc(ctx.connection, MATRIX_RPC_CHANNEL, endpoint, payload, signal);
|
|
499
518
|
const slackRpcCall = (endpoint, payload, signal) =>
|
|
500
519
|
callManagementRpc(ctx.connection, SLACK_RPC_CHANNEL, endpoint, payload, signal);
|
|
501
520
|
const officeRpcCall = (endpoint, payload, signal) =>
|
|
@@ -526,6 +545,7 @@ export function apply(ctx) {
|
|
|
526
545
|
imessageRpcCall,
|
|
527
546
|
officeRpcCall,
|
|
528
547
|
emailRpcCall,
|
|
548
|
+
matrixRpcCall,
|
|
529
549
|
updateRpcCall,
|
|
530
550
|
deliveryRpcCall,
|
|
531
551
|
globalSettingsRpcCall,
|
|
@@ -2,7 +2,7 @@ import { parseSessionChannelTitle } from '../../src/channels/shared/session-chan
|
|
|
2
2
|
import {
|
|
3
3
|
WeixinLogoGlyph, FeishuLogoGlyph, DingtalkLogoGlyph, WecomLogoGlyph, QqLogoGlyph,
|
|
4
4
|
SlackLogoGlyph, TelegramLogoGlyph, DiscordLogoGlyph, WhatsappLogoGlyph, OfficeLogoGlyph,
|
|
5
|
-
IMessageLogoGlyph,
|
|
5
|
+
IMessageLogoGlyph, MatrixLogoGlyph,
|
|
6
6
|
} from './channel-logos.js';
|
|
7
7
|
|
|
8
8
|
const GLYPHS = Object.freeze({
|
|
@@ -16,6 +16,7 @@ const GLYPHS = Object.freeze({
|
|
|
16
16
|
discord: [DiscordLogoGlyph, '#5865f2'],
|
|
17
17
|
whatsapp: [WhatsappLogoGlyph, '#25d366'],
|
|
18
18
|
imessage: [IMessageLogoGlyph, '#3478f6'],
|
|
19
|
+
matrix: [MatrixLogoGlyph, '#1a8f6f'],
|
|
19
20
|
office: [OfficeLogoGlyph, '#f97316'],
|
|
20
21
|
});
|
|
21
22
|
const CHANNEL_ATTR = 'data-dsh-im-session-channel';
|
|
@@ -60,7 +60,9 @@ const CSS = String.raw`
|
|
|
60
60
|
.dim-updateButton:hover:not(:disabled) { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
61
61
|
.dim-updateButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
|
|
62
62
|
.dim-updateButton:disabled { opacity: .55; cursor: default; }
|
|
63
|
-
.dim-
|
|
63
|
+
.dim-updateAction { position: relative; display: inline-flex; flex: none; }
|
|
64
|
+
.dim-updateTrigger { width: 30px; height: 30px; flex: none; padding: 0; }
|
|
65
|
+
.dim-updateTrigger svg { display: block; }
|
|
64
66
|
.dim-updateBackdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); }
|
|
65
67
|
.dim-updateBackdrop, .dim-updateBackdrop * { box-sizing: border-box; }
|
|
66
68
|
.dim-updateDialog { width: min(480px, 100%); max-height: calc(100vh - 48px); overflow-y: auto; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 16px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 20px 70px rgb(0 0 0 / 20%); text-align: left; }
|
|
@@ -97,8 +99,8 @@ const CSS = String.raw`
|
|
|
97
99
|
.dim-githubLink svg { display: block; }
|
|
98
100
|
.dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
99
101
|
.dim-githubLink:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
|
|
100
|
-
.dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
101
|
-
.dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
102
|
+
.dim-updateTooltip, .dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
103
|
+
.dim-updateAction:hover .dim-updateTooltip, .dim-updateTrigger:focus-visible + .dim-updateTooltip, .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
102
104
|
.dim-generalSettingsAction { position: relative; display: inline-flex; flex: none; }
|
|
103
105
|
.dim-generalSettingsButton { width: 30px; height: 30px; display: grid; place-items: center; flex: none; padding: 0; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); cursor: pointer; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
|
|
104
106
|
.dim-generalSettingsButton svg { display: block; }
|
|
@@ -611,6 +613,20 @@ const CSS = String.raw`
|
|
|
611
613
|
.dim-generalSettingsTab:focus-visible { outline: 2px solid var(--dim-blue); outline-offset: -2px; border-radius: 5px; }
|
|
612
614
|
.dim-generalSettingsTabPanel { min-width: 0; padding-top: 14px; }
|
|
613
615
|
.dim-globalSection { min-width: 0; padding: 14px 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
|
|
616
|
+
.dim-globalSection + .dim-globalSection { margin-top: 12px; }
|
|
617
|
+
.dim-imageSettings { container-type: inline-size; }
|
|
618
|
+
.dim-imageSettings .dim-globalHead { position: relative; }
|
|
619
|
+
.dim-imageSettings .dim-globalTtlHelp { position: static; }
|
|
620
|
+
.dim-globalTtlTooltip.dim-imageSettingsTooltip { width: min(320px, 100%); max-width: none; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; white-space: normal; overflow-wrap: anywhere; }
|
|
621
|
+
.dim-imageSettingsFields { min-width: 0; display: grid; gap: 12px; margin-top: 12px; }
|
|
622
|
+
.dim-imageSettingsField { min-width: 0; display: grid; grid-template-columns: minmax(0, 220px) minmax(0, 160px); align-items: center; gap: 6px 16px; }
|
|
623
|
+
.dim-imageSettingsField label { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }
|
|
624
|
+
.dim-imageSettingsField .dim-globalTtlInput { width: 100%; min-width: 0; }
|
|
625
|
+
.dim-imageSettingsActions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
|
|
626
|
+
.dim-globalInline.dim-imageSettingsFeedback { margin: 10px 0 0; }
|
|
627
|
+
@container (max-width: 380px) {
|
|
628
|
+
.dim-imageSettingsField { grid-template-columns: minmax(0, 1fr); }
|
|
629
|
+
}
|
|
614
630
|
.dim-globalHead { min-width: 0; display: flex; align-items: center; }
|
|
615
631
|
.dim-globalHeadTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
|
|
616
632
|
.dim-globalHead h3 { min-width: 0; overflow: hidden; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; line-height: 22px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom';
|
|
|
3
3
|
import validSemver from 'semver/functions/valid.js';
|
|
4
4
|
import compareVersionsDescending from 'semver/functions/rcompare.js';
|
|
5
5
|
|
|
6
|
-
import { h } from './i18n.js';
|
|
6
|
+
import { h, localizeText } from './i18n.js';
|
|
7
7
|
import { createPollScheduler } from './lifecycle.js';
|
|
8
8
|
|
|
9
9
|
export const UPDATE_RPC_CHANNEL = '/dsh-im';
|
|
@@ -240,6 +240,7 @@ function UpdateDialog({ children, onClose }) {
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
export function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|
243
|
+
const tooltipId = React.useId();
|
|
243
244
|
const [snapshot, setSnapshot] = React.useState(null);
|
|
244
245
|
const [action, setAction] = React.useState('status');
|
|
245
246
|
const [error, setError] = React.useState(null);
|
|
@@ -409,19 +410,32 @@ export function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|
|
409
410
|
: restartRequired ? '待手动重启'
|
|
410
411
|
: snapshot?.canInstall ? '更新至'
|
|
411
412
|
: '检查更新';
|
|
413
|
+
const buttonDescription = localizeText(buttonLabel) + (buttonLabel === '更新至' ? ` v${snapshot.latestVersion}` : '');
|
|
412
414
|
|
|
413
415
|
return h(React.Fragment, null,
|
|
414
|
-
h('
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
416
|
+
h('span', { className: 'dim-updateAction' },
|
|
417
|
+
h('button', {
|
|
418
|
+
type: 'button',
|
|
419
|
+
className: 'dim-updateButton dim-updateTrigger',
|
|
420
|
+
disabled: busyAction,
|
|
421
|
+
'aria-label': buttonDescription,
|
|
422
|
+
'aria-describedby': tooltipId,
|
|
423
|
+
'aria-haspopup': 'dialog',
|
|
424
|
+
onClick: () => {
|
|
425
|
+
setOpen(true);
|
|
426
|
+
if (restartRequired) void refreshStatus();
|
|
427
|
+
else if (!snapshot?.canInstall && !activeJob && !uncertainInstall) void check();
|
|
428
|
+
},
|
|
429
|
+
}, h('svg', {
|
|
430
|
+
width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none',
|
|
431
|
+
stroke: 'currentColor', strokeWidth: 2.3, strokeLinecap: 'round', strokeLinejoin: 'round',
|
|
432
|
+
focusable: 'false', 'aria-hidden': 'true',
|
|
423
433
|
},
|
|
424
|
-
|
|
434
|
+
h('path', { d: 'M3 12a9 9 0 0 1 15.36-6.36L21 8' }),
|
|
435
|
+
h('path', { d: 'M21 3v5h-5' }),
|
|
436
|
+
h('path', { d: 'M21 12a9 9 0 0 1-15.36 6.36L3 16' }),
|
|
437
|
+
h('path', { d: 'M8 16H3v5' }))),
|
|
438
|
+
h('span', { id: tooltipId, className: 'dim-updateTooltip', role: 'tooltip' }, buttonDescription)),
|
|
425
439
|
open ? h(UpdateDialog, { onClose: () => setOpen(false) },
|
|
426
440
|
h('div', { className: 'dim-updateBody' },
|
|
427
441
|
h('dl', { className: 'dim-updateVersions' },
|
|
@@ -453,6 +467,12 @@ export function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|
|
453
467
|
versionsDiffer && !restartRequired ? h('p', { className: 'dim-updateHint' }, '页面版本与运行版本不同,请手动刷新页面;若仍不一致,请手动重启 Harness 或 Desktop。') : null,
|
|
454
468
|
canConfirm ? h('p', { className: 'dim-updateHint' },
|
|
455
469
|
'请在机器人空闲时安装;安装会修改当前 profile 的依赖,完成后需手动重启。') : null,
|
|
470
|
+
h('aside', { className: 'dim-updateHint', 'aria-label': 'DSH 版本兼容说明' },
|
|
471
|
+
h('strong', null, 'DSH 版本兼容说明'),
|
|
472
|
+
h('p', { className: 'dim-updateManualHint' }, 'dsh-im 4.25.0 支持到 DSH v0.1.6-alpha.2。'),
|
|
473
|
+
h('p', { className: 'dim-updateManualHint' }, 'dsh-im 4.26.0 仅支持 DSH v0.1.7-alpha.1。'),
|
|
474
|
+
h('p', { className: 'dim-updateManualHint' },
|
|
475
|
+
'升级到 dsh-im 4.26.0 前,请先将 DSH 升级到 v0.1.7-alpha.1;使用旧版 DSH 请保留 dsh-im 4.25.0。')),
|
|
456
476
|
h(ManualUpdateCommand, {
|
|
457
477
|
key: manualCommand ?? 'unavailable', command: manualCommand,
|
|
458
478
|
disabled: busyAction || activeJob || uncertainInstall,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createProductionController } from './production.mjs';
|
|
2
|
+
import { createMatrixRpcHandler, installMatrixRpc, MATRIX_RPC_CHANNEL } from './rpc.mjs';
|
|
3
|
+
import { installProductionChannel } from '../shared/startup.mjs';
|
|
4
|
+
|
|
5
|
+
export const name = 'dsh-im-matrix-host';
|
|
6
|
+
export const inject = ['connection', 'credentials', 'typertGateway'];
|
|
7
|
+
|
|
8
|
+
export async function apply(ctx, config = {}) {
|
|
9
|
+
if (config?.controller) return installMatrixRpc(ctx, config.controller, config.rpcAuthority);
|
|
10
|
+
return installProductionChannel(ctx, config, {
|
|
11
|
+
channel: 'matrix',
|
|
12
|
+
rpcChannel: MATRIX_RPC_CHANNEL,
|
|
13
|
+
createProduction: () => createProductionController(ctx, config, config.internals ?? {}),
|
|
14
|
+
createHandler: controller => createMatrixRpcHandler(controller),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createMatrixHostPlugin(config) {
|
|
19
|
+
return Object.freeze({ name, inject, apply: (ctx) => apply(ctx, config) });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { createProductionController } from './production.mjs';
|
|
23
|
+
export {
|
|
24
|
+
MATRIX_ENDPOINTS,
|
|
25
|
+
MATRIX_RPC_CHANNEL,
|
|
26
|
+
MATRIX_RPC_ENDPOINTS,
|
|
27
|
+
createMatrixRpcHandler,
|
|
28
|
+
installMatrixRpc,
|
|
29
|
+
} from './rpc.mjs';
|
|
30
|
+
export { MatrixController } from '../../../../src/channels/matrix/matrix-controller.mjs';
|
|
31
|
+
export { MatrixRuntime } from '../../../../src/channels/matrix/matrix-runtime.mjs';
|