@xmanrui/dsh-im 4.38.0 → 4.38.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 (50) hide show
  1. package/PROACTIVE_DELIVERY.en.md +18 -2
  2. package/PROACTIVE_DELIVERY.md +18 -2
  3. package/README.en.md +2 -0
  4. package/README.md +2 -0
  5. package/lib/client.js +49 -5
  6. package/lib/index.js +320 -315
  7. package/locale/en.json +1 -1
  8. package/locale/zh.json +1 -1
  9. package/package.json +1 -1
  10. package/plugin-src/client/connection-error.js +12 -2
  11. package/plugin-src/host/channels/dingtalk/production.mjs +1 -1
  12. package/plugin-src/host/channels/feishu/production.mjs +1 -1
  13. package/plugin-src/host/channels/matrix/production.mjs +1 -1
  14. package/plugin-src/host/channels/qq/production.mjs +1 -1
  15. package/plugin-src/host/channels/shared/production.mjs +1 -1
  16. package/plugin-src/host/channels/slack/production.mjs +1 -1
  17. package/plugin-src/host/channels/wecom/production.mjs +1 -1
  18. package/plugin-src/host/channels/wecom-app/production.mjs +1 -1
  19. package/plugin-src/host/channels/weixin/production.mjs +1 -1
  20. package/plugin-src/host/channels/whatsapp/production.mjs +1 -1
  21. package/plugin-src/host/delivery-adapter.mjs +9 -1
  22. package/plugin-src/host/delivery-service.mjs +4 -3
  23. package/plugin-src/host/modern-harness-api.mjs +2 -1
  24. package/plugin-src/host/session-sync-coordinator.mjs +9 -5
  25. package/src/channels/dingtalk/dingtalk-api.mjs +41 -24
  26. package/src/channels/dingtalk/dingtalk-runtime.mjs +3 -2
  27. package/src/channels/discord/discord-runtime.mjs +13 -2
  28. package/src/channels/feishu/bridge.mjs +95 -24
  29. package/src/channels/matrix/matrix-runtime.mjs +16 -6
  30. package/src/channels/qq/markdown-reply.mjs +7 -340
  31. package/src/channels/qq/qq-runtime.mjs +11 -3
  32. package/src/channels/shared/bot-workspace-store.mjs +3 -3
  33. package/src/channels/shared/connection-error.mjs +29 -4
  34. package/src/channels/shared/diagnostic-details.mjs +6 -2
  35. package/src/channels/shared/harness-client.mjs +138 -19
  36. package/src/channels/shared/harness-mux.mjs +6 -4
  37. package/src/channels/shared/i18n-en/diagnostics.mjs +24 -0
  38. package/src/channels/shared/i18n-en/wecom.mjs +3 -0
  39. package/src/channels/shared/markdown-chunks.mjs +338 -0
  40. package/src/channels/shared/message-failure.mjs +31 -11
  41. package/src/channels/shared/text-harness-bridge.mjs +4 -1
  42. package/src/channels/shared/workspace-session.mjs +10 -1
  43. package/src/channels/slack/slack-api.mjs +2 -1
  44. package/src/channels/slack/slack-runtime.mjs +30 -0
  45. package/src/channels/telegram/telegram-runtime.mjs +1 -0
  46. package/src/channels/wecom/wecom-bridge.mjs +45 -10
  47. package/src/channels/wecom/wecom-runtime.mjs +11 -5
  48. package/src/channels/weixin/weixin-runtime.mjs +17 -10
  49. package/src/channels/whatsapp/whatsapp-markdown.mjs +59 -0
  50. package/src/channels/whatsapp/whatsapp-runtime.mjs +26 -1
@@ -175,9 +175,24 @@ await ctx.dshIm.send(botId, targetId, '# Daily report\n\n**Checks complete**', {
175
175
  });
