@xmanrui/dsh-im 0.13.0 → 0.14.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.
Files changed (41) hide show
  1. package/README.en.md +25 -10
  2. package/README.md +26 -11
  3. package/assets/logo-dsh-im-connecting-readme-3x2.png +0 -0
  4. package/assets/logo-dsh-im-connecting-square-v4.png +0 -0
  5. package/assets/logo-plugin-phone.png +0 -0
  6. package/lib/client.js +803 -171
  7. package/lib/index.js +142 -130
  8. package/package.json +4 -3
  9. package/plugin-src/client/build.mjs +1 -6
  10. package/plugin-src/client/channel-logos.js +12 -0
  11. package/plugin-src/client/channels/office/api.js +44 -0
  12. package/plugin-src/client/channels/office/index.js +152 -0
  13. package/plugin-src/client/channels/office/styles.js +50 -0
  14. package/plugin-src/client/channels/shared/token-api.js +5 -1
  15. package/plugin-src/client/channels/shared/token-channel.js +16 -1
  16. package/plugin-src/client/channels/telegram/api.js +17 -2
  17. package/plugin-src/client/channels/telegram/index.js +112 -0
  18. package/plugin-src/client/channels/telegram/styles.js +26 -0
  19. package/plugin-src/client/i18n.js +68 -0
  20. package/plugin-src/client/index.js +21 -11
  21. package/plugin-src/client/styles.js +5 -3
  22. package/plugin-src/host/channels/office/index.mjs +10 -0
  23. package/plugin-src/host/channels/office/production.mjs +45 -0
  24. package/plugin-src/host/channels/office/rpc.mjs +48 -0
  25. package/plugin-src/host/channels/shared/production.mjs +9 -1
  26. package/plugin-src/host/channels/telegram/production.mjs +2 -0
  27. package/plugin-src/host/channels/telegram/rpc.mjs +58 -8
  28. package/plugin-src/host/index.mjs +3 -0
  29. package/src/channels/discord/discord-api.mjs +1 -1
  30. package/src/channels/office/config-store.mjs +107 -0
  31. package/src/channels/office/office-controller.mjs +167 -0
  32. package/src/channels/office/office-job-executor.mjs +390 -0
  33. package/src/channels/office/office-runtime.mjs +171 -0
  34. package/src/channels/office/office-transport.mjs +170 -0
  35. package/src/channels/office/protocol.mjs +43 -0
  36. package/src/channels/shared/token-bot-controller.mjs +28 -0
  37. package/src/channels/shared/token-config-store.mjs +14 -1
  38. package/src/channels/telegram/config-store.mjs +62 -1
  39. package/src/channels/telegram/telegram-controller.mjs +25 -1
  40. package/src/channels/telegram/telegram-runtime.mjs +26 -1
  41. package/src/channels/weixin/weixin-api.mjs +1 -1
package/lib/client.js CHANGED
@@ -40,7 +40,7 @@ __export(index_exports, {
40
40
  name: () => name
41
41
  });
42
42
  module.exports = __toCommonJS(index_exports);
43
- var React16 = __toESM(require("react"), 1);
43
+ var React18 = __toESM(require("react"), 1);
44
44
 
45
45
  // plugin-src/client/channel-logos.js
46
46
  var React = __toESM(require("react"), 1);
@@ -171,6 +171,20 @@ function WhatsappLogoGlyph({ size } = {}) {
171
171
  d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.074-.297-.149-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.521.149-.173.198-.297.298-.495.099-.198.05-.372-.025-.521-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51a12.8 12.8 0 0 0-.57-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479s1.065 2.875 1.213 3.074c.149.198 2.095 3.2 5.077 4.487.709.306 1.262.489 1.694.626.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.29.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.981.999-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.83 9.83 0 0 1 2.893 6.991c-.003 5.45-4.437 9.884-9.886 9.884m8.413-18.297A11.8 11.8 0 0 0 12.055 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.9 11.9 0 0 0 5.688 1.448h.005c6.557 0 11.892-5.335 11.895-11.893a11.82 11.82 0 0 0-3.486-8.413"
172
172
  }));
173
173
  }
174
+ function OfficeLogoGlyph({ size } = {}) {
175
+ return h(
176
+ "svg",
177
+ {
178
+ ...dimensions(size),
179
+ viewBox: "0 0 24 24",
180
+ focusable: "false",
181
+ "aria-hidden": "true",
182
+ "data-im-channel-logo": "office"
183
+ },
184
+ h("path", { fill: "currentColor", d: "M4 3.5h10.5a2 2 0 0 1 2 2v13H4v-15Zm2.2 3v1.8h2V6.5h-2Zm4.1 0v1.8h2V6.5h-2Zm-4.1 4v1.8h2v-1.8h-2Zm4.1 0v1.8h2v-1.8h-2ZM8.4 15v3.5h3V15h-3Z" }),
185
+ h("path", { fill: "currentColor", d: "M18.3 8.2h1.5v3h3v1.5h-3v3h-1.5v-3h-3v-1.5h3v-3Z" })
186
+ );
187
+ }
174
188
 
175
189
  // plugin-src/client/channels/dingtalk/api.js
176
190
  var DINGTALK_RPC_CHANNEL = "/dingtalk";
