@xmanrui/dsh-im 4.21.0 → 4.21.2
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 +10 -0
- package/README.md +10 -0
- package/lib/client.js +46 -9
- package/lib/index.js +281 -280
- package/package.json +1 -1
- package/plugin-src/client/channels/feishu/index.js +22 -7
- package/plugin-src/client/credential-binding.js +2 -0
- package/plugin-src/client/i18n.js +6 -0
- package/plugin-src/host/channels/feishu/rpc.mjs +2 -1
- package/plugin-src/host/index.mjs +7 -0
- package/plugin-src/host/injected-context.mjs +104 -0
- package/scripts/verify-lan-management.mjs +53 -8
- package/src/channels/dingtalk/dingtalk-bridge.mjs +104 -27
- package/src/channels/feishu/bridge.mjs +35 -2
- package/src/channels/qq/qq-bridge.mjs +27 -2
- package/src/channels/shared/context-enhancement.mjs +40 -3
- package/src/channels/shared/control-command.mjs +8 -1
- package/src/channels/shared/harness-client.mjs +7 -0
- package/src/channels/shared/i18n-en/dingtalk.mjs +1 -0
- package/src/channels/shared/i18n-en/weixin.mjs +2 -0
- package/src/channels/shared/im-source-guidance.mjs +65 -0
- package/src/channels/shared/injected-context.mjs +362 -0
- package/src/channels/shared/semantic/artifact.mjs +3 -3
- package/src/channels/shared/semantic/reply-reference.mjs +2 -1
- package/src/channels/shared/text-harness-bridge.mjs +23 -2
- package/src/channels/shared/workspace-session.mjs +9 -0
- package/src/channels/wecom/wecom-bridge.mjs +11 -1
- package/src/channels/wecom-app/wecom-app-bridge.mjs +11 -1
- package/src/channels/weixin/weixin-api.mjs +52 -13
- package/src/channels/weixin/weixin-bridge.mjs +13 -1
package/README.en.md
CHANGED
|
@@ -253,6 +253,16 @@ node bin/dsh-im.mjs install --source .
|
|
|
253
253
|
|
|
254
254
|
IM management uses Harness browser authentication and Host/Origin trust checks by default. Once Harness allows and authenticates access from your LAN address, you can view and configure IM bots without any extra dsh-im configuration.
|
|
255
255
|
|
|
256
|
+
When accessing DSH through a custom domain, if IM settings report `transport failure for /api/dsh-im/...: HTTP 403`, add the browser-facing domain to your existing DSH launch command and restart DSH:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
dsh web --trusted-host dsh.example.com
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Replace `dsh.example.com` with the actual domain, without `http://`, `https://`, or a path. A domain without a port allows any port on that domain; use `--trusted-host dsh.example.com:8443` to restrict it to a particular access port. Repeat `--trusted-host` for multiple domains. This is a DSH option; dsh-im's `rpcAuthority: trusted-host` does not add domains to DSH's trust list. Local access through `localhost` or `127.0.0.1` normally needs no extra entry.
|
|
263
|
+
|
|
264
|
+
With a reverse proxy, preserve the browser-facing domain and port in the `Host` sent to DSH. The host parsed from an attached `Origin`, including any non-default port, must match that `Host`; adding two different hosts to the trust list still produces 403. `--trusted-host` configures the access check; the browser must still authenticate using a valid launch link.
|
|
265
|
+
|
|
256
266
|
To additionally restrict IM management to local access, set the following in the active Web profile's `cordis.patch.yml`:
|
|
257
267
|
|
|
258
268
|
```yaml
|
package/README.md
CHANGED
|
@@ -256,6 +256,16 @@ node bin/dsh-im.mjs install --source .
|
|
|
256
256
|
|
|
257
257
|
IM 管理接口默认沿用 Harness 的浏览器认证和 Host/Origin 信任检查。只要 Harness 已允许并认证当前局域网访问,便可直接查看和配置 IM 机器人,无需额外修改 dsh-im 配置。
|
|
258
258
|
|
|
259
|
+
通过自定义域名访问时,如果 IM 设置页出现 `transport failure for /api/dsh-im/...: HTTP 403`,请在原 DSH 启动命令中添加浏览器访问的域名,并重启 DSH:
|
|
260
|
+
|
|
261
|
+
```sh
|
|
262
|
+
dsh web --trusted-host dsh.example.com
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
将 `dsh.example.com` 替换为实际访问域名,不带 `http://`、`https://` 或路径。只写域名允许该域名的任意端口;如需限制到指定访问端口,使用 `--trusted-host dsh.example.com:8443`。多个域名可重复传入 `--trusted-host`。这个参数属于 DSH;dsh-im 的 `rpcAuthority: trusted-host` 本身不会把域名加入 DSH 信任列表。本机通过 `localhost` 或 `127.0.0.1` 访问通常不需要额外配置。
|
|
266
|
+
|
|
267
|
+
使用反向代理时,代理传给 DSH 的 `Host` 应保留浏览器访问的域名及端口;浏览器携带的 `Origin` 解析出的 host(含非默认端口)必须与该 `Host` 一致,仅将两者分别加入信任列表仍会返回 403。`--trusted-host` 只配置访问校验,浏览器仍需通过有效启动链接完成认证。
|
|
268
|
+
|
|
259
269
|
如需将 IM 管理额外限制为仅本机访问,可在当前 Web profile 的 `cordis.patch.yml` 中设置:
|
|
260
270
|
|
|
261
271
|
```yaml
|
package/lib/client.js
CHANGED
|
@@ -582,7 +582,7 @@ var React31 = __toESM(require("react"), 1);
|
|
|
582
582
|
// package.json
|
|
583
583
|
var package_default = {
|
|
584
584
|
name: "@xmanrui/dsh-im",
|
|
585
|
-
version: "4.21.
|
|
585
|
+
version: "4.21.2",
|
|
586
586
|
description: "\u628A\u5341\u4E00\u79CD IM \u6E20\u9053\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect eleven IM channels and a public AI Office to a local DeepSeek Harness.",
|
|
587
587
|
keywords: [
|
|
588
588
|
"deepseek-harness",
|
|
@@ -1789,6 +1789,12 @@ var EN = Object.freeze({
|
|
|
1789
1789
|
"Slack \u5DE5\u4F5C\u533A": "Slack workspace",
|
|
1790
1790
|
"Bot Token \u4E0E App Token": "Bot Token and App Token",
|
|
1791
1791
|
"\u586B\u5199 Bot Token": "Enter Bot Token",
|
|
1792
|
+
"\u5E94\u7528\u5E73\u53F0": "App platform",
|
|
1793
|
+
"Lark\uFF08\u56FD\u9645\u7248\uFF09": "Lark (international)",
|
|
1794
|
+
"\u624B\u52A8\u63A5\u5165Lark\u673A\u5668\u4EBA": "Connect Lark bot manually",
|
|
1795
|
+
"\u586B\u5199 Lark \u5F00\u653E\u5E73\u53F0 App ID": "Enter the Lark Developer App ID",
|
|
1796
|
+
"\u586B\u5199 Lark \u5F00\u653E\u5E73\u53F0 App Secret": "Enter the Lark Developer App Secret",
|
|
1797
|
+
"Lark \u673A\u5668\u4EBA\u51ED\u636E\u5DF2\u7ED1\u5B9A\u3002": "Lark bot credentials connected.",
|
|
1792
1798
|
"\u624B\u52A8\u63A5\u5165\u98DE\u4E66\u673A\u5668\u4EBA": "Connect Feishu bot manually",
|
|
1793
1799
|
"\u624B\u52A8\u63A5\u5165\u9489\u9489\u673A\u5668\u4EBA": "Connect DingTalk bot manually",
|
|
1794
1800
|
"\u624B\u52A8\u63A5\u5165\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA": "Connect WeCom bot manually",
|
|
@@ -2867,6 +2873,14 @@ var CONTEXT_ENHANCEMENT_FIELDS = Object.freeze([
|
|
|
2867
2873
|
"threadId",
|
|
2868
2874
|
"botId"
|
|
2869
2875
|
]);
|
|
2876
|
+
var INJECTED_CONTEXT_TAGS = Object.freeze({
|
|
2877
|
+
sourceOpen: "<dsh_im_source>",
|
|
2878
|
+
sourceClose: "</dsh_im_source>",
|
|
2879
|
+
guidanceOpen: "<dsh_im_source_guidance>",
|
|
2880
|
+
guidanceClose: "</dsh_im_source_guidance>",
|
|
2881
|
+
replyOpen: "<dsh_im_reply_to>",
|
|
2882
|
+
replyClose: "</dsh_im_reply_to>"
|
|
2883
|
+
});
|
|
2870
2884
|
var CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH = 8e3;
|
|
2871
2885
|
var CONTEXT_GROUP_GUIDANCE_EXAMPLE = `\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 <dsh_im_source> \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002
|
|
2872
2886
|
\u5F53\u524D\u6D88\u606F\u6765\u81EA\u7FA4\u804A\uFF0C\u8BF7\u4F7F\u7528\u4E25\u8083\u3001\u514B\u5236\u3001\u7B80\u6D01\u7684\u8868\u8FBE\u65B9\u5F0F\u3002`;
|
|
@@ -3501,7 +3515,8 @@ function CredentialBindingPanel({
|
|
|
3501
3515
|
busy = false,
|
|
3502
3516
|
error = null,
|
|
3503
3517
|
onSubmit,
|
|
3504
|
-
onCancel
|
|
3518
|
+
onCancel,
|
|
3519
|
+
children
|
|
3505
3520
|
}) {
|
|
3506
3521
|
const [identity, setIdentity] = React6.useState("");
|
|
3507
3522
|
const [secret, setSecret] = React6.useState("");
|
|
@@ -3521,6 +3536,7 @@ function CredentialBindingPanel({
|
|
|
3521
3536
|
"aria-labelledby": headingId
|
|
3522
3537
|
},
|
|
3523
3538
|
h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel5}\u673A\u5668\u4EBA`),
|
|
3539
|
+
children,
|
|
3524
3540
|
h2(
|
|
3525
3541
|
"form",
|
|
3526
3542
|
{
|
|
@@ -7700,6 +7716,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
7700
7716
|
const [pageBusy, setPageBusy] = React16.useState(false);
|
|
7701
7717
|
const [provisionBusy, setProvisionBusy] = React16.useState(false);
|
|
7702
7718
|
const [credentialOpen, setCredentialOpen] = React16.useState(false);
|
|
7719
|
+
const [credentialDomain, setCredentialDomain] = React16.useState("feishu");
|
|
7703
7720
|
const [credentialBusy, setCredentialBusy] = React16.useState(false);
|
|
7704
7721
|
const [credentialError, setCredentialError] = React16.useState(null);
|
|
7705
7722
|
const [busyByBot, setBusyByBot] = React16.useState({});
|
|
@@ -7882,13 +7899,13 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
7882
7899
|
try {
|
|
7883
7900
|
const snapshot = normalizeBotsSnapshot(await invoke(
|
|
7884
7901
|
FEISHU_ENDPOINTS.bindCredentials,
|
|
7885
|
-
{ appId: identity, appSecret: secret }
|
|
7902
|
+
{ appId: identity, appSecret: secret, domain: credentialDomain }
|
|
7886
7903
|
));
|
|
7887
7904
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
7888
7905
|
mergeSnapshot(snapshot);
|
|
7889
7906
|
}
|
|
7890
7907
|
setCredentialOpen(false);
|
|
7891
|
-
announce("\u98DE\u4E66\u673A\u5668\u4EBA\u51ED\u636E\u5DF2\u7ED1\u5B9A\u3002");
|
|
7908
|
+
announce(credentialDomain === "lark" ? "Lark \u673A\u5668\u4EBA\u51ED\u636E\u5DF2\u7ED1\u5B9A\u3002" : "\u98DE\u4E66\u673A\u5668\u4EBA\u51ED\u636E\u5DF2\u7ED1\u5B9A\u3002");
|
|
7892
7909
|
} catch (error) {
|
|
7893
7910
|
setCredentialError(presentError3(error));
|
|
7894
7911
|
} finally {
|
|
@@ -7896,7 +7913,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
7896
7913
|
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
7897
7914
|
setCredentialBusy(false);
|
|
7898
7915
|
}
|
|
7899
|
-
}, [announce, invoke, loadStatus, mergeSnapshot, workspaceFence]);
|
|
7916
|
+
}, [announce, credentialDomain, invoke, loadStatus, mergeSnapshot, workspaceFence]);
|
|
7900
7917
|
const cancelProvisioning = React16.useCallback(async () => {
|
|
7901
7918
|
const activeProvision = model.provisioning;
|
|
7902
7919
|
const attemptId = activeProvision?.attemptId;
|
|
@@ -8232,11 +8249,12 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
8232
8249
|
});
|
|
8233
8250
|
}
|
|
8234
8251
|
const credentialContent = credentialOpen ? h2(CredentialBindingPanel, {
|
|
8235
|
-
|
|
8252
|
+
key: credentialDomain,
|
|
8253
|
+
channel: credentialDomain === "lark" ? "Lark" : "\u98DE\u4E66",
|
|
8236
8254
|
identityLabel: "App ID",
|
|
8237
|
-
identityPlaceholder: "\u586B\u5199\u98DE\u4E66\u5F00\u653E\u5E73\u53F0 App ID",
|
|
8255
|
+
identityPlaceholder: credentialDomain === "lark" ? "\u586B\u5199 Lark \u5F00\u653E\u5E73\u53F0 App ID" : "\u586B\u5199\u98DE\u4E66\u5F00\u653E\u5E73\u53F0 App ID",
|
|
8238
8256
|
secretLabel: "App Secret",
|
|
8239
|
-
secretPlaceholder: "\u586B\u5199\u98DE\u4E66\u5F00\u653E\u5E73\u53F0 App Secret",
|
|
8257
|
+
secretPlaceholder: credentialDomain === "lark" ? "\u586B\u5199 Lark \u5F00\u653E\u5E73\u53F0 App Secret" : "\u586B\u5199\u98DE\u4E66\u5F00\u653E\u5E73\u53F0 App Secret",
|
|
8240
8258
|
busy: credentialBusy,
|
|
8241
8259
|
error: credentialError,
|
|
8242
8260
|
onSubmit: bindCredentials,
|
|
@@ -8244,7 +8262,26 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
8244
8262
|
setCredentialOpen(false);
|
|
8245
8263
|
setCredentialError(null);
|
|
8246
8264
|
}
|
|
8247
|
-
}
|
|
8265
|
+
}, h2(
|
|
8266
|
+
"label",
|
|
8267
|
+
{ className: "dim-credentialField" },
|
|
8268
|
+
h2("span", null, "\u5E94\u7528\u5E73\u53F0"),
|
|
8269
|
+
h2(
|
|
8270
|
+
"select",
|
|
8271
|
+
{
|
|
8272
|
+
className: "dim-feishuGroupSelect",
|
|
8273
|
+
"aria-label": "\u5E94\u7528\u5E73\u53F0",
|
|
8274
|
+
value: credentialDomain,
|
|
8275
|
+
disabled: credentialBusy,
|
|
8276
|
+
onChange: (event) => {
|
|
8277
|
+
setCredentialDomain(event.target.value);
|
|
8278
|
+
setCredentialError(null);
|
|
8279
|
+
}
|
|
8280
|
+
},
|
|
8281
|
+
h2("option", { value: "feishu" }, "\u98DE\u4E66"),
|
|
8282
|
+
h2("option", { value: "lark" }, "Lark\uFF08\u56FD\u9645\u7248\uFF09")
|
|
8283
|
+
)
|
|
8284
|
+
)) : null;
|
|
8248
8285
|
const setCardRef = React16.useCallback((botId, node) => {
|
|
8249
8286
|
if (node) cardRefs.current.set(botId, node);
|
|
8250
8287
|
else cardRefs.current.delete(botId);
|