176
176
  ```
177
177
 
178
- `format` accepts only `plain` and `markdown`, defaulting to `plain`. Markdown formatting is currently implemented for Feishu/Lark: both direct and group destinations receive a native Markdown card without starting a Session or a stream. Other channels retain their existing delivery behavior; Markdown rendering is not guaranteed there. HTTP and `message.send` RPC accept the same optional `format` field in their payloads.
178
+ `format` accepts only `plain` and `markdown`, defaulting to `plain`. HTTP and `message.send` RPC accept the same optional field. Markdown uses the existing channel delivery paths, without starting a Session or a new stream:
179
179
 
180
- The original Markdown, including whitespace, is preserved without silent truncation or automatic splitting; platform message-size and Markdown-syntax limits still apply. Rejection, timeout, and cancellation use the existing error handling, with no automatic plain-text resend that could duplicate delivery. Older dsh-im Host APIs may ignore this option; both the consumer and dsh-im must load the updated code.
180
+ | Channel | Markdown presentation |
181
+ | --- | --- |
182
+ | Feishu/Lark | Native Markdown card |
183
+ | Telegram | Rich Markdown, with the existing text fallback |
184
+ | QQ | Markdown message; known format rejection falls back for the current chunk |
185
+ | DingTalk | Proactive Markdown message; definite format rejection falls back to text |
186
+ | Slack | Standard Markdown block with top-level notification text; explicit block rejection falls back to the existing text sender |
187
+ | WeCom bot | Existing Markdown message type |
188
+ | Matrix | Sanitized HTML with a text body |
189
+ | Discord | Native Markdown in message content |
190
+ | WhatsApp | Limited conversion of common formatting; code is protected and complex syntax stays literal |
191
+ | WeCom app / Weixin | Full text, including code and link destinations |
192
+
193
+ Channels apply their own message limits and splitting. Feishu proactive cards retain their existing unsplit behavior and do not automatically resend as text after rejection or an uncertain result. Other newly added fallback paths only handle local formatting errors or definite format rejection; they do not resend accepted chunks or retry ambiguous network outcomes. Older Hosts may ignore `format`; load the updated plugin on the Host.
194
+
195
+ Session sync requests Markdown for final assistant answers and retains the existing default text behavior for user echoes. Feishu keeps its dedicated mirror cards and existing plain-text fallback when the mirror cannot confirm the final answer. This does not expand the supported sync targets.
181
196
 
182
197
  A same-Host plugin may also list the saved targets for one bot:
183
198
 
@@ -308,6 +323,7 @@ The HTTP protocol layer may also return `method-not-allowed` (405), `unsupported
308
323
  - Targets remain editable while a bot is offline, but testing and delivery require a connected bot.
309
324
  - WeChat proactive sends, connection tests, and deferred task results use the latest `context_token` received from the corresponding user by that bot. Context is stored only in the Host account state and restored after restart; it is never included in delivery targets or returned to callers. Rebinding with a different login credential clears it. After upgrading, an inbound user message is needed to populate the cache.
310
325
  - iLink server rules still govern whether WeChat accepts a send. Healthy long polling does not guarantee proactive delivery. If `ret=-2 prepare failed` persists, avoid repeated heartbeat messages as a renewal strategy; ask the recipient to send a message before retrying. This error alone does not establish login expiry, context expiry, or exhausted quota.
326
+ - Long proactive WeChat text uses the existing 1,800-character chunk budget. Synced assistant Markdown keeps complete code fences in each chunk. Each chunk consumes a platform send; splitting does not remove server quotas. A rejection or uncertain result stops delivery and reports failure without resending accepted chunks. Diagnostics identify the failed chunk and total chunk count.
311
327
 
312
328
  - Failed WeChat proactive sends remain visible in the account’s latest message error, with sanitized diagnostics including the provider code and whether context was included. Healthy polling does not clear this error; a successful outbound send does. HTTP/RPC still return the existing `delivery-failed` error, with no automatic retry or disconnection of healthy long polling.
313
329
 
@@ -175,9 +175,24 @@ await ctx.dshIm.send(botId, targetId, '# 每日报告\n\n**检查完成**', {
175
175
  });
