@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.
Files changed (30) hide show
  1. package/README.en.md +10 -0
  2. package/README.md +10 -0
  3. package/lib/client.js +46 -9
  4. package/lib/index.js +281 -280
  5. package/package.json +1 -1
  6. package/plugin-src/client/channels/feishu/index.js +22 -7
  7. package/plugin-src/client/credential-binding.js +2 -0
  8. package/plugin-src/client/i18n.js +6 -0
  9. package/plugin-src/host/channels/feishu/rpc.mjs +2 -1
  10. package/plugin-src/host/index.mjs +7 -0
  11. package/plugin-src/host/injected-context.mjs +104 -0
  12. package/scripts/verify-lan-management.mjs +53 -8
  13. package/src/channels/dingtalk/dingtalk-bridge.mjs +104 -27
  14. package/src/channels/feishu/bridge.mjs +35 -2
  15. package/src/channels/qq/qq-bridge.mjs +27 -2
  16. package/src/channels/shared/context-enhancement.mjs +40 -3
  17. package/src/channels/shared/control-command.mjs +8 -1
  18. package/src/channels/shared/harness-client.mjs +7 -0
  19. package/src/channels/shared/i18n-en/dingtalk.mjs +1 -0
  20. package/src/channels/shared/i18n-en/weixin.mjs +2 -0
  21. package/src/channels/shared/im-source-guidance.mjs +65 -0
  22. package/src/channels/shared/injected-context.mjs +362 -0
  23. package/src/channels/shared/semantic/artifact.mjs +3 -3
  24. package/src/channels/shared/semantic/reply-reference.mjs +2 -1
  25. package/src/channels/shared/text-harness-bridge.mjs +23 -2
  26. package/src/channels/shared/workspace-session.mjs +9 -0
  27. package/src/channels/wecom/wecom-bridge.mjs +11 -1
  28. package/src/channels/wecom-app/wecom-app-bridge.mjs +11 -1
  29. package/src/channels/weixin/weixin-api.mjs +52 -13
  30. 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.0",
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
- channel: "\u98DE\u4E66",
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
- }) : null;
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);