@@ -384,6 +398,51 @@ var EN = Object.freeze({
384
398
  "IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
385
399
  "IM \u6E20\u9053": "IM channels",
386
400
  "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA": "DeepSeek Harness, always within reach",
401
+ "AI Office": "AI Office",
402
+ "AI Office \u8BBE\u7F6E": "AI Office settings",
403
+ "AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5": "AI Office settings are missing an RPC connection",
404
+ "\u6B63\u5728\u8BFB\u53D6 AI Office Connector\u2026": "Loading AI Office Connector\u2026",
405
+ "\u672C\u673A\u4E3B\u52A8\u8FDE\u63A5\u516C\u7F51 Office\uFF1BHarness \u4E0D\u5F00\u653E\u7AEF\u53E3\u3002\u534F\u8BAE Hook \u56FA\u5B9A\u4E3A ": "This machine connects outward to the public Office; Harness exposes no port. Protocol hooks: ",
406
+ "\u5C1A\u672A\u914D\u7F6E": "Not configured",
407
+ "\u5DF2\u8FDE\u63A5 Office": "Connected to Office",
408
+ "\u5DF2\u914D\u7F6E": "Configured",
409
+ "\u7B49\u5F85\u91CD\u8FDE": "Waiting to reconnect",
410
+ "\u51ED\u636E\u7F3A\u5931": "Credential missing",
411
+ "\u6700\u8FD1\u5FC3\u8DF3": "Last heartbeat",
412
+ "\u6700\u8FD1\u4E8B\u4EF6": "Last event",
413
+ "\u91CD\u8FDE\u6B21\u6570": "Reconnects",
414
+ "\u8FD0\u884C Job": "Running Jobs",
415
+ "\u5B8C\u6210 Job": "Completed Jobs",
416
+ "\u5C1A\u65E0": "None yet",
417
+ "\u8BBE\u5907\u8FDE\u63A5": "Device connection",
418
+ "Token \u53EA\u5199\u5165\u672C\u673A\u51ED\u636E\u5B58\u50A8": "Token is written only to the local credential store",
419
+ "\u7C98\u8D34 Office \u4E00\u6B21\u6027\u51ED\u636E": "Paste the one-time Office credential",
420
+ "\u5DF2\u5B89\u5168\u4FDD\u5B58\uFF1B\u7559\u7A7A\u4FDD\u6301\u4E0D\u53D8": "Stored securely; leave blank to keep it",
421
+ "\u6700\u5927\u5E76\u53D1": "Max concurrency",
422
+ "Heartbeat \u79D2\u6570": "Heartbeat seconds",
423
+ "Workspace \u6620\u5C04": "Workspace mappings",
424
+ "\u6BCF\u884C alias=/\u672C\u673A/\u7EDD\u5BF9\u8DEF\u5F84\uFF1BOffice \u53EA\u80FD\u770B\u5230 alias\u3002": "One alias=/local/absolute/path per line; Office sees only aliases.",
425
+ "Instruction Preset \u6620\u5C04": "Instruction preset mappings",
426
+ "\u6BCF\u884C alias=\u6307\u4EE4\uFF1B\u65B0\u589E preset \u4E0D\u9700\u8981\u6539 Office \u4EE3\u7801\u3002": "One alias=instruction per line; new presets require no Office code change.",
427
+ "\u4FDD\u5B58\u5E76\u8FDE\u63A5": "Save and connect",
428
+ "\u6D4B\u8BD5\u8FDE\u63A5": "Test connection",
429
+ "\u6D4B\u8BD5\u4E2D\u2026": "Testing\u2026",
430
+ "\u91CD\u65B0\u8FDE\u63A5": "Reconnect",
431
+ "\u79FB\u9664\u8FDE\u63A5": "Remove connection",
432
+ "\u8FDE\u63A5\u6D4B\u8BD5\u901A\u8FC7\u3002": "Connection test passed.",
433
+ "\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002": "Configuration saved.",
434
+ "\u534F\u8BAE Hook \u9884\u89C8": "Protocol hook preview",
435
+ "\u7531 Base URL \u81EA\u52A8\u6D3E\u751F\uFF0C\u4E0D\u5355\u72EC\u586B\u5199": "Derived from Base URL; no separate input",
436
+ "Base URL \u65E0\u6548": "Invalid Base URL",
437
+ "Office Hook \u5C1A\u672A\u90E8\u7F72\u65F6\uFF0C\u914D\u7F6E\u4F1A\u5B89\u5168\u4FDD\u5B58\u5E76\u81EA\u52A8\u91CD\u8BD5\uFF1B\u51FA\u73B0 HTTP 404 \u4EE3\u8868\u534F\u8BAE\u7AEF\u70B9\u5F85\u4E0A\u7EBF\uFF0C\u4E0D\u4EE3\u8868 Harness \u6545\u969C\u3002": "Configuration is saved and retried while Office hooks are unavailable; HTTP 404 means the protocol endpoint is pending, not a Harness failure.",
438
+ "Workspace \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value": "Each workspace mapping must use alias=value",
439
+ "Instruction Preset \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value": "Each instruction preset mapping must use alias=value",
440
+ "action-items=\u8F6C\u6362\u4E3A\u8D1F\u8D23\u4EBA\u3001\u622A\u6B62\u548C\u9A8C\u6536\u660E\u786E\u7684\u5DE5\u5355": "action-items=Turn this into accountable tasks with deadlines and acceptance criteria",
441
+ "AI Office \u62D2\u7EDD\u4E86 Device Token\u3002": "AI Office rejected the Device Token.",
442
+ "AI Office Connector Hook \u5C1A\u672A\u5C31\u7EEA\u3002": "AI Office Connector hooks are not available yet.",
443
+ "AI Office Connector \u534F\u8BAE\u7248\u672C\u4E0D\u517C\u5BB9\u3002": "The AI Office Connector protocol is incompatible.",
444
+ "\u672C\u673A\u6682\u65F6\u65E0\u6CD5\u8BBF\u95EE AI Office\u3002": "AI Office cannot currently be reached from this machine.",
445
+ "AI Office \u8FDE\u63A5\u5DF2\u4E2D\u65AD\u3002": "The AI Office connection was interrupted.",
387
446
  "\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub": "Help & feedback \xB7 Open GitHub",
388
447
  "\u5FAE\u4FE1": "WeChat",
389
448
  "\u98DE\u4E66": "Feishu",
@@ -612,6 +671,29 @@ var EN = Object.freeze({
612
671
  "\u63A5\u5165 Telegram \u673A\u5668\u4EBA": "Connect a Telegram bot",
613
672
  "\u5148\u901A\u8FC7 @BotFather \u83B7\u53D6 Bot Token\uFF0C\u518D\u5728\u8FD9\u91CC\u5B8C\u6210\u63A5\u5165\u3002": "Get a Bot Token from @BotFather, then connect it here.",
614
673
  "\u586B\u5199 @BotFather \u751F\u6210\u7684 Bot Token": "Enter the Bot Token from @BotFather",
674
+ "\u8BBF\u95EE\u6A21\u5F0F": "Access mode",
675
+ "\u8BBF\u95EE\u8BBE\u7F6E": "Access settings",
676
+ "Telegram \u8BBF\u95EE\u6A21\u5F0F": "Telegram access mode",
677
+ "\u67E5\u770B Telegram \u8BBF\u95EE\u6A21\u5F0F\u8BF4\u660E": "View Telegram access mode details",
678
+ "\u7FA4\u804A\u5168\u90E8\u5FFD\u7565\uFF0C\u79C1\u804A\u4EC5\u5141\u8BB8\u767D\u540D\u5355\u7528\u6237\u3002": "All group messages are ignored; only allowlisted users may send DMs.",
679
+ "\u4FDD\u6301\u539F\u6709\u884C\u4E3A\uFF1A\u79C1\u804A\u76F4\u63A5\u54CD\u5E94\uFF0C\u7FA4\u804A\u5728\u88AB\u63D0\u53CA\u6216\u56DE\u590D\u65F6\u54CD\u5E94\u3002": "Keep the original behavior: respond to DMs and to group mentions or replies.",
680
+ "\u5B89\u5168\u6A21\u5F0F": "Safe mode",
681
+ "\u517C\u5BB9\u6A21\u5F0F": "Compatible mode",
682
+ "\u5DF2\u751F\u6548\uFF1A\u5B89\u5168\u6A21\u5F0F": "Active: Safe mode",
683
+ "\u5DF2\u751F\u6548\uFF1A\u517C\u5BB9\u6A21\u5F0F": "Active: Compatible mode",
684
+ "\u6A21\u5F0F": "Mode",
685
+ "\u517C\u5BB9\u6A21\u5F0F\uFF08\u9ED8\u8BA4\uFF09": "Compatible mode (default)",
686
+ "\u5B89\u5168\u6A21\u5F0F\uFF08\u79C1\u804A\u767D\u540D\u5355\uFF09": "Safe mode (private-chat allowlist)",
687
+ "\u5141\u8BB8\u79C1\u804A\u7684 Telegram User ID": "Telegram User IDs allowed to send DMs",
688
+ "\u6BCF\u884C\u4E00\u4E2A\u6570\u5B57 User ID": "One numeric User ID per line",
689
+ "\u767D\u540D\u5355\u4EC5\u5C5E\u4E8E\u5F53\u524D\u673A\u5668\u4EBA\u3002": "This allowlist belongs only to the current bot.",
690
+ "\u517C\u5BB9\u6A21\u5F0F\u4E0B\u6682\u4E0D\u4F7F\u7528\u767D\u540D\u5355\uFF0C\u5207\u6362\u6A21\u5F0F\u65F6\u4F1A\u4FDD\u7559\u3002": "Compatible mode does not enforce the allowlist; it is retained when modes change.",
691
+ "\u767D\u540D\u5355\u4E3A\u7A7A\uFF1B\u4FDD\u5B58\u540E\u8BE5\u673A\u5668\u4EBA\u4F1A\u62D2\u7EDD\u6240\u6709\u5165\u7AD9\u6D88\u606F\u3002": "The allowlist is empty; this bot will reject all inbound messages after saving.",
692
+ "\u6B63\u5728\u4FDD\u5B58\u2026": "Saving\u2026",
693
+ "\u4FDD\u5B58\u8BBF\u95EE\u8BBE\u7F6E": "Save access settings",
694
+ "User ID \u5FC5\u987B\u662F 1\u201316 \u4F4D\u6B63\u6574\u6570\uFF0C\u6BCF\u884C\u4E00\u4E2A\u3002": "Each User ID must be a 1\u201316 digit positive integer on its own line.",
695
+ "Telegram \u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002": "Telegram access settings are currently unavailable.",
696
+ "Telegram \u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002": "Could not save Telegram access settings.",
615
697
  "\u63A5\u5165 Discord \u673A\u5668\u4EBA": "Connect a Discord bot",
616
698
  "\u5148\u5728 Developer Portal \u521B\u5EFA Bot \u5E76\u9080\u8BF7\u5230\u670D\u52A1\u5668\uFF0C\u518D\u5728\u8FD9\u91CC\u5B8C\u6210\u63A5\u5165\u3002": "Create a bot in the Developer Portal and invite it to your server, then connect it here.",
617
699
  "\u586B\u5199 Discord Developer Portal \u7684 Bot Token": "Enter the Bot Token from the Discord Developer Portal",
@@ -1773,7 +1855,7 @@ function AccountCard({
1773
1855
  }) {
1774
1856
  const state = busy === "reconnect" ? "connecting" : account.state;
1775
1857
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
1776
- const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
1858
+ const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
1777
1859
  const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
1778
1860
  return h2(
1779
1861
  "article",
@@ -1799,7 +1881,7 @@ function AccountCard({
1799
1881
  "div",
1800
1882
  { className: "ddt-health dim-botHealth" },
1801
1883
  h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
1802
- h2("span", null, stateLabel)
1884
+ h2("span", null, stateLabel2)
1803
1885
  )
1804
1886
  ),
1805
1887
  h2(
@@ -2405,7 +2487,9 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
2405
2487
  deleteBot: "bot.delete",
2406
2488
  setWorkspace: "bot.workspace.set"
2407
2489
  });
2408
- function createTokenChannelApi(channel4, connectionSummary) {
2490
+ function createTokenChannelApi(channel4, connectionSummary, {
2491
+ normalizeBotExtension = () => ({})
2492
+ } = {}) {
2409
2493
  const unwrapRpcResult10 = (result) => {
2410
2494
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
2411
2495
  throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
@@ -2421,6 +2505,7 @@ function createTokenChannelApi(channel4, connectionSummary) {
2421
2505
  if (!isRecord2(value) || !id(value.botId)) return void 0;
2422
2506
  const connected = value.connected === true;
2423
2507
  const state = ACCOUNT_STATES2.has(value.state) ? value.state : "offline";
2508
+ const extension = normalizeBotExtension(value);
2424
2509
  return {
2425
2510
  botId: id(value.botId),
2426
2511
  connected,
@@ -2441,7 +2526,8 @@ function createTokenChannelApi(channel4, connectionSummary) {
2441
2526
  error: isRecord2(value.error) ? {
2442
2527
  code: text(value.error.code, `${channel4.toUpperCase()}_ACCOUNT_ERROR`, 80),
2443
2528
  message: text(value.error.message, `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
2444
- } : null
2529
+ } : null,
2530
+ ...isRecord2(extension) ? extension : {}
2445
2531
  };
2446
2532
  };
2447
2533
  const normalizeSnapshot9 = (value) => {
@@ -2521,12 +2607,14 @@ function createTokenChannelSettings(definition) {
2521
2607
  credentialOpenLabel = "\u624B\u52A8\u63A5\u5165",
2522
2608
  credentialCloseLabel = "\u6536\u8D77\u51ED\u636E",
2523
2609
  credentialNoun = "Bot Token",
2524
- emptyActionLabel = "\u586B\u5199 Bot Token"
2610
+ emptyActionLabel = "\u586B\u5199 Bot Token",
2611
+ AccountSettings = null,
2612
+ accountSettingsEndpoint = null
2525
2613
  } = definition;
2526
- function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
2614
+ function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
2527
2615
  const state = busy === "reconnect" ? "connecting" : account.state;
2528
2616
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
2529
- const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
2617
+ const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
2530
2618
  const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
2531
2619
  const identity = account.bot.username ? `@${account.bot.username}` : account.bot.idMasked;
2532
2620
  return h2(
@@ -2557,7 +2645,7 @@ function createTokenChannelSettings(definition) {
2557
2645
  "div",
2558
2646
  { className: "ddt-health dim-botHealth" },
2559
2647
  h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
2560
- h2("span", null, stateLabel)
2648
+ h2("span", null, stateLabel2)
2561
2649
  )
2562
2650
  ),
2563
2651
  h2(
@@ -2581,6 +2669,11 @@ function createTokenChannelSettings(definition) {
2581
2669
  disabled: Boolean(busy),
2582
2670
  onSave: onWorkspaceSave
2583
2671
  }),
2672
+ AccountSettings ? h2(AccountSettings, {
2673
+ account,
2674
+ busy: Boolean(busy),
2675
+ onSave: onAccountSettingsSave
2676
+ }) : null,
2584
2677
  h2(
2585
2678
  "div",
2586
2679
  { className: "ddt-accountFooter dim-cardFooter" },
@@ -2765,6 +2858,12 @@ function createTokenChannelSettings(definition) {
2765
2858
  endpoints.setWorkspace,
2766
2859
  { botId: account.botId, workspace }
2767
2860
  ),
2861
+ onAccountSettingsSave: AccountSettings && accountSettingsEndpoint ? (payload) => botAction(
2862
+ account,
2863
+ "settings",
2864
+ accountSettingsEndpoint,
2865
+ { botId: account.botId, ...payload }
2866
+ ) : void 0,
2768
2867
  onRequestRemove: () => setRemoveTarget(account.botId),
2769
2868
  onCancelRemove: () => setRemoveTarget(null),
2770
2869
  onConfirmRemove: async () => {
@@ -5148,7 +5247,7 @@ function AccountCard2({
5148
5247
  onCancelRemove
5149
5248
  }) {
5150
5249
  const tone = account.connected ? "success" : account.state === "error" ? "error" : "warning";
5151
- const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
5250
+ const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
5152
5251
  const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
5153
5252
  return h2(
5154
5253
  "article",
@@ -5174,7 +5273,7 @@ function AccountCard2({
5174
5273
  "div",
5175
5274
  { className: "ddt-health dim-botHealth" },
5176
5275
  h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
5177
- h2("span", null, stateLabel)
5276
+ h2("span", null, stateLabel2)
5178
5277
  )
5179
5278
  ),
5180
5279
  h2(
@@ -5490,6 +5589,350 @@ function QqSettingsTab({ rpcCall }) {
5490
5589
  );
5491
5590
  }
5492
5591
 
5592
+ // src/channels/office/protocol.mjs
5593
+ var OFFICE_PROTOCOL_VERSION = "office-harness.v1";
5594
+ var OFFICE_RPC_CHANNEL = "/office";
5595
+ var OFFICE_RPC_ENDPOINTS = Object.freeze({
5596
+ status: "connection.status",
5597
+ configure: "connector.configure",
5598
+ reconnect: "connector.reconnect",
5599
+ test: "connector.test",
5600
+ remove: "connector.remove"
5601
+ });
5602
+ var OFFICE_HOOK_PATHS = Object.freeze({
5603
+ stream: "/api/harness/connector/stream",
5604
+ heartbeat: "/api/harness/connector/heartbeat",
5605
+ job: "/api/harness/connector/jobs/:id",
5606
+ accept: "/api/harness/connector/jobs/:id/accept",
5607
+ renew: "/api/harness/connector/jobs/:id/renew",
5608
+ progress: "/api/harness/connector/jobs/:id/progress",
5609
+ approval: "/api/harness/connector/jobs/:id/approval",
5610
+ result: "/api/harness/connector/jobs/:id/result",
5611
+ fail: "/api/harness/connector/jobs/:id/fail"
5612
+ });
5613
+ function normalizeOfficeBaseUrl(value) {
5614
+ const url = new URL(typeof value === "string" ? value.trim() : "");
5615
+ const localHttp = url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
5616
+ if (url.protocol !== "https:" && !localHttp) {
5617
+ throw new TypeError("AI Office URL must use HTTPS (HTTP is allowed only for loopback testing)");
5618
+ }
5619
+ if (url.username || url.password || url.search || url.hash) {
5620
+ throw new TypeError("AI Office URL must be a bare origin");
5621
+ }
5622
+ url.pathname = "/";
5623
+ return url;
5624
+ }
5625
+ function officeHookUrls(baseUrl) {
5626
+ const origin = normalizeOfficeBaseUrl(baseUrl);
5627
+ return Object.fromEntries(Object.entries(OFFICE_HOOK_PATHS).map(([name2, path]) => [
5628
+ name2,
5629
+ new URL(path, origin).toString()
5630
+ ]));
5631
+ }
5632
+
5633
+ // plugin-src/client/channels/office/api.js
5634
+ function record(value) {
5635
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5636
+ }
5637
+ function unwrapOfficeRpc(result) {
5638
+ if (!record(result) || typeof result.ok !== "boolean") throw new Error("AI Office \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
5639
+ if (!result.ok) {
5640
+ const error = new Error(typeof result.error?.message === "string" ? result.error.message : "AI Office \u64CD\u4F5C\u5931\u8D25");
5641
+ error.code = typeof result.error?.code === "string" ? result.error.code : "office-rpc-error";
5642
+ throw error;
5643
+ }
5644
+ return result.value;
5645
+ }
5646
+ function normalizeOfficeStatus(value) {
5647
+ if (!record(value) || value.configured !== true) {
5648
+ return { configured: false, connected: false, state: "unconfigured", config: null, health: null };
5649
+ }
5650
+ const config = record(value.config) ? value.config : {};
5651
+ return {
5652
+ configured: true,
5653
+ connected: value.connected === true,
5654
+ state: typeof value.state === "string" ? value.state : "idle",
5655
+ tokenConfigured: value.tokenConfigured === true,
5656
+ config: {
5657
+ protocolVersion: config.protocolVersion ?? OFFICE_PROTOCOL_VERSION,
5658
+ baseUrl: typeof config.baseUrl === "string" ? config.baseUrl : "",
5659
+ deviceId: typeof config.deviceId === "string" ? config.deviceId : "",
5660
+ maxConcurrency: Number(config.maxConcurrency ?? 1),
5661
+ heartbeatSeconds: Number(config.heartbeatSeconds ?? 30),
5662
+ workspaces: record(config.workspaces) ? config.workspaces : {},
5663
+ instructionPresets: record(config.instructionPresets) ? config.instructionPresets : {},
5664
+ hooks: record(config.hooks) ? config.hooks : {}
5665
+ },
5666
+ health: record(value.health) ? value.health : null
5667
+ };
5668
+ }
5669
+
5670
+ // plugin-src/client/channels/office/index.js
5671
+ var React12 = __toESM(require("react"), 1);
5672
+ function Button9({ children, kind = "secondary", ...props }) {
5673
+ return h2("button", { ...props, type: "button", className: "ddt-button", "data-kind": kind }, children);
5674
+ }
5675
+ function mapText(value) {
5676
+ return Object.entries(value ?? {}).map(([key, item]) => `${key}=${item}`).join("\n");
5677
+ }
5678
+ function parseMap(value, label) {
5679
+ const output = {};
5680
+ for (const raw of value.split(/\r?\n/)) {
5681
+ const line = raw.trim();
5682
+ if (!line) continue;
5683
+ const index = line.indexOf("=");
5684
+ if (index < 1 || !line.slice(index + 1).trim()) {
5685
+ throw new Error(label === "Workspace \u6620\u5C04" ? "Workspace \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value" : "Instruction Preset \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value");
5686
+ }
5687
+ output[line.slice(0, index).trim()] = line.slice(index + 1).trim();
5688
+ }
5689
+ return output;
5690
+ }
5691
+ function stateLabel(model) {
5692
+ if (model.connected) return "\u5DF2\u8FDE\u63A5 Office";
5693
+ if (!model.configured) return "\u5C1A\u672A\u914D\u7F6E";
5694
+ if (model.state === "connecting") return "\u6B63\u5728\u8FDE\u63A5";
5695
+ if (model.state === "reconnecting") return "\u7B49\u5F85\u91CD\u8FDE";
5696
+ if (model.state === "missing-token") return "\u51ED\u636E\u7F3A\u5931";
5697
+ return "\u5DF2\u914D\u7F6E";
5698
+ }
5699
+ function OfficeSettingsTab({ rpcCall, initialStatus }) {
5700
+ const [model, setModel] = React12.useState(normalizeOfficeStatus(initialStatus));
5701
+ const [phase, setPhase] = React12.useState(initialStatus === void 0 ? "loading" : "ready");
5702
+ const [busy, setBusy] = React12.useState("");
5703
+ const [error, setError] = React12.useState("");
5704
+ const [notice, setNotice] = React12.useState("");
5705
+ const [form, setForm] = React12.useState({
5706
+ baseUrl: "",
5707
+ deviceId: "local-harness",
5708
+ deviceToken: "",
5709
+ maxConcurrency: "1",
5710
+ heartbeatSeconds: "30",
5711
+ workspaces: "",
5712
+ instructionPresets: ""
5713
+ });
5714
+ const invoke = React12.useCallback(async (endpoint, payload = {}) => {
5715
+ if (typeof rpcCall !== "function") throw new Error("AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
5716
+ return unwrapOfficeRpc(await rpcCall(endpoint, payload));
5717
+ }, [rpcCall]);
5718
+ const adopt = React12.useCallback((value) => {
5719
+ const next = normalizeOfficeStatus(value?.snapshot ?? value);
5720
+ setModel(next);
5721
+ if (next.config) setForm((current) => ({
5722
+ ...current,
5723
+ baseUrl: next.config.baseUrl,
5724
+ deviceId: next.config.deviceId,
5725
+ maxConcurrency: String(next.config.maxConcurrency),
5726
+ heartbeatSeconds: String(next.config.heartbeatSeconds),
5727
+ workspaces: mapText(next.config.workspaces),
5728
+ instructionPresets: mapText(next.config.instructionPresets),
5729
+ deviceToken: ""
5730
+ }));
5731
+ return next;
5732
+ }, []);
5733
+ const load = React12.useCallback(async () => {
5734
+ try {
5735
+ adopt(await invoke(OFFICE_RPC_ENDPOINTS.status));
5736
+ setPhase("ready");
5737
+ setError("");
5738
+ } catch (caught) {
5739
+ setPhase("error");
5740
+ setError(caught.message);
5741
+ }
5742
+ }, [adopt, invoke]);
5743
+ React12.useEffect(() => {
5744
+ void load();
5745
+ }, [load]);
5746
+ const run = async (name2, operation) => {
5747
+ setBusy(name2);
5748
+ setError("");
5749
+ setNotice("");
5750
+ try {
5751
+ const value = await operation();
5752
+ adopt(value);
5753
+ setNotice(name2 === "test" ? "\u8FDE\u63A5\u6D4B\u8BD5\u901A\u8FC7\u3002" : "\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002");
5754
+ } catch (caught) {
5755
+ setError(caught.message);
5756
+ } finally {
5757
+ setBusy("");
5758
+ }
5759
+ };
5760
+ const hooks = React12.useMemo(() => {
5761
+ try {
5762
+ return officeHookUrls(form.baseUrl);
5763
+ } catch {
5764
+ return {};
5765
+ }
5766
+ }, [form.baseUrl]);
5767
+ const health = model.health ?? {};
5768
+ if (phase === "loading") return h2("div", { className: "ddt-card ddt-loading", "aria-busy": "true" }, "\u6B63\u5728\u8BFB\u53D6 AI Office Connector\u2026");
5769
+ return h2(
5770
+ "section",
5771
+ { className: "dof-page", "aria-label": "AI Office \u8BBE\u7F6E" },
5772
+ h2(
5773
+ "div",
5774
+ { className: "dof-hero" },
5775
+ h2(
5776
+ "div",
5777
+ { className: "dof-heroCopy" },
5778
+ h2("h3", null, "AI Office Connector"),
5779
+ h2("p", null, "\u672C\u673A\u4E3B\u52A8\u8FDE\u63A5\u516C\u7F51 Office\uFF1BHarness \u4E0D\u5F00\u653E\u7AEF\u53E3\u3002\u534F\u8BAE Hook \u56FA\u5B9A\u4E3A ", OFFICE_PROTOCOL_VERSION, "\u3002")
5780
+ ),
5781
+ h2(
5782
+ "span",
5783
+ { className: "dof-status", "data-connected": String(model.connected) },
5784
+ h2("span", { className: "dof-dot" }),
5785
+ stateLabel(model)
5786
+ )
5787
+ ),
5788
+ model.configured ? h2(
5789
+ "div",
5790
+ { className: "dof-metrics" },
5791
+ h2("div", { className: "dof-metric" }, h2("span", null, "\u6700\u8FD1\u5FC3\u8DF3"), h2("strong", null, health.lastHeartbeatAt ?? "\u5C1A\u65E0")),
5792
+ h2("div", { className: "dof-metric" }, h2("span", null, "\u6700\u8FD1\u4E8B\u4EF6"), h2("strong", null, health.lastEventType ?? "\u5C1A\u65E0")),
5793
+ h2("div", { className: "dof-metric" }, h2("span", null, "\u91CD\u8FDE\u6B21\u6570"), h2("strong", null, String(health.reconnects ?? 0))),
5794
+ h2("div", { className: "dof-metric" }, h2("span", null, "Job Offer"), h2("strong", null, String(health.jobsOffered ?? 0))),
5795
+ h2("div", { className: "dof-metric" }, h2("span", null, "\u8FD0\u884C Job"), h2("strong", null, String(health.jobs?.running ?? 0))),
5796
+ h2("div", { className: "dof-metric" }, h2("span", null, "\u5B8C\u6210 Job"), h2("strong", null, String(health.jobs?.completed ?? 0)))
5797
+ ) : null,
5798
+ h2(
5799
+ "div",
5800
+ { className: "dof-card" },
5801
+ h2("div", { className: "dof-cardTitle" }, h2("h4", null, "\u8BBE\u5907\u8FDE\u63A5"), h2("span", null, "Token \u53EA\u5199\u5165\u672C\u673A\u51ED\u636E\u5B58\u50A8")),
5802
+ h2(
5803
+ "div",
5804
+ { className: "dof-grid" },
5805
+ h2(
5806
+ "label",
5807
+ { className: "dof-field", "data-wide": "true" },
5808
+ "Office Base URL",
5809
+ h2("input", { value: form.baseUrl, placeholder: "https://office.example.com", onChange: (event) => setForm({ ...form, baseUrl: event.target.value }) })
5810
+ ),
5811
+ h2(
5812
+ "label",
5813
+ { className: "dof-field" },
5814
+ "Device ID",
5815
+ h2("input", { value: form.deviceId, placeholder: "local-harness", onChange: (event) => setForm({ ...form, deviceId: event.target.value }) })
5816
+ ),
5817
+ h2(
5818
+ "label",
5819
+ { className: "dof-field" },
5820
+ "Device Token",
5821
+ h2("input", { type: "password", value: form.deviceToken, placeholder: model.tokenConfigured ? "\u5DF2\u5B89\u5168\u4FDD\u5B58\uFF1B\u7559\u7A7A\u4FDD\u6301\u4E0D\u53D8" : "\u7C98\u8D34 Office \u4E00\u6B21\u6027\u51ED\u636E", autoComplete: "new-password", onChange: (event) => setForm({ ...form, deviceToken: event.target.value }) })
5822
+ ),
5823
+ h2(
5824
+ "label",
5825
+ { className: "dof-field" },
5826
+ "\u6700\u5927\u5E76\u53D1",
5827
+ h2("input", { type: "number", min: 1, max: 4, value: form.maxConcurrency, onChange: (event) => setForm({ ...form, maxConcurrency: event.target.value }) })
5828
+ ),
5829
+ h2(
5830
+ "label",
5831
+ { className: "dof-field" },
5832
+ "Heartbeat \u79D2\u6570",
5833
+ h2("input", { type: "number", min: 10, max: 300, value: form.heartbeatSeconds, onChange: (event) => setForm({ ...form, heartbeatSeconds: event.target.value }) })
5834
+ ),
5835
+ h2(
5836
+ "label",
5837
+ { className: "dof-field", "data-wide": "true" },
5838
+ "Workspace \u6620\u5C04",
5839
+ h2("textarea", { value: form.workspaces, placeholder: "office-project=/Users/you/projects/ai-office", onChange: (event) => setForm({ ...form, workspaces: event.target.value }) }),
5840
+ h2("small", null, "\u6BCF\u884C alias=/\u672C\u673A/\u7EDD\u5BF9\u8DEF\u5F84\uFF1BOffice \u53EA\u80FD\u770B\u5230 alias\u3002")
5841
+ ),
5842
+ h2(
5843
+ "label",
5844
+ { className: "dof-field", "data-wide": "true" },
5845
+ "Instruction Preset \u6620\u5C04",
5846
+ h2("textarea", { value: form.instructionPresets, placeholder: "action-items=\u8F6C\u6362\u4E3A\u8D1F\u8D23\u4EBA\u3001\u622A\u6B62\u548C\u9A8C\u6536\u660E\u786E\u7684\u5DE5\u5355", onChange: (event) => setForm({ ...form, instructionPresets: event.target.value }) }),
5847
+ h2("small", null, "\u6BCF\u884C alias=\u6307\u4EE4\uFF1B\u65B0\u589E preset \u4E0D\u9700\u8981\u6539 Office \u4EE3\u7801\u3002")
5848
+ )
5849
+ ),
5850
+ error ? h2("p", { className: "dof-error", role: "alert" }, error) : null,
5851
+ notice ? h2("p", { className: "dof-notice", role: "status" }, notice) : null,
5852
+ health.error?.message ? h2("p", { className: "dof-error" }, health.error.message) : null,
5853
+ h2(
5854
+ "div",
5855
+ { className: "dof-actions" },
5856
+ h2(Button9, { kind: "primary", disabled: Boolean(busy), onClick: () => void run("save", () => invoke(OFFICE_RPC_ENDPOINTS.configure, {
5857
+ baseUrl: form.baseUrl,
5858
+ deviceId: form.deviceId,
5859
+ ...form.deviceToken ? { deviceToken: form.deviceToken } : {},
5860
+ maxConcurrency: Number(form.maxConcurrency),
5861
+ heartbeatSeconds: Number(form.heartbeatSeconds),
5862
+ workspaces: parseMap(form.workspaces, "Workspace \u6620\u5C04"),
5863
+ instructionPresets: parseMap(form.instructionPresets, "Instruction Preset \u6620\u5C04")
5864
+ })) }, busy === "save" ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u5E76\u8FDE\u63A5"),
5865
+ h2(Button9, { disabled: !model.configured || Boolean(busy), onClick: () => void run("test", () => invoke(OFFICE_RPC_ENDPOINTS.test)) }, busy === "test" ? "\u6D4B\u8BD5\u4E2D\u2026" : "\u6D4B\u8BD5\u8FDE\u63A5"),
5866
+ h2(Button9, { disabled: !model.configured || Boolean(busy), onClick: () => void run("reconnect", () => invoke(OFFICE_RPC_ENDPOINTS.reconnect)) }, "\u91CD\u65B0\u8FDE\u63A5"),
5867
+ h2(Button9, { kind: "danger", disabled: !model.configured || Boolean(busy), onClick: () => void run("remove", () => invoke(OFFICE_RPC_ENDPOINTS.remove, { confirm: true })) }, "\u79FB\u9664\u8FDE\u63A5")
5868
+ )
5869
+ ),
5870
+ h2(
5871
+ "div",
5872
+ { className: "dof-card" },
5873
+ h2("div", { className: "dof-cardTitle" }, h2("h4", null, "\u534F\u8BAE Hook \u9884\u89C8"), h2("span", null, "\u7531 Base URL \u81EA\u52A8\u6D3E\u751F\uFF0C\u4E0D\u5355\u72EC\u586B\u5199")),
5874
+ h2(
5875
+ "div",
5876
+ { className: "dof-hooks" },
5877
+ [["SSE", hooks.stream], ["Heartbeat", hooks.heartbeat], ["Job", hooks.job], ["Result", hooks.result]].map(([label, url]) => h2("div", { className: "dof-hook", key: label }, h2("strong", null, label), h2("code", null, url ?? "Base URL \u65E0\u6548")))
5878
+ )
5879
+ ),
5880
+ h2("p", { className: "dof-notice" }, "Office Hook \u5C1A\u672A\u90E8\u7F72\u65F6\uFF0C\u914D\u7F6E\u4F1A\u5B89\u5168\u4FDD\u5B58\u5E76\u81EA\u52A8\u91CD\u8BD5\uFF1B\u51FA\u73B0 HTTP 404 \u4EE3\u8868\u534F\u8BAE\u7AEF\u70B9\u5F85\u4E0A\u7EBF\uFF0C\u4E0D\u4EE3\u8868 Harness \u6545\u969C\u3002")
5881
+ );
5882
+ }
5883
+
5884
+ // plugin-src/client/channels/office/styles.js
5885
+ var OFFICE_STYLE_ID = "xmanrui-dsh-im-office-settings";
5886
+ var CSS5 = `
5887
+ .dof-page { --dof-accent: var(--dsw-alias-brand-primary, #3964fe); }
5888
+ .dof-hero { position: relative; overflow: hidden; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; align-items: center; margin-bottom: 12px; padding: 18px; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 16px; background: linear-gradient(135deg, color-mix(in srgb, var(--dof-accent) 9%, var(--dsw-alias-bg-layer-1, #fff)), var(--dsw-alias-bg-layer-1, #fff) 62%); }
5889
+ .dof-hero::after { content: ""; position: absolute; width: 150px; height: 150px; right: -75px; top: -90px; border: 24px solid color-mix(in srgb, var(--dof-accent) 12%, transparent); border-radius: 50%; pointer-events: none; }
5890
+ .dof-heroCopy { min-width: 0; }
5891
+ .dof-heroCopy h3 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 17px; line-height: 1.35; }
5892
+ .dof-heroCopy p { margin: 6px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 1.6; }
5893
+ .dof-status { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 7px; padding: 7px 10px; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 999px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; white-space: nowrap; }
5894
+ .dof-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--dsw-alias-state-warn-primary, #d97706); }
5895
+ .dof-status[data-connected="true"] .dof-dot { background: var(--dsw-alias-state-success-primary, #20a162); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-state-success-primary, #20a162) 14%, transparent); }
5896
+ .dof-card { margin-top: 10px; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 14px; background: var(--dsw-alias-bg-layer-1, #fff); }
5897
+ .dof-cardTitle { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; margin-bottom: 12px; }
5898
+ .dof-cardTitle h4 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 14px; }
5899
+ .dof-cardTitle span { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; }
5900
+ .dof-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
5901
+ .dof-field { min-width: 0; display: flex; flex-direction: column; gap: 6px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; }
5902
+ .dof-field[data-wide="true"] { grid-column: 1 / -1; }
5903
+ .dof-field input, .dof-field textarea { box-sizing: border-box; width: 100%; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2329); font: inherit; font-size: 13px; line-height: 1.5; outline: none; }
5904
+ .dof-field input { height: 38px; padding: 0 11px; }
5905
+ .dof-field textarea { min-height: 86px; resize: vertical; padding: 9px 11px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
5906
+ .dof-field input:focus, .dof-field textarea:focus { border-color: var(--dof-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dof-accent) 12%, transparent); }
5907
+ .dof-field small { color: var(--dsw-alias-label-tertiary, #8f959e); line-height: 1.45; }
5908
+ .dof-hooks { display: grid; gap: 7px; }
5909
+ .dof-hook { min-width: 0; display: grid; grid-template-columns: 82px minmax(0, 1fr); gap: 10px; align-items: center; padding: 8px 10px; border-radius: 9px; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
5910
+ .dof-hook strong { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; }
5911
+ .dof-hook code { overflow: hidden; color: var(--dsw-alias-label-primary, #1f2329); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
5912
+ .dof-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
5913
+ .dof-actions .ddt-button[data-kind="primary"] { color: #fff; border-color: var(--dof-accent); background: var(--dof-accent); }
5914
+ .dof-error, .dof-notice { margin: 10px 0 0; padding: 9px 11px; border-radius: 9px; font-size: 12px; line-height: 1.5; }
5915
+ .dof-error { color: var(--dsw-alias-state-error-primary, #d54941); background: var(--dsw-alias-state-error-secondary, #fff0ef); }
5916
+ .dof-notice { color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
5917
+ .dof-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
5918
+ .dof-metric { min-width: 0; padding: 9px; border-radius: 10px; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
5919
+ .dof-metric span { display: block; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 10px; }
5920
+ .dof-metric strong { display: block; overflow: hidden; margin-top: 4px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
5921
+ @container (max-width: 680px) { .dof-grid { grid-template-columns: minmax(0, 1fr); } .dof-field[data-wide="true"] { grid-column: auto; } .dof-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
5922
+ @media (prefers-reduced-motion: reduce) { .dof-page * { transition: none !important; } }
5923
+ `;
5924
+ function installOfficeStyles() {
5925
+ if (typeof document === "undefined") return () => {
5926
+ };
5927
+ if (document.querySelector(`style[data-plugin-css="${OFFICE_STYLE_ID}"]`)) return () => {
5928
+ };
5929
+ const style = document.createElement("style");
5930
+ style.dataset.pluginCss = OFFICE_STYLE_ID;
5931
+ style.textContent = CSS5;
5932
+ document.head.append(style);
5933
+ return () => style.remove();
5934
+ }
5935
+
5493
5936
  // plugin-src/client/channels/slack/api.js
5494
5937
  var SLACK_RPC_CHANNEL = "/slack";
5495
5938
  var SLACK_ENDPOINTS = TOKEN_BOT_ENDPOINTS;
@@ -5499,7 +5942,7 @@ var normalizeSnapshot4 = api2.normalizeSnapshot;
5499
5942
  var presentError5 = api2.presentError;
5500
5943
 
5501
5944
  // plugin-src/client/channels/slack/index.js
5502
- var React12 = __toESM(require("react"), 1);
5945
+ var React13 = __toESM(require("react"), 1);
5503
5946
 
5504
5947
  // src/channels/slack/manifest.mjs
5505
5948
  var SLACK_APP_MANIFEST_YAML = `_metadata:
@@ -5536,7 +5979,7 @@ var SLACK_CREATE_APP_URL = "https://api.slack.com/apps?new_app=1";
5536
5979
 
5537
5980
  // plugin-src/client/channels/slack/styles.js
5538
5981
  var SLACK_STYLE_ID = "xmanrui-dsh-im-slack-settings";
5539
- var CSS5 = String.raw`
5982
+ var CSS6 = String.raw`
5540
5983
  .dsl-page { --ddt-accent: #4a154b; --ddt-accent-deep: #321033; --ddt-accent-wash: #f7eef7; }
5541
5984
  .dsl-avatar { color: #fff; background: #4a154b; }
5542
5985
  .dsl-avatar svg { display: block; }
@@ -5565,17 +6008,17 @@ function installSlackStyles() {
5565
6008
  const style = document.createElement("style");
5566
6009
  style.dataset.plugin = "@xmanrui/dsh-im";
5567
6010
  style.dataset.pluginCss = SLACK_STYLE_ID;
5568
- style.textContent = CSS5;
6011
+ style.textContent = CSS6;
5569
6012
  document.head.appendChild(style);
5570
6013
  return () => style.remove();
5571
6014
  }
5572
6015
 
5573
6016
  // plugin-src/client/channels/slack/index.js
5574
6017
  function SlackCredentialPanel({ busy, error, onSubmit, onCancel }) {
5575
- const [botToken, setBotToken] = React12.useState("");
5576
- const [appToken, setAppToken] = React12.useState("");
5577
- const [copied, setCopied] = React12.useState(false);
5578
- const headingId = React12.useId();
6018
+ const [botToken, setBotToken] = React13.useState("");
6019
+ const [appToken, setAppToken] = React13.useState("");
6020
+ const [copied, setCopied] = React13.useState(false);
6021
+ const headingId = React13.useId();
5579
6022
  const copyManifest = async () => {
5580
6023
  try {
5581
6024
  await navigator.clipboard.writeText(SLACK_APP_MANIFEST_YAML);
@@ -5714,18 +6157,57 @@ var SlackAccountCard = channel2.AccountCard;
5714
6157
 
5715
6158
  // plugin-src/client/channels/telegram/api.js
5716
6159
  var TELEGRAM_RPC_CHANNEL = "/telegram";
5717
- var TELEGRAM_ENDPOINTS = TOKEN_BOT_ENDPOINTS;
5718
- var api3 = createTokenChannelApi("Telegram", " Bot API \u957F\u8F6E\u8BE2");
6160
+ var TELEGRAM_ENDPOINTS = Object.freeze({
6161
+ ...TOKEN_BOT_ENDPOINTS,
6162
+ setAccessPolicy: "bot.access-policy.set"
6163
+ });
6164
+ var api3 = createTokenChannelApi("Telegram", " Bot API \u957F\u8F6E\u8BE2", {
6165
+ normalizeBotExtension: (value) => {
6166
+ const source = value?.accessPolicy;
6167
+ const accessMode = source?.accessMode === "private-allowlist" ? "private-allowlist" : "compatible";
6168
+ const allowedUsers = Array.isArray(source?.allowedUsers) ? [...new Set(source.allowedUsers.filter((entry) => typeof entry === "string" && /^[1-9]\d{0,15}$/.test(entry)))] : [];
6169
+ return { accessPolicy: { accessMode, allowedUsers } };
6170
+ }
6171
+ });
5719
6172
  var unwrapRpcResult6 = api3.unwrapRpcResult;
5720
6173
  var normalizeSnapshot5 = api3.normalizeSnapshot;
5721
6174
  var presentError6 = api3.presentError;
5722
6175
 
6176
+ // plugin-src/client/channels/telegram/index.js
6177
+ var React14 = __toESM(require("react"), 1);
6178
+
5723
6179
  // plugin-src/client/channels/telegram/styles.js
5724
6180
  var TELEGRAM_STYLE_ID = "xmanrui-dsh-im-telegram-settings";
5725
- var CSS6 = String.raw`
6181
+ var CSS7 = String.raw`
5726
6182
  .dtg-page { --ddt-accent: #229ed9; --ddt-accent-deep: #1687bd; --ddt-accent-wash: #eaf7fd; }
5727
6183
  .dtg-avatar { color: #fff; background: #229ed9; }
5728
6184
  .dtg-avatar svg { display: block; }
6185
+ .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); }
6186
+ .dtg-accessHeading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
6187
+ .dtg-accessHeading > strong { font-size: 13px; }
6188
+ .dtg-accessStatus { min-width: 0; display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }
6189
+ .dtg-accessBadge { flex: none; padding: 3px 8px; border-radius: 999px; color: #1687bd; background: #eaf7fd; font-size: 11px; font-weight: 700; }
6190
+ .dtg-accessBadge[data-mode="private-allowlist"] { color: #a15c00; background: #fff3d6; }
6191
+ .dtg-accessHelp { position: relative; display: inline-flex; flex: none; }
6192
+ .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; }
6193
+ .dtg-accessHelpButton:hover { border-color: #229ed9; color: #1178a8; background: #eaf7fd; }
6194
+ .dtg-accessHelpButton:focus-visible { outline: none; border-color: #229ed9; box-shadow: 0 0 0 3px color-mix(in srgb, #229ed9 18%, transparent); }
6195
+ .dtg-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: 260px; max-width: min(280px, calc(100vw - 48px)); 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; }
6196
+ .dtg-accessTooltipItem { display: grid; gap: 2px; }
6197
+ .dtg-accessTooltipItem + .dtg-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
6198
+ .dtg-accessTooltipItem strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 17px; font-weight: 700; }
6199
+ .dtg-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; font-weight: 400; }
6200
+ .dtg-accessHelp:hover .dtg-accessTooltip, .dtg-accessHelp:focus-within .dtg-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
6201
+ .dtg-accessField { display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
6202
+ .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; }
6203
+ .dtg-accessField select { height: 34px; padding: 0 9px; }
6204
+ .dtg-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
6205
+ .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; }
6206
+ .dtg-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
6207
+ .dtg-accessWarning, .dtg-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
6208
+ .dtg-accessWarning { color: #a15c00; }
6209
+ .dtg-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
6210
+ .dtg-accessActions { display: flex; justify-content: flex-end; }
5729
6211
  `;
5730
6212
  function installTelegramStyles() {
5731
6213
  if (typeof document === "undefined") return () => {
@@ -5736,12 +6218,152 @@ function installTelegramStyles() {
5736
6218
  const style = document.createElement("style");
5737
6219
  style.dataset.plugin = "@xmanrui/dsh-im";
5738
6220
  style.dataset.pluginCss = TELEGRAM_STYLE_ID;
5739
- style.textContent = CSS6;
6221
+ style.textContent = CSS7;
5740
6222
  document.head.appendChild(style);
5741
6223
  return () => style.remove();
5742
6224
  }
5743
6225
 
5744
6226
  // plugin-src/client/channels/telegram/index.js
6227
+ function policyFor(account) {
6228
+ return {
6229
+ accessMode: account?.accessPolicy?.accessMode === "private-allowlist" ? "private-allowlist" : "compatible",
6230
+ allowedUsers: Array.isArray(account?.accessPolicy?.allowedUsers) ? account.accessPolicy.allowedUsers : []
6231
+ };
6232
+ }
6233
+ function allowedUsersFromText(value) {
6234
+ const entries = value.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
6235
+ if (entries.some((entry) => !/^[1-9]\d{0,15}$/.test(entry))) {
6236
+ throw new TypeError("User ID \u5FC5\u987B\u662F 1\u201316 \u4F4D\u6B63\u6574\u6570\uFF0C\u6BCF\u884C\u4E00\u4E2A\u3002");
6237
+ }
6238
+ return [...new Set(entries)];
6239
+ }
6240
+ function TelegramAccessSettings({ account, busy = false, onSave }) {
6241
+ const policy = policyFor(account);
6242
+ const sourceUsers = policy.allowedUsers.join("\n");
6243
+ const accessHelpId = React14.useId();
6244
+ const [accessMode, setAccessMode] = React14.useState(policy.accessMode);
6245
+ const [allowedUsers, setAllowedUsers] = React14.useState(sourceUsers);
6246
+ const [error, setError] = React14.useState(null);
6247
+ React14.useEffect(() => {
6248
+ setAccessMode(policy.accessMode);
6249
+ setAllowedUsers(sourceUsers);
6250
+ setError(null);
6251
+ }, [policy.accessMode, sourceUsers]);
6252
+ const save = async (event) => {
6253
+ event.preventDefault();
6254
+ setError(null);
6255
+ try {
6256
+ const normalized = allowedUsersFromText(allowedUsers);
6257
+ if (typeof onSave !== "function") throw new Error("Telegram \u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
6258
+ await onSave({ accessMode, allowedUsers: normalized });
6259
+ } catch (caught) {
6260
+ setError(caught?.message ?? "Telegram \u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
6261
+ }
6262
+ };
6263
+ const privateAllowlist = accessMode === "private-allowlist";
6264
+ const savedPrivateAllowlist = policy.accessMode === "private-allowlist";
6265
+ const emptyAllowlist = privateAllowlist && allowedUsers.trim() === "";
6266
+ return h2(
6267
+ "form",
6268
+ { className: "dtg-access", onSubmit: save },
6269
+ h2(
6270
+ "div",
6271
+ { className: "dtg-accessHeading" },
6272
+ h2("strong", null, "\u8BBF\u95EE\u8BBE\u7F6E"),
6273
+ h2(
6274
+ "span",
6275
+ { className: "dtg-accessStatus" },
6276
+ h2(
6277
+ "span",
6278
+ { className: "dtg-accessBadge", "data-mode": policy.accessMode },
6279
+ savedPrivateAllowlist ? "\u5DF2\u751F\u6548\uFF1A\u5B89\u5168\u6A21\u5F0F" : "\u5DF2\u751F\u6548\uFF1A\u517C\u5BB9\u6A21\u5F0F"
6280
+ ),
6281
+ h2(
6282
+ "span",
6283
+ { className: "dtg-accessHelp" },
6284
+ h2("button", {
6285
+ type: "button",
6286
+ className: "dtg-accessHelpButton",
6287
+ "aria-label": "\u67E5\u770B Telegram \u8BBF\u95EE\u6A21\u5F0F\u8BF4\u660E",
6288
+ "aria-describedby": accessHelpId
6289
+ }, h2("span", { "aria-hidden": "true" }, "?")),
6290
+ h2(
6291
+ "span",
6292
+ {
6293
+ id: accessHelpId,
6294
+ className: "dtg-accessTooltip",
6295
+ role: "tooltip"
6296
+ },
6297
+ h2(
6298
+ "span",
6299
+ { className: "dtg-accessTooltipItem" },
6300
+ h2("strong", null, "\u517C\u5BB9\u6A21\u5F0F"),
6301
+ h2("span", null, "\u4FDD\u6301\u539F\u6709\u884C\u4E3A\uFF1A\u79C1\u804A\u76F4\u63A5\u54CD\u5E94\uFF0C\u7FA4\u804A\u5728\u88AB\u63D0\u53CA\u6216\u56DE\u590D\u65F6\u54CD\u5E94\u3002")
6302
+ ),
6303
+ h2(
6304
+ "span",
6305
+ { className: "dtg-accessTooltipItem" },
6306
+ h2("strong", null, "\u5B89\u5168\u6A21\u5F0F"),
6307
+ h2("span", null, "\u7FA4\u804A\u5168\u90E8\u5FFD\u7565\uFF0C\u79C1\u804A\u4EC5\u5141\u8BB8\u767D\u540D\u5355\u7528\u6237\u3002")
6308
+ )
6309
+ )
6310
+ )
6311
+ )
6312
+ ),
6313
+ h2(
6314
+ "label",
6315
+ { className: "dtg-accessField" },
6316
+ h2("span", null, "\u6A21\u5F0F"),
6317
+ h2(
6318
+ "select",
6319
+ {
6320
+ value: accessMode,
6321
+ disabled: busy,
6322
+ "aria-label": "Telegram \u8BBF\u95EE\u6A21\u5F0F",
6323
+ onChange: (event) => {
6324
+ setAccessMode(event.target.value);
6325
+ setError(null);
6326
+ }
6327
+ },
6328
+ h2("option", { value: "compatible" }, "\u517C\u5BB9\u6A21\u5F0F\uFF08\u9ED8\u8BA4\uFF09"),
6329
+ h2("option", { value: "private-allowlist" }, "\u5B89\u5168\u6A21\u5F0F\uFF08\u79C1\u804A\u767D\u540D\u5355\uFF09")
6330
+ )
6331
+ ),
6332
+ h2(
6333
+ "label",
6334
+ { className: "dtg-accessField" },
6335
+ h2("span", null, "\u5141\u8BB8\u79C1\u804A\u7684 Telegram User ID"),
6336
+ h2("textarea", {
6337
+ value: allowedUsers,
6338
+ disabled: busy || !privateAllowlist,
6339
+ rows: 3,
6340
+ placeholder: "\u6BCF\u884C\u4E00\u4E2A\u6570\u5B57 User ID",
6341
+ "aria-label": "\u5141\u8BB8\u79C1\u804A\u7684 Telegram User ID",
6342
+ onChange: (event) => {
6343
+ setAllowedUsers(event.target.value);
6344
+ setError(null);
6345
+ }
6346
+ }),
6347
+ h2("small", null, privateAllowlist ? "\u767D\u540D\u5355\u4EC5\u5C5E\u4E8E\u5F53\u524D\u673A\u5668\u4EBA\u3002" : "\u517C\u5BB9\u6A21\u5F0F\u4E0B\u6682\u4E0D\u4F7F\u7528\u767D\u540D\u5355\uFF0C\u5207\u6362\u6A21\u5F0F\u65F6\u4F1A\u4FDD\u7559\u3002")
6348
+ ),
6349
+ emptyAllowlist ? h2(
6350
+ "p",
6351
+ { className: "dtg-accessWarning", role: "status" },
6352
+ "\u767D\u540D\u5355\u4E3A\u7A7A\uFF1B\u4FDD\u5B58\u540E\u8BE5\u673A\u5668\u4EBA\u4F1A\u62D2\u7EDD\u6240\u6709\u5165\u7AD9\u6D88\u606F\u3002"
6353
+ ) : null,
6354
+ error ? h2("p", { className: "dtg-accessError", role: "alert" }, error) : null,
6355
+ h2(
6356
+ "div",
6357
+ { className: "dtg-accessActions" },
6358
+ h2("button", {
6359
+ type: "submit",
6360
+ className: "ddt-button",
6361
+ "data-kind": "secondary",
6362
+ disabled: busy
6363
+ }, busy ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8BBF\u95EE\u8BBE\u7F6E")
6364
+ )
6365
+ );
6366
+ }
5745
6367
  var channel3 = createTokenChannelSettings({
5746
6368
  channel: "Telegram",
5747
6369
  endpoints: TELEGRAM_ENDPOINTS,
@@ -5754,7 +6376,9 @@ var channel3 = createTokenChannelSettings({
5754
6376
  tokenPlaceholder: "\u586B\u5199 @BotFather \u751F\u6210\u7684 Bot Token",
5755
6377
  emptyTitle: "\u63A5\u5165 Telegram \u673A\u5668\u4EBA",
5756
6378
  emptyDescription: "\u5148\u901A\u8FC7 @BotFather \u83B7\u53D6 Bot Token\uFF0C\u518D\u5728\u8FD9\u91CC\u5B8C\u6210\u63A5\u5165\u3002",
5757
- platformLabel: "Telegram"
6379
+ platformLabel: "Telegram",
6380
+ AccountSettings: TelegramAccessSettings,
6381
+ accountSettingsEndpoint: TELEGRAM_ENDPOINTS.setAccessPolicy
5758
6382
  });
5759
6383
  var TelegramSettingsTab = channel3.SettingsTab;
5760
6384
  var TelegramAccountCard = channel3.AccountCard;
@@ -5877,11 +6501,11 @@ function formatRemaining4(milliseconds) {
5877
6501
  }
5878
6502
 
5879
6503
  // plugin-src/client/channels/wecom/index.js
5880
- var React13 = __toESM(require("react"), 1);
6504
+ var React15 = __toESM(require("react"), 1);
5881
6505
 
5882
6506
  // plugin-src/client/channels/wecom/styles.js
5883
6507
  var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
5884
- var CSS7 = String.raw`
6508
+ var CSS8 = String.raw`
5885
6509
  .dwecom-page { --ddt-accent: #3370ff; --ddt-accent-deep: #245bdb; --ddt-accent-wash: #eef4ff; }
5886
6510
  .dwecom-avatar, .dwecom-brand { color: #3370ff; background: #fff; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); }
5887
6511
  .dwecom-avatar svg, .dwecom-brand svg { display: block; }
@@ -5895,14 +6519,14 @@ function installWecomStyles() {
5895
6519
  const style = document.createElement("style");
5896
6520
  style.dataset.plugin = "@xmanrui/dsh-im";
5897
6521
  style.dataset.pluginCss = WECOM_STYLE_ID;
5898
- style.textContent = CSS7;
6522
+ style.textContent = CSS8;
5899
6523
  document.head.appendChild(style);
5900
6524
  return () => style.remove();
5901
6525
  }
5902
6526
 
5903
6527
  // plugin-src/client/channels/wecom/index.js
5904
6528
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
5905
- var Button9 = React13.forwardRef(function Button10({ children, kind = "secondary", className = "", ...props }, ref) {
6529
+ var Button10 = React15.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
5906
6530
  return h2("button", {
5907
6531
  ...props,
5908
6532
  ref,
@@ -5933,7 +6557,7 @@ function Heading4({ totals, adding, busy, onAdd, onCredential, credentialOpen, a
5933
6557
  h2(
5934
6558
  "div",
5935
6559
  { className: "dim-bindActions" },
5936
- h2(Button9, {
6560
+ h2(Button10, {
5937
6561
  kind: "primary",
5938
6562
  className: "dim-scanButton",
5939
6563
  onClick: onAdd,
@@ -5941,7 +6565,7 @@ function Heading4({ totals, adding, busy, onAdd, onCredential, credentialOpen, a
5941
6565
  ref: addButtonRef,
5942
6566
  "aria-label": "\u626B\u7801\u63A5\u5165\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA"
5943
6567
  }, h2(QrActionIcon), adding ? "\u6B63\u5728\u63A5\u5165" : "\u626B\u7801\u63A5\u5165\u673A\u5668\u4EBA"),
5944
- h2(Button9, {
6568
+ h2(Button10, {
5945
6569
  kind: "credential",
5946
6570
  className: "dim-credentialButton",
5947
6571
  onClick: onCredential,
@@ -5988,7 +6612,7 @@ function EmptyView4({ busy, onStart }) {
5988
6612
  "div",
5989
6613
  { className: "ddt-actions dim-viewActions" },
5990
6614
  h2(
5991
- Button9,
6615
+ Button10,
5992
6616
  { kind: "primary", onClick: onStart, disabled: busy },
5993
6617
  busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u4F01\u4E1A\u5FAE\u4FE1\u4E8C\u7EF4\u7801"
5994
6618
  )
@@ -6059,8 +6683,8 @@ function QrPanel3({ provision, now, busy, onRefresh, onCancel }) {
6059
6683
  h2(
6060
6684
  "div",
6061
6685
  { className: "ddt-actions dim-viewActions" },
6062
- h2(Button9, { onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
6063
- h2(Button9, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
6686
+ h2(Button10, { onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
6687
+ h2(Button10, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
6064
6688
  )
6065
6689
  )
6066
6690
  )
@@ -6089,8 +6713,8 @@ function ProvisionView2({ provision, busy, onRetry, onClose }) {
6089
6713
  h2(
6090
6714
  "div",
6091
6715
  { className: "ddt-actions dim-viewActions" },
6092
- h2(Button9, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
6093
- h2(Button9, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
6716
+ h2(Button10, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
6717
+ h2(Button10, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
6094
6718
  )
6095
6719
  )
6096
6720
  );
@@ -6104,8 +6728,8 @@ function RemoveConfirmation4({ account, busy, onConfirm, onCancel }) {
6104
6728
  h2(
6105
6729
  "div",
6106
6730
  { className: "ddt-actions dim-viewActions" },
6107
- h2(Button9, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"),
6108
- h2(Button9, { kind: "danger", onClick: onConfirm, disabled: busy }, busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165")
6731
+ h2(Button10, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"),
6732
+ h2(Button10, { kind: "danger", onClick: onConfirm, disabled: busy }, busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165")
6109
6733
  )
6110
6734
  );
6111
6735
  }
@@ -6121,7 +6745,7 @@ function AccountCard3({
6121
6745
  onCancelRemove
6122
6746
  }) {
6123
6747
  const tone = account.connected ? "success" : account.state === "error" ? "error" : "warning";
6124
- const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
6748
+ const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
6125
6749
  const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
6126
6750
  return h2(
6127
6751
  "article",
@@ -6147,7 +6771,7 @@ function AccountCard3({
6147
6771
  "div",
6148
6772
  { className: "ddt-health dim-botHealth" },
6149
6773
  h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
6150
- h2("span", null, stateLabel)
6774
+ h2("span", null, stateLabel2)
6151
6775
  )
6152
6776
  ),
6153
6777
  h2(
@@ -6173,8 +6797,8 @@ function AccountCard3({
6173
6797
  h2(
6174
6798
  "div",
6175
6799
  { className: "ddt-actions dim-cardActions" },
6176
- h2(Button9, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6177
- h2(Button9, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
6800
+ h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6801
+ h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
6178
6802
  )
6179
6803
  )
6180
6804
  ),
@@ -6187,21 +6811,21 @@ function AccountCard3({
6187
6811
  );
6188
6812
  }
6189
6813
  function WecomSettingsTab({ rpcCall }) {
6190
- const [model, setModel] = React13.useState({ phase: "loading", bots: [], totals: { configured: 0, connected: 0 }, error: null });
6191
- const [provision, setProvision] = React13.useState(null);
6192
- const [busy, setBusy] = React13.useState(false);
6193
- const [busyByBot, setBusyByBot] = React13.useState({});
6194
- const [feedbackByBot, setFeedbackByBot] = React13.useState({});
6195
- const [removeTarget, setRemoveTarget] = React13.useState(null);
6196
- const [credentialOpen, setCredentialOpen] = React13.useState(false);
6197
- const [credentialError, setCredentialError] = React13.useState(null);
6198
- const [notice, setNotice] = React13.useState("");
6199
- const [now, setNow] = React13.useState(Date.now());
6200
- const mounted = React13.useRef(true);
6814
+ const [model, setModel] = React15.useState({ phase: "loading", bots: [], totals: { configured: 0, connected: 0 }, error: null });
6815
+ const [provision, setProvision] = React15.useState(null);
6816
+ const [busy, setBusy] = React15.useState(false);
6817
+ const [busyByBot, setBusyByBot] = React15.useState({});
6818
+ const [feedbackByBot, setFeedbackByBot] = React15.useState({});
6819
+ const [removeTarget, setRemoveTarget] = React15.useState(null);
6820
+ const [credentialOpen, setCredentialOpen] = React15.useState(false);
6821
+ const [credentialError, setCredentialError] = React15.useState(null);
6822
+ const [notice, setNotice] = React15.useState("");
6823
+ const [now, setNow] = React15.useState(Date.now());
6824
+ const mounted = React15.useRef(true);
6201
6825
  const workspaceFence = useWorkspaceSnapshotFence();
6202
- const addButtonRef = React13.useRef(null);
6203
- const noticeFrameRef = React13.useRef(null);
6204
- const announce = React13.useCallback((message) => {
6826
+ const addButtonRef = React15.useRef(null);
6827
+ const noticeFrameRef = React15.useRef(null);
6828
+ const announce = React15.useCallback((message) => {
6205
6829
  if (!mounted.current) return;
6206
6830
  if (noticeFrameRef.current !== null) {
6207
6831
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -6215,7 +6839,7 @@ function WecomSettingsTab({ rpcCall }) {
6215
6839
  });
6216
6840
  }
6217
6841
  }, []);
6218
- React13.useEffect(() => {
6842
+ React15.useEffect(() => {
6219
6843
  const disposeDingtalk = installDingtalkStyles();
6220
6844
  const disposeWecom = installWecomStyles();
6221
6845
  mounted.current = true;
@@ -6229,11 +6853,11 @@ function WecomSettingsTab({ rpcCall }) {
6229
6853
  disposeDingtalk();
6230
6854
  };
6231
6855
  }, []);
6232
- const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
6856
+ const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
6233
6857
  if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
6234
6858
  return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
6235
6859
  }, [rpcCall]);
6236
- const loadStatus = React13.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
6860
+ const loadStatus = React15.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
6237
6861
  const workspaceVersion = workspaceFence.beginStatus();
6238
6862
  if (workspaceVersion === null) return void 0;
6239
6863
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -6253,12 +6877,12 @@ function WecomSettingsTab({ rpcCall }) {
6253
6877
  return void 0;
6254
6878
  }
6255
6879
  }, [invoke, workspaceFence]);
6256
- React13.useEffect(() => {
6880
+ React15.useEffect(() => {
6257
6881
  const controller = new AbortController();
6258
6882
  void loadStatus({ signal: controller.signal, restore: true });
6259
6883
  return () => controller.abort();
6260
6884
  }, [loadStatus]);
6261
- React13.useEffect(() => {
6885
+ React15.useEffect(() => {
6262
6886
  if (model.phase !== "ready") return void 0;
6263
6887
  const controller = new AbortController();
6264
6888
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -6267,12 +6891,12 @@ function WecomSettingsTab({ rpcCall }) {
6267
6891
  window.clearInterval(timer);
6268
6892
  };
6269
6893
  }, [loadStatus, model.phase]);
6270
- React13.useEffect(() => {
6894
+ React15.useEffect(() => {
6271
6895
  if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
6272
6896
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
6273
6897
  return () => window.clearInterval(timer);
6274
6898
  }, [provision?.attemptId, provision?.status]);
6275
- const startProvisioning = React13.useCallback(async (replace = false) => {
6899
+ const startProvisioning = React15.useCallback(async (replace = false) => {
6276
6900
  setCredentialOpen(false);
6277
6901
  setCredentialError(null);
6278
6902
  setBusy(true);
@@ -6290,7 +6914,7 @@ function WecomSettingsTab({ rpcCall }) {
6290
6914
  if (mounted.current) setBusy(false);
6291
6915
  }
6292
6916
  }, [invoke, provision?.attemptId]);
6293
- const bindCredentials = React13.useCallback(async ({ identity, secret }) => {
6917
+ const bindCredentials = React15.useCallback(async ({ identity, secret }) => {
6294
6918
  const snapshotVersion = workspaceFence.beginMutation();
6295
6919
  setBusy(true);
6296
6920
  setCredentialError(null);
@@ -6312,7 +6936,7 @@ function WecomSettingsTab({ rpcCall }) {
6312
6936
  if (mounted.current) setBusy(false);
6313
6937
  }
6314
6938
  }, [invoke, loadStatus, workspaceFence]);
6315
- const closeProvision = React13.useCallback(async () => {
6939
+ const closeProvision = React15.useCallback(async () => {
6316
6940
  setBusy(true);
6317
6941
  try {
6318
6942
  if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
@@ -6323,7 +6947,7 @@ function WecomSettingsTab({ rpcCall }) {
6323
6947
  if (mounted.current) setBusy(false);
6324
6948
  }
6325
6949
  }, [invoke, provision?.attemptId, provision?.status]);
6326
- React13.useEffect(() => {
6950
+ React15.useEffect(() => {
6327
6951
  const attemptId = provision?.attemptId;
6328
6952
  if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
6329
6953
  const controller = new AbortController();
@@ -6353,7 +6977,7 @@ function WecomSettingsTab({ rpcCall }) {
6353
6977
  window.clearTimeout(timer);
6354
6978
  };
6355
6979
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
6356
- const botAction = React13.useCallback(async (account, operation, endpoint, payload) => {
6980
+ const botAction = React15.useCallback(async (account, operation, endpoint, payload) => {
6357
6981
  const snapshotVersion = workspaceFence.beginMutation();
6358
6982
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
6359
6983
  try {
@@ -6372,7 +6996,7 @@ function WecomSettingsTab({ rpcCall }) {
6372
6996
  });
6373
6997
  }
6374
6998
  }, [invoke, loadStatus, workspaceFence]);
6375
- const reconnect = React13.useCallback(async (account) => {
6999
+ const reconnect = React15.useCallback(async (account) => {
6376
7000
  setFeedbackByBot((current) => {
6377
7001
  const next = { ...current };
6378
7002
  delete next[account.botId];
@@ -6484,8 +7108,8 @@ function WecomSettingsTab({ rpcCall }) {
6484
7108
  addButtonRef
6485
7109
  }),
6486
7110
  h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
6487
- model.phase === "loading" ? h2(LoadingView4) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button9, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
6488
- React13.Fragment,
7111
+ model.phase === "loading" ? h2(LoadingView4) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button10, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
7112
+ React15.Fragment,
6489
7113
  null,
6490
7114
  credentialView,
6491
7115
  provisionView,
@@ -6496,7 +7120,7 @@ function WecomSettingsTab({ rpcCall }) {
6496
7120
  }
6497
7121
 
6498
7122
  // plugin-src/client/channels/weixin/index.js
6499
- var React14 = __toESM(require("react"), 1);
7123
+ var React16 = __toESM(require("react"), 1);
6500
7124
 
6501
7125
  // plugin-src/client/channels/weixin/api.js
6502
7126
  var WEIXIN_RPC_CHANNEL = "/weixin";
@@ -6648,7 +7272,7 @@ function formatRemaining5(milliseconds) {
6648
7272
 
6649
7273
  // plugin-src/client/channels/weixin/styles.js
6650
7274
  var WEIXIN_STYLE_ID = "xmanrui-dsh-weixin-settings";
6651
- var CSS8 = String.raw`
7275
+ var CSS9 = String.raw`
6652
7276
  .dxw-page {
6653
7277
  --dxw-accent: #07c160;
6654
7278
  --dxw-accent-dark: #05994c;
@@ -6763,13 +7387,13 @@ function installWeixinStyles() {
6763
7387
  const style = document.createElement("style");
6764
7388
  style.dataset.plugin = "@xmanrui/dsh-weixin";
6765
7389
  style.dataset.pluginCss = WEIXIN_STYLE_ID;
6766
- style.textContent = CSS8;
7390
+ style.textContent = CSS9;
6767
7391
  document.head.appendChild(style);
6768
7392
  return () => style.remove();
6769
7393
  }
6770
7394
 
6771
7395
  // plugin-src/client/channels/weixin/index.js
6772
- var Button11 = React14.forwardRef(function Button12({ children, kind = "secondary", className = "", ...props }, ref) {
7396
+ var Button12 = React16.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
6773
7397
  return h2("button", {
6774
7398
  ...props,
6775
7399
  ref,
@@ -6785,7 +7409,7 @@ function Heading5({ totals, adding, busy, onAdd, addButtonRef }) {
6785
7409
  h2(
6786
7410
  "div",
6787
7411
  { className: "dxw-tools" },
6788
- h2(Button11, {
7412
+ h2(Button12, {
6789
7413
  kind: "primary",
6790
7414
  className: "dim-scanButton",
6791
7415
  onClick: onAdd,
@@ -6831,7 +7455,7 @@ function EmptyView5({ onStart, busy }) {
6831
7455
  "div",
6832
7456
  { className: "dxw-actions dim-viewActions" },
6833
7457
  h2(
6834
- Button11,
7458
+ Button12,
6835
7459
  { kind: "primary", onClick: onStart, disabled: busy },
6836
7460
  busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u5FAE\u4FE1\u4E8C\u7EF4\u7801"
6837
7461
  )
@@ -6842,14 +7466,14 @@ function EmptyView5({ onStart, busy }) {
6842
7466
  );
6843
7467
  }
6844
7468
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
6845
- const [imageFailed, setImageFailed] = React14.useState(false);
7469
+ const [imageFailed, setImageFailed] = React16.useState(false);
6846
7470
  const source = safeQrSource5(provision.qrCodeDataUrl);
6847
7471
  const href = safeVerificationUrl(provision.verificationUrl);
6848
7472
  const remaining = Math.max(0, provision.expiresAt - now);
6849
7473
  const expired = remaining === 0 || provision.status === "expired";
6850
7474
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
6851
7475
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
6852
- React14.useEffect(() => setImageFailed(false), [source]);
7476
+ React16.useEffect(() => setImageFailed(false), [source]);
6853
7477
  return h2(
6854
7478
  "div",
6855
7479
  { className: "dxw-card dim-surfaceCard" },
@@ -6901,24 +7525,24 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
6901
7525
  h2(
6902
7526
  "div",
6903
7527
  { className: "dxw-actions dim-viewActions" },
6904
- expired ? h2(Button11, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null,
7528
+ expired ? h2(Button12, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null,
6905
7529
  href ? h2("a", {
6906
7530
  className: "dxw-button",
6907
7531
  href,
6908
7532
  target: "_blank",
6909
7533
  rel: "noopener noreferrer"
6910
7534
  }, "\u6253\u5F00\u5907\u7528\u94FE\u63A5") : null,
6911
- !expired ? h2(Button11, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null,
6912
- h2(Button11, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
7535
+ !expired ? h2(Button12, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null,
7536
+ h2(Button12, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
6913
7537
  )
6914
7538
  )
6915
7539
  )
6916
7540
  );
6917
7541
  }
6918
7542
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
6919
- const [code, setCode] = React14.useState("");
7543
+ const [code, setCode] = React16.useState("");
6920
7544
  const valid = /^\d{4,8}$/.test(code);
6921
- React14.useEffect(() => setCode(""), [provision.attemptId]);
7545
+ React16.useEffect(() => setCode(""), [provision.attemptId]);
6922
7546
  return h2(
6923
7547
  "div",
6924
7548
  { className: "dxw-card dim-surfaceCard" },
@@ -6959,7 +7583,7 @@ function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
6959
7583
  disabled: !valid || busy
6960
7584
  }, busy ? "\u6B63\u5728\u9A8C\u8BC1\u2026" : "\u7EE7\u7EED\u8FDE\u63A5")
6961
7585
  ),
6962
- h2(Button11, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u7ED1\u5B9A")
7586
+ h2(Button12, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u7ED1\u5B9A")
6963
7587
  )
6964
7588
  );
6965
7589
  }
@@ -6973,7 +7597,7 @@ function ProgressPanel2({ scanned, onCancel, busy }) {
6973
7597
  onCancel ? h2(
6974
7598
  "div",
6975
7599
  { className: "dxw-actions dim-viewActions", style: { justifyContent: "center", marginTop: 14 } },
6976
- h2(Button11, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
7600
+ h2(Button12, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
6977
7601
  ) : null
6978
7602
  );
6979
7603
  }
@@ -6991,8 +7615,8 @@ function ProvisionError3({ provision, busy, onRetry, onClose }) {
6991
7615
  h2(
6992
7616
  "div",
6993
7617
  { className: "dxw-actions dim-viewActions" },
6994
- h2(Button11, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
6995
- h2(Button11, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
7618
+ h2(Button12, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
7619
+ h2(Button12, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
6996
7620
  )
6997
7621
  )
6998
7622
  );
@@ -7079,11 +7703,11 @@ function AccountCard4({
7079
7703
  "div",
7080
7704
  { className: "dxw-actions dim-cardActions" },
7081
7705
  h2(
7082
- Button11,
7706
+ Button12,
7083
7707
  { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
7084
7708
  busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
7085
7709
  ),
7086
- h2(Button11, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7710
+ h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7087
7711
  )
7088
7712
  )
7089
7713
  ),
@@ -7095,9 +7719,9 @@ function AccountCard4({
7095
7719
  h2(
7096
7720
  "div",
7097
7721
  { className: "dxw-actions dim-viewActions" },
7098
- h2(Button11, { onClick: onCancelRemove, disabled: busy === "delete" }, "\u4FDD\u7559\u8D26\u53F7"),
7722
+ h2(Button12, { onClick: onCancelRemove, disabled: busy === "delete" }, "\u4FDD\u7559\u8D26\u53F7"),
7099
7723
  h2(
7100
- Button11,
7724
+ Button12,
7101
7725
  { kind: "danger", onClick: onConfirmRemove, disabled: busy === "delete" },
7102
7726
  busy === "delete" ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664"
7103
7727
  )
@@ -7138,40 +7762,40 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
7138
7762
  };
7139
7763
  }
7140
7764
  function WeixinSettingsTab({ rpcCall }) {
7141
- const [model, setModel] = React14.useState({
7765
+ const [model, setModel] = React16.useState({
7142
7766
  phase: "loading",
7143
7767
  bots: [],
7144
7768
  totals: EMPTY_TOTALS3,
7145
7769
  revision: 0,
7146
7770
  error: null
7147
7771
  });
7148
- const [provision, setProvision] = React14.useState(null);
7149
- const [busy, setBusy] = React14.useState(false);
7150
- const [busyByBot, setBusyByBot] = React14.useState({});
7151
- const [feedbackByBot, setFeedbackByBot] = React14.useState({});
7152
- const [removeTarget, setRemoveTarget] = React14.useState(null);
7153
- const [notice, setNotice] = React14.useState("");
7154
- const [now, setNow] = React14.useState(() => Date.now());
7155
- const addButtonRef = React14.useRef(null);
7156
- const mountedRef = React14.useRef(true);
7772
+ const [provision, setProvision] = React16.useState(null);
7773
+ const [busy, setBusy] = React16.useState(false);
7774
+ const [busyByBot, setBusyByBot] = React16.useState({});
7775
+ const [feedbackByBot, setFeedbackByBot] = React16.useState({});
7776
+ const [removeTarget, setRemoveTarget] = React16.useState(null);
7777
+ const [notice, setNotice] = React16.useState("");
7778
+ const [now, setNow] = React16.useState(() => Date.now());
7779
+ const addButtonRef = React16.useRef(null);
7780
+ const mountedRef = React16.useRef(true);
7157
7781
  const workspaceFence = useWorkspaceSnapshotFence();
7158
7782
  const scheduleAnimationFrame = useAnimationFrameScheduler();
7159
- React14.useEffect(() => {
7783
+ React16.useEffect(() => {
7160
7784
  mountedRef.current = true;
7161
7785
  return () => {
7162
7786
  mountedRef.current = false;
7163
7787
  };
7164
7788
  }, []);
7165
- const announce = React14.useCallback((value) => {
7789
+ const announce = React16.useCallback((value) => {
7166
7790
  setNotice("");
7167
7791
  scheduleAnimationFrame(() => {
7168
7792
  if (value) setNotice(value);
7169
7793
  }, "announcement");
7170
7794
  }, [scheduleAnimationFrame]);
7171
- const invoke = React14.useCallback(async (endpoint, payload = {}, signal) => {
7795
+ const invoke = React16.useCallback(async (endpoint, payload = {}, signal) => {
7172
7796
  return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
7173
7797
  }, [rpcCall]);
7174
- const loadStatus = React14.useCallback(async ({
7798
+ const loadStatus = React16.useCallback(async ({
7175
7799
  signal,
7176
7800
  silent = false,
7177
7801
  restoreProvisioning = false
@@ -7207,12 +7831,12 @@ function WeixinSettingsTab({ rpcCall }) {
7207
7831
  return void 0;
7208
7832
  }
7209
7833
  }, [invoke, workspaceFence]);
7210
- React14.useEffect(() => {
7834
+ React16.useEffect(() => {
7211
7835
  const controller = new AbortController();
7212
7836
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
7213
7837
  return () => controller.abort();
7214
7838
  }, [loadStatus]);
7215
- React14.useEffect(() => {
7839
+ React16.useEffect(() => {
7216
7840
  if (model.phase !== "ready") return void 0;
7217
7841
  const controller = new AbortController();
7218
7842
  let running = false;
@@ -7231,12 +7855,12 @@ function WeixinSettingsTab({ rpcCall }) {
7231
7855
  window.clearInterval(timer);
7232
7856
  };
7233
7857
  }, [loadStatus, model.phase]);
7234
- React14.useEffect(() => {
7858
+ React16.useEffect(() => {
7235
7859
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
7236
7860
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
7237
7861
  return () => window.clearInterval(timer);
7238
7862
  }, [provision?.attemptId, provision?.status]);
7239
- const startProvisioning = React14.useCallback(async ({ replace = false } = {}) => {
7863
+ const startProvisioning = React16.useCallback(async ({ replace = false } = {}) => {
7240
7864
  setBusy(true);
7241
7865
  try {
7242
7866
  if (replace && provision?.attemptId) {
@@ -7257,7 +7881,7 @@ function WeixinSettingsTab({ rpcCall }) {
7257
7881
  setBusy(false);
7258
7882
  }
7259
7883
  }, [announce, invoke, provision?.attemptId]);
7260
- const cancelProvisioning = React14.useCallback(async () => {
7884
+ const cancelProvisioning = React16.useCallback(async () => {
7261
7885
  setBusy(true);
7262
7886
  try {
7263
7887
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -7272,7 +7896,7 @@ function WeixinSettingsTab({ rpcCall }) {
7272
7896
  setBusy(false);
7273
7897
  }
7274
7898
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
7275
- const submitVerification = React14.useCallback(async (verifyCode) => {
7899
+ const submitVerification = React16.useCallback(async (verifyCode) => {
7276
7900
  if (!provision?.attemptId) return;
7277
7901
  setBusy(true);
7278
7902
  try {
@@ -7288,7 +7912,7 @@ function WeixinSettingsTab({ rpcCall }) {
7288
7912
  setBusy(false);
7289
7913
  }
7290
7914
  }, [announce, invoke, provision?.attemptId]);
7291
- React14.useEffect(() => {
7915
+ React16.useEffect(() => {
7292
7916
  const attemptId = provision?.attemptId;
7293
7917
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
7294
7918
  const controller = new AbortController();
@@ -7336,7 +7960,7 @@ function WeixinSettingsTab({ rpcCall }) {
7336
7960
  controller.abort();
7337
7961
  };
7338
7962
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
7339
- const setBotBusy = React14.useCallback((botId, value) => {
7963
+ const setBotBusy = React16.useCallback((botId, value) => {
7340
7964
  setBusyByBot((current) => {
7341
7965
  const next = { ...current };
7342
7966
  if (value) next[botId] = value;
@@ -7344,7 +7968,7 @@ function WeixinSettingsTab({ rpcCall }) {
7344
7968
  return next;
7345
7969
  });
7346
7970
  }, []);
7347
- const reconnect = React14.useCallback(async (account) => {
7971
+ const reconnect = React16.useCallback(async (account) => {
7348
7972
  const snapshotVersion = workspaceFence.beginMutation();
7349
7973
  setBotBusy(account.botId, "reconnect");
7350
7974
  setFeedbackByBot((current) => {
@@ -7389,7 +8013,7 @@ function WeixinSettingsTab({ rpcCall }) {
7389
8013
  setBotBusy(account.botId, null);
7390
8014
  }
7391
8015
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
7392
- const saveWorkspace = React14.useCallback(async (account, workspace) => {
8016
+ const saveWorkspace = React16.useCallback(async (account, workspace) => {
7393
8017
  const workspaceVersion = workspaceFence.beginMutation();
7394
8018
  setBotBusy(account.botId, "workspace");
7395
8019
  try {
@@ -7412,7 +8036,7 @@ function WeixinSettingsTab({ rpcCall }) {
7412
8036
  if (mountedRef.current) setBotBusy(account.botId, null);
7413
8037
  }
7414
8038
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
7415
- const remove = React14.useCallback(async (account) => {
8039
+ const remove = React16.useCallback(async (account) => {
7416
8040
  const snapshotVersion = workspaceFence.beginMutation();
7417
8041
  setBotBusy(account.botId, "delete");
7418
8042
  try {
@@ -7485,10 +8109,10 @@ function WeixinSettingsTab({ rpcCall }) {
7485
8109
  { className: "dxw-error dim-inlineError" },
7486
8110
  h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u5FAE\u4FE1\u72B6\u6001"),
7487
8111
  h2("p", null, model.error?.message ?? "\u8BF7\u7A0D\u540E\u91CD\u8BD5"),
7488
- h2(Button11, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
8112
+ h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
7489
8113
  )
7490
8114
  ) : h2(
7491
- React14.Fragment,
8115
+ React16.Fragment,
7492
8116
  null,
7493
8117
  provisionView,
7494
8118
  model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
@@ -7620,11 +8244,11 @@ function formatRemaining6(milliseconds) {
7620
8244
  }
7621
8245
 
7622
8246
  // plugin-src/client/channels/whatsapp/index.js
7623
- var React15 = __toESM(require("react"), 1);
8247
+ var React17 = __toESM(require("react"), 1);
7624
8248
 
7625
8249
  // plugin-src/client/channels/whatsapp/styles.js
7626
8250
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
7627
- var CSS9 = String.raw`
8251
+ var CSS10 = String.raw`
7628
8252
  .dwa-page { --ddt-accent: #25d366; --ddt-accent-deep: #128c7e; --ddt-accent-wash: #eafbf0; }
7629
8253
  .dwa-avatar { color: #fff; background: #25d366; }
7630
8254
  .dwa-avatar svg { display: block; }
@@ -7638,14 +8262,14 @@ function installWhatsappStyles() {
7638
8262
  const style = document.createElement("style");
7639
8263
  style.dataset.plugin = "@xmanrui/dsh-im";
7640
8264
  style.dataset.pluginCss = WHATSAPP_STYLE_ID;
7641
- style.textContent = CSS9;
8265
+ style.textContent = CSS10;
7642
8266
  document.head.appendChild(style);
7643
8267
  return () => style.remove();
7644
8268
  }
7645
8269
 
7646
8270
  // plugin-src/client/channels/whatsapp/index.js
7647
8271
  var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
7648
- var Button13 = React15.forwardRef(function Button14({ children, kind = "secondary", className = "", ...props }, ref) {
8272
+ var Button14 = React17.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
7649
8273
  return h2("button", {
7650
8274
  ...props,
7651
8275
  ref,
@@ -7685,7 +8309,7 @@ function Heading6({ totals, busy, onAdd, addButtonRef }) {
7685
8309
  h2(
7686
8310
  "div",
7687
8311
  { className: "dim-bindActions" },
7688
- h2(Button13, {
8312
+ h2(Button14, {
7689
8313
  kind: "primary",
7690
8314
  className: "dim-scanButton",
7691
8315
  onClick: onAdd,
@@ -7730,7 +8354,7 @@ function EmptyView6({ busy, onStart }) {
7730
8354
  "div",
7731
8355
  { className: "ddt-actions dim-viewActions" },
7732
8356
  h2(
7733
- Button13,
8357
+ Button14,
7734
8358
  { kind: "primary", onClick: onStart, disabled: busy },
7735
8359
  busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u4E8C\u7EF4\u7801"
7736
8360
  )
@@ -7799,8 +8423,8 @@ function QrPanel5({ provision, now, busy, onRefresh, onCancel }) {
7799
8423
  h2(
7800
8424
  "div",
7801
8425
  { className: "ddt-actions dim-viewActions" },
7802
- h2(Button13, { onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
7803
- h2(Button13, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
8426
+ h2(Button14, { onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
8427
+ h2(Button14, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
7804
8428
  )
7805
8429
  )
7806
8430
  )
@@ -7836,8 +8460,8 @@ function ProvisionView3({ provision, busy, onRetry, onClose }) {
7836
8460
  h2(
7837
8461
  "div",
7838
8462
  { className: "ddt-actions dim-viewActions" },
7839
- h2(Button13, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
7840
- h2(Button13, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
8463
+ h2(Button14, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
8464
+ h2(Button14, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
7841
8465
  )
7842
8466
  )
7843
8467
  );
@@ -7851,9 +8475,9 @@ function RemoveConfirmation5({ account, busy, onConfirm, onCancel }) {
7851
8475
  h2(
7852
8476
  "div",
7853
8477
  { className: "ddt-actions dim-viewActions" },
7854
- h2(Button13, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"),
8478
+ h2(Button14, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"),
7855
8479
  h2(
7856
- Button13,
8480
+ Button14,
7857
8481
  { kind: "danger", onClick: onConfirm, disabled: busy },
7858
8482
  busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165"
7859
8483
  )
@@ -7873,7 +8497,7 @@ function WhatsappAccountCard({
7873
8497
  }) {
7874
8498
  const state = busy === "reconnect" ? "connecting" : account.state;
7875
8499
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
7876
- const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
8500
+ const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
7877
8501
  const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
7878
8502
  return h2(
7879
8503
  "article",
@@ -7902,7 +8526,7 @@ function WhatsappAccountCard({
7902
8526
  "div",
7903
8527
  { className: "ddt-health dim-botHealth" },
7904
8528
  h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
7905
- h2("span", null, stateLabel)
8529
+ h2("span", null, stateLabel2)
7906
8530
  )
7907
8531
  ),
7908
8532
  h2(
@@ -7937,12 +8561,12 @@ function WhatsappAccountCard({
7937
8561
  h2(
7938
8562
  "div",
7939
8563
  { className: "ddt-actions dim-cardActions" },
7940
- h2(Button13, {
8564
+ h2(Button14, {
7941
8565
  className: "dim-cardAction",
7942
8566
  onClick: onReconnect,
7943
8567
  disabled: Boolean(busy)
7944
8568
  }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
7945
- h2(Button13, {
8569
+ h2(Button14, {
7946
8570
  className: "dim-cardAction",
7947
8571
  kind: "danger",
7948
8572
  onClick: onRequestRemove,
@@ -7960,22 +8584,22 @@ function WhatsappAccountCard({
7960
8584
  );
7961
8585
  }
7962
8586
  function WhatsappSettingsTab({ rpcCall }) {
7963
- const [model, setModel] = React15.useState({
8587
+ const [model, setModel] = React17.useState({
7964
8588
  phase: "loading",
7965
8589
  bots: [],
7966
8590
  totals: { configured: 0, connected: 0 },
7967
8591
  error: null
7968
8592
  });
7969
- const [provision, setProvision] = React15.useState(null);
7970
- const [busy, setBusy] = React15.useState(false);
7971
- const [busyByBot, setBusyByBot] = React15.useState({});
7972
- const [testNoticeByBot, setTestNoticeByBot] = React15.useState({});
7973
- const [removeTarget, setRemoveTarget] = React15.useState(null);
7974
- const [now, setNow] = React15.useState(Date.now());
7975
- const mounted = React15.useRef(true);
8593
+ const [provision, setProvision] = React17.useState(null);
8594
+ const [busy, setBusy] = React17.useState(false);
8595
+ const [busyByBot, setBusyByBot] = React17.useState({});
8596
+ const [testNoticeByBot, setTestNoticeByBot] = React17.useState({});
8597
+ const [removeTarget, setRemoveTarget] = React17.useState(null);
8598
+ const [now, setNow] = React17.useState(Date.now());
8599
+ const mounted = React17.useRef(true);
7976
8600
  const workspaceFence = useWorkspaceSnapshotFence();
7977
- const addButtonRef = React15.useRef(null);
7978
- React15.useEffect(() => {
8601
+ const addButtonRef = React17.useRef(null);
8602
+ React17.useEffect(() => {
7979
8603
  const disposeDingtalk = installDingtalkStyles();
7980
8604
  const disposeWhatsapp = installWhatsappStyles();
7981
8605
  mounted.current = true;
@@ -7985,11 +8609,11 @@ function WhatsappSettingsTab({ rpcCall }) {
7985
8609
  disposeDingtalk();
7986
8610
  };
7987
8611
  }, []);
7988
- const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
8612
+ const invoke = React17.useCallback(async (endpoint, payload = {}, signal) => {
7989
8613
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
7990
8614
  return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
7991
8615
  }, [rpcCall]);
7992
- const loadStatus = React15.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
8616
+ const loadStatus = React17.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
7993
8617
  const workspaceVersion = workspaceFence.beginStatus();
7994
8618
  if (workspaceVersion === null) return void 0;
7995
8619
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -8013,12 +8637,12 @@ function WhatsappSettingsTab({ rpcCall }) {
8013
8637
  return void 0;
8014
8638
  }
8015
8639
  }, [invoke, workspaceFence]);
8016
- React15.useEffect(() => {
8640
+ React17.useEffect(() => {
8017
8641
  const controller = new AbortController();
8018
8642
  void loadStatus({ signal: controller.signal, restore: true });
8019
8643
  return () => controller.abort();
8020
8644
  }, [loadStatus]);
8021
- React15.useEffect(() => {
8645
+ React17.useEffect(() => {
8022
8646
  if (model.phase !== "ready") return void 0;
8023
8647
  const controller = new AbortController();
8024
8648
  const timer = window.setInterval(
@@ -8030,12 +8654,12 @@ function WhatsappSettingsTab({ rpcCall }) {
8030
8654
  window.clearInterval(timer);
8031
8655
  };
8032
8656
  }, [loadStatus, model.phase]);
8033
- React15.useEffect(() => {
8657
+ React17.useEffect(() => {
8034
8658
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
8035
8659
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
8036
8660
  return () => window.clearInterval(timer);
8037
8661
  }, [provision?.attemptId, provision?.status]);
8038
- const startProvisioning = React15.useCallback(async (replace = false) => {
8662
+ const startProvisioning = React17.useCallback(async (replace = false) => {
8039
8663
  setBusy(true);
8040
8664
  try {
8041
8665
  if (replace && provision?.attemptId) {
@@ -8053,7 +8677,7 @@ function WhatsappSettingsTab({ rpcCall }) {
8053
8677
  if (mounted.current) setBusy(false);
8054
8678
  }
8055
8679
  }, [invoke, provision?.attemptId]);
8056
- const closeProvision = React15.useCallback(async () => {
8680
+ const closeProvision = React17.useCallback(async () => {
8057
8681
  setBusy(true);
8058
8682
  try {
8059
8683
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -8064,7 +8688,7 @@ function WhatsappSettingsTab({ rpcCall }) {
8064
8688
  if (mounted.current) setBusy(false);
8065
8689
  }
8066
8690
  }, [invoke, provision?.attemptId, provision?.status]);
8067
- React15.useEffect(() => {
8691
+ React17.useEffect(() => {
8068
8692
  const attemptId = provision?.attemptId;
8069
8693
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
8070
8694
  const controller = new AbortController();
@@ -8105,7 +8729,7 @@ function WhatsappSettingsTab({ rpcCall }) {
8105
8729
  if (timer) window.clearTimeout(timer);
8106
8730
  };
8107
8731
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
8108
- const botAction = React15.useCallback(async (account, operation, endpoint, payload) => {
8732
+ const botAction = React17.useCallback(async (account, operation, endpoint, payload) => {
8109
8733
  const snapshotVersion = workspaceFence.beginMutation();
8110
8734
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
8111
8735
  if (operation === "reconnect") {
@@ -8201,10 +8825,10 @@ function WhatsappSettingsTab({ rpcCall }) {
8201
8825
  { className: "ddt-inlineError dim-inlineError" },
8202
8826
  h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6 WhatsApp \u673A\u5668\u4EBA\u72B6\u6001"),
8203
8827
  h2("p", null, model.error?.message),
8204
- h2(Button13, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
8828
+ h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
8205
8829
  )
8206
8830
  ) : h2(
8207
- React15.Fragment,
8831
+ React17.Fragment,
8208
8832
  null,
8209
8833
  provision?.status === "pending" ? h2(QrPanel5, {
8210
8834
  provision,
@@ -8225,7 +8849,7 @@ function WhatsappSettingsTab({ rpcCall }) {
8225
8849
 
8226
8850
  // plugin-src/client/styles.js
8227
8851
  var IM_STYLE_ID = "xmanrui-dsh-im-settings";
8228
- var CSS10 = String.raw`
8852
+ var CSS11 = String.raw`
8229
8853
  .dim-page {
8230
8854
  --dim-blue: var(--dsw-alias-state-business-primary, #3370ff);
8231
8855
  --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent);
@@ -8237,9 +8861,9 @@ var CSS10 = String.raw`
8237
8861
  }
8238
8862
  .dim-page *, .dim-page *::before, .dim-page *::after { box-sizing: border-box; }
8239
8863
  .dim-title { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 18px; }
8240
- .dim-brand { min-width: 0; display: flex; align-items: center; gap: 12px; }
8241
- .dim-brandLogo { width: 48px; height: 48px; flex: 0 0 48px; display: block; object-fit: contain; filter: grayscale(1) contrast(1.08); }
8242
- .dim-title p { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 14px; line-height: 20px; font-weight: 600; white-space: nowrap; }
8864
+ .dim-brand { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
8865
+ .dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
8866
+ .dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
8243
8867
  .dim-githubAction { position: relative; display: inline-flex; flex: none; }
8244
8868
  .dim-githubLink { min-height: 30px; display: inline-flex; align-items: center; gap: 5px; flex: none; padding: 0 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-1, #fff); font-size: 12px; line-height: normal; font-weight: 560; text-decoration: none; transition: border-color .15s ease, color .15s ease, background .15s ease; }
8245
8869
  .dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
@@ -8269,6 +8893,8 @@ var CSS10 = String.raw`
8269
8893
  .dim-logoWecom svg { width: 22px; height: 22px; }
8270
8894
  .dim-logoTelegram { color: white; background: #229ed9; }
8271
8895
  .dim-logoTelegram svg { width: 21px; height: 21px; }
8896
+ .dim-logoOffice { color: white; background: linear-gradient(145deg, #12213f, #3964fe); }
8897
+ .dim-logoOffice svg { width: 23px; height: 23px; }
8272
8898
  .dim-logoDiscord { color: white; background: #5865f2; }
8273
8899
  .dim-logoDiscord svg { width: 21px; height: 21px; }
8274
8900
  .dim-logoSlack { color: white; background: #4a154b; }
@@ -8487,7 +9113,7 @@ function installImStyles() {
8487
9113
  const style = document.createElement("style");
8488
9114
  style.dataset.plugin = "@xmanrui/dsh-im";
8489
9115
  style.dataset.pluginCss = IM_STYLE_ID;
8490
- style.textContent = CSS10;
9116
+ style.textContent = CSS11;
8491
9117
  document.head.appendChild(style);
8492
9118
  return () => style.remove();
8493
9119
  }
@@ -8495,7 +9121,6 @@ function installImStyles() {
8495
9121
  // plugin-src/client/index.js
8496
9122
  var name = "im-settings";
8497
9123
  var inject = ["slots", "connection", "locale", "workspaces"];
8498
- var IM_PLUGIN_LOGO_URL = "data:image/png;base64,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";
8499
9124
  var CHANNELS = Object.freeze([
8500
9125
  { id: "weixin", label: "\u5FAE\u4FE1" },
8501
9126
  { id: "feishu", label: "\u98DE\u4E66" },
@@ -8505,7 +9130,8 @@ var CHANNELS = Object.freeze([
8505
9130
  { id: "slack", label: "Slack" },
8506
9131
  { id: "telegram", label: "Telegram" },
8507
9132
  { id: "discord", label: "Discord" },
8508
- { id: "whatsapp", label: "WhatsApp" }
9133
+ { id: "whatsapp", label: "WhatsApp" },
9134
+ { id: "office", label: "AI Office" }
8509
9135
  ]);
8510
9136
  function WeixinLogo() {
8511
9137
  return h2(
@@ -8562,6 +9188,13 @@ function WhatsappLogo() {
8562
9188
  h2(WhatsappLogoGlyph)
8563
9189
  );
8564
9190
  }
9191
+ function OfficeLogo() {
9192
+ return h2(
9193
+ "span",
9194
+ { className: "dim-logo dim-logoOffice", "aria-hidden": "true" },
9195
+ h2(OfficeLogoGlyph)
9196
+ );
9197
+ }
8565
9198
  function ChannelLogo({ channel: channel4 }) {
8566
9199
  if (channel4 === "weixin") return h2(WeixinLogo);
8567
9200
  if (channel4 === "feishu") return h2(FeishuLogo);
@@ -8571,7 +9204,8 @@ function ChannelLogo({ channel: channel4 }) {
8571
9204
  if (channel4 === "slack") return h2(SlackLogo);
8572
9205
  if (channel4 === "telegram") return h2(TelegramLogo);
8573
9206
  if (channel4 === "discord") return h2(DiscordLogo);
8574
- return h2(WhatsappLogo);
9207
+ if (channel4 === "whatsapp") return h2(WhatsappLogo);
9208
+ return h2(OfficeLogo);
8575
9209
  }
8576
9210
  function IMSettingsTab({
8577
9211
  dingtalkRpcCall,
@@ -8583,10 +9217,11 @@ function IMSettingsTab({
8583
9217
  wecomRpcCall,
8584
9218
  weixinRpcCall,
8585
9219
  whatsappRpcCall,
9220
+ officeRpcCall,
8586
9221
  workspaceDirectoryPicker
8587
9222
  }) {
8588
- const [selected, setSelected] = React16.useState("weixin");
8589
- const githubTooltipId = React16.useId();
9223
+ const [selected, setSelected] = React18.useState("weixin");
9224
+ const githubTooltipId = React18.useId();
8590
9225
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
8591
9226
  return h2(
8592
9227
  WorkspaceDirectoryPickerContext.Provider,
@@ -8600,13 +9235,7 @@ function IMSettingsTab({
8600
9235
  h2(
8601
9236
  "div",
8602
9237
  { className: "dim-brand" },
8603
- h2("img", {
8604
- className: "dim-brandLogo",
8605
- src: IM_PLUGIN_LOGO_URL,
8606
- alt: "dsh-im",
8607
- width: 48,
8608
- height: 48
8609
- }),
9238
+ h2("strong", { className: "dim-brandName" }, "DSH-IM"),
8610
9239
  h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA")
8611
9240
  ),
8612
9241
  h2(
@@ -8664,7 +9293,7 @@ function IMSettingsTab({
8664
9293
  role: "tabpanel",
8665
9294
  id: `dim-panel-${active.id}`,
8666
9295
  "aria-labelledby": `dim-tab-${active.id}`
8667
- }, active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: wecomRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: discordRpcCall }) : h2(WhatsappSettingsTab, { rpcCall: whatsappRpcCall }))
9296
+ }, active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: wecomRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: discordRpcCall }) : active.id === "whatsapp" ? h2(WhatsappSettingsTab, { rpcCall: whatsappRpcCall }) : h2(OfficeSettingsTab, { rpcCall: officeRpcCall }))
8668
9297
  )
8669
9298
  )
8670
9299
  );
@@ -8686,6 +9315,7 @@ function apply(ctx) {
8686
9315
  installTelegramStyles(),
8687
9316
  installDiscordStyles(),
8688
9317
  installWhatsappStyles(),
9318
+ installOfficeStyles(),
8689
9319
  installImStyles()
8690
9320
  ];
8691
9321
  return () => {
@@ -8701,6 +9331,7 @@ function apply(ctx) {
8701
9331
  const discordRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(DISCORD_RPC_CHANNEL, endpoint, payload, signal);
8702
9332
  const whatsappRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
8703
9333
  const slackRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(SLACK_RPC_CHANNEL, endpoint, payload, signal);
9334
+ const officeRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(OFFICE_RPC_CHANNEL, endpoint, payload, signal);
8704
9335
  const workspaceDirectoryPicker = Object.freeze({
8705
9336
  listDirectory: (path, signal) => ctx.workspaces.listDirectory(path, signal),
8706
9337
  pickDirectory: () => ctx.workspaces.pickDirectory()
@@ -8721,6 +9352,7 @@ function apply(ctx) {
8721
9352
  wecomRpcCall,
8722
9353
  weixinRpcCall,
8723
9354
  whatsappRpcCall,
9355
+ officeRpcCall,
8724
9356
  workspaceDirectoryPicker
8725
9357
  })
8726
9358
  }, IMSettingsTab));