176
176
  ```
177
177
 
178
- `format` 只接受 `plain` 和 `markdown`,省略时为 `plain`。当前 Markdown 格式适配用于飞书/Lark:私聊和群聊均通过原生 Markdown 卡片发送,不启动会话或流式输出;其他渠道保留原有发送行为,不保证 Markdown 渲染。HTTP 和 `message.send` RPC 可在请求体中添加同名 `format` 字段。
178
+ `format` 只接受 `plain` 和 `markdown`,省略时为 `plain`。HTTP 和 `message.send` RPC 可添加同名字段。Markdown 复用各渠道的发送路径,不启动 Session 或新的流式输出:
179
179
 
180
- Markdown 原文(含换行)完整传递,不进行静默截断或自动分段;消息仍受平台大小和 Markdown 语法限制。平台拒绝、超时或取消时沿用已有错误处理,不自动回退成纯文本重发,以免重复投递。旧版本 dsh-im 的 Host API 可能忽略这个新选项;调用方与 dsh-im 都需要加载支持该选项的代码。
180
+ | 渠道 | Markdown 呈现方式 |
181
+ | --- | --- |
182
+ | 飞书/Lark | 原生 Markdown 卡片 |
183
+ | Telegram | Rich Markdown,复用既有文本回退 |
184
+ | QQ | Markdown 消息;已知格式拒绝时仅当前分段回退文本 |
185
+ | 钉钉 | 主动 Markdown 消息;明确格式拒绝时回退文本 |
186
+ | Slack | 标准 Markdown block,保留通知文本;明确 block 拒绝时使用原有文本发送 |
187
+ | 企业微信机器人 | 现有 Markdown 消息类型 |
188
+ | Matrix | 清理后的 HTML,并附带文本正文 |
189
+ | Discord | 消息正文的原生 Markdown |
190
+ | WhatsApp | 有限转换常用格式,保护代码,复杂语法保留原文 |
191
+ | 企业微信应用/微信 | 完整文本,保留代码和链接目标 |
192
+
193
+ 长消息按渠道限制分段。飞书主动卡片保留原有不自动分段的行为,平台拒绝或结果未知时不自动改发文本。其他新增回退仅针对本地格式处理错误或明确的格式拒绝,不重发已成功的分段,不因网络结果未知而改格式重试。旧 Host 可能忽略 `format`,需要加载更新后的插件。
194
+
195
+ 会话同步的最终助手回答请求 Markdown,用户回显继续使用原有默认文字行为。飞书继续使用专用镜像卡片,无法确认最终答案可见时仍走现有纯文本兜底。同步目标范围不变。
181
196
 
182
197
  同 Host 插件也可以列出某个机器人的已保存目标:
183
198
 
@@ -308,6 +323,7 @@ HTTP 协议层还可能返回 `method-not-allowed`(405)、`unsupported-media
308
323
  - 机器人离线时仍可编辑目标,但不能测试或主动发送。
309
324
  - 微信主动投递、连接测试和延迟任务结果会使用该机器人最近收到的对应用户 `context_token`。上下文仅保存在 Host 的账号状态中,重启后恢复,不放进投递目标或返回给调用方;重新绑定并更换登录凭据后清理。升级后需要收到一次用户消息才能建立缓存。
310
325
  - 微信是否接受发送仍受 iLink 服务端规则约束。长轮询在线不保证主动发送可用;若持续出现 `ret=-2 prepare failed`,不要通过反复发送心跳尝试续期。可让目标用户发一条消息后重试;这不是登录凭据失效的确定证据,也不能仅凭此错误确定上下文过期或额度耗尽。
326
+ - 微信主动长文本沿用 1,800 字符分段预算,同步助手的 Markdown 代码块在各段补齐围栏。每一段都占用平台发送次数;分段不会解除平台额度限制。中途拒发或结果不确定时停止并报告失败,不重发已经接受的段;诊断会标明失败段序号和总段数。
311
327
 
312
328
  - 微信主动发送失败会保留在账号的最近消息错误中,包含平台错误码和是否携带上下文等脱敏诊断;健康轮询不会清除此错误,后续成功投递会清除。HTTP/RPC 仍返回既有的 `delivery-failed`,不会自动重试或断开正常的长轮询连接。
313
329
 
