@xmanrui/dsh-im 2.6.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +4 -4
- package/README.md +3 -3
- package/bin/dsh-im.mjs +1 -1
- package/lib/client.js +1440 -1432
- package/lib/index.js +187 -172
- package/package.json +2 -2
- package/plugin-src/client/channels/dingtalk/index.js +0 -17
- package/plugin-src/client/channels/dingtalk/styles.js +2 -2
- package/plugin-src/client/channels/feishu/index.js +0 -29
- package/plugin-src/client/channels/feishu/styles.js +2 -2
- package/plugin-src/client/channels/qq/index.js +0 -9
- package/plugin-src/client/channels/telegram/styles.js +12 -10
- package/plugin-src/client/channels/wecom/index.js +0 -9
- package/plugin-src/client/channels/weixin/index.js +0 -19
- package/plugin-src/client/channels/weixin/styles.js +2 -2
- package/plugin-src/client/i18n.js +4 -1
- package/plugin-src/client/index.js +4 -4
- package/plugin-src/client/styles.js +15 -12
- package/scripts/verify-package.mjs +48 -11
- package/src/channels/feishu/bridge.mjs +5 -2
- package/src/channels/feishu/message-utils.mjs +1 -1
- package/src/channels/qq/markdown-reply.mjs +324 -56
- package/src/channels/qq/qq-bridge.mjs +2 -10
- package/src/channels/qq/qq-runtime.mjs +3 -0
- package/src/channels/shared/connection-test.mjs +1 -1
- package/src/channels/shared/i18n-en/feishu.mjs +6 -6
- package/src/channels/shared/i18n-en/shared-c.mjs +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmanrui/dsh-im",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "把九种 IM 机器人和公网 AI Office 接入本机 DeepSeek Harness。 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"scripts": {
|
|
84
84
|
"build": "node plugin-src/client/build.mjs && node plugin-src/host/build.mjs",
|
|
85
85
|
"test": "node --test test/*.test.mjs test/channels/*/*.test.mjs",
|
|
86
|
-
"check": "npm
|
|
86
|
+
"check": "npm run build && npm test && node scripts/verify-package.mjs"
|
|
87
87
|
},
|
|
88
88
|
"engines": {
|
|
89
89
|
"node": ">=22.19"
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
} from '../../channel-card-meta.js';
|
|
17
17
|
import {
|
|
18
18
|
DINGTALK_ENDPOINTS,
|
|
19
|
-
DINGTALK_RPC_CHANNEL,
|
|
20
19
|
connectionTestFeedback,
|
|
21
20
|
formatRemaining,
|
|
22
21
|
normalizeProvisioning,
|
|
@@ -29,9 +28,6 @@ import { installDingtalkStyles } from './styles.js';
|
|
|
29
28
|
|
|
30
29
|
const ACTIVE_PROVISION_STATES = new Set(['pending', 'scanned', 'authorizing', 'creating', 'connecting']);
|
|
31
30
|
|
|
32
|
-
export const name = 'dingtalk-settings';
|
|
33
|
-
export const inject = ['slots', 'connection'];
|
|
34
|
-
|
|
35
31
|
function DingtalkIcon({ size = 28 }) {
|
|
36
32
|
return h('svg', {
|
|
37
33
|
width: size,
|
|
@@ -864,16 +860,3 @@ export function DingtalkSettingsTab({ rpcCall }) {
|
|
|
864
860
|
})
|
|
865
861
|
: null)));
|
|
866
862
|
}
|
|
867
|
-
|
|
868
|
-
export function apply(ctx) {
|
|
869
|
-
ctx.effect(() => installDingtalkStyles(), 'dingtalk-settings: install client styles');
|
|
870
|
-
const rpcCall = (endpoint, payload, signal) =>
|
|
871
|
-
ctx.connection.rpc.call(DINGTALK_RPC_CHANNEL, endpoint, payload, signal);
|
|
872
|
-
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
|
|
873
|
-
name: 'settings.plugins.tab',
|
|
874
|
-
id: 'dingtalk',
|
|
875
|
-
order: 40,
|
|
876
|
-
label: '钉钉',
|
|
877
|
-
inject: () => ({ rpcCall }),
|
|
878
|
-
}, DingtalkSettingsTab));
|
|
879
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const DINGTALK_STYLE_ID = 'xmanrui-dsh-dingtalk-settings';
|
|
1
|
+
export const DINGTALK_STYLE_ID = 'xmanrui-dsh-im-dingtalk-settings';
|
|
2
2
|
|
|
3
3
|
const CSS = String.raw`
|
|
4
4
|
.ddt-page {
|
|
@@ -126,7 +126,7 @@ export function installDingtalkStyles() {
|
|
|
126
126
|
const existing = document.querySelector(`style[data-plugin-css="${DINGTALK_STYLE_ID}"]`);
|
|
127
127
|
if (existing) return () => {};
|
|
128
128
|
const style = document.createElement('style');
|
|
129
|
-
style.dataset.plugin = '@xmanrui/dsh-
|
|
129
|
+
style.dataset.plugin = '@xmanrui/dsh-im';
|
|
130
130
|
style.dataset.pluginCss = DINGTALK_STYLE_ID;
|
|
131
131
|
style.textContent = CSS;
|
|
132
132
|
document.head.appendChild(style);
|
|
@@ -6,7 +6,6 @@ import { h } from "../../i18n.js";
|
|
|
6
6
|
import {
|
|
7
7
|
FEISHU_ENDPOINTS,
|
|
8
8
|
FEISHU_REGISTRATION_OPERATIONS,
|
|
9
|
-
FEISHU_RPC_CHANNEL,
|
|
10
9
|
formatRemaining,
|
|
11
10
|
normalizeBotsSnapshot,
|
|
12
11
|
normalizeGroupResponseMode,
|
|
@@ -28,11 +27,6 @@ import {
|
|
|
28
27
|
ChannelListHeading,
|
|
29
28
|
LastMessageErrorSummary,
|
|
30
29
|
} from "../../channel-card-meta.js";
|
|
31
|
-
import { installFeishuStyles } from "./styles.js";
|
|
32
|
-
|
|
33
|
-
export const name = "feishu-settings";
|
|
34
|
-
export const inject = ["slots", "connection"];
|
|
35
|
-
|
|
36
30
|
const CALLBACK_REPAIR_OPERATION = FEISHU_REGISTRATION_OPERATIONS.CALLBACK_REPAIR;
|
|
37
31
|
const GROUP_MESSAGE_PERMISSION_OPERATION = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
|
|
38
32
|
|
|
@@ -1540,26 +1534,3 @@ export function FeishuSettingsTab({ rpcCall }) {
|
|
|
1540
1534
|
),
|
|
1541
1535
|
));
|
|
1542
1536
|
}
|
|
1543
|
-
|
|
1544
|
-
export function apply(ctx) {
|
|
1545
|
-
ctx.effect(
|
|
1546
|
-
() => installFeishuStyles(),
|
|
1547
|
-
"feishu-settings: install client styles",
|
|
1548
|
-
);
|
|
1549
|
-
|
|
1550
|
-
const rpcCall = (endpoint, payload, signal) =>
|
|
1551
|
-
ctx.connection.rpc.call(FEISHU_RPC_CHANNEL, endpoint, payload, signal);
|
|
1552
|
-
|
|
1553
|
-
ctx.slots.inject("settings.plugins.tab", () =>
|
|
1554
|
-
ctx.slots.register(
|
|
1555
|
-
{
|
|
1556
|
-
name: "settings.plugins.tab",
|
|
1557
|
-
id: "feishu",
|
|
1558
|
-
order: 20,
|
|
1559
|
-
label: "飞书",
|
|
1560
|
-
inject: () => ({ rpcCall }),
|
|
1561
|
-
},
|
|
1562
|
-
FeishuSettingsTab,
|
|
1563
|
-
),
|
|
1564
|
-
);
|
|
1565
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const FEISHU_STYLE_ID = "
|
|
1
|
+
export const FEISHU_STYLE_ID = "xmanrui-dsh-im-feishu-settings";
|
|
2
2
|
|
|
3
3
|
const CSS = String.raw`
|
|
4
4
|
.bxf-page {
|
|
@@ -562,7 +562,7 @@ export function installFeishuStyles() {
|
|
|
562
562
|
}
|
|
563
563
|
|
|
564
564
|
const style = document.createElement("style");
|
|
565
|
-
style.dataset.plugin = "@xmanrui/dsh-
|
|
565
|
+
style.dataset.plugin = "@xmanrui/dsh-im";
|
|
566
566
|
style.dataset.pluginCss = FEISHU_STYLE_ID;
|
|
567
567
|
style.textContent = CSS;
|
|
568
568
|
document.head.appendChild(style);
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
19
19
|
import {
|
|
20
20
|
QQ_ENDPOINTS,
|
|
21
|
-
QQ_RPC_CHANNEL,
|
|
22
21
|
connectionTestFeedback,
|
|
23
22
|
formatRemaining,
|
|
24
23
|
normalizeProvisioning,
|
|
@@ -514,11 +513,3 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
514
513
|
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
|
|
515
514
|
botList)));
|
|
516
515
|
}
|
|
517
|
-
|
|
518
|
-
export function apply(ctx) {
|
|
519
|
-
ctx.effect(() => installQqStyles(), 'qq-settings: install client styles');
|
|
520
|
-
const rpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(QQ_RPC_CHANNEL, endpoint, payload, signal);
|
|
521
|
-
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
|
|
522
|
-
name: 'settings.plugins.tab', id: 'qq', order: 50, label: 'QQ', inject: () => ({ rpcCall }),
|
|
523
|
-
}, QqSettingsTab));
|
|
524
|
-
}
|
|
@@ -4,32 +4,34 @@ const CSS = String.raw`
|
|
|
4
4
|
.dtg-page { --ddt-accent: #229ed9; --ddt-accent-deep: #1687bd; --ddt-accent-wash: #eaf7fd; }
|
|
5
5
|
.dtg-avatar { color: #fff; background: #229ed9; }
|
|
6
6
|
.dtg-avatar svg { display: block; }
|
|
7
|
-
.dtg-access { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
|
|
8
|
-
.dtg-accessHeading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
9
|
-
.dtg-accessHeading > strong { font-size: 13px; }
|
|
10
|
-
.dtg-accessStatus { min-width: 0; display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }
|
|
11
|
-
.dtg-accessBadge { flex:
|
|
7
|
+
.dtg-access { min-width: 0; width: 100%; max-width: 100%; display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
|
|
8
|
+
.dtg-accessHeading { position: relative; min-width: 0; max-width: 100%; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; }
|
|
9
|
+
.dtg-accessHeading > strong { min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
|
|
10
|
+
.dtg-accessStatus { min-width: 0; max-width: 100%; flex: 0 1 auto; display: inline-flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 6px; }
|
|
11
|
+
.dtg-accessBadge { min-width: 0; max-width: 100%; flex: 0 1 auto; padding: 3px 8px; border-radius: 999px; color: #1687bd; background: #eaf7fd; font-size: 11px; font-weight: 700; overflow-wrap: anywhere; text-align: center; }
|
|
12
12
|
.dtg-accessBadge[data-mode="private-allowlist"] { color: #a15c00; background: #fff3d6; }
|
|
13
|
-
.dtg-accessHelp { position:
|
|
13
|
+
.dtg-accessHelp { position: static; display: inline-flex; flex: none; }
|
|
14
14
|
.dtg-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #229ed9 28%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #1687bd; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
|
|
15
15
|
.dtg-accessHelpButton:hover { border-color: #229ed9; color: #1178a8; background: #eaf7fd; }
|
|
16
16
|
.dtg-accessHelpButton:focus-visible { outline: none; border-color: #229ed9; box-shadow: 0 0 0 3px color-mix(in srgb, #229ed9 18%, transparent); }
|
|
17
|
-
.dtg-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width:
|
|
17
|
+
.dtg-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: min(300px, 100%); max-width: 100%; display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
18
18
|
.dtg-accessTooltipItem { display: grid; gap: 2px; }
|
|
19
19
|
.dtg-accessTooltipItem + .dtg-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
|
|
20
20
|
.dtg-accessTooltipItem strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 17px; font-weight: 700; }
|
|
21
21
|
.dtg-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; font-weight: 400; }
|
|
22
22
|
.dtg-accessHelp:hover .dtg-accessTooltip, .dtg-accessHelp:focus-within .dtg-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
23
|
-
.dtg-accessField { display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
|
|
24
|
-
.dtg-accessField select, .dtg-accessField textarea { width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
|
|
23
|
+
.dtg-accessField { min-width: 0; max-width: 100%; display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
|
|
24
|
+
.dtg-accessField select, .dtg-accessField textarea { min-width: 0; width: 100%; max-width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
|
|
25
25
|
.dtg-accessField select { height: 34px; padding: 0 9px; }
|
|
26
26
|
.dtg-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
27
27
|
.dtg-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
|
|
28
|
+
.dtg-accessField > span, .dtg-accessField small { overflow-wrap: anywhere; }
|
|
28
29
|
.dtg-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
|
|
29
30
|
.dtg-accessWarning, .dtg-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
|
|
30
31
|
.dtg-accessWarning { color: #a15c00; }
|
|
31
32
|
.dtg-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
|
|
32
|
-
.dtg-accessActions { display: flex; justify-content: flex-end; }
|
|
33
|
+
.dtg-accessActions { min-width: 0; max-width: 100%; display: flex; justify-content: flex-end; flex-wrap: wrap; }
|
|
34
|
+
.dtg-accessActions .ddt-button { max-width: 100%; white-space: normal; }
|
|
33
35
|
`;
|
|
34
36
|
|
|
35
37
|
export function installTelegramStyles() {
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
19
19
|
import {
|
|
20
20
|
WECOM_ENDPOINTS,
|
|
21
|
-
WECOM_RPC_CHANNEL,
|
|
22
21
|
formatRemaining,
|
|
23
22
|
normalizeProvisioning,
|
|
24
23
|
normalizeSnapshot,
|
|
@@ -546,11 +545,3 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
546
545
|
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
|
|
547
546
|
botList)));
|
|
548
547
|
}
|
|
549
|
-
|
|
550
|
-
export function apply(ctx) {
|
|
551
|
-
ctx.effect(() => installWecomStyles(), 'wecom-settings: install client styles');
|
|
552
|
-
const rpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WECOM_RPC_CHANNEL, endpoint, payload, signal);
|
|
553
|
-
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
|
|
554
|
-
name: 'settings.plugins.tab', id: 'wecom', order: 45, label: '企业微信', inject: () => ({ rpcCall }),
|
|
555
|
-
}, WecomSettingsTab));
|
|
556
|
-
}
|
|
@@ -5,7 +5,6 @@ import { QrActionIcon } from '../../credential-binding.js';
|
|
|
5
5
|
import { h } from '../../i18n.js';
|
|
6
6
|
import {
|
|
7
7
|
WEIXIN_ENDPOINTS,
|
|
8
|
-
WEIXIN_RPC_CHANNEL,
|
|
9
8
|
formatRemaining,
|
|
10
9
|
normalizeProvisioning,
|
|
11
10
|
normalizeSnapshot,
|
|
@@ -27,11 +26,6 @@ import {
|
|
|
27
26
|
ChannelListHeading,
|
|
28
27
|
LastMessageErrorSummary,
|
|
29
28
|
} from '../../channel-card-meta.js';
|
|
30
|
-
import { installWeixinStyles } from './styles.js';
|
|
31
|
-
|
|
32
|
-
export const name = 'weixin-settings';
|
|
33
|
-
export const inject = ['slots', 'connection'];
|
|
34
|
-
|
|
35
29
|
const Button = React.forwardRef(function Button(
|
|
36
30
|
{ children, kind = 'secondary', className = '', ...props },
|
|
37
31
|
ref,
|
|
@@ -717,16 +711,3 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
717
711
|
: null),
|
|
718
712
|
));
|
|
719
713
|
}
|
|
720
|
-
|
|
721
|
-
export function apply(ctx) {
|
|
722
|
-
ctx.effect(() => installWeixinStyles(), 'weixin-settings: install client styles');
|
|
723
|
-
const rpcCall = (endpoint, payload, signal) =>
|
|
724
|
-
ctx.connection.rpc.call(WEIXIN_RPC_CHANNEL, endpoint, payload, signal);
|
|
725
|
-
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
|
|
726
|
-
name: 'settings.plugins.tab',
|
|
727
|
-
id: 'weixin',
|
|
728
|
-
order: 30,
|
|
729
|
-
label: '微信',
|
|
730
|
-
inject: () => ({ rpcCall }),
|
|
731
|
-
}, WeixinSettingsTab));
|
|
732
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const WEIXIN_STYLE_ID = 'xmanrui-dsh-weixin-settings';
|
|
1
|
+
export const WEIXIN_STYLE_ID = 'xmanrui-dsh-im-weixin-settings';
|
|
2
2
|
|
|
3
3
|
const CSS = String.raw`
|
|
4
4
|
.dxw-page {
|
|
@@ -107,7 +107,7 @@ export function installWeixinStyles() {
|
|
|
107
107
|
const existing = document.querySelector(`style[data-plugin-css="${WEIXIN_STYLE_ID}"]`);
|
|
108
108
|
if (existing) return () => {};
|
|
109
109
|
const style = document.createElement('style');
|
|
110
|
-
style.dataset.plugin = '@xmanrui/dsh-
|
|
110
|
+
style.dataset.plugin = '@xmanrui/dsh-im';
|
|
111
111
|
style.dataset.pluginCss = WEIXIN_STYLE_ID;
|
|
112
112
|
style.textContent = CSS;
|
|
113
113
|
document.head.appendChild(style);
|
|
@@ -7,7 +7,7 @@ const EN = Object.freeze({
|
|
|
7
7
|
'IM机器人': 'IM bots',
|
|
8
8
|
'IM机器人设置': 'IM bot settings',
|
|
9
9
|
'IM 渠道': 'IM channels',
|
|
10
|
-
'让 DeepSeek Harness 触手可及': 'DeepSeek Harness
|
|
10
|
+
'让 DeepSeek Harness 触手可及': 'Connecting DeepSeek Harness',
|
|
11
11
|
'当前版本': 'Current version',
|
|
12
12
|
'AI Office': 'AI Office',
|
|
13
13
|
'(实验功能)': '(Experimental)',
|
|
@@ -517,6 +517,9 @@ const EN = Object.freeze({
|
|
|
517
517
|
'QQ 服务没有返回扫码绑定进度': 'QQ did not return QR setup progress',
|
|
518
518
|
'QQ 扫码服务没有返回有效的绑定任务': 'QQ did not return a valid setup attempt',
|
|
519
519
|
'QQ WebSocket 长连接运行正常': 'QQ WebSocket connection is healthy',
|
|
520
|
+
'QQ 连接未就绪,插件会自动重试。': 'The QQ connection is not ready; the plugin will retry automatically.',
|
|
521
|
+
'QQ 连接未就绪,插件会自动重试': 'The QQ connection is not ready; the plugin will retry automatically',
|
|
522
|
+
'QQ 连接当前离线': 'The QQ connection is currently offline',
|
|
520
523
|
'QQ 服务没有返回有效的机器人列表': 'QQ did not return a valid bot list',
|
|
521
524
|
'尚未绑定 QQ 机器人': 'No QQ bot connected yet',
|
|
522
525
|
'用于绑定 QQ 机器人的一次性二维码': 'One-time QR code for connecting a QQ bot',
|
|
@@ -333,10 +333,10 @@ export function apply(ctx) {
|
|
|
333
333
|
pickDirectory: () => ctx.workspaces.pickDirectory(),
|
|
334
334
|
});
|
|
335
335
|
|
|
336
|
-
ctx.slots.inject('settings.
|
|
337
|
-
name: 'settings.
|
|
338
|
-
id: 'im',
|
|
339
|
-
order:
|
|
336
|
+
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
337
|
+
name: 'settings.section',
|
|
338
|
+
id: 'xmanrui-dsh-im',
|
|
339
|
+
order: 21,
|
|
340
340
|
label: () => t('IM机器人'),
|
|
341
341
|
locale: IM_LOCALE_NAMESPACE,
|
|
342
342
|
inject: () => ({
|
|
@@ -16,7 +16,7 @@ const CSS = String.raw`
|
|
|
16
16
|
.dim-brand:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
|
|
17
17
|
.dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
|
|
18
18
|
.dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
|
|
19
|
-
.dim-versionTooltip { position: absolute;
|
|
19
|
+
.dim-versionTooltip { position: absolute; top: calc(100% + 8px); left: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); display: inline-flex; align-items: center; gap: 6px; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-secondary, #646a73); 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; }
|
|
20
20
|
.dim-versionTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font: 600 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
21
21
|
.dim-brand:hover .dim-versionTooltip, .dim-brand:focus .dim-versionTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
22
22
|
.dim-githubAction { position: relative; display: inline-flex; flex: none; }
|
|
@@ -24,7 +24,7 @@ const CSS = String.raw`
|
|
|
24
24
|
.dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
25
25
|
.dim-githubLink:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
|
|
26
26
|
.dim-githubArrow { font-size: 13px; line-height: 1; }
|
|
27
|
-
.dim-githubTooltip { position: absolute;
|
|
27
|
+
.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; }
|
|
28
28
|
.dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
29
29
|
.dim-layout { display: grid; grid-template-columns: 174px 1px minmax(0, 1fr); gap: 24px; align-items: start; }
|
|
30
30
|
.dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 1px 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; }
|
|
@@ -81,7 +81,7 @@ const CSS = String.raw`
|
|
|
81
81
|
.dim-panel .dim-credentialButton:hover:not(:disabled) { border-color: #4e5969; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
82
82
|
.dim-panel .dim-credentialButton[aria-pressed="true"] { border-color: #4e5969; background: var(--dsw-alias-bg-module-platform, #f2f3f5); box-shadow: inset 0 0 0 1px rgb(78 89 105 / 8%); }
|
|
83
83
|
.dim-panel .bxf-headingTools .dim-onlineBadge, .dim-panel .dxw-tools .dim-onlineBadge, .dim-panel .ddt-tools .dim-onlineBadge { min-height: 30px; display: inline-flex; align-items: center; justify-self: end; gap: 0; padding: 0 11px; border: 0; border-radius: 999px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f2f3f5); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; white-space: nowrap; }
|
|
84
|
-
.dim-panel .dim-channelPage { width: 100%; max-width: none; display: flex; flex-direction: column; gap: 12px; padding: 0 0 24px; color: var(--dsw-alias-label-primary, #1f2329); box-sizing: border-box; }
|
|
84
|
+
.dim-panel .dim-channelPage { min-width: 0; width: 100%; max-width: none; display: flex; flex-direction: column; gap: 12px; padding: 0 0 24px; color: var(--dsw-alias-label-primary, #1f2329); box-sizing: border-box; }
|
|
85
85
|
.dim-panel .dim-surfaceCard { position: relative; overflow: hidden; 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%); }
|
|
86
86
|
.dim-panel .dim-surfaceCard::before { display: none; }
|
|
87
87
|
.dim-panel .dim-surfaceBody { padding: 24px; }
|
|
@@ -96,7 +96,7 @@ const CSS = String.raw`
|
|
|
96
96
|
.dim-panel .dim-credentialError, .dim-panel .dim-credentialActions { grid-column: 1 / -1; }
|
|
97
97
|
.dim-panel .dim-credentialError { margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.5; }
|
|
98
98
|
.dim-panel .dim-credentialActions { margin-top: 0; }
|
|
99
|
-
.dim-panel .dim-listSection { display: flex; flex-direction: column; gap: 0; }
|
|
99
|
+
.dim-panel .dim-listSection { min-width: 0; width: 100%; max-width: 100%; display: flex; flex-direction: column; gap: 0; }
|
|
100
100
|
.dim-panel .dim-listHeading { min-height: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 6px; padding: 0; }
|
|
101
101
|
.dim-panel .dim-listHeading h3 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 14px; line-height: normal; font-weight: 650; }
|
|
102
102
|
.dim-panel .dim-listTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
|
|
@@ -107,7 +107,8 @@ const CSS = String.raw`
|
|
|
107
107
|
.dim-panel .dim-channelTooltip { position: absolute; top: calc(100% + 7px); left: 0; z-index: 30; width: max-content; max-width: min(280px, calc(100vw - 48px)); display: flex; align-items: baseline; gap: 5px; padding: 8px 10px; 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-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); font-size: 11px; line-height: 16px; font-weight: 400; white-space: normal; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
108
108
|
.dim-panel .dim-channelTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font-weight: 600; white-space: nowrap; }
|
|
109
109
|
.dim-panel .dim-channelHelp:hover .dim-channelTooltip, .dim-panel .dim-channelHelp:focus-within .dim-channelTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
110
|
-
.dim-panel .dim-botList { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
|
|
110
|
+
.dim-panel .dim-botList { min-width: 0; width: 100%; max-width: 100%; display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; margin: 0; padding: 0; list-style: none; }
|
|
111
|
+
.dim-panel .dim-botList > li { min-width: 0; max-width: 100%; }
|
|
111
112
|
.dim-panel .dim-loadingView { padding: 38px; color: var(--dsw-alias-label-secondary, #646a73); text-align: center; }
|
|
112
113
|
.dim-panel .dim-loadingView h3 { margin: 0 0 7px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 17px; line-height: normal; font-weight: 650; }
|
|
113
114
|
.dim-panel .dim-loadingView p { margin: 0; line-height: 1.6; }
|
|
@@ -161,7 +162,7 @@ const CSS = String.raw`
|
|
|
161
162
|
.dim-panel .dim-workspaceHeader > span { grid-column: 1; grid-row: 1; white-space: nowrap; }
|
|
162
163
|
.dim-panel .dim-workspaceEdit { grid-column: 2; grid-row: 1; padding: 0; border: 0; color: #1677ff; background: transparent; font: inherit; font-weight: 560; white-space: nowrap; cursor: pointer; }
|
|
163
164
|
.dim-panel .dim-workspaceEdit:disabled { cursor: not-allowed; opacity: .55; }
|
|
164
|
-
.dim-panel .dim-workspacePath { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; display: block; overflow
|
|
165
|
+
.dim-panel .dim-workspacePath { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; display: block; overflow: hidden; color: var(--dsw-alias-label-primary, #1f2329); font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; white-space: normal; }
|
|
165
166
|
.dim-panel .dim-preset { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; align-items: center; column-gap: 10px; row-gap: 4px; margin-top: 6px; padding: 6px 10px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
|
|
166
167
|
.dim-panel .dim-presetHeader { position: relative; min-width: 0; grid-column: 1 / -1; grid-row: 1; display: flex; align-items: center; justify-content: space-between; gap: 10px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
|
|
167
168
|
.dim-panel .dim-presetTitle { min-width: 0; display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
|
|
@@ -216,7 +217,7 @@ const CSS = String.raw`
|
|
|
216
217
|
.dim-directoryPickerActions .dim-directoryPickerPrimary { border-color: var(--dim-blue); color: #fff; background: var(--dim-blue); }
|
|
217
218
|
.dim-directoryPickerActions button:hover:not(:disabled) { filter: brightness(.97); }
|
|
218
219
|
.dim-directoryPickerActions button:disabled { cursor: not-allowed; opacity: .52; }
|
|
219
|
-
.dim-panel .dim-cardSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; }
|
|
220
|
+
.dim-panel .dim-cardSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; overflow-wrap: anywhere; white-space: normal; }
|
|
220
221
|
.dim-panel .dim-cardFooterLayout { min-width: 0; width: 100%; display: flex; flex-direction: column; align-items: stretch; gap: 9px; }
|
|
221
222
|
.dim-panel .dim-cardFooterLayout > .dim-cardActions { align-self: stretch; }
|
|
222
223
|
.dim-panel .dim-cardFeedback { width: 100%; padding: 8px 10px; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 12px; font-weight: 400; line-height: 18px; overflow-wrap: anywhere; white-space: normal; }
|
|
@@ -224,17 +225,17 @@ const CSS = String.raw`
|
|
|
224
225
|
.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; }
|
|
225
226
|
.dim-panel .dim-cardActions .dim-cardAction:hover:not(:disabled) { border-color: #aeb3bb; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
226
227
|
.dim-panel .dim-cardActions .dim-cardAction[data-kind="danger"] { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
227
|
-
.dim-panel .dim-botCard { position: relative; overflow: hidden; 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%); }
|
|
228
|
+
.dim-panel .dim-botCard { position: relative; min-width: 0; width: 100%; max-width: 100%; overflow: hidden; 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%); }
|
|
228
229
|
.dim-panel .dim-botCard::before { display: none; }
|
|
229
|
-
.dim-panel .dim-botCardBody { position: relative; padding: 12px; }
|
|
230
|
-
.dim-panel .dim-botCardTop { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
231
|
-
.dim-panel .dim-botIdentity { min-width: 0; display: flex; align-items: center; gap: 10px; }
|
|
230
|
+
.dim-panel .dim-botCardBody { position: relative; min-width: 0; width: 100%; max-width: 100%; padding: 12px; }
|
|
231
|
+
.dim-panel .dim-botCardTop { min-width: 0; max-width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
232
|
+
.dim-panel .dim-botIdentity { min-width: 0; flex: 1 1 0; display: flex; align-items: center; gap: 10px; }
|
|
232
233
|
.dim-panel .dim-botAvatar { flex: none; width: 38px; height: 38px; display: grid; place-items: center; overflow: hidden; border-radius: 11px; box-shadow: none; }
|
|
233
234
|
.dim-panel .dim-botAvatar svg { width: 27px; height: 27px; }
|
|
234
235
|
.dim-panel .dim-botName { min-width: 0; }
|
|
235
236
|
.dim-panel .dim-botName h3 { overflow: hidden; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; font-weight: 650; line-height: normal; text-overflow: ellipsis; white-space: nowrap; }
|
|
236
237
|
.dim-panel .dim-botName p { overflow: hidden; margin: 4px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font: 12px ui-monospace, SFMono-Regular, monospace; line-height: normal; text-overflow: ellipsis; white-space: nowrap; }
|
|
237
|
-
.dim-panel .dim-botHealthGroup { flex: none; display: grid; justify-items: end; gap: 5px; }
|
|
238
|
+
.dim-panel .dim-botHealthGroup { min-width: 0; max-width: 100%; flex: none; display: grid; justify-items: end; gap: 5px; }
|
|
238
239
|
.dim-panel .dim-botCard .dim-botHealth { flex: none; min-height: 0; display: inline-flex; align-items: center; gap: 7px; padding: 0; border: 0; border-radius: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 12px; font-weight: 400; line-height: normal; white-space: nowrap; }
|
|
239
240
|
.dim-panel .dim-lastChecked { display: inline-flex; align-items: baseline; gap: 4px; color: var(--dsw-alias-label-tertiary, #8f959e); font: inherit; font-size: 11px; font-weight: 400; line-height: normal; white-space: nowrap; }
|
|
240
241
|
.dim-panel .dim-botCard .dim-healthDot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: #aeb3bb; box-shadow: none; }
|
|
@@ -246,6 +247,8 @@ const CSS = String.raw`
|
|
|
246
247
|
.dim-panel .ddt-qrFrame, .dim-panel .ddt-countdown { width: min(270px, 100%); }
|
|
247
248
|
@container (max-width: 680px) {
|
|
248
249
|
.dim-panel .bxf-headingTools, .dim-panel .dxw-tools, .dim-panel .ddt-tools { gap: 6px; }
|
|
250
|
+
.dim-panel .dim-botCardTop { flex-direction: column; align-items: stretch; }
|
|
251
|
+
.dim-panel .dim-botHealthGroup { justify-items: start; }
|
|
249
252
|
.dim-panel .dim-bindActions { gap: 6px; }
|
|
250
253
|
.dim-panel .bxf-headingTools .dim-scanButton, .dim-panel .dxw-tools .dim-scanButton, .dim-panel .ddt-tools .dim-scanButton, .dim-panel .dim-credentialButton { gap: 5px; padding-inline: 8px; font-size: 12px; }
|
|
251
254
|
.dim-panel .dim-actionIcon { width: 13px; height: 13px; flex-basis: 13px; }
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
-
import { access, readFile, stat } from 'node:fs/promises';
|
|
1
|
+
import { access, readFile, readdir, stat } from 'node:fs/promises';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
|
|
5
5
|
const root = resolve(import.meta.dirname, '..');
|
|
6
|
+
|
|
7
|
+
async function readSourceTree(directory) {
|
|
8
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
9
|
+
const chunks = [];
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
const path = resolve(directory, entry.name);
|
|
12
|
+
if (entry.isDirectory()) {
|
|
13
|
+
chunks.push(await readSourceTree(path));
|
|
14
|
+
} else if (entry.isFile() && /\.m?js$/u.test(entry.name)) {
|
|
15
|
+
chunks.push(await readFile(path, 'utf8'));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return chunks.join('\n');
|
|
19
|
+
}
|
|
20
|
+
|
|
6
21
|
const required = [
|
|
7
22
|
'lib/index.js',
|
|
8
23
|
'lib/client.js',
|
|
@@ -35,7 +50,17 @@ const required = [
|
|
|
35
50
|
];
|
|
36
51
|
await Promise.all(required.map((path) => access(resolve(root, path))));
|
|
37
52
|
|
|
38
|
-
const [
|
|
53
|
+
const [
|
|
54
|
+
client,
|
|
55
|
+
host,
|
|
56
|
+
patch,
|
|
57
|
+
manifestText,
|
|
58
|
+
lockText,
|
|
59
|
+
hostSource,
|
|
60
|
+
clientEntrySource,
|
|
61
|
+
clientSources,
|
|
62
|
+
executable,
|
|
63
|
+
] = await Promise.all([
|
|
39
64
|
readFile(resolve(root, 'lib/client.js'), 'utf8'),
|
|
40
65
|
readFile(resolve(root, 'lib/index.js'), 'utf8'),
|
|
41
66
|
readFile(resolve(root, 'cordis.patch.yml'), 'utf8'),
|
|
@@ -43,6 +68,7 @@ const [client, host, patch, manifestText, lockText, hostSource, clientSource, ex
|
|
|
43
68
|
readFile(resolve(root, 'package-lock.json'), 'utf8'),
|
|
44
69
|
readFile(resolve(root, 'plugin-src/host/index.mjs'), 'utf8'),
|
|
45
70
|
readFile(resolve(root, 'plugin-src/client/index.js'), 'utf8'),
|
|
71
|
+
readSourceTree(resolve(root, 'plugin-src/client')),
|
|
46
72
|
stat(resolve(root, 'bin/dsh-im.mjs')),
|
|
47
73
|
]);
|
|
48
74
|
const manifest = JSON.parse(manifestText);
|
|
@@ -82,17 +108,28 @@ if (forbiddenDshLockPaths.length > 0) {
|
|
|
82
108
|
);
|
|
83
109
|
}
|
|
84
110
|
|
|
85
|
-
if (
|
|
111
|
+
if (!/\bid\s*:\s*["']@xmanrui\/dsh-im["']/u.test(client)) {
|
|
86
112
|
throw new Error('client bundle does not register the dsh-im loader id');
|
|
87
113
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
114
|
+
const sourceSectionMarkers = [
|
|
115
|
+
/ctx\.slots\.inject\(\s*["']settings\.section["']/u,
|
|
116
|
+
/name\s*:\s*["']settings\.section["']/u,
|
|
117
|
+
/id\s*:\s*["']xmanrui-dsh-im["']/u,
|
|
118
|
+
/order\s*:\s*21\b/u,
|
|
119
|
+
/label\s*:\s*\(\)\s*=>\s*t\(\s*["']IM机器人["']\s*\)/u,
|
|
120
|
+
/locale\s*:\s*IM_LOCALE_NAMESPACE\b/u,
|
|
121
|
+
];
|
|
122
|
+
const bundleSectionPattern = /name\s*:\s*["']settings\.section["']\s*,\s*id\s*:\s*["']xmanrui-dsh-im["']\s*,\s*order\s*:\s*21\s*,\s*label\s*:\s*\(\)\s*=>\s*[$A-Z_a-z][$\w]*\(\s*["']IM(?:机器人|\\u673A\\u5668\\u4EBA)["']\s*\)\s*,\s*locale\s*:\s*(?:[$A-Z_a-z][$\w]*|["']dsh-im["'])/u;
|
|
123
|
+
if (sourceSectionMarkers.some((pattern) => !pattern.test(clientEntrySource))
|
|
124
|
+
|| !/IM_LOCALE_NAMESPACE\s*=\s*["']dsh-im["']/u.test(clientSources)
|
|
125
|
+
|| !bundleSectionPattern.test(client)) {
|
|
126
|
+
throw new Error('client bundle does not register the localized top-level IM settings section');
|
|
127
|
+
}
|
|
128
|
+
if ((client.match(/\.slots\.inject\(\s*["']settings\.section["']/gu) ?? []).length !== 1) {
|
|
129
|
+
throw new Error('client bundle must register exactly one top-level settings section');
|
|
93
130
|
}
|
|
94
|
-
if (
|
|
95
|
-
throw new Error('client bundle
|
|
131
|
+
if (client.includes('settings.plugins.tab') || clientSources.includes('settings.plugins.tab')) {
|
|
132
|
+
throw new Error('client source or bundle still contains the legacy Plugins-tab settings entry');
|
|
96
133
|
}
|
|
97
134
|
if (/role:\s*["']switch|type:\s*["']checkbox/.test(client)) {
|
|
98
135
|
throw new Error('client bundle contains a channel enable switch');
|
|
@@ -115,7 +152,7 @@ if (/@xmanrui\/dsh-(?:feishu|weixin|dingtalk)/.test(host)) {
|
|
|
115
152
|
throw new Error('host bundle still imports an external channel plugin');
|
|
116
153
|
}
|
|
117
154
|
if (/@xmanrui\/dsh-(?:feishu|weixin|dingtalk)/.test(
|
|
118
|
-
manifestText + lockText + hostSource +
|
|
155
|
+
manifestText + lockText + hostSource + clientSources,
|
|
119
156
|
)) {
|
|
120
157
|
throw new Error('source or package metadata still depends on an external channel plugin');
|
|
121
158
|
}
|
|
@@ -159,7 +159,7 @@ function artifactFailureText(fileName, error) {
|
|
|
159
159
|
const name = String(fileName ?? t('结果文件')).replace(/[\r\n]+/g, ' ').trim() || t('结果文件');
|
|
160
160
|
switch (error?.code) {
|
|
161
161
|
case 'artifact-permission-required':
|
|
162
|
-
return t('结果文件「{name}」已生成,但机器人缺少飞书文件上传权限 im:resource。请私聊机器人执行 /repair
|
|
162
|
+
return t('结果文件「{name}」已生成,但机器人缺少飞书文件上传权限 im:resource。请私聊机器人执行 /repair 命令,或者在「IM机器人」设置页点击“补全权限”按钮并扫码。完成飞书要求的发布审批后重试。', { name });
|
|
163
163
|
case 'artifact-too-large':
|
|
164
164
|
return t('结果文件「{name}」超过飞书 30 MB 上限,未发送。', { name });
|
|
165
165
|
case 'artifact-empty':
|
|
@@ -945,7 +945,10 @@ export class FeishuHarnessBridge {
|
|
|
945
945
|
const text = message.content;
|
|
946
946
|
const hasImages = hasInboundImages(message);
|
|
947
947
|
const hasFiles = hasInboundFiles(message);
|
|
948
|
-
|
|
948
|
+
// 命令识别对 text 与纯文本 post 一视同仁:post 富文本若仅含单个
|
|
949
|
+
// 文本段落(如复制粘贴的 /new),同样按命令处理;带图片/文件不认。
|
|
950
|
+
// accept() 侧已用 nonEmptyString(content) 判定,两侧保持一致。
|
|
951
|
+
const commandText = !hasImages && !hasFiles && text ? text.trim() : null;
|
|
949
952
|
if (!text && !hasImages && !hasFiles) {
|
|
950
953
|
await this.#send(event.message.chat_id, t('目前支持文字、图片和文件消息。'));
|
|
951
954
|
return;
|
|
@@ -5,7 +5,7 @@ const FEISHU_MISSING_MESSAGE_SCOPE_CODE = 99991672;
|
|
|
5
5
|
const FEISHU_ERROR_BODY_LIMIT = 64 * 1024;
|
|
6
6
|
const FEISHU_ERROR_BODY_TIMEOUT_MS = 1_000;
|
|
7
7
|
const FEISHU_IMAGE_PERMISSION_MESSAGE =
|
|
8
|
-
'飞书机器人缺少图片读取权限 im:message:readonly(飞书显示为“获取单聊、群组消息”)。请私聊机器人执行 /repair
|
|
8
|
+
'飞书机器人缺少图片读取权限 im:message:readonly(飞书显示为“获取单聊、群组消息”)。请私聊机器人执行 /repair 命令,或者在「IM机器人」设置页点击“补全权限”按钮并扫码。按飞书提示发布新版本、完成必要审批后,再重新发送图片。';
|
|
9
9
|
|
|
10
10
|
export function conversationKey(event) {
|
|
11
11
|
const chatType = event?.message?.chat_type;
|