@xmanrui/dsh-im 4.17.1 → 4.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.en.md +24 -16
  2. package/README.md +23 -18
  3. package/lib/client.js +428 -246
  4. package/lib/index.js +280 -258
  5. package/package.json +11 -2
  6. package/plugin-src/client/access-policy-settings.js +5 -0
  7. package/plugin-src/client/channel-logos.js +10 -0
  8. package/plugin-src/client/channels/imessage/api.js +12 -0
  9. package/plugin-src/client/channels/imessage/index.js +45 -0
  10. package/plugin-src/client/channels/imessage/styles.js +19 -0
  11. package/plugin-src/client/channels/shared/token-api.js +1 -0
  12. package/plugin-src/client/channels/shared/token-channel.js +5 -1
  13. package/plugin-src/client/delivery-settings.js +5 -0
  14. package/plugin-src/client/i18n.js +23 -1
  15. package/plugin-src/client/index.js +20 -0
  16. package/plugin-src/client/session-channel-logos.js +2 -0
  17. package/plugin-src/client/styles.js +1 -0
  18. package/plugin-src/host/channels/imessage/index.mjs +21 -0
  19. package/plugin-src/host/channels/imessage/production.mjs +13 -0
  20. package/plugin-src/host/channels/imessage/rpc.mjs +70 -0
  21. package/plugin-src/host/channels/shared/access-policy-production.mjs +1 -1
  22. package/plugin-src/host/delivery-adapter.mjs +4 -0
  23. package/plugin-src/host/index.mjs +3 -0
  24. package/plugin-src/host/modern-harness-api.mjs +1 -1
  25. package/plugin-src/host/rpc-authority.mjs +3 -2
  26. package/scripts/verify-lan-management.mjs +176 -0
  27. package/src/channels/imessage/config-store.mjs +24 -0
  28. package/src/channels/imessage/controller.mjs +37 -0
  29. package/src/channels/imessage/harness-client.mjs +7 -0
  30. package/src/channels/imessage/imessage-api.mjs +194 -0
  31. package/src/channels/imessage/imessage-bridge.mjs +16 -0
  32. package/src/channels/imessage/runtime.mjs +98 -0
  33. package/src/channels/imessage/state-store.mjs +3 -0
  34. package/src/channels/shared/i18n-en/shared-a.mjs +2 -2
  35. package/src/channels/shared/message-failure.mjs +5 -5
  36. package/src/channels/shared/session-channel-labels.mjs +1 -0
  37. package/src/channels/shared/text-harness-bridge.mjs +38 -0
  38. package/src/channels/telegram/telegram-runtime.mjs +77 -25