package/README.en.md CHANGED
@@ -181,6 +181,8 @@ IM channels with proactive delivery support can send text through a stable `botI
181
181
 
182
182
  Saved direct-message targets also offer an opt-in **Two-way Session sync** switch. Once enabled, user text submitted from DSH Web/CLI and the final assistant text in that DM's current Session are mirrored back to the DM, including final assistant text from successfully completed scheduled tasks; ordinary IM prompts and `/steer` are not duplicated. The switch follows the current Session across `/session`, `/new`, and workspace changes. The first version supports text DMs on the current Host only; groups, Topics, Threads, and explicit remote `harnessBaseUrl` connections are unavailable.
183
183
 
184
+ Synced answers use channel-specific Markdown rendering: Feishu cards, Telegram rich text, QQ/DingTalk/Slack formatted messages, and existing WeCom bot, Matrix and Discord support. WhatsApp adapts common formatting; WeCom app and Weixin preserve the full text. Formatting fallback and long-message handling reuse channel mechanisms without adding retries for uncertain delivery.
185
+
184
186
  See the [Proactive Delivery Guide](PROACTIVE_DELIVERY.en.md) ([简体中文](PROACTIVE_DELIVERY.md)) for setup steps, native fields for each supported channel, complete call examples, management endpoints, error codes, and troubleshooting.
185
187
 
186
188
  ### Client panel integration
package/README.md CHANGED
@@ -183,6 +183,8 @@ Logo 由 dsh-im 的浏览器适配显示,无需修改 DSH。适配保留原始
183
183
 
184
184
  已保存的私聊目标还可以开启默认关闭的「会话双向同步」。开启后,DSH Web/CLI 在该私聊当前 Session 中发送的用户文字和最终助手文字会同步回私聊,定时任务成功完成后的最终助手文字也会同步;IM 侧原有提问与 `/steer` 不会重复。开关自动跟随 `/session`、`/new` 和工作区切换后的当前 Session。首版仅支持当前 Host 的私聊文字;群聊、Topic、Thread 与显式远程 `harnessBaseUrl` 不支持。
185
185
 
186
+ 同步回答按渠道能力呈现 Markdown:复用飞书卡片、Telegram 富文本、QQ/钉钉/Slack 的格式消息,以及企业微信机器人、Matrix、Discord 的已有能力;WhatsApp 适配常用格式,企业微信应用和微信保留完整文本。格式降级与长消息处理沿用或复用渠道机制,发送结果未知时不新增自动重发。
187
+
186
188
  设置步骤、各渠道字段、完整调用示例、管理端点、错误码与排错说明请查看[《主动投递使用指南》](PROACTIVE_DELIVERY.md)([English](PROACTIVE_DELIVERY.en.md))。
187
189
 
188
190
  ### 客户端面板接入
package/lib/client.js CHANGED
@@ -595,7 +595,7 @@ var React40 = __toESM(require("react"), 1);
595
595
  // package.json
596
596
  var package_default = {
597
597
  name: "@xmanrui/dsh-im",
598
- version: "4.38.0",
598
+ version: "4.38.2",
599
599
  icon: "./assets/logo-plugin-message-link-gradient.webp",
600
600
  description: "\u628A\u5FAE\u4FE1\u3001\u98DE\u4E66\u3001\u4F01\u5FAE\u3001\u9489\u9489\u3001QQ\u3001Telegram\u3001WhatsApp\u3001Slack\u3001Discord\u3001Matrix\u63A5\u5165DSH\u3002 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.",
601
601
  keywords: [
@@ -962,6 +962,25 @@ var image_input_default = {
962
962
 
963
963
  // src/channels/shared/i18n-en/diagnostics.mjs
964
964
  var diagnostics_default = Object.freeze({
965
+ "\u51C6\u5907\u4F1A\u8BDD": "Prepare session",
966
+ "\u51C6\u5907\u6D88\u606F": "Prepare message",
967
+ "\u5EFA\u7ACB\u4EA4\u4E92\u901A\u9053": "Open interaction channel",
968
+ "\u63D0\u4EA4\u6D88\u606F": "Submit message",
969
+ "\u7B49\u5F85\u5904\u7406\u7ED3\u679C": "Wait for result",
970
+ "\u6D88\u606F\u63D0\u4EA4\u72B6\u6001": "Message submission status",
971
+ "\u672A\u63D0\u4EA4": "Not submitted",
972
+ "\u5DF2\u786E\u8BA4\u63A5\u6536": "Acceptance confirmed",
973
+ "\u63D0\u4EA4\u7ED3\u679C\u672A\u77E5": "Submission outcome unknown",
974
+ "\u8FDE\u63A5\u5C1D\u8BD5\u6B21\u6570": "Connection attempts",
975
+ "\u6700\u8FD1\u4E00\u6B21\u8FDE\u63A5\u5931\u8D25": "Last observed connection failure",
976
+ "\u6253\u5F00\u524D\u5173\u95ED": "Closed before opening",
977
+ "\u6253\u5F00\u524D\u5931\u8D25": "Failed before opening",
978
+ "\u901A\u9053\u8FDE\u63A5\u5931\u8D25": "Stream connection failed",
979
+ "\u4E0E DSH \u7684\u4EA4\u4E92\u901A\u9053\u5728 30 \u79D2\u5185\u672A\u5C31\u7EEA\uFF0C\u672C\u6761\u6D88\u606F\u5C1A\u672A\u63D0\u4EA4\u6267\u884C\u3002\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002": "The DSH interaction channel was not ready within 30 seconds. This message has not been submitted for execution. Please try again later.",
980
+ "\u6D88\u606F\u63D0\u4EA4\u524D\u7684\u64CD\u4F5C\u8D85\u65F6\uFF0C\u672C\u6761\u6D88\u606F\u5C1A\u672A\u63D0\u4EA4\u6267\u884C\u3002\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002": "An operation timed out before submission. This message has not been submitted for execution. Please try again later.",
981
+ "\u6D88\u606F\u63D0\u4EA4\u524D\u7684\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF0C\u672C\u6761\u6D88\u606F\u5C1A\u672A\u63D0\u4EA4\u6267\u884C\u3002\u8BF7\u68C0\u67E5\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002": "A network request failed before submission. This message has not been submitted for execution. Check the connection and try again.",
982
+ "\u6D88\u606F\u5728\u63D0\u4EA4\u524D\u5904\u7406\u5931\u8D25\uFF0C\u5C1A\u672A\u63D0\u4EA4\u6267\u884C\u3002\u8BF7\u91CD\u8BD5\uFF1B\u82E5\u6301\u7EED\u53D1\u751F\uFF0C\u8BF7\u5C06\u53C2\u8003\u53F7\u63D0\u4F9B\u7ED9\u7BA1\u7406\u5458\u3002": "Message preparation failed before submission. It has not been submitted for execution. Try again; if this persists, share the reference with your administrator.",
983
+ "\u6D88\u606F\u5DF2\u5C1D\u8BD5\u63D0\u4EA4\uFF0C\u4F46\u4EFB\u52A1\u7ED3\u679C\u5C1A\u672A\u786E\u8BA4\u3002\u8BF7\u5148\u5230 DSH \u67E5\u770B\u72B6\u6001\uFF0C\u4E0D\u8981\u7ACB\u5373\u91CD\u590D\u63D0\u4EA4\uFF1B\u82E5\u6301\u7EED\u53D1\u751F\uFF0C\u8BF7\u5C06\u53C2\u8003\u53F7\u63D0\u4F9B\u7ED9\u7BA1\u7406\u5458\u3002": "Message submission was attempted, but the task outcome is unconfirmed. Check its status in DSH before resubmitting; if this persists, share the reference with your administrator.",
965
984
  "DSH \u7248\u672C": "DSH version",
966
985
  "\u4F9D\u8D56\u7248\u672C": "Dependency versions",
967
986
  "\u4EE3\u7406\u5DF2\u914D\u7F6E": "Proxy configured",
@@ -2525,6 +2544,11 @@ var OPERATIONS = /* @__PURE__ */ new Set([
2525
2544
  "bot.alias.set"
2526
2545
  ]);
2527
2546
  var STAGES = /* @__PURE__ */ new Set([
2547
+ "session.prepare",
2548
+ "prompt.prepare",
2549
+ "interaction.open",
2550
+ "prompt.submit",
2551
+ "reply.wait",
2528
2552
  "credential.verify",
2529
2553
  "permission.check",
2530
2554
  "sdk.load",
@@ -2559,6 +2583,9 @@ var STAGES = /* @__PURE__ */ new Set([
2559
2583
  "management.request"
2560
2584
  ]);
2561
2585
  var REASONS = /* @__PURE__ */ new Set([
2586
+ "stream-closed-before-open",
2587
+ "stream-failed-before-open",
2588
+ "stream-failed",
2562
2589
  "ENOTFOUND",
2563
2590
  "EAI_AGAIN",
2564
2591
  "ECONNREFUSED",
@@ -2624,7 +2651,8 @@ var RPC_METHODS = /* @__PURE__ */ new Set([
2624
2651
  "session.selectModel",
2625
2652
  "llm.models"
2626
2653
  ]);
2627
- var TRANSPORTS = /* @__PURE__ */ new Set(["host-api", "http"]);
2654
+ var TRANSPORTS = /* @__PURE__ */ new Set(["host-api", "http", "websocket"]);
2655
+ var SUBMISSION_STATES = /* @__PURE__ */ new Set(["not-submitted", "accepted", "unknown"]);
2628
2656
  var CONFIG_FILES = /* @__PURE__ */ new Set(["config.json", "workspaces.json"]);
2629
2657
  var CONFIG_ISSUE_LABELS = Object.freeze({
2630
2658
  "expected-object": "\u5E94\u4E3A JSON \u5BF9\u8C61\u3002",
@@ -2646,7 +2674,7 @@ var CONFIG_FIELD = /^(?:\$|version|accounts(?:\[\d{1,10}\](?:\.(?:accountId|owne
2646
2674
  function normalizeDiagnosticDetails(value) {
2647
2675
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
2648
2676
  const result = {};
2649
- for (const [field2, allowed] of [["operation", OPERATIONS], ["stage", STAGES], ["reason", REASONS], ["resource", RESOURCES], ["method", RPC_METHODS], ["transport", TRANSPORTS]]) {
2677
+ for (const [field2, allowed] of [["operation", OPERATIONS], ["stage", STAGES], ["reason", REASONS], ["resource", RESOURCES], ["method", RPC_METHODS], ["transport", TRANSPORTS], ["submissionState", SUBMISSION_STATES], ["lastFailureReason", REASONS]]) {
2650
2678
  if (allowed.has(value[field2])) result[field2] = value[field2];
2651
2679
  }
2652
2680
  if (DIAGNOSTIC_CHANNELS.includes(value.channel)) result.channel = value.channel;
@@ -2655,6 +2683,7 @@ function normalizeDiagnosticDetails(value) {
2655
2683
  if (reasons.length) result.reasons = reasons;
2656
2684
  }
2657
2685
  for (const field2 of ["durationMs", "timeoutMs"]) if (Number.isFinite(value[field2]) && value[field2] >= 0) result[field2] = Math.round(value[field2]);
2686
+ if (Number.isSafeInteger(value.attempts) && value.attempts >= 0) result.attempts = value.attempts;
2658
2687
  for (const field2 of ["nodeVersion", "dshVersion"]) if (typeof value[field2] === "string" && /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/.test(value[field2]) && value[field2].length < 80) result[field2] = value[field2];
2659
2688
  if (["darwin", "linux", "win32", "freebsd"].includes(value.platform)) result.platform = value.platform;
2660
2689
  if (["ilinkai.weixin.qq.com", "oapi.dingtalk.com", "api.dingtalk.com", "api.telegram.org", "discord.com", "slack.com", "open.feishu.cn", "qyapi.weixin.qq.com"].includes(value.host)) result.host = value.host;
@@ -2694,6 +2723,11 @@ function diagnosticFields(value) {
2694
2723
 
2695
2724
  // plugin-src/client/connection-error.js
2696
2725
  var STAGE_LABELS = {
2726
+ "session.prepare": "\u51C6\u5907\u4F1A\u8BDD",
2727
+ "prompt.prepare": "\u51C6\u5907\u6D88\u606F",
2728
+ "interaction.open": "\u5EFA\u7ACB\u4EA4\u4E92\u901A\u9053",
2729
+ "prompt.submit": "\u63D0\u4EA4\u6D88\u606F",
2730
+ "reply.wait": "\u7B49\u5F85\u5904\u7406\u7ED3\u679C",
2697
2731
  "credential.verify": "\u9A8C\u8BC1\u51ED\u636E",
2698
2732
  "permission.check": "\u68C0\u67E5\u6743\u9650",
2699
2733
  "sdk.load": "\u52A0\u8F7D\u6E20\u9053\u7EC4\u4EF6",
@@ -2727,6 +2761,13 @@ var STAGE_LABELS = {
2727
2761
  rollback: "\u6062\u590D\u539F\u8D26\u53F7\u72B6\u6001",
2728
2762
  "management.request": "\u8BBF\u95EE DSH \u7BA1\u7406\u63A5\u53E3"
2729
2763
  };
2764
+ var SUBMISSION_LABELS = { "not-submitted": "\u672A\u63D0\u4EA4", accepted: "\u5DF2\u786E\u8BA4\u63A5\u6536", unknown: "\u63D0\u4EA4\u7ED3\u679C\u672A\u77E5" };
2765
+ var STREAM_REASON_LABELS = {
2766
+ "stream-closed-before-open": "\u6253\u5F00\u524D\u5173\u95ED",
2767
+ "stream-failed-before-open": "\u6253\u5F00\u524D\u5931\u8D25",
2768
+ "stream-failed": "\u901A\u9053\u8FDE\u63A5\u5931\u8D25",
2769
+ unknown: "\u6682\u672A\u8BC6\u522B"
2770
+ };
2730
2771
  function provisioningErrorTitle(error) {
2731
2772
  const stage = error?.details?.stage;
2732
2773
  if (stage === "qr.begin" || stage === "qr.encode") return "\u65E0\u6CD5\u751F\u6210\u5FAE\u4FE1\u4E8C\u7EF4\u7801";
@@ -2741,7 +2782,7 @@ function formatConnectionDiagnostic(value) {
2741
2782
  localizeText(error.message),
2742
2783
  details.hint ? localizeText(details.hint) : null,
2743
2784
  localizeText("\u9519\u8BEF\u7801") + ": " + error.code,
2744
- ...["channel", "operation", "stage", "method", "transport", "reason", "reasons", "host", "durationMs", "timeoutMs", "nodeVersion", "dshVersion", "platform", "dependencies", "proxyConfigured", "truncated", "httpStatus", "providerCode", "resource", "file", "field", "issue", "referenceId", "occurredAt", "rollback", "pluginVersion"].filter((field2) => details[field2] !== void 0).map((field2) => `${field2}: ${typeof details[field2] === "object" ? JSON.stringify(details[field2]) : details[field2]}`)
2785
+ ...["channel", "operation", "stage", "method", "transport", "submissionState", "attempts", "lastFailureReason", "reason", "reasons", "host", "durationMs", "timeoutMs", "nodeVersion", "dshVersion", "platform", "dependencies", "proxyConfigured", "truncated", "httpStatus", "providerCode", "resource", "file", "field", "issue", "referenceId", "occurredAt", "rollback", "pluginVersion"].filter((field2) => details[field2] !== void 0).map((field2) => `${field2}: ${typeof details[field2] === "object" ? JSON.stringify(details[field2]) : details[field2]}`)
2745
2786
  ].filter(Boolean).join("\n");
2746
2787
  }
2747
2788
  function ConnectionError({ error: value, warning = false, showMessage = true }) {
@@ -2763,7 +2804,10 @@ function ConnectionError({ error: value, warning = false, showMessage = true })
2763
2804
  ["\u9519\u8BEF\u7801", error.code],
2764
2805
  ["\u5931\u8D25\u9636\u6BB5", localizeText(STAGE_LABELS[details.stage] ?? details.stage ?? "")],
2765
2806
  ["RPC \u65B9\u6CD5", details.method],
2766
- ["\u8C03\u7528\u65B9\u5F0F", details.transport === "host-api" ? localizeText("\u5BBF\u4E3B API\uFF08\u8FDB\u7A0B\u5185\uFF09") : details.transport === "http" ? "HTTP" : void 0],
2807
+ ["\u8C03\u7528\u65B9\u5F0F", details.transport === "host-api" ? localizeText("\u5BBF\u4E3B API\uFF08\u8FDB\u7A0B\u5185\uFF09") : details.transport === "http" ? "HTTP" : details.transport === "websocket" ? "WebSocket" : void 0],
2808
+ ["\u6D88\u606F\u63D0\u4EA4\u72B6\u6001", localizeText(SUBMISSION_LABELS[details.submissionState] ?? "")],
2809
+ ["\u8FDE\u63A5\u5C1D\u8BD5\u6B21\u6570", details.attempts],
2810
+ ["\u6700\u8FD1\u4E00\u6B21\u8FDE\u63A5\u5931\u8D25", localizeText(STREAM_REASON_LABELS[details.lastFailureReason] ?? details.lastFailureReason ?? "")],
2767
2811
  ["\u5E95\u5C42\u539F\u56E0", details.reason === "unknown" ? localizeText("\u6682\u672A\u8BC6\u522B") : details.reason],
2768
2812
  ["\u591A\u4E2A\u539F\u56E0", details.reasons?.join(", ")],
2769
2813
  ["\u670D\u52A1\u57DF\u540D", details.host],