@xmanrui/dsh-im 4.17.1 → 4.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.en.md +17 -13
  2. package/README.md +16 -15
  3. package/lib/client.js +424 -246
  4. package/lib/index.js +280 -258
  5. package/package.json +7 -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/src/channels/imessage/config-store.mjs +24 -0
  26. package/src/channels/imessage/controller.mjs +37 -0
  27. package/src/channels/imessage/harness-client.mjs +7 -0
  28. package/src/channels/imessage/imessage-api.mjs +194 -0
  29. package/src/channels/imessage/imessage-bridge.mjs +16 -0
  30. package/src/channels/imessage/runtime.mjs +98 -0
  31. package/src/channels/imessage/state-store.mjs +3 -0
  32. package/src/channels/shared/i18n-en/shared-a.mjs +2 -2
  33. package/src/channels/shared/message-failure.mjs +5 -5
  34. package/src/channels/shared/session-channel-labels.mjs +1 -0
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.0",
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,10 @@ 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"
628
633
  }
629
634
  ],
630
635
  license: "MIT",
@@ -855,6 +860,18 @@ function WhatsappLogoGlyph({ size } = {}) {
855
860
  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
861
  }));
857
862
  }
863
+ function IMessageLogoGlyph({ size } = {}) {
864
+ return h("svg", {
865
+ ...dimensions(size),
866
+ viewBox: "0 0 24 24",
867
+ focusable: "false",
868
+ "aria-hidden": "true",
869
+ "data-im-channel-logo": "imessage"
870
+ }, h("path", {
871
+ fill: "currentColor",
872
+ 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"
873
+ }));
874
+ }
858
875
  function OfficeLogoGlyph({ size } = {}) {
859
876
  return h(
860
877
  "svg",
@@ -878,6 +895,27 @@ var React2 = __toESM(require("react"), 1);
878
895
  var IM_LOCALE_NAMESPACE = "dsh-im";
879
896
  var EN = Object.freeze({
880
897
  "$locale": "en",
898
+ " macOS Messages \u8FDE\u63A5": " macOS Messages connection",
899
+ "\u63A5\u5165 iMessage": "Connect iMessage",
900
+ "\u5148\u5728 macOS \u7CFB\u7EDF\u8BBE\u7F6E\u4E2D\u6388\u4E88 Messages \u6743\u9650\u3002": "Grant Messages permissions in macOS System Settings first.",
901
+ "\u914D\u7F6E macOS Messages \u6743\u9650": "Configure macOS Messages permissions",
902
+ "\u914D\u7F6E\u672C\u673A\u6743\u9650": "Configure local permissions",
903
+ "\u542F\u7528 macOS \u539F\u751F iMessage": "Enable native macOS iMessage",
904
+ "\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.",
905
+ "\u68C0\u67E5\u6743\u9650\u5E76\u542F\u7528": "Check permissions and enable",
906
+ "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:",
907
+ "\u2713 \u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u5DF2\u6388\u4E88": "\u2713 Full Disk Access granted",
908
+ "1. \u6388\u4E88\u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650": "1. Grant Full Disk Access",
909
+ "\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.",
910
+ "\u6253\u5F00\u5B8C\u5168\u78C1\u76D8\u8BBF\u95EE\u6743\u9650\u8BBE\u7F6E": "Open Full Disk Access settings",
911
+ "\u2713 Messages \u81EA\u52A8\u5316\u6743\u9650\u5DF2\u6388\u4E88": "\u2713 Messages automation granted",
912
+ "2. \u5141\u8BB8\u81EA\u52A8\u5316\u63A7\u5236 Messages": "2. Allow automation control of Messages",
913
+ "\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.",
914
+ "\u6253\u5F00\u81EA\u52A8\u5316\u8BBE\u7F6E": "Open Automation settings",
915
+ "\u6B63\u5728\u68C0\u67E5\u2026": "Checking\u2026",
916
+ "\u63A5\u5165 macOS \u539F\u751F iMessage": "Connect native macOS iMessage",
917
+ "\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.",
918
+ "macOS Messages \u6743\u9650": "macOS Messages permissions",
881
919
  "IM\u673A\u5668\u4EBA": "IM bots",
882
920
  "IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
883
921
  "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E": "More bot settings",
@@ -1929,6 +1967,8 @@ function translateDynamic(text7) {
1929
1967
  ["\u4F01\u4E1A\u5FAE\u4FE1", "WeCom"],
1930
1968
  ["DeepSeek Harness", "DeepSeek Harness"],
1931
1969
  ["WhatsApp", "WhatsApp"],
1970
+ ["iMessage", "iMessage"],
1971
+ ["macOS Messages", "macOS Messages"],
1932
1972
  ["Telegram", "Telegram"],
1933
1973
  ["Discord", "Discord"],
1934
1974
  ["Slack", "Slack"],
@@ -2968,7 +3008,7 @@ function CredentialActionIcon() {
2968
3008
  );
2969
3009
  }
2970
3010
  function CredentialBindingPanel({
2971
- channel: channel4,
3011
+ channel: channel5,
2972
3012
  identityLabel,
2973
3013
  identityPlaceholder,
2974
3014
  secretLabel,
@@ -2995,7 +3035,7 @@ function CredentialBindingPanel({
2995
3035
  className: "ddt-card dim-surfaceCard dim-credentialPanel",
2996
3036
  "aria-labelledby": headingId
2997
3037
  },
2998
- h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel4}\u673A\u5668\u4EBA`),
3038
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel5}\u673A\u5668\u4EBA`),
2999
3039
  h2(
3000
3040
  "form",
3001
3041
  {
@@ -4055,7 +4095,7 @@ function SettingsGlyph() {
4055
4095
  );
4056
4096
  }
4057
4097
  function BotSettingsButton({
4058
- channel: channel4,
4098
+ channel: channel5,
4059
4099
  botId,
4060
4100
  botName,
4061
4101
  connected,
@@ -4070,12 +4110,12 @@ function BotSettingsButton({
4070
4110
  h2("button", {
4071
4111
  type: "button",
4072
4112
  className: "dim-botSettingsButton",
4073
- "data-delivery-channel": channel4,
4113
+ "data-delivery-channel": channel5,
4074
4114
  "aria-label": "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E",
4075
4115
  "aria-describedby": tooltipId,
4076
4116
  onClick: () => openBotSettings?.({
4077
4117
  ...channelSettings && typeof channelSettings === "object" ? channelSettings : {},
4078
- channel: channel4,
4118
+ channel: channel5,
4079
4119
  botId,
4080
4120
  botName,
4081
4121
  connected: Boolean(connected),
@@ -5366,16 +5406,16 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
5366
5406
  setContextEnhancement: "bot.context-enhancement.set",
5367
5407
  setAccessPolicy: "bot.access-policy.set"
5368
5408
  });
5369
- function createTokenChannelApi(channel4, connectionSummary, {
5409
+ function createTokenChannelApi(channel5, connectionSummary, {
5370
5410
  normalizeBotExtension = () => ({})
5371
5411
  } = {}) {
5372
- const unwrapRpcResult14 = (result) => {
5412
+ const unwrapRpcResult15 = (result) => {
5373
5413
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
5374
- throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
5414
+ throw new Error(`${channel5} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
5375
5415
  }
5376
5416
  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);
5417
+ const error = new Error(text2(result.error?.message, `${channel5} \u64CD\u4F5C\u5931\u8D25`));
5418
+ error.code = text2(result.error?.code, `${channel5.toUpperCase()}_RPC_ERROR`, 80);
5379
5419
  throw error;
5380
5420
  }
5381
5421
  return result.value;
@@ -5395,29 +5435,29 @@ function createTokenChannelApi(channel4, connectionSummary, {
5395
5435
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
5396
5436
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
5397
5437
  bot: {
5398
- name: text2(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
5438
+ name: text2(value.bot?.name, `${channel5}\u673A\u5668\u4EBA`, 100),
5399
5439
  username: text2(value.bot?.username, "", 100),
5400
5440
  idMasked: text2(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
5401
5441
  },
5402
5442
  health: {
5403
5443
  summary: text2(
5404
5444
  value.health?.summary,
5405
- connected ? `${channel4}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
5445
+ connected ? `${channel5}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel5}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
5406
5446
  ),
5407
5447
  lastCheckedAt: timestamp2(value.health?.lastCheckedAt)
5408
5448
  },
5409
5449
  lastMessageError: normalizeLastMessageError(value.lastMessageError),
5410
5450
  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`)
5451
+ code: text2(value.error.code, `${channel5.toUpperCase()}_ACCOUNT_ERROR`, 80),
5452
+ message: text2(value.error.message, `${channel5}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
5413
5453
  } : null,
5414
5454
  ...isRecord2(extension) ? extension : {}
5415
5455
  };
5416
5456
  };
5417
- const normalizeSnapshot10 = (value) => {
5457
+ const normalizeSnapshot11 = (value) => {
5418
5458
  const source = isRecord2(value?.snapshot) ? value.snapshot : value;
5419
5459
  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`);
5460
+ throw new Error(`${channel5} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
5421
5461
  }
5422
5462
  const bots = source.bots.map(normalizeBot8).filter(Boolean);
5423
5463
  return {
@@ -5425,14 +5465,15 @@ function createTokenChannelApi(channel4, connectionSummary, {
5425
5465
  bots,
5426
5466
  totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
5427
5467
  agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
5428
- modelCatalog: normalizeModelCatalog(source.modelCatalog)
5468
+ modelCatalog: normalizeModelCatalog(source.modelCatalog),
5469
+ ...isRecord2(source.permissions) ? { permissions: source.permissions } : {}
5429
5470
  };
5430
5471
  };
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`)
5472
+ const presentError15 = (error) => ({
5473
+ code: text2(error?.code, `${channel5.toUpperCase()}_ERROR`, 80),
5474
+ message: text2(error?.message, `${channel5}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
5434
5475
  });
5435
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult14, normalizeSnapshot: normalizeSnapshot10, presentError: presentError14 });
5476
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult15, normalizeSnapshot: normalizeSnapshot11, presentError: presentError15 });
5436
5477
  }
5437
5478
 
5438
5479
  // plugin-src/client/channels/discord/api.js
@@ -5475,9 +5516,9 @@ function connectionTestNotice(value) {
5475
5516
  }
5476
5517
  function createTokenChannelSettings(definition) {
5477
5518
  const {
5478
- channel: channel4,
5519
+ channel: channel5,
5479
5520
  endpoints,
5480
- api: api4,
5521
+ api: api5,
5481
5522
  LogoGlyph,
5482
5523
  installStyles,
5483
5524
  pageClass,
@@ -5489,7 +5530,7 @@ function createTokenChannelSettings(definition) {
5489
5530
  platformLabel,
5490
5531
  CredentialPanel = null,
5491
5532
  credentialPayload = ({ secret }) => ({ token: secret }),
5492
- credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel4} \u673A\u5668\u4EBA`,
5533
+ credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel5} \u673A\u5668\u4EBA`,
5493
5534
  credentialOpenLabel = "\u624B\u52A8\u63A5\u5165",
5494
5535
  credentialCloseLabel = "\u6536\u8D77\u51ED\u636E",
5495
5536
  credentialNoun = "Bot Token",
@@ -5552,7 +5593,7 @@ function createTokenChannelSettings(definition) {
5552
5593
  formatCheckedTime: checkedTime2
5553
5594
  }),
5554
5595
  h2(BotSettingsButton, {
5555
- channel: channel4.toLowerCase(),
5596
+ channel: channel5.toLowerCase(),
5556
5597
  botId: account.botId,
5557
5598
  botName: account.bot.name,
5558
5599
  connected: account.connected,
@@ -5645,7 +5686,8 @@ function createTokenChannelSettings(definition) {
5645
5686
  totals: { configured: 0, connected: 0 },
5646
5687
  error: null,
5647
5688
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
5648
- modelCatalog: EMPTY_MODEL_CATALOG
5689
+ modelCatalog: EMPTY_MODEL_CATALOG,
5690
+ permissions: null
5649
5691
  });
5650
5692
  const [credentialOpen, setCredentialOpen] = React13.useState(false);
5651
5693
  const [credentialError, setCredentialError] = React13.useState(null);
@@ -5666,15 +5708,15 @@ function createTokenChannelSettings(definition) {
5666
5708
  };
5667
5709
  }, []);
5668
5710
  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));
5711
+ if (typeof rpcCall !== "function") throw new TypeError(`${channel5} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
5712
+ return api5.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
5671
5713
  }, [rpcCall]);
5672
5714
  const loadStatus = React13.useCallback(async ({ signal, silent = false } = {}) => {
5673
5715
  const workspaceVersion = workspaceFence.beginStatus();
5674
5716
  if (workspaceVersion === null) return;
5675
5717
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
5676
5718
  try {
5677
- const snapshot = api4.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
5719
+ const snapshot = api5.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
5678
5720
  if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return;
5679
5721
  setModel({
5680
5722
  phase: "ready",
@@ -5682,14 +5724,15 @@ function createTokenChannelSettings(definition) {
5682
5724
  totals: snapshot.totals,
5683
5725
  error: null,
5684
5726
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
5685
- modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
5727
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
5728
+ permissions: snapshot.permissions ?? null
5686
5729
  });
5687
5730
  } catch (error) {
5688
5731
  if (error?.name !== "AbortError" && mounted.current && !signal?.aborted && workspaceFence.canCommitStatus(workspaceVersion)) {
5689
5732
  setModel((current) => ({
5690
5733
  ...current,
5691
5734
  phase: silent ? current.phase : "error",
5692
- error: api4.presentError(error)
5735
+ error: api5.presentError(error)
5693
5736
  }));
5694
5737
  }
5695
5738
  }
@@ -5716,7 +5759,7 @@ function createTokenChannelSettings(definition) {
5716
5759
  setBusy(true);
5717
5760
  setCredentialError(null);
5718
5761
  try {
5719
- const snapshot = api4.normalizeSnapshot(await invoke(
5762
+ const snapshot = api5.normalizeSnapshot(await invoke(
5720
5763
  endpoints.bindCredentials,
5721
5764
  credentialPayload(values)
5722
5765
  ));
@@ -5728,12 +5771,13 @@ function createTokenChannelSettings(definition) {
5728
5771
  totals: snapshot.totals,
5729
5772
  error: null,
5730
5773
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
5731
- modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
5774
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
5775
+ permissions: snapshot.permissions ?? null
5732
5776
  });
5733
5777
  }
5734
5778
  setCredentialOpen(false);
5735
5779
  } catch (error) {
5736
- if (mounted.current) setCredentialError(api4.presentError(error));
5780
+ if (mounted.current) setCredentialError(api5.presentError(error));
5737
5781
  } finally {
5738
5782
  const shouldRefresh = workspaceFence.endMutation();
5739
5783
  if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
@@ -5745,7 +5789,7 @@ function createTokenChannelSettings(definition) {
5745
5789
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
5746
5790
  try {
5747
5791
  const value = await invoke(endpoint, payload);
5748
- const snapshot = api4.normalizeSnapshot(value);
5792
+ const snapshot = api5.normalizeSnapshot(value);
5749
5793
  if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
5750
5794
  setModel({
5751
5795
  phase: "ready",
@@ -5785,7 +5829,7 @@ function createTokenChannelSettings(definition) {
5785
5829
  { className: "dim-listSection" },
5786
5830
  h2(ChannelListHeading, {
5787
5831
  className: "ddt-listHeading",
5788
- title: `\u5DF2\u63A5\u5165\u7684 ${channel4} \u673A\u5668\u4EBA`,
5832
+ title: `\u5DF2\u63A5\u5165\u7684 ${channel5} \u673A\u5668\u4EBA`,
5789
5833
  connectionLabel
5790
5834
  }),
5791
5835
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard6, {
@@ -5848,7 +5892,7 @@ function createTokenChannelSettings(definition) {
5848
5892
  "section",
5849
5893
  {
5850
5894
  className: `ddt-page ${pageClass} dim-channelPage`,
5851
- "aria-label": `${channel4} \u8BBE\u7F6E`
5895
+ "aria-label": `${channel5} \u8BBE\u7F6E`
5852
5896
  },
5853
5897
  h2(
5854
5898
  "div",
@@ -5881,13 +5925,13 @@ function createTokenChannelSettings(definition) {
5881
5925
  model.phase === "loading" ? h2("div", {
5882
5926
  className: "ddt-card ddt-loading dim-surfaceCard dim-loadingView",
5883
5927
  "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(
5928
+ }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel5} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
5885
5929
  "div",
5886
5930
  { className: "ddt-card dim-surfaceCard" },
5887
5931
  h2(
5888
5932
  "div",
5889
5933
  { className: "ddt-inlineError dim-inlineError" },
5890
- h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel4} \u673A\u5668\u4EBA\u72B6\u6001`),
5934
+ h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel5} \u673A\u5668\u4EBA\u72B6\u6001`),
5891
5935
  h2("p", null, model.error?.message),
5892
5936
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
5893
5937
  )
@@ -5895,6 +5939,8 @@ function createTokenChannelSettings(definition) {
5895
5939
  React13.Fragment,
5896
5940
  null,
5897
5941
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
5942
+ channel: channel5,
5943
+ permissions: model.permissions,
5898
5944
  busy,
5899
5945
  error: credentialError,
5900
5946
  onSubmit: bindCredentials,
@@ -5903,7 +5949,7 @@ function createTokenChannelSettings(definition) {
5903
5949
  setCredentialError(null);
5904
5950
  }
5905
5951
  }) : h2(CredentialBindingPanel, {
5906
- channel: channel4,
5952
+ channel: channel5,
5907
5953
  secretLabel: "Bot Token",
5908
5954
  secretPlaceholder: tokenPlaceholder,
5909
5955
  busy,
@@ -5927,7 +5973,7 @@ function createTokenChannelSettings(definition) {
5927
5973
  "div",
5928
5974
  { className: "ddt-stateLabel dim-stateLabel" },
5929
5975
  h2("span", { className: "ddt-dot dim-stateDot" }),
5930
- h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel4} \u673A\u5668\u4EBA`)
5976
+ h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel5} \u673A\u5668\u4EBA`)
5931
5977
  ),
5932
5978
  h2("h3", null, emptyTitle),
5933
5979
  h2("p", null, emptyDescription),
@@ -13423,11 +13469,115 @@ function WhatsappSettingsTab({ rpcCall }) {
13423
13469
  )));
13424
13470
  }
13425
13471
 
13472
+ // plugin-src/client/channels/imessage/api.js
13473
+ var IMESSAGE_RPC_CHANNEL = "/imessage";
13474
+ var IMESSAGE_ENDPOINTS = Object.freeze({
13475
+ ...TOKEN_BOT_ENDPOINTS,
13476
+ bindCredentials: "bot.bind-native"
13477
+ });
13478
+ var api4 = createTokenChannelApi("iMessage", " macOS Messages \u8FDE\u63A5");
13479
+ var unwrapRpcResult11 = api4.unwrapRpcResult;
13480
+ var normalizeSnapshot10 = api4.normalizeSnapshot;
13481
+ var presentError11 = api4.presentError;
13482
+
13483
+ // plugin-src/client/channels/imessage/index.js
13484
+ var React23 = __toESM(require("react"), 1);
13485
+
13486
+ // plugin-src/client/channels/imessage/styles.js
13487
+ var IMESSAGE_STYLE_ID = "xmanrui-dsh-im-imessage-settings";
13488
+ var CSS12 = String.raw`
13489
+ .dim-pageIMessage { --ddt-accent: #32a852; --ddt-accent-deep: #248a40; --ddt-accent-wash: #edf9f0; }
13490
+ .dim-avatarIMessage { color: #fff; background: #32a852; }
13491
+ .dim-avatarIMessage svg { display: block; }
13492
+ .dim-imessagePermissionPanel { padding: 20px; }
13493
+ .dim-imessagePermissionPanel p { color: var(--dsw-alias-label-secondary, #646a73); }
13494
+ .dim-imessagePermissionSteps { margin: 16px 0; padding-left: 22px; }
13495
+ .dim-imessagePermissionSteps li { margin: 12px 0; }
13496
+ .dim-imessagePermissionSteps a { color: var(--ddt-accent-deep); }
13497
+ `;
13498
+ function installIMessageStyles() {
13499
+ if (typeof document === "undefined") return () => {
13500
+ };
13501
+ const existing = document.querySelector(`style[data-plugin-css="${IMESSAGE_STYLE_ID}"]`);
13502
+ if (existing) return () => {
13503
+ };
13504
+ const style = document.createElement("style");
13505
+ style.dataset.plugin = "@xmanrui/dsh-im";
13506
+ style.dataset.pluginCss = IMESSAGE_STYLE_ID;
13507
+ style.textContent = CSS12;
13508
+ document.head.appendChild(style);
13509
+ return () => style.remove();
13510
+ }
13511
+
13512
+ // plugin-src/client/channels/imessage/index.js
13513
+ function PermissionPanel({ permissions, busy, error, onSubmit, onCancel }) {
13514
+ const databaseReady = permissions?.database === "granted";
13515
+ const automationReady = permissions?.automation === "granted";
13516
+ return h2(
13517
+ "section",
13518
+ { className: "ddt-card dim-surfaceCard dim-imessagePermissionPanel" },
13519
+ h2("h3", null, "\u542F\u7528 macOS \u539F\u751F iMessage"),
13520
+ 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"),
13521
+ 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"),
13522
+ h2(
13523
+ "ol",
13524
+ { className: "dim-imessagePermissionSteps" },
13525
+ h2(
13526
+ "li",
13527
+ null,
13528
+ 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"),
13529
+ 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"),
13530
+ 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")
13531
+ ),
13532
+ h2(
13533
+ "li",
13534
+ null,
13535
+ h2("strong", null, automationReady ? "\u2713 Messages \u81EA\u52A8\u5316\u6743\u9650\u5DF2\u6388\u4E88" : "2. \u5141\u8BB8\u81EA\u52A8\u5316\u63A7\u5236 Messages"),
13536
+ 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"),
13537
+ automationReady ? null : h2("a", { href: "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation" }, "\u6253\u5F00\u81EA\u52A8\u5316\u8BBE\u7F6E")
13538
+ )
13539
+ ),
13540
+ error ? h2("p", { className: "dim-inlineError", role: "alert" }, error.message ?? String(error)) : null,
13541
+ h2(
13542
+ "div",
13543
+ { className: "ddt-actions dim-viewActions" },
13544
+ h2("button", { type: "button", className: "ddt-button", onClick: onCancel, disabled: busy }, "\u53D6\u6D88"),
13545
+ h2(
13546
+ "button",
13547
+ { type: "button", className: "ddt-button", "data-kind": "primary", onClick: () => onSubmit({}), disabled: busy },
13548
+ busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u6743\u9650\u5E76\u542F\u7528"
13549
+ )
13550
+ )
13551
+ );
13552
+ }
13553
+ var channel4 = createTokenChannelSettings({
13554
+ channel: "iMessage",
13555
+ endpoints: IMESSAGE_ENDPOINTS,
13556
+ api: api4,
13557
+ LogoGlyph: IMessageLogoGlyph,
13558
+ installStyles: installIMessageStyles,
13559
+ pageClass: "dim-pageIMessage",
13560
+ avatarClass: "dim-avatarIMessage",
13561
+ connectionLabel: " macOS Messages \u8FDE\u63A5",
13562
+ tokenPlaceholder: "",
13563
+ emptyTitle: "\u63A5\u5165 macOS \u539F\u751F iMessage",
13564
+ emptyDescription: "\u65E0\u9700\u5B89\u88C5\u7B2C\u4E09\u65B9\u670D\u52A1\uFF1B\u8BF7\u6309\u6307\u5F15\u6388\u4E88 macOS Messages \u8BBF\u95EE\u6743\u9650\u3002",
13565
+ platformLabel: "macOS Messages",
13566
+ credentialPayload: () => ({}),
13567
+ CredentialPanel: PermissionPanel,
13568
+ credentialAriaLabel: "\u914D\u7F6E macOS Messages \u6743\u9650",
13569
+ credentialOpenLabel: "\u914D\u7F6E\u672C\u673A\u6743\u9650",
13570
+ credentialNoun: "macOS Messages \u6743\u9650",
13571
+ emptyActionLabel: "\u914D\u7F6E\u672C\u673A\u6743\u9650"
13572
+ });
13573
+ var IMessageSettingsTab = channel4.SettingsTab;
13574
+ var IMessageAccountCard = channel4.AccountCard;
13575
+
13426
13576
  // plugin-src/client/delivery-settings.js
13427
- var React25 = __toESM(require("react"), 1);
13577
+ var React26 = __toESM(require("react"), 1);
13428
13578
 
13429
13579
  // plugin-src/client/access-policy-settings.js
13430
- var React23 = __toESM(require("react"), 1);
13580
+ var React24 = __toESM(require("react"), 1);
13431
13581
  var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
13432
13582
  var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
13433
13583
  weixin: Object.freeze({
@@ -13488,6 +13638,11 @@ var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
13488
13638
  directPlaceholder: "8613800000000 \u6216\u5B8C\u6574 JID",
13489
13639
  groupUserLabel: "\u7FA4\u6210\u5458\u7535\u8BDD\u53F7\u7801\u6216 JID",
13490
13640
  groupPlaceholder: "8613800000000 \u6216\u5B8C\u6574 JID"
13641
+ }),
13642
+ imessage: Object.freeze({
13643
+ directUserLabel: "iMessage Chat GUID",
13644
+ directPlaceholder: "iMessage;+;chat123",
13645
+ groupSupported: false
13491
13646
  })
13492
13647
  });
13493
13648
  function clonePolicy(policy) {
@@ -13508,7 +13663,7 @@ function clonePolicy(policy) {
13508
13663
  group: cloneScope(policy.group)
13509
13664
  };
13510
13665
  }
13511
- function unwrapRpcResult11(result) {
13666
+ function unwrapRpcResult12(result) {
13512
13667
  if (result?.ok === true) return result.value;
13513
13668
  if (result?.ok === false) {
13514
13669
  const error = new Error(result.error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -13535,8 +13690,8 @@ function ScenePolicyEditor({
13535
13690
  unsupported = false,
13536
13691
  onChange
13537
13692
  }) {
13538
- const ownerHelpId = React23.useId();
13539
- const emptyAllowlistHelpId = React23.useId();
13693
+ const ownerHelpId = React24.useId();
13694
+ const emptyAllowlistHelpId = React24.useId();
13540
13695
  const allowlist = policy.mode === "allowlist";
13541
13696
  const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
13542
13697
  const branchKey = allowlist ? "allowlist" : "open";
@@ -13588,7 +13743,7 @@ function ScenePolicyEditor({
13588
13743
  h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
13589
13744
  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
13745
  ) : h2(
13591
- React23.Fragment,
13746
+ React24.Fragment,
13592
13747
  null,
13593
13748
  h2(
13594
13749
  "div",
@@ -13725,20 +13880,20 @@ function ScenePolicyEditor({
13725
13880
  )
13726
13881
  );
13727
13882
  }
13728
- function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved }) {
13729
- const definition = ACCESS_CHANNEL_DEFINITIONS[channel4];
13883
+ function AccessPolicySettingsPage({ channel: channel5, account, rpcCall, onSaved }) {
13884
+ const definition = ACCESS_CHANNEL_DEFINITIONS[channel5];
13730
13885
  const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
13731
13886
  const initialKey = JSON.stringify(initialPolicy);
13732
- const [draft, setDraft] = React23.useState(() => clonePolicy(
13887
+ const [draft, setDraft] = React24.useState(() => clonePolicy(
13733
13888
  initialPolicy ?? DEFAULT_ACCESS_POLICY
13734
13889
  ));
13735
- const [saving, setSaving] = React23.useState(false);
13736
- const [feedback, setFeedback] = React23.useState(null);
13737
- React23.useEffect(() => {
13890
+ const [saving, setSaving] = React24.useState(false);
13891
+ const [feedback, setFeedback] = React24.useState(null);
13892
+ React24.useEffect(() => {
13738
13893
  const next = normalizeAccessPolicy(account?.accessPolicy);
13739
13894
  setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
13740
13895
  }, [account?.botId, initialKey]);
13741
- React23.useEffect(() => {
13896
+ React24.useEffect(() => {
13742
13897
  setFeedback(null);
13743
13898
  }, [account?.botId]);
13744
13899
  if (!definition) {
@@ -13755,7 +13910,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
13755
13910
  try {
13756
13911
  const policy = validateAccessPolicy(draft);
13757
13912
  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, {
13913
+ const value = unwrapRpcResult12(await rpcCall(ACCESS_POLICY_ENDPOINT, {
13759
13914
  botId: account.botId,
13760
13915
  policy
13761
13916
  }));
@@ -13829,7 +13984,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
13829
13984
  }
13830
13985
 
13831
13986
  // plugin-src/client/channels/feishu/group-settings.js
13832
- var React24 = __toESM(require("react"), 1);
13987
+ var React25 = __toESM(require("react"), 1);
13833
13988
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
13834
13989
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
13835
13990
  return h2("button", {
@@ -13890,9 +14045,9 @@ function GroupResponseModeEditor({
13890
14045
  onAuthorize
13891
14046
  }) {
13892
14047
  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);
14048
+ const [saving, setSaving] = React25.useState(false);
14049
+ const [authorizing, setAuthorizing] = React25.useState(false);
14050
+ const [error, setError] = React25.useState(null);
13896
14051
  const change = async (event) => {
13897
14052
  const next = normalizeGroupResponseMode(event.target.value);
13898
14053
  if (next === current || saving || disabled) return;
@@ -13973,8 +14128,8 @@ function GroupResponseModeEditor({
13973
14128
  }
13974
14129
  function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
13975
14130
  const current = value === true ? "on" : "off";
13976
- const [saving, setSaving] = React24.useState(false);
13977
- const [error, setError] = React24.useState(null);
14131
+ const [saving, setSaving] = React25.useState(false);
14132
+ const [error, setError] = React25.useState(null);
13978
14133
  const change = async (event) => {
13979
14134
  const next = event.target.value === "on";
13980
14135
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -14161,14 +14316,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
14161
14316
  );
14162
14317
  }
14163
14318
  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(() => {
14319
+ const [settings, setSettings] = React25.useState(() => groupSettingsFrom(account));
14320
+ const [refreshing, setRefreshing] = React25.useState(false);
14321
+ const [refreshError, setRefreshError] = React25.useState(null);
14322
+ const [provision, setProvision] = React25.useState(null);
14323
+ const [provisionBusy, setProvisionBusy] = React25.useState(false);
14324
+ const [now, setNow] = React25.useState(() => Date.now());
14325
+ const mounted = React25.useRef(true);
14326
+ React25.useEffect(() => {
14172
14327
  setSettings(groupSettingsFrom(account));
14173
14328
  }, [
14174
14329
  account.botId,
@@ -14176,22 +14331,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14176
14331
  account.groupTopicReply,
14177
14332
  account.groupMessagePermissionGranted
14178
14333
  ]);
14179
- React24.useEffect(() => {
14334
+ React25.useEffect(() => {
14180
14335
  mounted.current = true;
14181
14336
  return () => {
14182
14337
  mounted.current = false;
14183
14338
  };
14184
14339
  }, []);
14185
- const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
14340
+ const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
14186
14341
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
14187
14342
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
14188
14343
  }, [rpcCall]);
14189
- const applySnapshot = React24.useCallback((value) => {
14344
+ const applySnapshot = React25.useCallback((value) => {
14190
14345
  const result = targetBotFromSnapshot(value, account.botId);
14191
14346
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
14192
14347
  return result;
14193
14348
  }, [account.botId]);
14194
- const loadSettings = React24.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
14349
+ const loadSettings = React25.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
14195
14350
  setRefreshing(true);
14196
14351
  setRefreshError(null);
14197
14352
  try {
@@ -14220,16 +14375,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14220
14375
  if (!signal?.aborted && mounted.current) setRefreshing(false);
14221
14376
  }
14222
14377
  }, [account.botId, applySnapshot, invoke]);
14223
- React24.useEffect(() => {
14378
+ React25.useEffect(() => {
14224
14379
  const controller = new AbortController();
14225
14380
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
14226
14381
  return () => controller.abort();
14227
14382
  }, [loadSettings]);
14228
- const saveSetting = React24.useCallback(async (endpoint, payload) => {
14383
+ const saveSetting = React25.useCallback(async (endpoint, payload) => {
14229
14384
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
14230
14385
  applySnapshot(value);
14231
14386
  }, [account.botId, applySnapshot, invoke]);
14232
- const startAuthorization = React24.useCallback(async ({ replace = false } = {}) => {
14387
+ const startAuthorization = React25.useCallback(async ({ replace = false } = {}) => {
14233
14388
  if (provisionBusy) return;
14234
14389
  const previousAttemptId = provision?.attemptId;
14235
14390
  setProvisionBusy(true);
@@ -14270,13 +14425,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14270
14425
  if (mounted.current) setProvisionBusy(false);
14271
14426
  }
14272
14427
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
14273
- const finishAuthorization = React24.useCallback(async (signal) => {
14428
+ const finishAuthorization = React25.useCallback(async (signal) => {
14274
14429
  const bot = await loadSettings({ signal, restoreProvisioning: false });
14275
14430
  if (signal?.aborted || !mounted.current) return;
14276
14431
  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
14432
  setProvision(null);
14278
14433
  }, [loadSettings]);
14279
- React24.useEffect(() => {
14434
+ React25.useEffect(() => {
14280
14435
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
14281
14436
  const timerHost = globalThis.window ?? globalThis;
14282
14437
  const controller = new AbortController();
@@ -14320,7 +14475,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14320
14475
  timerHost.clearTimeout(timer);
14321
14476
  };
14322
14477
  }, [account.botId, finishAuthorization, invoke, provision]);
14323
- React24.useEffect(() => {
14478
+ React25.useEffect(() => {
14324
14479
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
14325
14480
  const timerHost = globalThis.window ?? globalThis;
14326
14481
  const tick = () => {
@@ -14334,7 +14489,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
14334
14489
  const timer = timerHost.setInterval(tick, 1e3);
14335
14490
  return () => timerHost.clearInterval(timer);
14336
14491
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
14337
- const cancelAuthorization = React24.useCallback(async () => {
14492
+ const cancelAuthorization = React25.useCallback(async () => {
14338
14493
  if (!provision?.attemptId || provisionBusy) {
14339
14494
  setProvision(null);
14340
14495
  return;
@@ -14445,8 +14600,8 @@ var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
14445
14600
  ...BOT_SETTINGS_TABS,
14446
14601
  Object.freeze({ id: "group", label: "\u7FA4\u804A" })
14447
14602
  ]);
14448
- function botSettingsTabsForChannel(channel4) {
14449
- return channel4 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
14603
+ function botSettingsTabsForChannel(channel5) {
14604
+ return channel5 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
14450
14605
  }
14451
14606
  var CHANNEL_DEFINITIONS = Object.freeze({
14452
14607
  weixin: {
@@ -14527,12 +14682,17 @@ var CHANNEL_DEFINITIONS = Object.freeze({
14527
14682
  user: [{ key: "jid", label: "\u7528\u6237 JID", placeholder: "8613800000000@s.whatsapp.net" }],
14528
14683
  group: [{ key: "jid", label: "\u7FA4 JID", placeholder: "1234567890@g.us" }]
14529
14684
  }
14685
+ },
14686
+ imessage: {
14687
+ label: "iMessage",
14688
+ kinds: [{ value: "user", label: "\u79C1\u804A" }],
14689
+ fields: { user: [{ key: "chatGuid", label: "Chat GUID", placeholder: "iMessage;+;chat123" }] }
14530
14690
  }
14531
14691
  });
14532
- function presentError11(error, fallback) {
14692
+ function presentError12(error, fallback) {
14533
14693
  return error?.message || fallback;
14534
14694
  }
14535
- function unwrapRpcResult12(result) {
14695
+ function unwrapRpcResult13(result) {
14536
14696
  if (result?.ok === true) return result.value;
14537
14697
  if (result?.ok === false) {
14538
14698
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -14650,13 +14810,13 @@ function TargetForm({
14650
14810
  }) {
14651
14811
  const editing = mode === "edit";
14652
14812
  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);
14813
+ const [targetId, setTargetId] = React26.useState(initialValue?.targetId ?? "");
14814
+ const [name2, setName] = React26.useState(initialValue?.name ?? "");
14815
+ const [kind, setKind] = React26.useState(initialKind);
14816
+ const [route, setRoute] = React26.useState(initialValue?.route ?? {});
14817
+ const [error, setError] = React26.useState(null);
14818
+ const [testing, setTesting] = React26.useState(false);
14819
+ const [testState, setTestState] = React26.useState(null);
14660
14820
  const currentTarget = () => {
14661
14821
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field) => {
14662
14822
  const raw = String(route[field.key] ?? "").trim();
@@ -14677,7 +14837,7 @@ function TargetForm({
14677
14837
  ...currentTarget()
14678
14838
  });
14679
14839
  } catch (caught) {
14680
- setError(presentError11(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
14840
+ setError(presentError12(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
14681
14841
  }
14682
14842
  };
14683
14843
  const testTarget = async () => {
@@ -14689,7 +14849,7 @@ function TargetForm({
14689
14849
  await onTest({ kind: target.kind, route: target.route });
14690
14850
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
14691
14851
  } catch (caught) {
14692
- setTestState({ tone: "error", message: presentError11(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14852
+ setTestState({ tone: "error", message: presentError12(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14693
14853
  } finally {
14694
14854
  setTesting(false);
14695
14855
  }
@@ -14873,7 +15033,7 @@ function TargetSuggestionPicker({
14873
15033
  suggestions.map((suggestion, index) => {
14874
15034
  const identity = routeIdentity(definition, suggestion);
14875
15035
  const added = configured.has(identity);
14876
- return React25.createElement("option", {
15036
+ return React26.createElement("option", {
14877
15037
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
14878
15038
  value: String(index),
14879
15039
  disabled: added
@@ -14890,11 +15050,11 @@ function TargetSuggestionPicker({
14890
15050
  );
14891
15051
  }
14892
15052
  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);
15053
+ const [action, setAction] = React26.useState(null);
15054
+ const [testState, setTestState] = React26.useState(null);
15055
+ const [syncFeedback, setSyncFeedback] = React26.useState(null);
15056
+ const [copyState, setCopyState] = React26.useState(null);
15057
+ const [confirmDelete, setConfirmDelete] = React26.useState(false);
14898
15058
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
14899
15059
  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
15060
  const testTarget = async () => {
@@ -14904,7 +15064,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14904
15064
  await rpcCall(DELIVERY_ENDPOINTS.test, { botId, targetId: target.targetId });
14905
15065
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
14906
15066
  } catch (error) {
14907
- setTestState({ tone: "error", message: presentError11(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
15067
+ setTestState({ tone: "error", message: presentError12(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14908
15068
  } finally {
14909
15069
  setAction(null);
14910
15070
  }
@@ -14915,7 +15075,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14915
15075
  await copyText(JSON.stringify({ botId, targetId: target.targetId }));
14916
15076
  setCopyState("\u5DF2\u590D\u5236\u8C03\u7528\u53C2\u6570");
14917
15077
  } catch (error) {
14918
- setCopyState(presentError11(error, "\u590D\u5236\u5931\u8D25\u3002"));
15078
+ setCopyState(presentError12(error, "\u590D\u5236\u5931\u8D25\u3002"));
14919
15079
  }
14920
15080
  };
14921
15081
  const deleteTarget = async () => {
@@ -14924,7 +15084,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14924
15084
  await rpcCall(DELIVERY_ENDPOINTS.delete, { botId, targetId: target.targetId });
14925
15085
  await onChanged();
14926
15086
  } catch (error) {
14927
- setTestState({ tone: "error", message: presentError11(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
15087
+ setTestState({ tone: "error", message: presentError12(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14928
15088
  setAction(null);
14929
15089
  setConfirmDelete(false);
14930
15090
  }
@@ -14942,7 +15102,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14942
15102
  } catch (error) {
14943
15103
  setSyncFeedback({
14944
15104
  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")
15105
+ 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
15106
  });
14947
15107
  } finally {
14948
15108
  setAction(null);
@@ -14957,7 +15117,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
14957
15117
  h2(
14958
15118
  "div",
14959
15119
  { className: "dim-targetTitle" },
14960
- React25.createElement("strong", null, target.name || target.targetId),
15120
+ React26.createElement("strong", null, target.name || target.targetId),
14961
15121
  h2("span", null, kindLabel(definition, target.kind))
14962
15122
  ),
14963
15123
  h2("code", null, `targetId: ${target.targetId}`)
@@ -15036,33 +15196,33 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
15036
15196
  );
15037
15197
  }
15038
15198
  function DeliveryTargetSettingsPage({
15039
- channel: channel4,
15199
+ channel: channel5,
15040
15200
  account,
15041
15201
  rpcCall,
15042
15202
  accessRpcCall,
15043
15203
  onBack
15044
15204
  }) {
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(() => {
15205
+ const definition = CHANNEL_DEFINITIONS[channel5];
15206
+ const [activeTabId, setActiveTabId] = React26.useState(BOT_SETTINGS_TABS[0].id);
15207
+ const [phase, setPhase] = React26.useState("loading");
15208
+ const [targets, setTargets] = React26.useState([]);
15209
+ const [suggestionPhase, setSuggestionPhase] = React26.useState("idle");
15210
+ const [suggestions, setSuggestions] = React26.useState([]);
15211
+ const [suggestionError, setSuggestionError] = React26.useState(null);
15212
+ const [error, setError] = React26.useState(null);
15213
+ const [editor, setEditor] = React26.useState(null);
15214
+ const [saving, setSaving] = React26.useState(false);
15215
+ const [botCopyState, setBotCopyState] = React26.useState(null);
15216
+ const [accessPolicy, setAccessPolicy] = React26.useState(account.accessPolicy);
15217
+ const mounted = React26.useRef(true);
15218
+ React26.useEffect(() => {
15059
15219
  setAccessPolicy(account.accessPolicy);
15060
15220
  }, [account.botId, account.accessPolicy]);
15061
- const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
15221
+ const invoke = React26.useCallback(async (endpoint, payload = {}, signal) => {
15062
15222
  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));
15223
+ return unwrapRpcResult13(await rpcCall(endpoint, payload, signal));
15064
15224
  }, [rpcCall]);
15065
- const loadTargets = React25.useCallback(async ({ signal, silent = false } = {}) => {
15225
+ const loadTargets = React26.useCallback(async ({ signal, silent = false } = {}) => {
15066
15226
  if (!silent) setPhase("loading");
15067
15227
  setError(null);
15068
15228
  try {
@@ -15072,11 +15232,11 @@ function DeliveryTargetSettingsPage({
15072
15232
  setPhase("ready");
15073
15233
  } catch (caught) {
15074
15234
  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"));
15235
+ setError(presentError12(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15076
15236
  setPhase("error");
15077
15237
  }
15078
15238
  }, [account.botId, invoke]);
15079
- const loadSuggestions = React25.useCallback(async () => {
15239
+ const loadSuggestions = React26.useCallback(async () => {
15080
15240
  setSuggestionPhase("loading");
15081
15241
  setSuggestionError(null);
15082
15242
  try {
@@ -15086,11 +15246,11 @@ function DeliveryTargetSettingsPage({
15086
15246
  setSuggestionPhase("ready");
15087
15247
  } catch (caught) {
15088
15248
  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"));
15249
+ setSuggestionError(presentError12(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15090
15250
  setSuggestionPhase("error");
15091
15251
  }
15092
15252
  }, [account.botId, definition, invoke]);
15093
- React25.useEffect(() => {
15253
+ React26.useEffect(() => {
15094
15254
  mounted.current = true;
15095
15255
  const controller = new AbortController();
15096
15256
  void loadTargets({ signal: controller.signal });
@@ -15158,10 +15318,10 @@ function DeliveryTargetSettingsPage({
15158
15318
  await copyText(account.botId);
15159
15319
  setBotCopyState("\u5DF2\u590D\u5236 Bot ID");
15160
15320
  } catch (caught) {
15161
- setBotCopyState(presentError11(caught, "\u590D\u5236\u5931\u8D25\u3002"));
15321
+ setBotCopyState(presentError12(caught, "\u590D\u5236\u5931\u8D25\u3002"));
15162
15322
  }
15163
15323
  };
15164
- const settingsTabs = botSettingsTabsForChannel(channel4);
15324
+ const settingsTabs = botSettingsTabsForChannel(channel5);
15165
15325
  const activeTab = settingsTabs.find((tab) => tab.id === activeTabId) ?? settingsTabs[0];
15166
15326
  const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
15167
15327
  const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
@@ -15204,15 +15364,15 @@ function DeliveryTargetSettingsPage({
15204
15364
  "aria-labelledby": activeTabDomId
15205
15365
  },
15206
15366
  activeTab.id === "access" ? h2(AccessPolicySettingsPage, {
15207
- channel: channel4,
15367
+ channel: channel5,
15208
15368
  account: { ...account, accessPolicy },
15209
15369
  rpcCall: accessRpcCall,
15210
15370
  onSaved: setAccessPolicy
15211
- }) : activeTab.id === "group" && channel4 === "feishu" ? h2(FeishuGroupSettingsPage, {
15371
+ }) : activeTab.id === "group" && channel5 === "feishu" ? h2(FeishuGroupSettingsPage, {
15212
15372
  account,
15213
15373
  rpcCall: accessRpcCall
15214
15374
  }) : h2(
15215
- React25.Fragment,
15375
+ React26.Fragment,
15216
15376
  null,
15217
15377
  h2(
15218
15378
  "section",
@@ -15323,7 +15483,7 @@ function DeliveryTargetSettingsPage({
15323
15483
  }
15324
15484
 
15325
15485
  // plugin-src/client/global-settings.js
15326
- var React26 = __toESM(require("react"), 1);
15486
+ var React27 = __toESM(require("react"), 1);
15327
15487
 
15328
15488
  // src/channels/shared/inbound-ttl.mjs
15329
15489
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -15352,10 +15512,10 @@ var GLOBAL_SETTINGS_ENDPOINTS = Object.freeze({
15352
15512
  setTtl: "settings.inbound-ttl.set",
15353
15513
  sweep: "settings.inbound-ttl.sweep"
15354
15514
  });
15355
- function presentError12(error, fallback) {
15515
+ function presentError13(error, fallback) {
15356
15516
  return error?.message || fallback;
15357
15517
  }
15358
- function unwrapRpcResult13(result) {
15518
+ function unwrapRpcResult14(result) {
15359
15519
  if (result?.ok === true) return result.value;
15360
15520
  if (result?.ok === false) {
15361
15521
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -15385,29 +15545,29 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
15385
15545
  }, children);
15386
15546
  }
15387
15547
  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) => {
15548
+ const [phase, setPhase] = React27.useState("loading");
15549
+ const [loadError, setLoadError] = React27.useState(null);
15550
+ const [ttlInput, setTtlInput] = React27.useState("");
15551
+ const [savedTtl, setSavedTtl] = React27.useState(null);
15552
+ const [ttlError, setTtlError] = React27.useState(false);
15553
+ const [saveError, setSaveError] = React27.useState(null);
15554
+ const [saveSucceeded, setSaveSucceeded] = React27.useState(false);
15555
+ const [isSaving, setIsSaving] = React27.useState(false);
15556
+ const [sweepConfirming, setSweepConfirming] = React27.useState(false);
15557
+ const [sweeping, setSweeping] = React27.useState(false);
15558
+ const ttlErrorId = React27.useId();
15559
+ const ttlHintsId = React27.useId();
15560
+ const sweepTriggerId = React27.useId();
15561
+ const sweepConfirmId = React27.useId();
15562
+ const sweepConfirmTextId = React27.useId();
15563
+ const sweepConfirmButtonId = React27.useId();
15564
+ const mounted = React27.useRef(true);
15565
+ const saving = React27.useRef(false);
15566
+ const invoke = React27.useCallback(async (endpoint, payload = {}, signal) => {
15407
15567
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
15408
- return unwrapRpcResult13(await rpcCall(endpoint, payload, signal));
15568
+ return unwrapRpcResult14(await rpcCall(endpoint, payload, signal));
15409
15569
  }, [rpcCall]);
15410
- const loadSettings = React26.useCallback(async ({ signal } = {}) => {
15570
+ const loadSettings = React27.useCallback(async ({ signal } = {}) => {
15411
15571
  setPhase("loading");
15412
15572
  setLoadError(null);
15413
15573
  try {
@@ -15427,11 +15587,11 @@ function GlobalSettingsPanel({ rpcCall }) {
15427
15587
  setPhase("ready");
15428
15588
  } catch (caught) {
15429
15589
  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"));
15590
+ setLoadError(presentError13(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15431
15591
  setPhase("error");
15432
15592
  }
15433
15593
  }, [invoke]);
15434
- React26.useEffect(() => {
15594
+ React27.useEffect(() => {
15435
15595
  mounted.current = true;
15436
15596
  const controller = new AbortController();
15437
15597
  void loadSettings({ signal: controller.signal });
@@ -15440,7 +15600,7 @@ function GlobalSettingsPanel({ rpcCall }) {
15440
15600
  controller.abort();
15441
15601
  };
15442
15602
  }, [loadSettings]);
15443
- React26.useEffect(() => {
15603
+ React27.useEffect(() => {
15444
15604
  if (!sweepConfirming) return;
15445
15605
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
15446
15606
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -15471,7 +15631,7 @@ function GlobalSettingsPanel({ rpcCall }) {
15471
15631
  setPhase("ready");
15472
15632
  } catch (caught) {
15473
15633
  if (mounted.current) {
15474
- setSaveError(presentError12(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15634
+ setSaveError(presentError13(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15475
15635
  }
15476
15636
  } finally {
15477
15637
  saving.current = false;
@@ -15747,7 +15907,7 @@ function replacePageLocation(url, location = globalThis.location) {
15747
15907
 
15748
15908
  // plugin-src/client/styles.js
15749
15909
  var IM_STYLE_ID = "xmanrui-dsh-im-settings";
15750
- var CSS12 = String.raw`
15910
+ var CSS13 = String.raw`
15751
15911
  .dim-page {
15752
15912
  --dim-blue: var(--dsw-alias-state-business-primary, #3370ff);
15753
15913
  --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent);
@@ -15844,6 +16004,7 @@ var CSS12 = String.raw`
15844
16004
  .dim-logoSlack { color: white; background: #4a154b; }
15845
16005
  .dim-logoSlack svg { width: 21px; height: 21px; }
15846
16006
  .dim-logoWhatsapp { color: white; background: #25d366; }
16007
+ .dim-logoIMessage { color: white; background: #32a852; }
15847
16008
  .dim-logoWhatsapp svg { width: 21px; height: 21px; }
15848
16009
  .dim-channelCopy { min-width: 0; display: grid; }
15849
16010
  .dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; }
@@ -16420,7 +16581,7 @@ function installImStyles() {
16420
16581
  const style = document.createElement("style");
16421
16582
  style.dataset.plugin = "@xmanrui/dsh-im";
16422
16583
  style.dataset.pluginCss = IM_STYLE_ID;
16423
- style.textContent = CSS12;
16584
+ style.textContent = CSS13;
16424
16585
  document.head.appendChild(style);
16425
16586
  return () => style.remove();
16426
16587
  }
@@ -16436,15 +16597,16 @@ var SESSION_CHANNEL_LABELS = Object.freeze(Object.fromEntries(Object.entries({
16436
16597
  telegram: ["Telegram", "Telegram"],
16437
16598
  discord: ["Discord", "Discord"],
16438
16599
  whatsapp: ["WhatsApp", "WhatsApp"],
16600
+ imessage: ["iMessage", "iMessage"],
16439
16601
  office: ["AI Office", "AI Office"]
16440
- }).map(([channel4, labels]) => [channel4, Object.freeze(labels)])));
16602
+ }).map(([channel5, labels]) => [channel5, Object.freeze(labels)])));
16441
16603
  function parseSessionChannelTitle(title) {
16442
16604
  if (typeof title !== "string") return null;
16443
- for (const [channel4, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
16605
+ for (const [channel5, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
16444
16606
  for (const label of labels) {
16445
16607
  const prefix = `${label} \xB7 `;
16446
16608
  if (title.startsWith(prefix) && title.slice(prefix.length).trim()) {
16447
- return { channel: channel4, title: title.slice(prefix.length) };
16609
+ return { channel: channel5, title: title.slice(prefix.length) };
16448
16610
  }
16449
16611
  }
16450
16612
  }
@@ -16462,6 +16624,7 @@ var GLYPHS = Object.freeze({
16462
16624
  telegram: [TelegramLogoGlyph, "#229ed9"],
16463
16625
  discord: [DiscordLogoGlyph, "#5865f2"],
16464
16626
  whatsapp: [WhatsappLogoGlyph, "#25d366"],
16627
+ imessage: [IMessageLogoGlyph, "#3478f6"],
16465
16628
  office: [OfficeLogoGlyph, "#f97316"]
16466
16629
  });
16467
16630
  var CHANNEL_ATTR = "data-dsh-im-session-channel";
@@ -16485,8 +16648,8 @@ function titleOf(row) {
16485
16648
  }
16486
16649
  return title?.childNodes.length === 1 && title.firstChild.nodeType === 3 ? title : null;
16487
16650
  }
16488
- function logoUri(document2, channel4) {
16489
- const [Glyph, color] = GLYPHS[channel4];
16651
+ function logoUri(document2, channel5) {
16652
+ const [Glyph, color] = GLYPHS[channel5];
16490
16653
  const render = (node) => {
16491
16654
  if (!["svg", "path"].includes(node.type)) throw new Error("Unsupported channel logo element");
16492
16655
  const element = document2.createElementNS(SVG_NS, node.type);
@@ -16513,7 +16676,7 @@ function createInstallation(document2) {
16513
16676
  let scheduled = false;
16514
16677
  const style = document2.createElement("style");
16515
16678
  style.dataset.pluginCss = "dsh-im-session-channel-logos";
16516
- const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel4) => [channel4, logoUri(document2, channel4)]));
16679
+ const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel5) => [channel5, logoUri(document2, channel5)]));
16517
16680
  style.textContent = `
16518
16681
  ${MARKED}[${TITLE_ATTR}] {
16519
16682
  position: relative;
@@ -16545,7 +16708,7 @@ ${MARKED}[${TITLE_ATTR}]::after {
16545
16708
  text-overflow: ellipsis;
16546
16709
  pointer-events: none;
16547
16710
  }
16548
- ${Object.entries(uris).map(([channel4, uri]) => `[${CHANNEL_ATTR}="${channel4}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
16711
+ ${Object.entries(uris).map(([channel5, uri]) => `[${CHANNEL_ATTR}="${channel5}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
16549
16712
  `;
16550
16713
  document2.head.appendChild(style);
16551
16714
  const restore = (title) => {
@@ -16628,12 +16791,12 @@ ${Object.entries(uris).map(([channel4, uri]) => `[${CHANNEL_ATTR}="${channel4}"]
16628
16791
  attributes: true,
16629
16792
  attributeFilter: ["class", "role", "aria-selected", "contenteditable"]
16630
16793
  });
16631
- for (const [channel4, uri] of Object.entries(uris)) {
16794
+ for (const [channel5, uri] of Object.entries(uris)) {
16632
16795
  const image = new view.Image();
16633
16796
  images.push(image);
16634
16797
  image.onload = () => {
16635
16798
  if (closed) return;
16636
- ready.add(channel4);
16799
+ ready.add(channel5);
16637
16800
  collect(document2.body, true);
16638
16801
  };
16639
16802
  image.src = uri;
@@ -16674,7 +16837,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
16674
16837
  }
16675
16838
 
16676
16839
  // plugin-src/client/update-panel.js
16677
- var React27 = __toESM(require("react"), 1);
16840
+ var React28 = __toESM(require("react"), 1);
16678
16841
  var import_react_dom3 = require("react-dom");
16679
16842
  var import_valid = __toESM(require_valid(), 1);
16680
16843
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -16721,7 +16884,7 @@ function unwrapSnapshot(result) {
16721
16884
  }
16722
16885
  return value;
16723
16886
  }
16724
- function presentError13(error) {
16887
+ function presentError14(error) {
16725
16888
  const code = error?.rpcError?.code ?? error?.code ?? "";
16726
16889
  const message = error?.rpcError?.message ?? error?.message ?? "";
16727
16890
  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 +16927,11 @@ function manualUpdateCommand(snapshot) {
16764
16927
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
16765
16928
  }
16766
16929
  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(() => {
16930
+ const [copyState, setCopyState] = React28.useState("idle");
16931
+ const commandRef = React28.useRef(null);
16932
+ const mounted = React28.useRef(false);
16933
+ const copying = React28.useRef(false);
16934
+ React28.useEffect(() => {
16772
16935
  mounted.current = true;
16773
16936
  return () => {
16774
16937
  mounted.current = false;
@@ -16800,7 +16963,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16800
16963
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
16801
16964
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
16802
16965
  command ? h2(
16803
- React27.Fragment,
16966
+ React28.Fragment,
16804
16967
  null,
16805
16968
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
16806
16969
  h2(
@@ -16836,7 +16999,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16836
16999
  "aria-hidden": "true",
16837
17000
  focusable: "false"
16838
17001
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
16839
- React27.Fragment,
17002
+ React28.Fragment,
16840
17003
  null,
16841
17004
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
16842
17005
  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 +17024,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
16861
17024
  );
16862
17025
  }
16863
17026
  function UpdateDialog({ children, onClose }) {
16864
- const dialogRef = React27.useRef(null);
16865
- const titleId = React27.useId();
16866
- const descriptionId = React27.useId();
16867
- React27.useEffect(() => {
17027
+ const dialogRef = React28.useRef(null);
17028
+ const titleId = React28.useId();
17029
+ const descriptionId = React28.useId();
17030
+ React28.useEffect(() => {
16868
17031
  const previous = globalThis.document?.activeElement;
16869
17032
  dialogRef.current?.focus?.();
16870
17033
  return () => {
@@ -16922,19 +17085,19 @@ function UpdateDialog({ children, onClose }) {
16922
17085
  return typeof document !== "undefined" && document.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
16923
17086
  }
16924
17087
  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);
17088
+ const [snapshot, setSnapshot] = React28.useState(null);
17089
+ const [action, setAction] = React28.useState("status");
17090
+ const [error, setError] = React28.useState(null);
17091
+ const [open, setOpen] = React28.useState(false);
17092
+ const [uncertainInstall, setUncertainInstall] = React28.useState(false);
17093
+ const mounted = React28.useRef(false);
17094
+ const busy = React28.useRef(false);
17095
+ const readController = React28.useRef(null);
17096
+ const pollReadController = React28.useRef(null);
17097
+ const installRequest = React28.useRef(null);
17098
+ const onStatusRef = React28.useRef(onStatus);
16936
17099
  onStatusRef.current = onStatus;
16937
- const accept = React27.useCallback((next) => {
17100
+ const accept = React28.useCallback((next) => {
16938
17101
  setSnapshot(next);
16939
17102
  onStatusRef.current?.(next);
16940
17103
  }, []);
@@ -16943,7 +17106,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16943
17106
  setUncertainInstall(false);
16944
17107
  accept(next);
16945
17108
  };
16946
- const invoke = React27.useCallback(async (endpoint, payload = {}, signal) => {
17109
+ const invoke = React28.useCallback(async (endpoint, payload = {}, signal) => {
16947
17110
  if (typeof rpcCall !== "function") {
16948
17111
  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
17112
  unavailable.code = "update-unavailable";
@@ -16951,14 +17114,14 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16951
17114
  }
16952
17115
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
16953
17116
  }, [rpcCall]);
16954
- React27.useEffect(() => {
17117
+ React28.useEffect(() => {
16955
17118
  mounted.current = true;
16956
17119
  busy.current = true;
16957
17120
  const controller = new AbortController();
16958
17121
  void invoke("update.status", {}, controller.signal).then((next) => {
16959
17122
  if (!controller.signal.aborted) accept(next);
16960
17123
  }).catch((cause) => {
16961
- if (!controller.signal.aborted) setError(presentError13(cause));
17124
+ if (!controller.signal.aborted) setError(presentError14(cause));
16962
17125
  }).finally(() => {
16963
17126
  if (!controller.signal.aborted) {
16964
17127
  busy.current = false;
@@ -16974,7 +17137,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16974
17137
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
16975
17138
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
16976
17139
  const shouldPoll = activeJob || uncertainInstall;
16977
- React27.useEffect(() => {
17140
+ React28.useEffect(() => {
16978
17141
  if (!shouldPoll) return void 0;
16979
17142
  let controller;
16980
17143
  const scheduler = createPollScheduler({
@@ -16995,7 +17158,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
16995
17158
  keepPolling = ACTIVE_STATES4.has(next.job?.state);
16996
17159
  }
16997
17160
  } catch (cause) {
16998
- if (!pendingController.signal.aborted) setError(presentError13(cause));
17161
+ if (!pendingController.signal.aborted) setError(presentError14(cause));
16999
17162
  } finally {
17000
17163
  if (pollReadController.current === pendingController) pollReadController.current = null;
17001
17164
  }
@@ -17026,7 +17189,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17026
17189
  else acceptAuthoritative(next);
17027
17190
  }
17028
17191
  } catch (cause) {
17029
- if (!controller.signal.aborted && mounted.current) setError(presentError13(cause));
17192
+ if (!controller.signal.aborted && mounted.current) setError(presentError14(cause));
17030
17193
  } finally {
17031
17194
  if (!controller.signal.aborted && mounted.current) {
17032
17195
  busy.current = false;
@@ -17052,7 +17215,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17052
17215
  if (mounted.current) acceptAuthoritative(next);
17053
17216
  } catch (cause) {
17054
17217
  if (mounted.current) {
17055
- setError(presentError13(cause));
17218
+ setError(presentError14(cause));
17056
17219
  setUncertainInstall(true);
17057
17220
  }
17058
17221
  } finally {
@@ -17072,7 +17235,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17072
17235
  const manualCommand = manualUpdateCommand(snapshot);
17073
17236
  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
17237
  return h2(
17075
- React27.Fragment,
17238
+ React28.Fragment,
17076
17239
  null,
17077
17240
  h2("button", {
17078
17241
  type: "button",
@@ -17097,13 +17260,13 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
17097
17260
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
17098
17261
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
17099
17262
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
17100
- React27.Fragment,
17263
+ React28.Fragment,
17101
17264
  null,
17102
17265
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
17103
17266
  h2("dd", null, `v${snapshot.installedVersion}`)
17104
17267
  ) : null,
17105
17268
  targetVersion ? h2(
17106
- React27.Fragment,
17269
+ React28.Fragment,
17107
17270
  null,
17108
17271
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
17109
17272
  h2("dd", null, `v${targetVersion}`)
@@ -17194,6 +17357,7 @@ var CHANNELS = Object.freeze([
17194
17357
  { id: "discord", label: "Discord" },
17195
17358
  { id: "whatsapp", label: "WhatsApp" },
17196
17359
  { id: "wecomApp", label: "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
17360
+ { id: "imessage", label: "iMessage", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
17197
17361
  { id: "office", label: "AI Office", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" }
17198
17362
  ]);
17199
17363
  function WeixinLogo() {
@@ -17254,6 +17418,13 @@ function WhatsappLogo() {
17254
17418
  h2(WhatsappLogoGlyph)
17255
17419
  );
17256
17420
  }
17421
+ function IMessageLogo() {
17422
+ return h2(
17423
+ "span",
17424
+ { className: "dim-logo dim-logoIMessage", "aria-hidden": "true" },
17425
+ h2(IMessageLogoGlyph)
17426
+ );
17427
+ }
17257
17428
  function OfficeLogo() {
17258
17429
  return h2(
17259
17430
  "span",
@@ -17261,17 +17432,18 @@ function OfficeLogo() {
17261
17432
  h2(OfficeLogoGlyph)
17262
17433
  );
17263
17434
  }
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);
17435
+ function ChannelLogo({ channel: channel5 }) {
17436
+ if (channel5 === "weixin") return h2(WeixinLogo);
17437
+ if (channel5 === "feishu") return h2(FeishuLogo);
17438
+ if (channel5 === "dingtalk") return h2(DingtalkLogo);
17439
+ if (channel5 === "wecom") return h2(WecomLogo);
17440
+ if (channel5 === "wecomApp") return h2(WecomAppLogo);
17441
+ if (channel5 === "qq") return h2(QqLogo);
17442
+ if (channel5 === "slack") return h2(SlackLogo);
17443
+ if (channel5 === "telegram") return h2(TelegramLogo);
17444
+ if (channel5 === "discord") return h2(DiscordLogo);
17445
+ if (channel5 === "whatsapp") return h2(WhatsappLogo);
17446
+ if (channel5 === "imessage") return h2(IMessageLogo);
17275
17447
  return h2(OfficeLogo);
17276
17448
  }
17277
17449
  function LoopbackRecoveryNotice({ recovery, onNavigate = replacePageLocation }) {
@@ -17299,6 +17471,7 @@ function IMSettingsTab({
17299
17471
  dingtalkRpcCall,
17300
17472
  discordRpcCall,
17301
17473
  feishuRpcCall,
17474
+ imessageRpcCall,
17302
17475
  qqRpcCall,
17303
17476
  slackRpcCall,
17304
17477
  telegramRpcCall,
@@ -17314,23 +17487,23 @@ function IMSettingsTab({
17314
17487
  browserLocation = globalThis.location,
17315
17488
  navigateToRecoveryUrl = replacePageLocation
17316
17489
  }) {
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();
17490
+ const [selected, setSelected] = React29.useState("weixin");
17491
+ const [loopbackRecovery, setLoopbackRecovery] = React29.useState(null);
17492
+ const [runningVersion, setRunningVersion] = React29.useState(IM_PLUGIN_VERSION);
17493
+ const [deliverySettings, setDeliverySettings] = React29.useState(null);
17494
+ const githubTooltipId = React29.useId();
17495
+ const generalSettingsTooltipId = React29.useId();
17323
17496
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
17324
- const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
17497
+ const active = CHANNELS.find((channel5) => channel5.id === selected) ?? CHANNELS[0];
17325
17498
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
17326
17499
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
17327
- const reportLoopbackRecovery = React28.useCallback((recovery) => {
17500
+ const reportLoopbackRecovery = React29.useCallback((recovery) => {
17328
17501
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
17329
17502
  }, []);
17330
- const reportUpdateStatus = React28.useCallback((snapshot) => {
17503
+ const reportUpdateStatus = React29.useCallback((snapshot) => {
17331
17504
  setRunningVersion(snapshot.runningVersion);
17332
17505
  }, []);
17333
- const rpcCalls = React28.useMemo(() => createLoopbackAwareRpcCalls({
17506
+ const rpcCalls = React29.useMemo(() => createLoopbackAwareRpcCalls({
17334
17507
  dingtalkRpcCall,
17335
17508
  discordRpcCall,
17336
17509
  feishuRpcCall,
@@ -17344,7 +17517,8 @@ function IMSettingsTab({
17344
17517
  officeRpcCall,
17345
17518
  updateRpcCall,
17346
17519
  deliveryRpcCall,
17347
- globalSettingsRpcCall
17520
+ globalSettingsRpcCall,
17521
+ imessageRpcCall
17348
17522
  }, {
17349
17523
  location: browserLocation,
17350
17524
  onRecovery: reportLoopbackRecovery
@@ -17355,6 +17529,7 @@ function IMSettingsTab({
17355
17529
  deliveryRpcCall,
17356
17530
  feishuRpcCall,
17357
17531
  globalSettingsRpcCall,
17532
+ imessageRpcCall,
17358
17533
  officeRpcCall,
17359
17534
  qqRpcCall,
17360
17535
  reportLoopbackRecovery,
@@ -17366,7 +17541,7 @@ function IMSettingsTab({
17366
17541
  weixinRpcCall,
17367
17542
  whatsappRpcCall
17368
17543
  ]);
17369
- const botSettingsContext = React28.useMemo(() => Object.freeze({
17544
+ const botSettingsContext = React29.useMemo(() => Object.freeze({
17370
17545
  openBotSettings: setDeliverySettings
17371
17546
  }), []);
17372
17547
  return h2(
@@ -17449,27 +17624,27 @@ function IMSettingsTab({
17449
17624
  h2(
17450
17625
  "nav",
17451
17626
  { className: "dim-rail", role: "tablist", "aria-label": "IM \u8BBE\u7F6E\u5BFC\u822A" },
17452
- CHANNELS.map((channel4) => h2(
17627
+ CHANNELS.map((channel5) => h2(
17453
17628
  "button",
17454
17629
  {
17455
- key: channel4.id,
17630
+ key: channel5.id,
17456
17631
  type: "button",
17457
17632
  role: "tab",
17458
- id: `dim-tab-${channel4.id}`,
17633
+ id: `dim-tab-${channel5.id}`,
17459
17634
  className: "dim-channel",
17460
- "aria-selected": !globalSettingsSelected && channel4.id === active.id,
17461
- "aria-controls": `dim-panel-${channel4.id}`,
17635
+ "aria-selected": !globalSettingsSelected && channel5.id === active.id,
17636
+ "aria-controls": `dim-panel-${channel5.id}`,
17462
17637
  onClick: () => {
17463
- setSelected(channel4.id);
17638
+ setSelected(channel5.id);
17464
17639
  setDeliverySettings(null);
17465
17640
  }
17466
17641
  },
17467
- h2(ChannelLogo, { channel: channel4.id }),
17642
+ h2(ChannelLogo, { channel: channel5.id }),
17468
17643
  h2(
17469
17644
  "span",
17470
17645
  { className: "dim-channelCopy" },
17471
- h2("strong", null, channel4.label),
17472
- channel4.note ? h2("small", { className: "dim-channelNote" }, channel4.note) : null
17646
+ h2("strong", null, channel5.label),
17647
+ channel5.note ? h2("small", { className: "dim-channelNote" }, channel5.note) : null
17473
17648
  )
17474
17649
  ))
17475
17650
  ),
@@ -17495,7 +17670,7 @@ function IMSettingsTab({
17495
17670
  rpcCall: rpcCalls.deliveryRpcCall,
17496
17671
  accessRpcCall: rpcCalls[`${active.id}RpcCall`],
17497
17672
  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 })
17673
+ }) : 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
17674
  )
17500
17675
  )
17501
17676
  )
@@ -17521,6 +17696,7 @@ function apply(ctx) {
17521
17696
  installTelegramStyles(),
17522
17697
  installDiscordStyles(),
17523
17698
  installWhatsappStyles(),
17699
+ installIMessageStyles(),
17524
17700
  installOfficeStyles(),
17525
17701
  installImStyles()
17526
17702
  ];
@@ -17537,6 +17713,7 @@ function apply(ctx) {
17537
17713
  const telegramRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, TELEGRAM_RPC_CHANNEL, endpoint, payload, signal);
17538
17714
  const discordRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, DISCORD_RPC_CHANNEL, endpoint, payload, signal);
17539
17715
  const whatsappRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
17716
+ const imessageRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, IMESSAGE_RPC_CHANNEL, endpoint, payload, signal);
17540
17717
  const slackRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, SLACK_RPC_CHANNEL, endpoint, payload, signal);
17541
17718
  const officeRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, OFFICE_RPC_CHANNEL, endpoint, payload, signal);
17542
17719
  const updateRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, UPDATE_RPC_CHANNEL, endpoint, payload, signal);
@@ -17563,6 +17740,7 @@ function apply(ctx) {
17563
17740
  wecomAppRpcCall,
17564
17741
  weixinRpcCall,
17565
17742
  whatsappRpcCall,
17743
+ imessageRpcCall,
17566
17744
  officeRpcCall,
17567
17745
  updateRpcCall,
17568
17746
  deliveryRpcCall,