package/lib/client.js CHANGED
@@ -568,22 +568,22 @@ __export(index_exports, {
568
568
  module.exports = __toCommonJS(index_exports);
569
569
 
570
570
  // plugin-src/management-rpc.mjs
571
- function rpcEndpoint(channel4) {
572
- if (!/^\/[A-Za-z0-9._~-]+$/.test(channel4)) throw new TypeError("Invalid IM RPC channel");
573
- return `dsh-im${channel4}`;
571
+ function rpcEndpoint(channel5) {
572
+ if (!/^\/[A-Za-z0-9._~-]+$/.test(channel5)) throw new TypeError("Invalid IM RPC channel");
573
+ return `dsh-im${channel5}`;
574
574
  }
575
- function callManagementRpc(connection, channel4, method, payload, signal) {
576
- return connection.rpc.call("/api", rpcEndpoint(channel4), { method, payload }, signal);
575
+ function callManagementRpc(connection, channel5, method, payload, signal) {
576
+ return connection.rpc.call("/api", rpcEndpoint(channel5), { method, payload }, signal);
577
577
  }
578
578
 
579
579
  // plugin-src/client/index.js
580
- var React28 = __toESM(require("react"), 1);
580
+ var React29 = __toESM(require("react"), 1);
581
581
 
582
582
  // package.json
583
583
  var package_default = {
584
584
  name: "@xmanrui/dsh-im",
585
- version: "4.17.1",
586
- description: "\u628A\u5341\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect ten IM channels and a public AI Office to a local DeepSeek Harness.",
585
+ version: "4.18.1",
586
+ description: "\u628A\u5341\u4E00\u79CD IM \u6E20\u9053\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect eleven IM channels and a public AI Office to a local DeepSeek Harness.",
587
587
  keywords: [
588
588
  "deepseek-harness",
589
589
  "dsh",
@@ -602,6 +602,7 @@ var package_default = {
602
602
  "telegram",
603
603
  "discord",
604
604
  "whatsapp",
605
+ "imessage",
605
606
  "ai-office"
606
607
  ],
607
608
  author: "xmanrui (https://github.com/xmanrui)",
@@ -625,6 +626,14 @@ var package_default = {
625
626
  {
626
627
  name: "masucc",
627
628
  url: "https://github.com/masucc"
629
+ },
630
+ {
631
+ name: "cherryFloris",
632
+ url: "https://github.com/cherryFloris"
633
+ },
634
+ {
635
+ name: "geekyfoxlab",
636
+ url: "https://github.com/geekyfoxlab"
628
637
  }
629
638
  ],
630
639
  license: "MIT",
@@ -855,6 +864,18 @@ function WhatsappLogoGlyph({ size } = {}) {
855
864
  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"
856
865
  }));
857
866
  }
867
+ function IMessageLogoGlyph({ size } = {}) {
868
+ return h("svg", {
869
+ ...dimensions(size),
870
+ viewBox: "0 0 24 24",
871
+ focusable: "false",
872
+ "aria-hidden": "true",
873
+ "data-im-channel-logo": "imessage"
874
+ }, h("path", {
875
+ fill: "currentColor",
876
+ d: "M12 2.2c-5.52 0-10 3.75-10 8.38 0 2.63 1.52 4.98 3.9 6.52l-.92 3.43a.5.5 0 0 0 .72.56l3.54-1.96c.87.23 1.8.35 2.76.35 5.52 0 10-3.75 10-8.9S17.52 2.2 12 2.2Zm-3.4 8.2a1.2 1.2 0 1 1 0 2.4 1.2 1.2 0 0 1 0-2.4Zm3.4 0a1.2 1.2 0 1 1 0 2.4 1.2 1.2 0 0 1 0-2.4Zm3.4 0a1.2 1.2 0 1 1 0 2.4 1.2 1.2 0 0 1 0-2.4Z"
877
+ }));
878
+ }
858
879
  function OfficeLogoGlyph({ size } = {}) {
859
880
  return h(
860
881
  "svg",
@@ -878,6 +899,27 @@ var React2 = __toESM(require("react"), 1);
878
899
  var IM_LOCALE_NAMESPACE = "dsh-im";
879
900
  var EN = Object.freeze({
880
901
  "$locale": "en",
902
+ " macOS Messages \u8FDE\u63A5": " macOS Messages connection",
903
+ "\u63A5\u5165 iMessage": "Connect iMessage",
904
+ "\u5148\u5728 macOS \u7CFB\u7EDF\u8BBE\u7F6E\u4E2D\u6388\u4E88 Messages \u6743\u9650\u3002": "Grant Messages permissions in macOS System Settings first.",
905
+ "\u914D\u7F6E macOS Messages \u6743\u9650": "Configure macOS Messages permissions",
906
+ "\u914D\u7F6E\u672C\u673A\u6743\u9650": "Configure local permissions",
907
+ "\u542F\u7528 macOS \u539F\u751F iMessage": "Enable native macOS iMessage",
908
+ "\u652F\u6301\u540C\u8D26\u53F7\u81EA\u804A\uFF1A\u5728 iPhone \u6216 Mac \u4E0A\u7ED9\u81EA\u5DF1\u5DF2\u767B\u5F55\u7684 iMessage \u90AE\u7BB1\u6216\u53F7\u7801\u53D1\u6307\u4EE4\u3002AI \u56DE\u590D\u4EE5 \u{1F916} DSH \u5F00\u5934\uFF0C\u4E0D\u4F1A\u518D\u6B21\u89E6\u53D1\u673A\u5668\u4EBA\u3002": "Self-chat is supported: send instructions from your iPhone or Mac to your signed-in iMessage email or phone number. AI replies start with \u{1F916} DSH and do not trigger the bot again.",
909
+ "\u68C0\u67E5\u6743\u9650\u5E76\u542F\u7528": "Check permissions and enable",
910
+ "DeepSeek Harness \u901A\u8FC7 macOS Messages.app \u6536\u53D1\u6587\u672C\u6D88\u606F\u3002\u9996\u6B21\u4F7F\u7528\u9700\u8981\u6388\u4E88\u4EE5\u4E0B\u6743\u9650\uFF1A": "DeepSeek Harness sends and receives messages through macOS Messages.app. The following permissions are required the first time:",
911
+ "\u2713 \u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u5DF2\u6388\u4E88": "\u2713 Full Disk Access granted",
912
+ "1. \u6388\u4E88\u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650": "1. Grant Full Disk Access",
913
+ "\u5728\u201C\u7CFB\u7EDF\u8BBE\u7F6E \u2192 \u9690\u79C1\u4E0E\u5B89\u5168\u6027 \u2192 \u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u201D\u4E2D\uFF0C\u6253\u5F00\u8FD0\u884C DeepSeek Harness \u7684\u7EC8\u7AEF\u6216\u5E94\u7528\u3002": "In System Settings \u2192 Privacy & Security \u2192 Full Disk Access, enable the terminal or app running DeepSeek Harness.",
914
+ "\u6253\u5F00\u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u8BBE\u7F6E": "Open Full Disk Access settings",
915
+ "\u2713 Messages \u81EA\u52A8\u5316\u6743\u9650\u5DF2\u6388\u4E88": "\u2713 Messages automation granted",
916
+ "2. \u5141\u8BB8\u81EA\u52A8\u5316\u63A7\u5236 Messages": "2. Allow automation control of Messages",
917
+ "\u5728\u201C\u7CFB\u7EDF\u8BBE\u7F6E \u2192 \u9690\u79C1\u4E0E\u5B89\u5168\u6027 \u2192 \u81EA\u52A8\u5316\u201D\u4E2D\uFF0C\u5141\u8BB8\u8FD0\u884C DeepSeek Harness \u7684\u5E94\u7528\u63A7\u5236 Messages\u3002": "In System Settings \u2192 Privacy & Security \u2192 Automation, allow the app running DeepSeek Harness to control Messages.",
918
+ "\u6253\u5F00\u81EA\u52A8\u5316\u8BBE\u7F6E": "Open Automation settings",
919
+ "\u6B63\u5728\u68C0\u67E5\u2026": "Checking\u2026",
920
+ "\u63A5\u5165 macOS \u539F\u751F iMessage": "Connect native macOS iMessage",
921
+ "\u65E0\u9700\u5B89\u88C5\u7B2C\u4E09\u65B9\u670D\u52A1\uFF1B\u8BF7\u6309\u6307\u5F15\u6388\u4E88 macOS Messages \u8BBF\u95EE\u6743\u9650\u3002": "No third-party service is required; follow the guide to grant macOS Messages access.",
922
+ "macOS Messages \u6743\u9650": "macOS Messages permissions",
881
923
  "IM\u673A\u5668\u4EBA": "IM bots",
882
924
  "IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
883
925
  "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E": "More bot settings",
@@ -1929,6 +1971,8 @@ function translateDynamic(text7) {
1929
1971
  ["\u4F01\u4E1A\u5FAE\u4FE1", "WeCom"],
1930
1972
  ["DeepSeek Harness", "DeepSeek Harness"],
1931
1973
  ["WhatsApp", "WhatsApp"],
1974
+ ["iMessage", "iMessage"],
1975
+ ["macOS Messages", "macOS Messages"],
1932
1976
  ["Telegram", "Telegram"],
1933
1977
  ["Discord", "Discord"],
1934
1978
  ["Slack", "Slack"],
@@ -2968,7 +3012,7 @@ function CredentialActionIcon() {
2968
3012
  );
2969
3013
  }
2970
3014
  function CredentialBindingPanel({
2971
- channel: channel4,
3015
+ channel: channel5,
2972
3016
  identityLabel,
2973
3017
  identityPlaceholder,
2974
3018
  secretLabel,
@@ -2995,7 +3039,7 @@ function CredentialBindingPanel({
2995
3039
  className: "ddt-card dim-surfaceCard dim-credentialPanel",
2996
3040
  "aria-labelledby": headingId
2997
3041
  },
2998
- h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel4}\u673A\u5668\u4EBA`),
3042
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel5}\u673A\u5668\u4EBA`),
2999
3043
  h2(
3000
3044
  "form",
3001
3045
  {
@@ -4055,7 +4099,7 @@ function SettingsGlyph() {
4055
4099
  );
4056
4100
  }
4057
4101
  function BotSettingsButton({
4058
- channel: channel4,
4102
+ channel: channel5,
4059
4103
  botId,
4060
4104
  botName,
4061
4105
  connected,
@@ -4070,12 +4114,12 @@ function BotSettingsButton({
4070
4114
  h2("button", {
4071
4115
  type: "button",
4072
4116
  className: "dim-botSettingsButton",
4073
- "data-delivery-channel": channel4,
4117
+ "data-delivery-channel": channel5,
4074
4118
  "aria-label": "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E",
4075
4119
  "aria-describedby": tooltipId,
4076
4120
  onClick: () => openBotSettings?.({
4077
4121
  ...channelSettings && typeof channelSettings === "object" ? channelSettings : {},
4078
- channel: channel4,
4122
+ channel: channel5,
4079
4123
  botId,
4080
4124
  botName,
4081
4125
  connected: Boolean(connected),
@@ -5366,16 +5410,16 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
5366
5410
  setContextEnhancement: "bot.context-enhancement.set",
5367
5411
  setAccessPolicy: "bot.access-policy.set"
5368
5412
  });
5369
- function createTokenChannelApi(channel4, connectionSummary, {
5413
+ function createTokenChannelApi(channel5, connectionSummary, {
5370
5414
  normalizeBotExtension = () => ({})
5371
5415
  } = {}) {
5372
- const unwrapRpcResult14 = (result) => {
5416
+ const unwrapRpcResult15 = (result) => {
5373
5417
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
5374
- throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
5418
+ throw new Error(`${channel5} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
5375
5419
  }
5376
5420
  if (!result.ok) {
5377
- const error = new Error(text2(result.error?.message, `${channel4} \u64CD\u4F5C\u5931\u8D25`));
5378
- error.code = text2(result.error?.code, `${channel4.toUpperCase()}_RPC_ERROR`, 80);
5421
+ const error = new Error(text2(result.error?.message, `${channel5} \u64CD\u4F5C\u5931\u8D25`));
5422
+ error.code = text2(result.error?.code, `${channel5.toUpperCase()}_RPC_ERROR`, 80);
5379
5423
  throw error;
5380
5424
  }
5381
5425
  return result.value;
@@ -5395,29 +5439,29 @@ function createTokenChannelApi(channel4, connectionSummary, {
5395
5439
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
5396
5440
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
5397
5441
  bot: {
5398
- name: text2(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
5442
+ name: text2(value.bot?.name, `${channel5}\u673A\u5668\u4EBA`, 100),
5399
5443
  username: text2(value.bot?.username, "", 100),
5400
5444
  idMasked: text2(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
5401
5445
  },
5402
5446
  health: {
5403
5447
  summary: text2(
5404
5448
  value.health?.summary,
5405
- connected ? `${channel4}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
5449
+ connected ? `${channel5}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel5}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
5406
5450
  ),
5407
5451
  lastCheckedAt: timestamp2(value.health?.lastCheckedAt)
5408
5452
  },
5409
5453
  lastMessageError: normalizeLastMessageError(value.lastMessageError),
5410
5454
  error: isRecord2(value.error) ? {
5411
- code: text2(value.error.code, `${channel4.toUpperCase()}_ACCOUNT_ERROR`, 80),
5412
- message: text2(value.error.message, `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
5455
+ code: text2(value.error.code, `${channel5.toUpperCase()}_ACCOUNT_ERROR`, 80),
5456
+ message: text2(value.error.message, `${channel5}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
5413
5457
  } : null,
5414
5458
  ...isRecord2(extension) ? extension : {}
5415
5459
  };
5416
5460
  };
5417
- const normalizeSnapshot10 = (value) => {
5461
+ const normalizeSnapshot11 = (value) => {
5418
5462
  const source = isRecord2(value?.snapshot) ? value.snapshot : value;
5419
5463
  if (!isRecord2(source) || !Array.isArray(source.bots)) {
5420
- throw new Error(`${channel4} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
5464
+ throw new Error(`${channel5} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
5421
5465
  }
5422
5466
  const bots = source.bots.map(normalizeBot8).filter(Boolean);
5423
5467
  return {
@@ -5425,14 +5469,15 @@ function createTokenChannelApi(channel4, connectionSummary, {
5425
5469
  bots,
5426
5470
  totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
5427
5471
  agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
5428
- modelCatalog: normalizeModelCatalog(source.modelCatalog)
5472
+ modelCatalog: normalizeModelCatalog(source.modelCatalog),
5473
+ ...isRecord2(source.permissions) ? { permissions: source.permissions } : {}
5429
5474
  };
5430
5475
  };
5431
- const presentError14 = (error) => ({
5432
- code: text2(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
5433
- message: text2(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
5476
+ const presentError15 = (error) => ({
5477
+ code: text2(error?.code, `${channel5.toUpperCase()}_ERROR`, 80),
5478
+ message: text2(error?.message, `${channel5}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
5434
5479
  });
5435
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult14, normalizeSnapshot: normalizeSnapshot10, presentError: presentError14 });
5480
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult15, normalizeSnapshot: normalizeSnapshot11, presentError: presentError15 });
5436
5481
  }
5437
5482
 
5438
5483
  // plugin-src/client/channels/discord/api.js
@@ -5475,9 +5520,9 @@ function connectionTestNotice(value) {
5475
5520
  }
5476
5521
  function createTokenChannelSettings(definition) {
5477
5522
  const {
5478
- channel: channel4,
5523
+ channel: channel5,
5479
5524
  endpoints,
5480
- api: api4,
5525
+ api: api5,
5481
5526
  LogoGlyph,
5482
5527
  installStyles,
5483
5528
  pageClass,
@@ -5489,7 +5534,7 @@ function createTokenChannelSettings(definition) {
5489
5534
  platformLabel,
5490
5535
  CredentialPanel = null,
5491
5536
  credentialPayload = ({ secret }) => ({ token: secret }),
5492
- credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel4} \u673A\u5668\u4EBA`,
5537
+ credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel5} \u673A\u5668\u4EBA`,
5493
5538
  credentialOpenLabel = "\u624B\u52A8\u63A5\u5165",
5494
5539
  credentialCloseLabel = "\u6536\u8D77\u51ED\u636E",
5495
5540
  credentialNoun = "Bot Token",
@@ -5552,7 +5597,7 @@ function createTokenChannelSettings(definition) {
5552
5597
  formatCheckedTime: checkedTime2
5553
5598
  }),
5554
5599
  h2(BotSettingsButton, {
5555
- channel: channel4.toLowerCase(),
5600
+ channel: channel5.toLowerCase(),
5556
5601
  botId: account.botId,
5557
5602
  botName: account.bot.name,
5558
5603
  connected: account.connected,
@@ -5645,7 +5690,8 @@ function createTokenChannelSettings(definition) {
5645
5690
  totals: { configured: 0, connected: 0 },
5646
5691
  error: null,
5647
5692
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
5648
- modelCatalog: EMPTY_MODEL_CATALOG
5693
+ modelCatalog: EMPTY_MODEL_CATALOG,
5694
+ permissions: null
5649
5695
  });
5650
5696
  const [credentialOpen, setCredentialOpen] = React13.useState(false);
5651
5697
  const [credentialError, setCredentialError] = React13.useState(null);
@@ -5666,15 +5712,15 @@ function createTokenChannelSettings(definition) {
5666
5712
  };
5667
5713
  }, []);
5668
5714
  const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
5669
- if (typeof rpcCall !== "function") throw new TypeError(`${channel4} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
5670
- return api4.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
5715
+ if (typeof rpcCall !== "function") throw new TypeError(`${channel5} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
5716
+ return api5.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
5671
5717
  }, [rpcCall]);
5672
5718
  const loadStatus = React13.useCallback(async ({ signal, silent = false } = {}) => {
5673
5719
  const workspaceVersion = workspaceFence.beginStatus();
5674
5720
  if (workspaceVersion === null) return;
5675
5721
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
5676
5722
  try {
5677
- const snapshot = api4.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
5723
+ const snapshot = api5.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
5678
5724
  if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return;
5679
5725
  setModel({
5680
5726
  phase: "ready",
@@ -5682,14 +5728,15 @@ function createTokenChannelSettings(definition) {
5682
5728
  totals: snapshot.totals,
5683
5729
  error: null,
5684
5730
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
5685
- modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
5731
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
5732
+ permissions: snapshot.permissions ?? null
5686
5733
  });
5687
5734
  } catch (error) {
5688
5735
  if (error?.name !== "AbortError" && mounted.current && !signal?.aborted && workspaceFence.canCommitStatus(workspaceVersion)) {
5689
5736
  setModel((current) => ({
5690
5737
  ...current,
5691
5738
  phase: silent ? current.phase : "error",
5692
- error: api4.presentError(error)
5739
+ error: api5.presentError(error)
5693
5740
  }));
5694
5741
  }
5695
5742
  }
@@ -5716,7 +5763,7 @@ function createTokenChannelSettings(definition) {
5716
5763
  setBusy(true);
5717
5764
  setCredentialError(null);
5718
5765
  try {
5719
- const snapshot = api4.normalizeSnapshot(await invoke(
5766
+ const snapshot = api5.normalizeSnapshot(await invoke(
5720
5767
  endpoints.bindCredentials,
5721
5768
  credentialPayload(values)
5722
5769
  ));
@@ -5728,12 +5775,13 @@ function createTokenChannelSettings(definition) {
5728
5775
  totals: snapshot.totals,
5729
5776
  error: null,
5730
5777
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
5731
- modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
5778
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
5779
+ permissions: snapshot.permissions ?? null
5732
5780
  });
5733
5781
  }
5734
5782
  setCredentialOpen(false);
5735
5783
  } catch (error) {
5736
- if (mounted.current) setCredentialError(api4.presentError(error));
5784
+ if (mounted.current) setCredentialError(api5.presentError(error));
5737
5785
  } finally {
5738
5786
  const shouldRefresh = workspaceFence.endMutation();
5739
5787
  if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
@@ -5745,7 +5793,7 @@ function createTokenChannelSettings(definition) {
5745
5793
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
5746
5794
  try {
5747
5795
  const value = await invoke(endpoint, payload);
5748
- const snapshot = api4.normalizeSnapshot(value);
5796
+ const snapshot = api5.normalizeSnapshot(value);
5749
5797
  if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
5750
5798
  setModel({
5751
5799
  phase: "ready",
@@ -5785,7 +5833,7 @@ function createTokenChannelSettings(definition) {
5785
5833
  { className: "dim-listSection" },
5786
5834
  h2(ChannelListHeading, {
5787
5835
  className: "ddt-listHeading",
5788
- title: `\u5DF2\u63A5\u5165\u7684 ${channel4} \u673A\u5668\u4EBA`,
5836
+ title: `\u5DF2\u63A5\u5165\u7684 ${channel5} \u673A\u5668\u4EBA`,
5789
5837
  connectionLabel
5790
5838
  }),
5791
5839
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard6, {
@@ -5848,7 +5896,7 @@ function createTokenChannelSettings(definition) {
5848
5896
  "section",
5849
5897
  {
5850
5898
  className: `ddt-page ${pageClass} dim-channelPage`,
5851
- "aria-label": `${channel4} \u8BBE\u7F6E`
5899
+ "aria-label": `${channel5} \u8BBE\u7F6E`
5852
5900
  },
5853
5901
  h2(
5854
5902
  "div",
@@ -5881,13 +5929,13 @@ function createTokenChannelSettings(definition) {
5881
5929
  model.phase === "loading" ? h2("div", {
5882
5930
  className: "ddt-card ddt-loading dim-surfaceCard dim-loadingView",
5883
5931
  "aria-busy": "true"
5884
- }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel4} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
5932
+ }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel5} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
5885
5933
  "div",
5886
5934
  { className: "ddt-card dim-surfaceCard" },
5887
5935
  h2(
5888
5936
  "div",
5889
5937
  { className: "ddt-inlineError dim-inlineError" },
5890
- h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel4} \u673A\u5668\u4EBA\u72B6\u6001`),
5938
+ h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel5} \u673A\u5668\u4EBA\u72B6\u6001`),
5891
5939
  h2("p", null, model.error?.message),
5892
5940
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
5893
5941
  )
@@ -5895,6 +5943,8 @@ function createTokenChannelSettings(definition) {
5895
5943
  React13.Fragment,
5896
5944
  null,
5897
5945
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
5946
+ channel: channel5,
5947
+ permissions: model.permissions,
5898
5948
  busy,
5899
5949
  error: credentialError,
5900
5950
  onSubmit: bindCredentials,
@@ -5903,7 +5953,7 @@ function createTokenChannelSettings(definition) {
5903
5953
  setCredentialError(null);
5904
5954
  }
5905
5955
  }) : h2(CredentialBindingPanel, {
5906
- channel: channel4,
5956
+ channel: channel5,
5907
5957
  secretLabel: "Bot Token",
5908
5958
  secretPlaceholder: tokenPlaceholder,
5909
5959
  busy,
@@ -5927,7 +5977,7 @@ function createTokenChannelSettings(definition) {
5927
5977
  "div",
5928
5978
  { className: "ddt-stateLabel dim-stateLabel" },
5929
5979
  h2("span", { className: "ddt-dot dim-stateDot" }),
5930
- h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel4} \u673A\u5668\u4EBA`)
5980
+ h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel5} \u673A\u5668\u4EBA`)
5931
5981
  ),
5932
5982
  h2("h3", null, emptyTitle),
5933
5983
  h2("p", null, emptyDescription),
@@ -13423,11 +13473,115 @@ function WhatsappSettingsTab({ rpcCall }) {
13423
13473
  )));
13424
13474
  }
13425
13475
 
13476
+ // plugin-src/client/channels/imessage/api.js
13477
+ var IMESSAGE_RPC_CHANNEL = "/imessage";
13478
+ var IMESSAGE_ENDPOINTS = Object.freeze({
13479
+ ...TOKEN_BOT_ENDPOINTS,
13480
+ bindCredentials: "bot.bind-native"
13481
+ });
13482
+ var api4 = createTokenChannelApi("iMessage", " macOS Messages \u8FDE\u63A5");
13483
+ var unwrapRpcResult11 = api4.unwrapRpcResult;
13484
+ var normalizeSnapshot10 = api4.normalizeSnapshot;
13485
+ var presentError11 = api4.presentError;
13486
+
13487
+ // plugin-src/client/channels/imessage/index.js
13488
+ var React23 = __toESM(require("react"), 1);
13489
+
13490
+ // plugin-src/client/channels/imessage/styles.js
13491
+ var IMESSAGE_STYLE_ID = "xmanrui-dsh-im-imessage-settings";
13492
+ var CSS12 = String.raw`
13493
+ .dim-pageIMessage { --ddt-accent: #32a852; --ddt-accent-deep: #248a40; --ddt-accent-wash: #edf9f0; }
13494
+ .dim-avatarIMessage { color: #fff; background: #32a852; }
13495
+ .dim-avatarIMessage svg { display: block; }
13496
+ .dim-imessagePermissionPanel { padding: 20px; }
13497
+ .dim-imessagePermissionPanel p { color: var(--dsw-alias-label-secondary, #646a73); }
13498
+ .dim-imessagePermissionSteps { margin: 16px 0; padding-left: 22px; }
13499
+ .dim-imessagePermissionSteps li { margin: 12px 0; }
13500
+ .dim-imessagePermissionSteps a { color: var(--ddt-accent-deep); }
13501
+ `;
13502
+ function installIMessageStyles() {
13503
+ if (typeof document === "undefined") return () => {
13504
+ };
13505
+ const existing = document.querySelector(`style[data-plugin-css="${IMESSAGE_STYLE_ID}"]`);
13506
+ if (existing) return () => {
13507
+ };
13508
+ const style = document.createElement("style");
13509
+ style.dataset.plugin = "@xmanrui/dsh-im";
13510
+ style.dataset.pluginCss = IMESSAGE_STYLE_ID;
13511
+ style.textContent = CSS12;
13512
+ document.head.appendChild(style);
13513
+ return () => style.remove();
13514
+ }
13515
+
13516
+ // plugin-src/client/channels/imessage/index.js
13517
+ function PermissionPanel({ permissions, busy, error, onSubmit, onCancel }) {
13518
+ const databaseReady = permissions?.database === "granted";
13519
+ const automationReady = permissions?.automation === "granted";
13520
+ return h2(
13521
+ "section",
13522
+ { className: "ddt-card dim-surfaceCard dim-imessagePermissionPanel" },
13523
+ h2("h3", null, "\u542F\u7528 macOS \u539F\u751F iMessage"),
13524
+ h2("p", null, "\u652F\u6301\u540C\u8D26\u53F7\u81EA\u804A\uFF1A\u5728 iPhone \u6216 Mac \u4E0A\u7ED9\u81EA\u5DF1\u5DF2\u767B\u5F55\u7684 iMessage \u90AE\u7BB1\u6216\u53F7\u7801\u53D1\u6307\u4EE4\u3002AI \u56DE\u590D\u4EE5 \u{1F916} DSH \u5F00\u5934\uFF0C\u4E0D\u4F1A\u518D\u6B21\u89E6\u53D1\u673A\u5668\u4EBA\u3002"),
13525
+ h2("p", null, "DeepSeek Harness \u901A\u8FC7 macOS Messages.app \u6536\u53D1\u6587\u672C\u6D88\u606F\u3002\u9996\u6B21\u4F7F\u7528\u9700\u8981\u6388\u4E88\u4EE5\u4E0B\u6743\u9650\uFF1A"),
13526
+ h2(
13527
+ "ol",
13528
+ { className: "dim-imessagePermissionSteps" },
13529
+ h2(
13530
+ "li",
13531
+ null,
13532
+ h2("strong", null, databaseReady ? "\u2713 \u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u5DF2\u6388\u4E88" : "1. \u6388\u4E88\u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650"),
13533
+ databaseReady ? null : h2("p", null, "\u5728\u201C\u7CFB\u7EDF\u8BBE\u7F6E \u2192 \u9690\u79C1\u4E0E\u5B89\u5168\u6027 \u2192 \u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u201D\u4E2D\uFF0C\u6253\u5F00\u8FD0\u884C DeepSeek Harness \u7684\u7EC8\u7AEF\u6216\u5E94\u7528\u3002"),
13534
+ databaseReady ? null : h2("a", { href: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles" }, "\u6253\u5F00\u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u8BBE\u7F6E")
13535
+ ),
13536
+ h2(
13537
+ "li",
13538
+ null,
13539
+ h2("strong", null, automationReady ? "\u2713 Messages \u81EA\u52A8\u5316\u6743\u9650\u5DF2\u6388\u4E88" : "2. \u5141\u8BB8\u81EA\u52A8\u5316\u63A7\u5236 Messages"),
13540
+ automationReady ? null : h2("p", null, "\u5728\u201C\u7CFB\u7EDF\u8BBE\u7F6E \u2192 \u9690\u79C1\u4E0E\u5B89\u5168\u6027 \u2192 \u81EA\u52A8\u5316\u201D\u4E2D\uFF0C\u5141\u8BB8\u8FD0\u884C DeepSeek Harness \u7684\u5E94\u7528\u63A7\u5236 Messages\u3002"),
13541
+ automationReady ? null : h2("a", { href: "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation" }, "\u6253\u5F00\u81EA\u52A8\u5316\u8BBE\u7F6E")
13542
+ )
13543
+ ),
13544
+ error ? h2("p", { className: "dim-inlineError", role: "alert" }, error.message ?? String(error)) : null,
13545
+ h2(
13546
+ "div",
13547
+ { className: "ddt-actions dim-viewActions" },
13548
+ h2("button", { type: "button", className: "ddt-button", onClick: onCancel, disabled: busy }, "\u53D6\u6D88"),
13549
+ h2(
13550
+ "button",
13551
+ { type: "button", className: "ddt-button", "data-kind": "primary", onClick: () => onSubmit({}), disabled: busy },
13552
+ busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u6743\u9650\u5E76\u542F\u7528"
13553
+ )
13554
+ )
13555
+ );
13556
+ }
13557
+ var channel4 = createTokenChannelSettings({
13558
+ channel: "iMessage",
13559
+ endpoints: IMESSAGE_ENDPOINTS,
13560
+ api: api4,
13561
+ LogoGlyph: IMessageLogoGlyph,
13562
+ installStyles: installIMessageStyles,
13563
+ pageClass: "dim-pageIMessage",
13564
+ avatarClass: "dim-avatarIMessage",
13565
+ connectionLabel: " macOS Messages \u8FDE\u63A5",
13566
+ tokenPlaceholder: "",
13567
+ emptyTitle: "\u63A5\u5165 macOS \u539F\u751F iMessage",
13568
+ emptyDescription: "\u65E0\u9700\u5B89\u88C5\u7B2C\u4E09\u65B9\u670D\u52A1\uFF1B\u8BF7\u6309\u6307\u5F15\u6388\u4E88 macOS Messages \u8BBF\u95EE\u6743\u9650\u3002",
13569
+ platformLabel: "macOS Messages",
13570
+ credentialPayload: () => ({}),
13571
+ CredentialPanel: PermissionPanel,
13572
+ credentialAriaLabel: "\u914D\u7F6E macOS Messages \u6743\u9650",
13573
+ credentialOpenLabel: "\u914D\u7F6E\u672C\u673A\u6743\u9650",
13574
+ credentialNoun: "macOS Messages \u6743\u9650",
13575
+ emptyActionLabel: "\u914D\u7F6E\u672C\u673A\u6743\u9650"
13576
+ });
13577
+ var IMessageSettingsTab = channel4.SettingsTab;
13578
+ var IMessageAccountCard = channel4.AccountCard;
13579
+
13426
13580
  // plugin-src/client/delivery-settings.js
13427
- var React25 = __toESM(require("react"), 1);
13581
+ var React26 = __toESM(require("react"), 1);
13428
13582
 
13429
13583
  // plugin-src/client/access-policy-settings.js
13430
- var React23 = __toESM(require("react"), 1);
13584
+ var React24 = __toESM(require("react"), 1);
13431
13585
  var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
13432
13586
  var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
13433
13587
  weixin: Object.freeze({
@@ -13488,6 +13642,11 @@ var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
13488
13642
  directPlaceholder: "8613800000000 \u6216\u5B8C\u6574 JID",
13489
13643
  groupUserLabel: "\u7FA4\u6210\u5458\u7535\u8BDD\u53F7\u7801\u6216 JID",
13490
13644
  groupPlaceholder: "8613800000000 \u6216\u5B8C\u6574 JID"
13645
+ }),
13646
+ imessage: Object.freeze({
13647
+ directUserLabel: "iMessage Chat GUID",
13648
+ directPlaceholder: "iMessage;+;chat123",
13649
+ groupSupported: false
13491
13650
  })
13492
13651
  });
13493
13652
  function clonePolicy(policy) {
@@ -13508,7 +13667,7 @@ function clonePolicy(policy) {
13508
13667
  group: cloneScope(policy.group)
13509
13668
  };
13510
13669
  }
13511
- function unwrapRpcResult11(result) {
13670
+ function unwrapRpcResult12(result) {
13512
13671
  if (result?.ok === true) return result.value;
13513
13672
  if (result?.ok === false) {
13514
13673
  const error = new Error(result.error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -13535,8 +13694,8 @@ function ScenePolicyEditor({
13535
13694
  unsupported = false,
13536
13695
  onChange
13537
13696
  }) {
13538
- const ownerHelpId = React23.useId();
13539
- const emptyAllowlistHelpId = React23.useId();
13697
+ const ownerHelpId = React24.useId();
13698
+ const emptyAllowlistHelpId = React24.useId();
13540
13699
  const allowlist = policy.mode === "allowlist";
13541
13700
  const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
13542
13701
  const branchKey = allowlist ? "allowlist" : "open";
@@ -13588,7 +13747,7 @@ function ScenePolicyEditor({
13588
13747
  h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
13589
13748
  h2("p", null, "\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002")
13590
13749
  ) : h2(
13591
- React23.Fragment,
13750
+ React24.Fragment,
13592
13751
  null,
13593
13752
  h2(
13594
13753
  "div",
@@ -13725,20 +13884,20 @@ function ScenePolicyEditor({
13725
13884
  )
13726
13885
  );
13727
13886
  }
13728
- function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved }) {
13729
- const definition = ACCESS_CHANNEL_DEFINITIONS[channel4];
13887
+ function AccessPolicySettingsPage({ channel: channel5, account, rpcCall, onSaved }) {
13888
+ const definition = ACCESS_CHANNEL_DEFINITIONS[channel5];
13730
13889
  const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
13731
13890
  const initialKey = JSON.stringify(initialPolicy);
13732
- const [draft, setDraft] = React23.useState(() => clonePolicy(
13891
+ const [draft, setDraft] = React24.useState(() => clonePolicy(
13733
13892
  initialPolicy ?? DEFAULT_ACCESS_POLICY
13734
13893
  ));
13735
- const [saving, setSaving] = React23.useState(false);
13736
- const [feedback, setFeedback] = React23.useState(null);
13737
- React23.useEffect(() => {
13894
+ const [saving, setSaving] = React24.useState(false);
13895
+ const [feedback, setFeedback] = React24.useState(null);
13896
+ React24.useEffect(() => {
13738
13897
  const next = normalizeAccessPolicy(account?.accessPolicy);
13739
13898
  setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
13740
13899
  }, [account?.botId, initialKey]);
13741
- React23.useEffect(() => {
13900
+ React24.useEffect(() => {
13742
13901
  setFeedback(null);
13743
13902
  }, [account?.botId]);
13744
13903
  if (!definition) {
@@ -13755,7 +13914,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
13755
13914
  try {
13756
13915
  const policy = validateAccessPolicy(draft);
13757
13916
  if (typeof rpcCall !== "function") throw new Error("\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
13758
- const value = unwrapRpcResult11(await rpcCall(ACCESS_POLICY_ENDPOINT, {
13917
+ const value = unwrapRpcResult12(await rpcCall(ACCESS_POLICY_ENDPOINT, {
13759
13918
  botId: account.botId,
13760
13919
  policy
13761
13920
  }));
@@ -13829,7 +13988,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
13829
13988
  }
13830
13989
 
13831
13990
  // plugin-src/client/channels/feishu/group-settings.js
13832
- var React24 = __toESM(require("react"), 1);
13991
+ var React25 = __toESM(require("react"), 1);
13833
13992
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
13834
13993
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
13835
13994
  return h2("button", {
@@ -13890,9 +14049,9 @@ function GroupResponseModeEditor({
13890
14049
  onAuthorize
13891
14050
  }) {
13892
14051
  const current = normalizeGroupResponseMode(value);
13893
- const [saving, setSaving] = React24.useState(false);
13894
- const [authorizing, setAuthorizing] = React24.useState(false);
13895
- const [error, setError] = React24.useState(null);
14052
+ const [saving, setSaving] = React25.useState(false);
14053
+ const [authorizing, setAuthorizing] = React25.useState(false);
14054
+ const [error, setError] = React25.useState(null);
13896
14055
  const change = async (event) => {
13897
14056
  const next = normalizeGroupResponseMode(event.target.value);
13898
14057
  if (next === current || saving || disabled) return;
@@ -13973,8 +14132,8 @@ function GroupResponseModeEditor({
13973
14132
  }
13974
14133
  function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
13975
14134
  const current = value === true ? "on" : "off";
13976
- const [saving, setSaving] = React24.useState(false);
13977
- const [error, setError] = React24.useState(null);
14135
+ const [saving, setSaving] = React25.useState(false);
14136
+ const [error, setError] = React25.useState(null);
13978
14137
  const change = async (event) => {
13979
14138
  const next = event.target.value === "on";
13980
14139
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -14161,14 +14320,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
14161
14320
  );
14162
14321
  }
14163
14322
  function FeishuGroupSettingsPage({ account, rpcCall }) {
14164
- const [settings, setSettings] = React24.useState(() => groupSettingsFrom(account));
14165
- const [refreshing, setRefreshing] = React24.useState(false);
14166
- const [refreshError, setRefreshError] = React24.useState(null);
14167
- const [provision, setProvision] = React24.useState(null);
14168
- const [provisionBusy, setProvisionBusy] = React24.useState(false);
14169
- const [now, setNow] = React24.useState(() => Date.now());
14170
- const mounted = React24.useRef(true);
14171
- React24.useEffect(() => {
14323
+ const [settings, setSettings] = React25.useState(() => groupSettingsFrom(account));
14324
+ const [refreshing, setRefreshing] = React25.useState(false);
14325
+ const [refreshError, setRefreshError] = React25.useState(null);
14326
+ const [provision, setProvision] = React25.useState(null);
14327
+ const [provisionBusy, setProvisionBusy] = React25.useState(false);
14328
+ const [now, setNow] = React25.useState(() => Date.now());
14329
+ const mounted = React25.useRef(true);
14330
+ React25.useEffect(() => {
14172
14331
  setSettings(groupSettingsFrom(account));
14173
14332
  }, [
14174
14333
  account.botId,
@@ -14176,22 +14335,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14176
14335
  account.groupTopicReply,
14177
14336
  account.groupMessagePermissionGranted
14178
14337
  ]);
14179
- React24.useEffect(() => {
14338
+ React25.useEffect(() => {
14180
14339
  mounted.current = true;
14181
14340
  return () => {
14182
14341
  mounted.current = false;
14183
14342
  };
14184
14343
  }, []);
14185
- const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
14344
+ const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
14186
14345
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
14187
14346
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
14188
14347
  }, [rpcCall]);
14189
- const applySnapshot = React24.useCallback((value) => {
14348
+ const applySnapshot = React25.useCallback((value) => {
14190
14349
  const result = targetBotFromSnapshot(value, account.botId);
14191
14350
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
14192
14351
  return result;
14193
14352
  }, [account.botId]);
14194
- const loadSettings = React24.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
14353
+ const loadSettings = React25.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
14195
14354
  setRefreshing(true);
14196
14355
  setRefreshError(null);
14197
14356
  try {
@@ -14220,16 +14379,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14220
14379
  if (!signal?.aborted && mounted.current) setRefreshing(false);
14221
14380
  }
14222
14381
  }, [account.botId, applySnapshot, invoke]);
14223
- React24.useEffect(() => {
14382
+ React25.useEffect(() => {
14224
14383
  const controller = new AbortController();
14225
14384
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
14226
14385
  return () => controller.abort();
14227
14386
  }, [loadSettings]);
14228
- const saveSetting = React24.useCallback(async (endpoint, payload) => {
14387
+ const saveSetting = React25.useCallback(async (endpoint, payload) => {
14229
14388
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
14230
14389
  applySnapshot(value);
14231
14390
  }, [account.botId, applySnapshot, invoke]);
14232
- const startAuthorization = React24.useCallback(async ({ replace = false } = {}) => {
14391
+ const startAuthorization = React25.useCallback(async ({ replace = false } = {}) => {
14233
14392
  if (provisionBusy) return;
14234
14393
  const previousAttemptId = provision?.attemptId;
14235
14394
  setProvisionBusy(true);
@@ -14270,13 +14429,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14270
14429
  if (mounted.current) setProvisionBusy(false);
14271
14430
  }
14272
14431
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
14273
- const finishAuthorization = React24.useCallback(async (signal) => {
14432
+ const finishAuthorization = React25.useCallback(async (signal) => {
14274
14433
  const bot = await loadSettings({ signal, restoreProvisioning: false });
14275
14434
  if (signal?.aborted || !mounted.current) return;
14276
14435
  if (!bot) throw new Error("\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u66F4\u65B0\uFF0C\u4F46\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u673A\u5668\u4EBA\u8FDE\u63A5\u72B6\u6001");
14277
14436
  setProvision(null);
14278
14437
  }, [loadSettings]);
14279
- React24.useEffect(() => {
14438
+ React25.useEffect(() => {
14280
14439
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
14281
14440
  const timerHost = globalThis.window ?? globalThis;
14282
14441
  const controller = new AbortController();
@@ -14320,7 +14479,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14320
14479
  timerHost.clearTimeout(timer);
14321
14480
  };
14322
14481
  }, [account.botId, finishAuthorization, invoke, provision]);
14323
- React24.useEffect(() => {
14482
+ React25.useEffect(() => {
14324
14483
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
14325
14484
  const timerHost = globalThis.window ?? globalThis;
14326
14485
  const tick = () => {
@@ -14334,7 +14493,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14334
14493
  const timer = timerHost.setInterval(tick, 1e3);
14335
14494
  return () => timerHost.clearInterval(timer);
14336
14495
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
14337
- const cancelAuthorization = React24.useCallback(async () => {
14496
+ const cancelAuthorization = React25.useCallback(async () => {
14338
14497
  if (!provision?.attemptId || provisionBusy) {
14339
14498
  setProvision(null);
14340
14499
  return;
@@ -14445,8 +14604,8 @@ var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
14445
14604
  ...BOT_SETTINGS_TABS,
14446
14605
  Object.freeze({ id: "group", label: "\u7FA4\u804A" })
14447
14606
  ]);
14448
- function botSettingsTabsForChannel(channel4) {
14449
- return channel4 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
14607
+ function botSettingsTabsForChannel(channel5) {
14608
+ return channel5 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
14450
14609
  }
14451
14610
  var CHANNEL_DEFINITIONS = Object.freeze({
14452
14611
  weixin: {
@@ -14527,12 +14686,17 @@ var CHANNEL_DEFINITIONS = Object.freeze({
14527
14686
  user: [{ key: "jid", label: "\u7528\u6237 JID", placeholder: "8613800000000@s.whatsapp.net" }],
14528
14687
  group: [{ key: "jid", label: "\u7FA4 JID", placeholder: "1234567890@g.us" }]
14529
14688
  }
14689
+ },
14690
+ imessage: {
14691
+ label: "iMessage",
14692
+ kinds: [{ value: "user", label: "\u79C1\u804A" }],
14693
+ fields: { user: [{ key: "chatGuid", label: "Chat GUID", placeholder: "iMessage;+;chat123" }] }
14530
14694
  }
14531
14695
  });
14532
- function presentError11(error, fallback) {
14696
+ function presentError12(error, fallback) {
14533
14697
  return error?.message || fallback;
14534
14698
  }
14535
- function unwrapRpcResult12(result) {
14699
+ function unwrapRpcResult13(result) {
14536
14700
  if (result?.ok === true) return result.value;
14537
14701
  if (result?.ok === false) {
14538
14702
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -14650,13 +14814,13 @@ function TargetForm({
14650
14814
  }) {
14651
14815
  const editing = mode === "edit";
14652
14816
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
14653
- const [targetId, setTargetId] = React25.useState(initialValue?.targetId ?? "");
14654
- const [name2, setName] = React25.useState(initialValue?.name ?? "");
14655
- const [kind, setKind] = React25.useState(initialKind);
14656
- const [route, setRoute] = React25.useState(initialValue?.route ?? {});
14657
- const [error, setError] = React25.useState(null);
14658
- const [testing, setTesting] = React25.useState(false);
14659
- const [testState, setTestState] = React25.useState(null);
14817
+ const [targetId, setTargetId] = React26.useState(initialValue?.targetId ?? "");
14818
+ const [name2, setName] = React26.useState(initialValue?.name ?? "");
14819
+ const [kind, setKind] = React26.useState(initialKind);
14820
+ const [route, setRoute] = React26.useState(initialValue?.route ?? {});
14821
+ const [error, setError] = React26.useState(null);
14822
+ const [testing, setTesting] = React26.useState(false);
14823
+ const [testState, setTestState] = React26.useState(null);
14660
14824
  const currentTarget = () => {
14661
14825
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field) => {
14662
14826
  const raw = String(route[field.key] ?? "").trim();
@@ -14677,7 +14841,7 @@ function TargetForm({
14677
14841
  ...currentTarget()
14678
14842
  });
14679
14843
  } catch (caught) {
14680
- setError(presentError11(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
14844
+ setError(presentError12(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
14681
14845
  }
14682
14846
  };
14683
14847
  const testTarget = async () => {
@@ -14689,7 +14853,7 @@ function TargetForm({
14689
14853
  await onTest({ kind: target.kind, route: target.route });
14690
14854
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
14691
14855
  } catch (caught) {
14692
- setTestState({ tone: "error", message: presentError11(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14856
+ setTestState({ tone: "error", message: presentError12(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14693
14857
  } finally {
14694
14858
  setTesting(false);
14695
14859
  }
@@ -14873,7 +15037,7 @@ function TargetSuggestionPicker({
14873
15037
  suggestions.map((suggestion, index) => {
14874
15038
  const identity = routeIdentity(definition, suggestion);
14875
15039
  const added = configured.has(identity);
14876
- return React25.createElement("option", {
15040
+ return React26.createElement("option", {
14877
15041
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
14878
15042
  value: String(index),
14879
15043
  disabled: added
@@ -14890,11 +15054,11 @@ function TargetSuggestionPicker({
14890
15054
  );
14891
15055
  }
14892
15056
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
14893
- const [action, setAction] = React25.useState(null);
14894
- const [testState, setTestState] = React25.useState(null);
14895
- const [syncFeedback, setSyncFeedback] = React25.useState(null);
14896
- const [copyState, setCopyState] = React25.useState(null);
14897
- const [confirmDelete, setConfirmDelete] = React25.useState(false);
15057
+ const [action, setAction] = React26.useState(null);
15058
+ const [testState, setTestState] = React26.useState(null);
15059
+ const [syncFeedback, setSyncFeedback] = React26.useState(null);
15060
+ const [copyState, setCopyState] = React26.useState(null);
15061
+ const [confirmDelete, setConfirmDelete] = React26.useState(false);
14898
15062
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
14899
15063
  const syncDescription = sessionSync.state === "active" ? "\u81EA\u52A8\u8DDF\u968F\u8BE5\u79C1\u804A\u7684\u5F53\u524D\u4F1A\u8BDD" : sessionSync.state === "waiting" ? "\u7B49\u5F85\u8BE5\u79C1\u804A\u5EFA\u7ACB\u65B0\u4F1A\u8BDD" : sessionSync.state === "unavailable" ? "\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807" : "\u5173\u95ED\u65F6\u4E0D\u53D1\u9001 DSH \u4F1A\u8BDD\u6D88\u606F";
14900
15064
  const testTarget = async () => {
@@ -14904,7 +15068,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14904
15068
  await rpcCall(DELIVERY_ENDPOINTS.test, { botId, targetId: target.targetId });
14905
15069
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
14906
15070
  } catch (error) {
14907
- setTestState({ tone: "error", message: presentError11(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
15071
+ setTestState({ tone: "error", message: presentError12(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14908
15072
  } finally {
14909
15073
  setAction(null);
14910
15074
  }
@@ -14915,7 +15079,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14915
15079
  await copyText(JSON.stringify({ botId, targetId: target.targetId }));
14916
15080
  setCopyState("\u5DF2\u590D\u5236\u8C03\u7528\u53C2\u6570");
14917
15081
  } catch (error) {
14918
- setCopyState(presentError11(error, "\u590D\u5236\u5931\u8D25\u3002"));
15082
+ setCopyState(presentError12(error, "\u590D\u5236\u5931\u8D25\u3002"));
14919
15083
  }
14920
15084
  };
14921
15085
  const deleteTarget = async () => {
@@ -14924,7 +15088,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14924
15088
  await rpcCall(DELIVERY_ENDPOINTS.delete, { botId, targetId: target.targetId });
14925
15089
  await onChanged();
14926
15090
  } catch (error) {
14927
- setTestState({ tone: "error", message: presentError11(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
15091
+ setTestState({ tone: "error", message: presentError12(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14928
15092
  setAction(null);
14929
15093
  setConfirmDelete(false);
14930
15094
  }
@@ -14942,7 +15106,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14942
15106
  } catch (error) {
14943
15107
  setSyncFeedback({
14944
15108
  tone: "error",
14945
- message: error?.code === "session-sync-unavailable" ? "\u4F1A\u8BDD\u540C\u6B65\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807\u3002" : presentError11(error, "\u4F1A\u8BDD\u540C\u6B65\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")
15109
+ message: error?.code === "session-sync-unavailable" ? "\u4F1A\u8BDD\u540C\u6B65\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807\u3002" : presentError12(error, "\u4F1A\u8BDD\u540C\u6B65\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")
14946
15110
  });
14947
15111
  } finally {
14948
15112
  setAction(null);
@@ -14957,7 +15121,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14957
15121
  h2(
14958
15122
  "div",
14959
15123
  { className: "dim-targetTitle" },
14960
- React25.createElement("strong", null, target.name || target.targetId),
15124
+ React26.createElement("strong", null, target.name || target.targetId),
14961
15125
  h2("span", null, kindLabel(definition, target.kind))
14962
15126
  ),
14963
15127
  h2("code", null, `targetId: ${target.targetId}`)
@@ -15036,33 +15200,33 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
15036
15200
  );
15037
15201
  }
15038
15202
  function DeliveryTargetSettingsPage({
15039
- channel: channel4,
15203
+ channel: channel5,
15040
15204
  account,
15041
15205
  rpcCall,
15042
15206
  accessRpcCall,
15043
15207
  onBack
15044
15208
  }) {
15045
- const definition = CHANNEL_DEFINITIONS[channel4];
15046
- const [activeTabId, setActiveTabId] = React25.useState(BOT_SETTINGS_TABS[0].id);
15047
- const [phase, setPhase] = React25.useState("loading");
15048
- const [targets, setTargets] = React25.useState([]);
15049
- const [suggestionPhase, setSuggestionPhase] = React25.useState("idle");
15050
- const [suggestions, setSuggestions] = React25.useState([]);
15051
- const [suggestionError, setSuggestionError] = React25.useState(null);
15052
- const [error, setError] = React25.useState(null);
15053
- const [editor, setEditor] = React25.useState(null);
15054
- const [saving, setSaving] = React25.useState(false);
15055
- const [botCopyState, setBotCopyState] = React25.useState(null);
15056
- const [accessPolicy, setAccessPolicy] = React25.useState(account.accessPolicy);
15057
- const mounted = React25.useRef(true);
15058
- React25.useEffect(() => {
15209
+ const definition = CHANNEL_DEFINITIONS[channel5];
15210
+ const [activeTabId, setActiveTabId] = React26.useState(BOT_SETTINGS_TABS[0].id);
15211
+ const [phase, setPhase] = React26.useState("loading");
15212
+ const [targets, setTargets] = React26.useState([]);
15213
+ const [suggestionPhase, setSuggestionPhase] = React26.useState("idle");
15214
+ const [suggestions, setSuggestions] = React26.useState([]);
15215
+ const [suggestionError, setSuggestionError] = React26.useState(null);
15216
+ const [error, setError] = React26.useState(null);
15217
+ const [editor, setEditor] = React26.useState(null);
15218
+ const [saving, setSaving] = React26.useState(false);
15219
+ const [botCopyState, setBotCopyState] = React26.useState(null);
15220
+ const [accessPolicy, setAccessPolicy] = React26.useState(account.accessPolicy);
15221
+ const mounted = React26.useRef(true);
15222
+ React26.useEffect(() => {
15059
15223
  setAccessPolicy(account.accessPolicy);
15060
15224
  }, [account.botId, account.accessPolicy]);
15061
- const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
15225
+ const invoke = React26.useCallback(async (endpoint, payload = {}, signal) => {
15062
15226
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
15063
- return unwrapRpcResult12(await rpcCall(endpoint, payload, signal));
15227
+ return unwrapRpcResult13(await rpcCall(endpoint, payload, signal));
15064
15228
  }, [rpcCall]);
15065
- const loadTargets = React25.useCallback(async ({ signal, silent = false } = {}) => {
15229
+ const loadTargets = React26.useCallback(async ({ signal, silent = false } = {}) => {
15066
15230
  if (!silent) setPhase("loading");
15067
15231
  setError(null);
15068
15232
  try {
@@ -15072,11 +15236,11 @@ function DeliveryTargetSettingsPage({
15072
15236
  setPhase("ready");
15073
15237
  } catch (caught) {
15074
15238
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
15075
- setError(presentError11(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15239
+ setError(presentError12(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15076
15240
  setPhase("error");
15077
15241
  }
15078
15242
  }, [account.botId, invoke]);
15079
- const loadSuggestions = React25.useCallback(async () => {
15243
+ const loadSuggestions = React26.useCallback(async () => {
15080
15244
  setSuggestionPhase("loading");
15081
15245
  setSuggestionError(null);
15082
15246
  try {
@@ -15086,11 +15250,11 @@ function DeliveryTargetSettingsPage({
15086
15250
  setSuggestionPhase("ready");
15087
15251
  } catch (caught) {
15088
15252
  if (caught?.name === "AbortError" || !mounted.current) return;
15089
- setSuggestionError(presentError11(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15253
+ setSuggestionError(presentError12(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15090
15254
  setSuggestionPhase("error");
15091
15255
  }
15092
15256
  }, [account.botId, definition, invoke]);
15093
- React25.useEffect(() => {
15257
+ React26.useEffect(() => {
15094
15258
  mounted.current = true;
15095
15259
  const controller = new AbortController();
15096
15260
  void loadTargets({ signal: controller.signal });
@@ -15158,10 +15322,10 @@ function DeliveryTargetSettingsPage({
15158
15322
  await copyText(account.botId);
15159
15323
  setBotCopyState("\u5DF2\u590D\u5236 Bot ID");
15160
15324
  } catch (caught) {
15161
- setBotCopyState(presentError11(caught, "\u590D\u5236\u5931\u8D25\u3002"));
15325
+ setBotCopyState(presentError12(caught, "\u590D\u5236\u5931\u8D25\u3002"));
15162
15326
  }
15163
15327
  };
15164
- const settingsTabs = botSettingsTabsForChannel(channel4);
15328
+ const settingsTabs = botSettingsTabsForChannel(channel5);
15165
15329
  const activeTab = settingsTabs.find((tab) => tab.id === activeTabId) ?? settingsTabs[0];
15166
15330
  const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
15167
15331
  const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
@@ -15204,15 +15368,15 @@ function DeliveryTargetSettingsPage({
15204
15368
  "aria-labelledby": activeTabDomId
15205
15369
  },
15206
15370
  activeTab.id === "access" ? h2(AccessPolicySettingsPage, {
15207
- channel: channel4,
15371
+ channel: channel5,
15208
15372
  account: { ...account, accessPolicy },
15209
15373
  rpcCall: accessRpcCall,
15210
15374
  onSaved: setAccessPolicy
15211
- }) : activeTab.id === "group" && channel4 === "feishu" ? h2(FeishuGroupSettingsPage, {
15375
+ }) : activeTab.id === "group" && channel5 === "feishu" ? h2(FeishuGroupSettingsPage, {
15212
15376
  account,
15213
15377
  rpcCall: accessRpcCall
15214
15378
  }) : h2(
15215
- React25.Fragment,
15379
+ React26.Fragment,
15216
15380
  null,
15217
15381
  h2(
15218
15382
  "section",
@@ -15323,7 +15487,7 @@ function DeliveryTargetSettingsPage({
15323
15487
  }
15324
15488
 
15325
15489
  // plugin-src/client/global-settings.js
15326
- var React26 = __toESM(require("react"), 1);
15490
+ var React27 = __toESM(require("react"), 1);
15327
15491
 
15328
15492
  // src/channels/shared/inbound-ttl.mjs
15329
15493
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -15352,10 +15516,10 @@ var GLOBAL_SETTINGS_ENDPOINTS = Object.freeze({
15352
15516
  setTtl: "settings.inbound-ttl.set",
15353
15517
  sweep: "settings.inbound-ttl.sweep"
15354
15518
  });
15355
- function presentError12(error, fallback) {
15519
+ function presentError13(error, fallback) {
15356
15520
  return error?.message || fallback;
15357
15521
  }
15358
- function unwrapRpcResult13(result) {
15522
+ function unwrapRpcResult14(result) {
15359
15523
  if (result?.ok === true) return result.value;
15360
15524
  if (result?.ok === false) {
15361
15525
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -15385,29 +15549,29 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
15385
15549
  }, children);
15386
15550
  }
15387
15551
  function GlobalSettingsPanel({ rpcCall }) {
15388
- const [phase, setPhase] = React26.useState("loading");
15389
- const [loadError, setLoadError] = React26.useState(null);
15390
- const [ttlInput, setTtlInput] = React26.useState("");
15391
- const [savedTtl, setSavedTtl] = React26.useState(null);
15392
- const [ttlError, setTtlError] = React26.useState(false);
15393
- const [saveError, setSaveError] = React26.useState(null);
15394
- const [saveSucceeded, setSaveSucceeded] = React26.useState(false);
15395
- const [isSaving, setIsSaving] = React26.useState(false);
15396
- const [sweepConfirming, setSweepConfirming] = React26.useState(false);
15397
- const [sweeping, setSweeping] = React26.useState(false);
15398
- const ttlErrorId = React26.useId();
15399
- const ttlHintsId = React26.useId();
15400
- const sweepTriggerId = React26.useId();
15401
- const sweepConfirmId = React26.useId();
15402
- const sweepConfirmTextId = React26.useId();
15403
- const sweepConfirmButtonId = React26.useId();
15404
- const mounted = React26.useRef(true);
15405
- const saving = React26.useRef(false);
15406
- const invoke = React26.useCallback(async (endpoint, payload = {}, signal) => {
15552
+ const [phase, setPhase] = React27.useState("loading");
15553
+ const [loadError, setLoadError] = React27.useState(null);
15554
+ const [ttlInput, setTtlInput] = React27.useState("");
15555
+ const [savedTtl, setSavedTtl] = React27.useState(null);
15556
+ const [ttlError, setTtlError] = React27.useState(false);
15557
+ const [saveError, setSaveError] = React27.useState(null);
15558
+ const [saveSucceeded, setSaveSucceeded] = React27.useState(false);
15559
+ const [isSaving, setIsSaving] = React27.useState(false);
15560
+ const [sweepConfirming, setSweepConfirming] = React27.useState(false);
15561
+ const [sweeping, setSweeping] = React27.useState(false);
15562
+ const ttlErrorId = React27.useId();
15563
+ const ttlHintsId = React27.useId();
15564
+ const sweepTriggerId = React27.useId();
15565
+ const sweepConfirmId = React27.useId();
15566
+ const sweepConfirmTextId = React27.useId();
15567
+ const sweepConfirmButtonId = React27.useId();
15568
+ const mounted = React27.useRef(true);
15569
+ const saving = React27.useRef(false);
15570
+ const invoke = React27.useCallback(async (endpoint, payload = {}, signal) => {
15407
15571
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
15408
- return unwrapRpcResult13(await rpcCall(endpoint, payload, signal));
15572
+ return unwrapRpcResult14(await rpcCall(endpoint, payload, signal));
15409
15573
  }, [rpcCall]);
15410
- const loadSettings = React26.useCallback(async ({ signal } = {}) => {
15574
+ const loadSettings = React27.useCallback(async ({ signal } = {}) => {
15411
15575
  setPhase("loading");
15412
15576
  setLoadError(null);
15413
15577
  try {
@@ -15427,11 +15591,11 @@ function GlobalSettingsPanel({ rpcCall }) {
15427
15591
  setPhase("ready");
15428
15592
  } catch (caught) {
15429
15593
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
15430
- setLoadError(presentError12(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15594
+ setLoadError(presentError13(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15431
15595
  setPhase("error");
15432
15596
  }
15433
15597
  }, [invoke]);
15434
- React26.useEffect(() => {
15598
+ React27.useEffect(() => {
15435
15599
  mounted.current = true;
15436
15600
  const controller = new AbortController();
15437
15601
  void loadSettings({ signal: controller.signal });
@@ -15440,7 +15604,7 @@ function GlobalSettingsPanel({ rpcCall }) {
15440
15604
  controller.abort();
15441
15605
  };
15442
15606
  }, [loadSettings]);
15443
- React26.useEffect(() => {
15607
+ React27.useEffect(() => {
15444
15608
  if (!sweepConfirming) return;
15445
15609
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
15446
15610
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -15471,7 +15635,7 @@ function GlobalSettingsPanel({ rpcCall }) {
15471
15635
  setPhase("ready");
15472
15636
  } catch (caught) {
15473
15637
  if (mounted.current) {
15474
- setSaveError(presentError12(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15638
+ setSaveError(presentError13(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15475
15639
  }
15476
15640
  } finally {
15477
15641
  saving.current = false;
@@ -15747,7 +15911,7 @@ function replacePageLocation(url, location = globalThis.location) {
15747
15911
 
15748
15912
  // plugin-src/client/styles.js
15749
15913
  var IM_STYLE_ID = "xmanrui-dsh-im-settings";
15750
- var CSS12 = String.raw`
15914
+ var CSS13 = String.raw`
15751
15915
  .dim-page {
15752
15916
  --dim-blue: var(--dsw-alias-state-business-primary, #3370ff);
15753
15917
  --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent);
@@ -15844,6 +16008,7 @@ var CSS12 = String.raw`
15844
16008
  .dim-logoSlack { color: white; background: #4a154b; }
15845
16009
  .dim-logoSlack svg { width: 21px; height: 21px; }
15846
16010
  .dim-logoWhatsapp { color: white; background: #25d366; }
16011
+ .dim-logoIMessage { color: white; background: #32a852; }
15847
16012
  .dim-logoWhatsapp svg { width: 21px; height: 21px; }
15848
16013
  .dim-channelCopy { min-width: 0; display: grid; }
15849
16014
  .dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; }
@@ -16420,7 +16585,7 @@ function installImStyles() {
16420
16585
  const style = document.createElement("style");
16421
16586
  style.dataset.plugin = "@xmanrui/dsh-im";
16422
16587
  style.dataset.pluginCss = IM_STYLE_ID;
16423
- style.textContent = CSS12;
16588
+ style.textContent = CSS13;
16424
16589
  document.head.appendChild(style);
16425
16590
  return () => style.remove();
16426
16591
  }
@@ -16436,15 +16601,16 @@ var SESSION_CHANNEL_LABELS = Object.freeze(Object.fromEntries(Object.entries({
16436
16601
  telegram: ["Telegram", "Telegram"],
16437
16602
  discord: ["Discord", "Discord"],
16438
16603
  whatsapp: ["WhatsApp", "WhatsApp"],
16604
+ imessage: ["iMessage", "iMessage"],
16439
16605
  office: ["AI Office", "AI Office"]
16440
- }).map(([channel4, labels]) => [channel4, Object.freeze(labels)])));
16606
+ }).map(([channel5, labels]) => [channel5, Object.freeze(labels)])));
16441
16607
  function parseSessionChannelTitle(title) {
16442
16608
  if (typeof title !== "string") return null;
16443
- for (const [channel4, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
16609
+ for (const [channel5, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
16444
16610
  for (const label of labels) {
16445
16611
  const prefix = `${label} \xB7 `;
16446
16612
  if (title.startsWith(prefix) && title.slice(prefix.length).trim()) {
16447
- return { channel: channel4, title: title.slice(prefix.length) };
16613
+ return { channel: channel5, title: title.slice(prefix.length) };
16448
16614
  }
16449
16615
  }
16450
16616
  }
@@ -16462,6 +16628,7 @@ var GLYPHS = Object.freeze({
16462
16628
  telegram: [TelegramLogoGlyph, "#229ed9"],
16463
16629
  discord: [DiscordLogoGlyph, "#5865f2"],
16464
16630
  whatsapp: [WhatsappLogoGlyph, "#25d366"],
16631
+ imessage: [IMessageLogoGlyph, "#3478f6"],
16465
16632
  office: [OfficeLogoGlyph, "#f97316"]
16466
16633
  });
16467
16634
  var CHANNEL_ATTR = "data-dsh-im-session-channel";
@@ -16485,8 +16652,8 @@ function titleOf(row) {
16485
16652
  }
16486
16653
  return title?.childNodes.length === 1 && title.firstChild.nodeType === 3 ? title : null;
16487
16654
  }
16488
- function logoUri(document2, channel4) {
16489
- const [Glyph, color] = GLYPHS[channel4];
16655
+ function logoUri(document2, channel5) {
16656
+ const [Glyph, color] = GLYPHS[channel5];
16490
16657
  const render = (node) => {
16491
16658
  if (!["svg", "path"].includes(node.type)) throw new Error("Unsupported channel logo element");
16492
16659
  const element = document2.createElementNS(SVG_NS, node.type);
@@ -16513,7 +16680,7 @@ function createInstallation(document2) {
16513
16680
  let scheduled = false;
16514
16681
  const style = document2.createElement("style");
16515
16682
  style.dataset.pluginCss = "dsh-im-session-channel-logos";
16516
- const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel4) => [channel4, logoUri(document2, channel4)]));
16683
+ const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel5) => [channel5, logoUri(document2, channel5)]));
16517
16684
  style.textContent = `
16518
16685
  ${MARKED}[${TITLE_ATTR}] {
16519
16686
  position: relative;
@@ -16545,7 +16712,7 @@ ${MARKED}[${TITLE_ATTR}]::after {
16545
16712
  text-overflow: ellipsis;
16546
16713
  pointer-events: none;
16547
16714
  }
16548
- ${Object.entries(uris).map(([channel4, uri]) => `[${CHANNEL_ATTR}="${channel4}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
16715
+ ${Object.entries(uris).map(([channel5, uri]) => `[${CHANNEL_ATTR}="${channel5}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
16549
16716
  `;
16550
16717
  document2.head.appendChild(style);
16551
16718
  const restore = (title) => {
@@ -16628,12 +16795,12 @@ ${Object.entries(uris).map(([channel4, uri]) => `[${CHANNEL_ATTR}="${channel4}"]
16628
16795
  attributes: true,
16629
16796
  attributeFilter: ["class", "role", "aria-selected", "contenteditable"]
16630
16797
  });
16631
- for (const [channel4, uri] of Object.entries(uris)) {
16798
+ for (const [channel5, uri] of Object.entries(uris)) {
16632
16799
  const image = new view.Image();
16633
16800
  images.push(image);
16634
16801
  image.onload = () => {
16635
16802
  if (closed) return;
16636
- ready.add(channel4);
16803
+ ready.add(channel5);
16637
16804
  collect(document2.body, true);
16638
16805
  };
16639
16806
  image.src = uri;
@@ -16674,7 +16841,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
16674
16841
  }
16675
16842
 
16676
16843
  // plugin-src/client/update-panel.js
16677
- var React27 = __toESM(require("react"), 1);
16844
+ var React28 = __toESM(require("react"), 1);
16678
16845
  var import_react_dom3 = require("react-dom");
16679
16846
  var import_valid = __toESM(require_valid(), 1);
16680
16847
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -16721,7 +16888,7 @@ function unwrapSnapshot(result) {
16721
16888
  }
16722
16889
  return value;
16723
16890
  }
16724
- function presentError13(error) {
16891
+ function presentError14(error) {
16725
16892
  const code = error?.rpcError?.code ?? error?.code ?? "";
16726
16893
  const message = error?.rpcError?.message ?? error?.message ?? "";
16727
16894
  if (code === "update-unavailable" || /(?:not[-_ ]found|unimplemented|unknown[-_ ](?:endpoint|channel)|no[-_ ]handler)/i.test(code) || /(?:not found|unknown (?:endpoint|channel)|not registered|no .*handler|HTTP 404)/i.test(message)) {
@@ -16764,11 +16931,11 @@ function manualUpdateCommand(snapshot) {
16764
16931
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
16765
16932
  }
16766
16933
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16767
- const [copyState, setCopyState] = React27.useState("idle");
16768
- const commandRef = React27.useRef(null);
16769
- const mounted = React27.useRef(false);
16770
- const copying = React27.useRef(false);
16771
- React27.useEffect(() => {
16934
+ const [copyState, setCopyState] = React28.useState("idle");
16935
+ const commandRef = React28.useRef(null);
16936
+ const mounted = React28.useRef(false);
16937
+ const copying = React28.useRef(false);
16938
+ React28.useEffect(() => {
16772
16939
  mounted.current = true;
16773
16940
  return () => {
16774
16941
  mounted.current = false;
@@ -16800,7 +16967,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16800
16967
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
16801
16968
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
16802
16969
  command ? h2(
16803
- React27.Fragment,
16970
+ React28.Fragment,
16804
16971
  null,
16805
16972
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
16806
16973
  h2(
@@ -16836,7 +17003,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16836
17003
  "aria-hidden": "true",
16837
17004
  focusable: "false"
16838
17005
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
16839
- React27.Fragment,
17006
+ React28.Fragment,
16840
17007
  null,
16841
17008
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
16842
17009
  h2("path", { d: "M5 13H3.5A1.5 1.5 0 0 1 2 11.5v-8A1.5 1.5 0 0 1 3.5 2h8A1.5 1.5 0 0 1 13 3.5V5" })
@@ -16861,10 +17028,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16861
17028
  );
16862
17029
  }
16863
17030
  function UpdateDialog({ children, onClose }) {
16864
- const dialogRef = React27.useRef(null);
16865
- const titleId = React27.useId();
16866
- const descriptionId = React27.useId();
16867
- React27.useEffect(() => {
17031
+ const dialogRef = React28.useRef(null);
17032
+ const titleId = React28.useId();
17033
+ const descriptionId = React28.useId();
17034
+ React28.useEffect(() => {
16868
17035
  const previous = globalThis.document?.activeElement;
16869
17036
  dialogRef.current?.focus?.();
16870
17037
  return () => {
@@ -16922,19 +17089,19 @@ function UpdateDialog({ children, onClose }) {
16922
17089
  return typeof document !== "undefined" && document.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
16923
17090
  }
16924
17091
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16925
- const [snapshot, setSnapshot] = React27.useState(null);
16926
- const [action, setAction] = React27.useState("status");
16927
- const [error, setError] = React27.useState(null);
16928
- const [open, setOpen] = React27.useState(false);
16929
- const [uncertainInstall, setUncertainInstall] = React27.useState(false);
16930
- const mounted = React27.useRef(false);
16931
- const busy = React27.useRef(false);
16932
- const readController = React27.useRef(null);
16933
- const pollReadController = React27.useRef(null);
16934
- const installRequest = React27.useRef(null);
16935
- const onStatusRef = React27.useRef(onStatus);
17092
+ const [snapshot, setSnapshot] = React28.useState(null);
17093
+ const [action, setAction] = React28.useState("status");
17094
+ const [error, setError] = React28.useState(null);
17095
+ const [open, setOpen] = React28.useState(false);
17096
+ const [uncertainInstall, setUncertainInstall] = React28.useState(false);
17097
+ const mounted = React28.useRef(false);
17098
+ const busy = React28.useRef(false);
17099
+ const readController = React28.useRef(null);
17100
+ const pollReadController = React28.useRef(null);
17101
+ const installRequest = React28.useRef(null);
17102
+ const onStatusRef = React28.useRef(onStatus);
16936
17103
  onStatusRef.current = onStatus;
16937
- const accept = React27.useCallback((next) => {
17104
+ const accept = React28.useCallback((next) => {
16938
17105
  setSnapshot(next);
16939
17106
  onStatusRef.current?.(next);
16940
17107
  }, []);
@@ -16943,7 +17110,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16943
17110
  setUncertainInstall(false);
16944
17111
  accept(next);
16945
17112
  };
16946
- const invoke = React27.useCallback(async (endpoint, payload = {}, signal) => {
17113
+ const invoke = React28.useCallback(async (endpoint, payload = {}, signal) => {
16947
17114
  if (typeof rpcCall !== "function") {
16948
17115
  const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
16949
17116
  unavailable.code = "update-unavailable";
@@ -16951,14 +17118,14 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16951
17118
  }
16952
17119
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
16953
17120
  }, [rpcCall]);
16954
- React27.useEffect(() => {
17121
+ React28.useEffect(() => {
16955
17122
  mounted.current = true;
16956
17123
  busy.current = true;
16957
17124
  const controller = new AbortController();
16958
17125
  void invoke("update.status", {}, controller.signal).then((next) => {
16959
17126
  if (!controller.signal.aborted) accept(next);
16960
17127
  }).catch((cause) => {
16961
- if (!controller.signal.aborted) setError(presentError13(cause));
17128
+ if (!controller.signal.aborted) setError(presentError14(cause));
16962
17129
  }).finally(() => {
16963
17130
  if (!controller.signal.aborted) {
16964
17131
  busy.current = false;
@@ -16974,7 +17141,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16974
17141
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
16975
17142
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
16976
17143
  const shouldPoll = activeJob || uncertainInstall;
16977
- React27.useEffect(() => {
17144
+ React28.useEffect(() => {
16978
17145
  if (!shouldPoll) return void 0;
16979
17146
  let controller;
16980
17147
  const scheduler = createPollScheduler({
@@ -16995,7 +17162,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16995
17162
  keepPolling = ACTIVE_STATES4.has(next.job?.state);
16996
17163
  }
16997
17164
  } catch (cause) {
16998
- if (!pendingController.signal.aborted) setError(presentError13(cause));
17165
+ if (!pendingController.signal.aborted) setError(presentError14(cause));
16999
17166
  } finally {
17000
17167
  if (pollReadController.current === pendingController) pollReadController.current = null;
17001
17168
  }
@@ -17026,7 +17193,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17026
17193
  else acceptAuthoritative(next);
17027
17194
  }
17028
17195
  } catch (cause) {
17029
- if (!controller.signal.aborted && mounted.current) setError(presentError13(cause));
17196
+ if (!controller.signal.aborted && mounted.current) setError(presentError14(cause));
17030
17197
  } finally {
17031
17198
  if (!controller.signal.aborted && mounted.current) {
17032
17199
  busy.current = false;
@@ -17052,7 +17219,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17052
17219
  if (mounted.current) acceptAuthoritative(next);
17053
17220
  } catch (cause) {
17054
17221
  if (mounted.current) {
17055
- setError(presentError13(cause));
17222
+ setError(presentError14(cause));
17056
17223
  setUncertainInstall(true);
17057
17224
  }
17058
17225
  } finally {
@@ -17072,7 +17239,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17072
17239
  const manualCommand = manualUpdateCommand(snapshot);
17073
17240
  const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
17074
17241
  return h2(
17075
- React27.Fragment,
17242
+ React28.Fragment,
17076
17243
  null,
17077
17244
  h2("button", {
17078
17245
  type: "button",
@@ -17097,13 +17264,13 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17097
17264
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
17098
17265
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
17099
17266
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
17100
- React27.Fragment,
17267
+ React28.Fragment,
17101
17268
  null,
17102
17269
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
17103
17270
  h2("dd", null, `v${snapshot.installedVersion}`)
17104
17271
  ) : null,
17105
17272
  targetVersion ? h2(
17106
- React27.Fragment,
17273
+ React28.Fragment,
17107
17274
  null,
17108
17275
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
17109
17276
  h2("dd", null, `v${targetVersion}`)
@@ -17194,6 +17361,7 @@ var CHANNELS = Object.freeze([
17194
17361
  { id: "discord", label: "Discord" },
17195
17362
  { id: "whatsapp", label: "WhatsApp" },
17196
17363
  { id: "wecomApp", label: "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
17364
+ { id: "imessage", label: "iMessage", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
17197
17365
  { id: "office", label: "AI Office", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" }
17198
17366
  ]);
17199
17367
  function WeixinLogo() {
@@ -17254,6 +17422,13 @@ function WhatsappLogo() {
17254
17422
  h2(WhatsappLogoGlyph)
17255
17423
  );
17256
17424
  }
17425
+ function IMessageLogo() {
17426
+ return h2(
17427
+ "span",
17428
+ { className: "dim-logo dim-logoIMessage", "aria-hidden": "true" },
17429
+ h2(IMessageLogoGlyph)
17430
+ );
17431
+ }
17257
17432
  function OfficeLogo() {
17258
17433
  return h2(
17259
17434
  "span",
@@ -17261,17 +17436,18 @@ function OfficeLogo() {
17261
17436
  h2(OfficeLogoGlyph)
17262
17437
  );
17263
17438
  }
17264
- function ChannelLogo({ channel: channel4 }) {
17265
- if (channel4 === "weixin") return h2(WeixinLogo);
17266
- if (channel4 === "feishu") return h2(FeishuLogo);
17267
- if (channel4 === "dingtalk") return h2(DingtalkLogo);
17268
- if (channel4 === "wecom") return h2(WecomLogo);
17269
- if (channel4 === "wecomApp") return h2(WecomAppLogo);
17270
- if (channel4 === "qq") return h2(QqLogo);
17271
- if (channel4 === "slack") return h2(SlackLogo);
17272
- if (channel4 === "telegram") return h2(TelegramLogo);
17273
- if (channel4 === "discord") return h2(DiscordLogo);
17274
- if (channel4 === "whatsapp") return h2(WhatsappLogo);
17439
+ function ChannelLogo({ channel: channel5 }) {
17440
+ if (channel5 === "weixin") return h2(WeixinLogo);
17441
+ if (channel5 === "feishu") return h2(FeishuLogo);
17442
+ if (channel5 === "dingtalk") return h2(DingtalkLogo);
17443
+ if (channel5 === "wecom") return h2(WecomLogo);
17444
+ if (channel5 === "wecomApp") return h2(WecomAppLogo);
17445
+ if (channel5 === "qq") return h2(QqLogo);
17446
+ if (channel5 === "slack") return h2(SlackLogo);
17447
+ if (channel5 === "telegram") return h2(TelegramLogo);
17448
+ if (channel5 === "discord") return h2(DiscordLogo);
17449
+ if (channel5 === "whatsapp") return h2(WhatsappLogo);
17450
+ if (channel5 === "imessage") return h2(IMessageLogo);
17275
17451
  return h2(OfficeLogo);
17276
17452
  }
17277
17453
  function LoopbackRecoveryNotice({ recovery, onNavigate = replacePageLocation }) {
@@ -17299,6 +17475,7 @@ function IMSettingsTab({
17299
17475
  dingtalkRpcCall,
17300
17476
  discordRpcCall,
17301
17477
  feishuRpcCall,
17478
+ imessageRpcCall,
17302
17479
  qqRpcCall,
17303
17480
  slackRpcCall,
17304
17481
  telegramRpcCall,
@@ -17314,23 +17491,23 @@ function IMSettingsTab({
17314
17491
  browserLocation = globalThis.location,
17315
17492
  navigateToRecoveryUrl = replacePageLocation
17316
17493
  }) {
17317
- const [selected, setSelected] = React28.useState("weixin");
17318
- const [loopbackRecovery, setLoopbackRecovery] = React28.useState(null);
17319
- const [runningVersion, setRunningVersion] = React28.useState(IM_PLUGIN_VERSION);
17320
- const [deliverySettings, setDeliverySettings] = React28.useState(null);
17321
- const githubTooltipId = React28.useId();
17322
- const generalSettingsTooltipId = React28.useId();
17494
+ const [selected, setSelected] = React29.useState("weixin");
17495
+ const [loopbackRecovery, setLoopbackRecovery] = React29.useState(null);
17496
+ const [runningVersion, setRunningVersion] = React29.useState(IM_PLUGIN_VERSION);
17497
+ const [deliverySettings, setDeliverySettings] = React29.useState(null);
17498
+ const githubTooltipId = React29.useId();
17499
+ const generalSettingsTooltipId = React29.useId();
17323
17500
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
17324
- const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
17501
+ const active = CHANNELS.find((channel5) => channel5.id === selected) ?? CHANNELS[0];
17325
17502
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
17326
17503
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
17327
- const reportLoopbackRecovery = React28.useCallback((recovery) => {
17504
+ const reportLoopbackRecovery = React29.useCallback((recovery) => {
17328
17505
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
17329
17506
  }, []);
17330
- const reportUpdateStatus = React28.useCallback((snapshot) => {
17507
+ const reportUpdateStatus = React29.useCallback((snapshot) => {
17331
17508
  setRunningVersion(snapshot.runningVersion);
17332
17509
  }, []);
17333
- const rpcCalls = React28.useMemo(() => createLoopbackAwareRpcCalls({
17510
+ const rpcCalls = React29.useMemo(() => createLoopbackAwareRpcCalls({
17334
17511
  dingtalkRpcCall,
17335
17512
  discordRpcCall,
17336
17513
  feishuRpcCall,
@@ -17344,7 +17521,8 @@ function IMSettingsTab({
17344
17521
  officeRpcCall,
17345
17522
  updateRpcCall,
17346
17523
  deliveryRpcCall,
17347
- globalSettingsRpcCall
17524
+ globalSettingsRpcCall,
17525
+ imessageRpcCall
17348
17526
  }, {
17349
17527
  location: browserLocation,
17350
17528
  onRecovery: reportLoopbackRecovery
@@ -17355,6 +17533,7 @@ function IMSettingsTab({
17355
17533
  deliveryRpcCall,
17356
17534
  feishuRpcCall,
17357
17535
  globalSettingsRpcCall,
17536
+ imessageRpcCall,
17358
17537
  officeRpcCall,
17359
17538
  qqRpcCall,
17360
17539
  reportLoopbackRecovery,
@@ -17366,7 +17545,7 @@ function IMSettingsTab({
17366
17545
  weixinRpcCall,
17367
17546
  whatsappRpcCall
17368
17547
  ]);
17369
- const botSettingsContext = React28.useMemo(() => Object.freeze({
17548
+ const botSettingsContext = React29.useMemo(() => Object.freeze({
17370
17549
  openBotSettings: setDeliverySettings
17371
17550
  }), []);
17372
17551
  return h2(
@@ -17449,27 +17628,27 @@ function IMSettingsTab({
17449
17628
  h2(
17450
17629
  "nav",
17451
17630
  { className: "dim-rail", role: "tablist", "aria-label": "IM \u8BBE\u7F6E\u5BFC\u822A" },
17452
- CHANNELS.map((channel4) => h2(
17631
+ CHANNELS.map((channel5) => h2(
17453
17632
  "button",
17454
17633
  {
17455
- key: channel4.id,
17634
+ key: channel5.id,
17456
17635
  type: "button",
17457
17636
  role: "tab",
17458
- id: `dim-tab-${channel4.id}`,
17637
+ id: `dim-tab-${channel5.id}`,
17459
17638
  className: "dim-channel",
17460
- "aria-selected": !globalSettingsSelected && channel4.id === active.id,
17461
- "aria-controls": `dim-panel-${channel4.id}`,
17639
+ "aria-selected": !globalSettingsSelected && channel5.id === active.id,
17640
+ "aria-controls": `dim-panel-${channel5.id}`,
17462
17641
  onClick: () => {
17463
- setSelected(channel4.id);
17642
+ setSelected(channel5.id);
17464
17643
  setDeliverySettings(null);
17465
17644
  }
17466
17645
  },
17467
- h2(ChannelLogo, { channel: channel4.id }),
17646
+ h2(ChannelLogo, { channel: channel5.id }),
17468
17647
  h2(
17469
17648
  "span",
17470
17649
  { className: "dim-channelCopy" },
17471
- h2("strong", null, channel4.label),
17472
- channel4.note ? h2("small", { className: "dim-channelNote" }, channel4.note) : null
17650
+ h2("strong", null, channel5.label),
17651
+ channel5.note ? h2("small", { className: "dim-channelNote" }, channel5.note) : null
17473
17652
  )
17474
17653
  ))
17475
17654
  ),
@@ -17495,7 +17674,7 @@ function IMSettingsTab({
17495
17674
  rpcCall: rpcCalls.deliveryRpcCall,
17496
17675
  accessRpcCall: rpcCalls[`${active.id}RpcCall`],
17497
17676
  onBack: () => setDeliverySettings(null)
17498
- }) : active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: rpcCalls.weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: rpcCalls.feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: rpcCalls.dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: rpcCalls.wecomRpcCall }) : active.id === "wecomApp" ? h2(WecomAppSettingsTab, { rpcCall: rpcCalls.wecomAppRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: rpcCalls.qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: rpcCalls.slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: rpcCalls.telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: rpcCalls.discordRpcCall }) : active.id === "whatsapp" ? h2(WhatsappSettingsTab, { rpcCall: rpcCalls.whatsappRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
17677
+ }) : active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: rpcCalls.weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: rpcCalls.feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: rpcCalls.dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: rpcCalls.wecomRpcCall }) : active.id === "wecomApp" ? h2(WecomAppSettingsTab, { rpcCall: rpcCalls.wecomAppRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: rpcCalls.qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: rpcCalls.slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: rpcCalls.telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: rpcCalls.discordRpcCall }) : active.id === "whatsapp" ? h2(WhatsappSettingsTab, { rpcCall: rpcCalls.whatsappRpcCall }) : active.id === "imessage" ? h2(IMessageSettingsTab, { rpcCall: rpcCalls.imessageRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
17499
17678
  )
17500
17679
  )
17501
17680
  )
@@ -17521,6 +17700,7 @@ function apply(ctx) {
17521
17700
  installTelegramStyles(),
17522
17701
  installDiscordStyles(),
17523
17702
  installWhatsappStyles(),
17703
+ installIMessageStyles(),
17524
17704
  installOfficeStyles(),
17525
17705
  installImStyles()
17526
17706
  ];
@@ -17537,6 +17717,7 @@ function apply(ctx) {
17537
17717
  const telegramRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, TELEGRAM_RPC_CHANNEL, endpoint, payload, signal);
17538
17718
  const discordRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, DISCORD_RPC_CHANNEL, endpoint, payload, signal);
17539
17719
  const whatsappRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
17720
+ const imessageRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, IMESSAGE_RPC_CHANNEL, endpoint, payload, signal);
17540
17721
  const slackRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, SLACK_RPC_CHANNEL, endpoint, payload, signal);
17541
17722
  const officeRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, OFFICE_RPC_CHANNEL, endpoint, payload, signal);
17542
17723
  const updateRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, UPDATE_RPC_CHANNEL, endpoint, payload, signal);
@@ -17563,6 +17744,7 @@ function apply(ctx) {
17563
17744
  wecomAppRpcCall,
17564
17745
  weixinRpcCall,
17565
17746
  whatsappRpcCall,
17747
+ imessageRpcCall,
17566
17748
  officeRpcCall,
17567
17749
  updateRpcCall,
17568
17750
  deliveryRpcCall,