@openclaw/imessage 2026.8.1-beta.2 → 2026.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/{accounts-D00Njxg2.js → accounts-CCirBEIm.js} +4 -5
  2. package/dist/{actions.runtime-DTFKDN5p.js → actions.runtime-CAl3WcqD.js} +2 -3
  3. package/dist/api.js +6 -5
  4. package/dist/{approval-handler.runtime-BtLs4gho.js → approval-handler.runtime-UBd1j2Sg.js} +15 -9
  5. package/dist/approval-reactions-LL5yn1Rc.js +562 -0
  6. package/dist/{channel-lppmI51h.js → channel-DNI9DKGN.js} +26 -21
  7. package/dist/channel-config-api.js +1 -1
  8. package/dist/channel-plugin-api.js +1 -1
  9. package/dist/{channel.runtime-5wpCKQb7.js → channel.runtime-HSkrmWfW.js} +58 -11
  10. package/dist/{config-schema-DV0KP5nC.js → config-schema-DuGbA8Kp.js} +8 -7
  11. package/dist/contract-api.js +1 -1
  12. package/dist/doctor-contract-api.js +8 -281
  13. package/dist/{group-policy-DF9xSdik.js → group-policy-Dvc-BcWo.js} +19 -651
  14. package/dist/{media-contract-BEgdvYhW.js → media-contract-D-FhGE98.js} +1 -1
  15. package/dist/media-contract-api.js +1 -1
  16. package/dist/{message-tool-api-CPDfJJoE.js → message-tool-api-CvIgJpOo.js} +7 -4
  17. package/dist/message-tool-api.js +1 -1
  18. package/dist/{monitor-DnxJ8pW9.js → monitor-BywJn1QW.js} +343 -111
  19. package/dist/{question-reactions-DVe50UhB.js → question-reactions-viP7ZcyG.js} +2 -1
  20. package/dist/reaction-context-BAYI7pz0.js +105 -0
  21. package/dist/{remote-file-DLwO9ved.js → remote-file-6mCj2ZBy.js} +7 -3
  22. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  23. package/dist/runtime-Cza4CY5T.js +8 -0
  24. package/dist/runtime-api.js +10 -9
  25. package/dist/{sanitize-outbound-CoTZLXMw.js → sanitize-outbound-Du-r1lNQ.js} +345 -58
  26. package/dist/{send-BUXW76tw.js → send-mgWPKqSV.js} +147 -26
  27. package/dist/state-contract-4TK_cDDb.js +56 -0
  28. package/dist/state-migrations-SFdKp3GQ.js +277 -0
  29. package/node_modules/typebox/build/format/date.d.mts +1 -1
  30. package/node_modules/typebox/build/format/date.mjs +1 -1
  31. package/node_modules/typebox/build/format/date_time.d.mts +2 -2
  32. package/node_modules/typebox/build/format/date_time.mjs +3 -3
  33. package/node_modules/typebox/build/format/email.d.mts +1 -1
  34. package/node_modules/typebox/build/format/email.mjs +2 -2
  35. package/node_modules/typebox/build/format/hostname.mjs +2 -10
  36. package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
  37. package/node_modules/typebox/build/format/idn_email.mjs +3 -3
  38. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
  39. package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
  40. package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
  41. package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
  42. package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
  43. package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
  44. package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
  45. package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
  46. package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
  47. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
  48. package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
  49. package/node_modules/typebox/build/format/idna/index.mjs +2 -0
  50. package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
  51. package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
  52. package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
  53. package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
  54. package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
  55. package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
  56. package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
  57. package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
  58. package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
  59. package/node_modules/typebox/build/format/ipv4.mjs +2 -32
  60. package/node_modules/typebox/build/format/ipv6.mjs +2 -61
  61. package/node_modules/typebox/build/format/iri.d.mts +2 -2
  62. package/node_modules/typebox/build/format/iri.mjs +26 -8
  63. package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
  64. package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
  65. package/node_modules/typebox/build/format/regex.d.mts +1 -2
  66. package/node_modules/typebox/build/format/regex.mjs +2 -6
  67. package/node_modules/typebox/build/format/time.d.mts +2 -2
  68. package/node_modules/typebox/build/format/time.mjs +19 -14
  69. package/node_modules/typebox/build/format/uri.d.mts +1 -1
  70. package/node_modules/typebox/build/format/uri.mjs +3 -130
  71. package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
  72. package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
  73. package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
  74. package/node_modules/typebox/build/format/uri_template.mjs +4 -5
  75. package/node_modules/typebox/build/format/url.d.mts +3 -3
  76. package/node_modules/typebox/build/format/url.mjs +4 -5
  77. package/node_modules/typebox/build/guard/emit.d.mts +3 -1
  78. package/node_modules/typebox/build/guard/emit.mjs +12 -5
  79. package/node_modules/typebox/build/guard/guard.d.mts +8 -2
  80. package/node_modules/typebox/build/guard/guard.mjs +25 -4
  81. package/node_modules/typebox/build/guard/string.d.mts +2 -2
  82. package/node_modules/typebox/build/guard/string.mjs +7 -7
  83. package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
  84. package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
  85. package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
  86. package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
  87. package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
  88. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
  89. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
  90. package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
  91. package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
  92. package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
  93. package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
  94. package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
  95. package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
  96. package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
  97. package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
  98. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
  99. package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
  100. package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
  101. package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
  102. package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
  103. package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
  104. package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
  105. package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
  106. package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
  107. package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
  108. package/node_modules/typebox/build/schema/types/index.mjs +0 -2
  109. package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
  110. package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
  111. package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
  112. package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
  113. package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
  114. package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
  115. package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
  116. package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
  117. package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
  118. package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
  119. package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
  120. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
  121. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
  122. package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
  123. package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
  124. package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
  125. package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
  126. package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
  127. package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
  128. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
  129. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
  130. package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
  131. package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
  132. package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
  133. package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
  134. package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
  135. package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
  136. package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
  137. package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
  138. package/node_modules/typebox/build/type/script/parser.mjs +27 -23
  139. package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
  140. package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
  141. package/node_modules/typebox/package.json +27 -27
  142. package/node_modules/typebox/readme.md +79 -82
  143. package/openclaw.plugin.json +0 -6
  144. package/package.json +5 -5
  145. package/dist/catchup-D32oYNxR.js +0 -294
  146. package/dist/monitor-reply-cache-DKlYGd5x.js +0 -348
  147. package/dist/persisted-echo-cache-BPWGUK-L.js +0 -143
  148. package/node_modules/typebox/build/format/_idna.d.mts +0 -2
  149. package/node_modules/typebox/build/format/_idna.mjs +0 -246
  150. package/node_modules/typebox/build/format/_puny.d.mts +0 -1
  151. package/node_modules/typebox/build/format/_puny.mjs +0 -77
  152. package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
  153. package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
  154. package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
  155. package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
  156. package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
  157. package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
@@ -1,49 +1,28 @@
1
- import { a as resolveDefaultIMessageAccountId, l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-D00Njxg2.js";
2
- import { S as IMESSAGE_ACTION_NAMES, _ as normalizeBareIMessageChatIdentifier, b as setCachedIMessagePrivateApiStatus, l as parseIMessageTarget, s as normalizeIMessageHandle$1, t as describeIMessageMessageTool, v as getCachedIMessagePrivateApiStatus, x as IMESSAGE_ACTIONS, y as imessageRpcSupportsMethod } from "./message-tool-api-CPDfJJoE.js";
3
- import { a as findLatestIMessageEntryForChat, c as rememberIMessageReplyCache, h as chatContextFromIMessageTarget, o as isIMessageCurrentMessageInChat, p as getOptionalIMessageRuntime } from "./monitor-reply-cache-DKlYGd5x.js";
4
- import { o as createIMessageRpcClient } from "./sanitize-outbound-CoTZLXMw.js";
5
- import { createLazyRuntimeNamedExport, createLazyRuntimeSurface } from "openclaw/plugin-sdk/lazy-runtime";
6
- import { collectStatusIssuesFromLastError } from "openclaw/plugin-sdk/status-helpers";
1
+ import { a as resolveDefaultIMessageAccountId, l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-CCirBEIm.js";
2
+ import { d as normalizeBareIMessageChatIdentifier, f as getCachedIMessagePrivateApiStatus, g as IMESSAGE_ACTION_NAMES, h as IMESSAGE_ACTIONS, l as parseIMessageTarget, m as setCachedIMessagePrivateApiStatus, p as imessageRpcSupportsMethod, s as normalizeIMessageHandle$1, t as describeIMessageMessageTool, u as isIMessagePhoneLikeHandle } from "./message-tool-api-CvIgJpOo.js";
3
+ import { c as isIMessageCurrentMessageInChat, h as chatContextFromIMessageTarget, o as createIMessageRpcClient, s as findLatestIMessageEntryForChat, u as rememberIMessageReplyCache } from "./sanitize-outbound-Du-r1lNQ.js";
4
+ import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
7
5
  import path from "node:path";
8
6
  import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
9
7
  import { filterStringEntries, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
10
8
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
11
9
  import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
12
10
  import { createActionGate, jsonResult, readNonNegativeIntegerParam, readPositiveIntegerParam, readReactionParams, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/channel-actions";
11
+ import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
13
12
  import { normalizePollInput } from "openclaw/plugin-sdk/poll-runtime";
14
13
  import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
15
- import { asDateTimestampMs, isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
14
+ import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
16
15
  import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
17
16
  import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
18
17
  import { detectBinary } from "openclaw/plugin-sdk/setup";
19
18
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
20
- import { isApprovalNotFoundError } from "openclaw/plugin-sdk/error-runtime";
21
19
  import { parseAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
22
20
  import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
23
21
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
24
22
  import { createCliPathTextInput, createDelegatedSetupWizardProxy, createDelegatedTextInputShouldPrompt, createPatchedAccountSetupAdapter, createSetupTranslator, promptParsedAllowFromForAccount, setAccountAllowFromForChannel, setSetupChannelEnabled as setSetupChannelEnabled$1 } from "openclaw/plugin-sdk/setup-runtime";
25
23
  import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
26
24
  import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
27
- import { addApprovalReactionHintToText, approvalReactionDecisionSetsMatch, buildApprovalReactionHint, createApprovalReactionTargetStore, extractApprovalReactionPromptBinding, hasApprovalReactionHintText, listApprovalReactionBindings, normalizeApprovalReactionDecision, readApprovalReactionDeliveredBinding, readApprovalReactionPresentationBinding, resolveTypedApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
28
- import { createPluginStateErrorReporter } from "openclaw/plugin-sdk/plugin-state-runtime";
29
- import { formatTrimmedAllowFromEntries as formatTrimmedAllowFromEntries$1 } from "openclaw/plugin-sdk/channel-config-helpers";
30
- import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
31
- import { DEFAULT_ACCOUNT_ID, getChatChannelMeta } from "openclaw/plugin-sdk/core";
32
- import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
33
- import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
34
25
  import { buildChannelGroupsScopeTree, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
35
- //#region \0rolldown/runtime.js
36
- var __defProp = Object.defineProperty;
37
- var __exportAll = (all, no_symbols) => {
38
- let target = {};
39
- for (var name in all) __defProp(target, name, {
40
- get: all[name],
41
- enumerable: true
42
- });
43
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
44
- return target;
45
- };
46
- //#endregion
47
26
  //#region extensions/imessage/src/message-action-reference.ts
48
27
  async function resolveAuthorizedIMessageActionReference(params) {
49
28
  const options = {
@@ -540,7 +519,7 @@ async function probeIMessage(timeoutMs, opts = {}) {
540
519
  }
541
520
  //#endregion
542
521
  //#region extensions/imessage/src/actions.ts
543
- const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-DTFKDN5p.js"), "imessageActionsRuntime");
522
+ const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-CAl3WcqD.js"), "imessageActionsRuntime");
544
523
  const log = createSubsystemLogger("channels/imessage");
545
524
  const providerId = "imessage";
546
525
  const SUPPORTED_ACTIONS = /* @__PURE__ */ new Set([...IMESSAGE_ACTION_NAMES, "upload-file"]);
@@ -701,7 +680,9 @@ function mapTapbackReaction(emoji) {
701
680
  function decodeBase64Buffer(params, action) {
702
681
  const base64Buffer = readStringParam(params, "buffer");
703
682
  if (!base64Buffer) throw new Error(`iMessage ${action} requires buffer (base64) parameter.`);
704
- return Uint8Array.from(Buffer.from(base64Buffer, "base64"));
683
+ const canonical = canonicalizeBase64(base64Buffer.replaceAll("-", "+").replaceAll("_", "/"));
684
+ if (!canonical) throw new Error(`iMessage ${action} buffer must be valid base64.`);
685
+ return Uint8Array.from(Buffer.from(canonical, "base64"));
705
686
  }
706
687
  const REPLY_ATTACHMENT_PATH_PARAM_NAMES = [
707
688
  "filePath",
@@ -711,13 +692,12 @@ const REPLY_ATTACHMENT_PATH_PARAM_NAMES = [
711
692
  "fileUrl"
712
693
  ];
713
694
  function extractReplyAttachment(params) {
714
- const buffer = readStringParam(params, "buffer");
715
- if (buffer) {
695
+ if (readStringParam(params, "buffer")) {
716
696
  const filename = readStringParam(params, "filename") ?? "attachment.bin";
717
697
  return {
718
698
  spec: {
719
699
  kind: "buffer",
720
- buffer: Uint8Array.from(Buffer.from(buffer, "base64")),
700
+ buffer: decodeBase64Buffer(params, "reply attachment"),
721
701
  filename
722
702
  },
723
703
  sourceParam: "buffer"
@@ -1093,7 +1073,7 @@ const imessageMessageActions = {
1093
1073
  if (action === "sendAttachment" || action === "upload-file") {
1094
1074
  await assertPrivateApiEnabled();
1095
1075
  const filename = readStringParam(params, "filename", { required: true });
1096
- const asVoice = readBooleanParam(params, "asVoice") ?? readBooleanParam(params, "as_voice");
1076
+ const asVoice = readBooleanParam(params, "asVoice");
1097
1077
  const resolvedChatGuid = await chatGuid();
1098
1078
  const result = await runtime.sendAttachment({
1099
1079
  chatGuid: resolvedChatGuid,
@@ -1213,608 +1193,6 @@ const imessageApproval = createChannelApprovalAuth({
1213
1193
  const getIMessageApprovalApprovers = imessageApproval.resolveApprovers;
1214
1194
  const imessageApprovalAuth = imessageApproval.approvalAuth;
1215
1195
  //#endregion
1216
- //#region extensions/imessage/src/approval-target-keys.ts
1217
- /** Strip the `p:<n>/` part prefix Messages puts on some GUIDs so keys match. */
1218
- function normalizeIMessageGuid(value) {
1219
- return value.trim().replace(/^p:\d+\//iu, "");
1220
- }
1221
- function chatIdToKeyValue(chatId) {
1222
- if (chatId == null || chatId === "") return null;
1223
- if (typeof chatId === "number") return Number.isFinite(chatId) && chatId > 0 ? String(chatId) : null;
1224
- return chatId.trim() || null;
1225
- }
1226
- function enumerateConversationKeyForms(conversation) {
1227
- const forms = [];
1228
- const chatGuid = conversation.chatGuid?.trim();
1229
- if (chatGuid) forms.push(`chat_guid:${chatGuid}`);
1230
- const chatIdentifier = conversation.chatIdentifier?.trim();
1231
- if (chatIdentifier) forms.push(`chat_identifier:${chatIdentifier}`);
1232
- const chatIdValue = chatIdToKeyValue(conversation.chatId);
1233
- if (chatIdValue) forms.push(`chat_id:${chatIdValue}`);
1234
- const handle = conversation.handle?.trim();
1235
- if (handle) forms.push(`handle:${handle}`);
1236
- return forms;
1237
- }
1238
- function normalizeConversationKey(conversation) {
1239
- return enumerateConversationKeyForms(conversation)[0];
1240
- }
1241
- /**
1242
- * Index a binding under every key derivable from the conversation. Outbound and
1243
- * inbound disagree about which key exists: send may only know
1244
- * `{handle: "+1..."}` for a DM, while the bridge populates chat_guid on the
1245
- * inbound event. Enumerating all forms keeps the two symmetric without making
1246
- * callers guess which one the bridge will pick.
1247
- */
1248
- function enumerateApprovalTargetKeys(params) {
1249
- const accountId = params.accountId.trim();
1250
- const messageId = params.messageId.trim();
1251
- if (!accountId || !messageId) return [];
1252
- return enumerateConversationKeyForms(params.conversation).map((form) => `${accountId}:${form}:${messageId}`);
1253
- }
1254
- function buildIMessageApprovalConversationKeyForTarget(to) {
1255
- try {
1256
- const target = parseIMessageTarget(to);
1257
- if (target.kind === "chat_id") return { chatId: target.chatId };
1258
- if (target.kind === "chat_guid") return { chatGuid: target.chatGuid };
1259
- if (target.kind === "chat_identifier") return { chatIdentifier: target.chatIdentifier };
1260
- const handle = normalizeIMessageHandle$1(target.to);
1261
- return handle ? { handle } : null;
1262
- } catch {
1263
- return null;
1264
- }
1265
- }
1266
- /** Conversation key for an inbound event, mirroring the outbound key forms. */
1267
- function buildIMessageApprovalConversationKeyForInbound(params) {
1268
- return {
1269
- ...params.chatGuid?.trim() ? { chatGuid: params.chatGuid.trim() } : {},
1270
- ...params.chatIdentifier?.trim() ? { chatIdentifier: params.chatIdentifier.trim() } : {},
1271
- ...chatIdToKeyValue(params.chatId ?? void 0) ? { chatId: params.chatId } : {},
1272
- ...params.isGroup ? {} : { handle: params.actorHandle }
1273
- };
1274
- }
1275
- //#endregion
1276
- //#region extensions/imessage/src/monitor/reaction-context.ts
1277
- const TAPBACK_TEXT_PATTERNS = [
1278
- {
1279
- prefix: "loved",
1280
- action: "added",
1281
- emoji: "❤️"
1282
- },
1283
- {
1284
- prefix: "liked",
1285
- action: "added",
1286
- emoji: "👍"
1287
- },
1288
- {
1289
- prefix: "disliked",
1290
- action: "added",
1291
- emoji: "👎"
1292
- },
1293
- {
1294
- prefix: "laughed at",
1295
- action: "added",
1296
- emoji: "😂"
1297
- },
1298
- {
1299
- prefix: "emphasized",
1300
- action: "added",
1301
- emoji: "‼️"
1302
- },
1303
- {
1304
- prefix: "questioned",
1305
- action: "added",
1306
- emoji: "❓"
1307
- },
1308
- {
1309
- prefix: "removed a heart from",
1310
- action: "removed",
1311
- emoji: "❤️"
1312
- },
1313
- {
1314
- prefix: "removed a like from",
1315
- action: "removed",
1316
- emoji: "👍"
1317
- },
1318
- {
1319
- prefix: "removed a dislike from",
1320
- action: "removed",
1321
- emoji: "👎"
1322
- },
1323
- {
1324
- prefix: "removed a laugh from",
1325
- action: "removed",
1326
- emoji: "😂"
1327
- },
1328
- {
1329
- prefix: "removed an emphasis from",
1330
- action: "removed",
1331
- emoji: "‼️"
1332
- },
1333
- {
1334
- prefix: "removed a question from",
1335
- action: "removed",
1336
- emoji: "❓"
1337
- }
1338
- ];
1339
- function normalizeReactionValue(value) {
1340
- return typeof value === "string" ? value.trim().replace(/^p:\d+\//iu, "") || void 0 : void 0;
1341
- }
1342
- function resolveReactionTargetGuidCandidates(...values) {
1343
- const candidates = [];
1344
- for (const value of values) {
1345
- if (typeof value !== "string") continue;
1346
- const raw = value.trim();
1347
- if (!raw) continue;
1348
- const normalized = raw.replace(/^p:\d+\//iu, "");
1349
- for (const candidate of [normalized, raw]) if (candidate && !candidates.includes(candidate)) candidates.push(candidate);
1350
- }
1351
- return candidates;
1352
- }
1353
- function resolveTapbackTextContext(bodyText) {
1354
- const lower = bodyText.toLowerCase();
1355
- for (const pattern of TAPBACK_TEXT_PATTERNS) {
1356
- if (!lower.startsWith(pattern.prefix)) continue;
1357
- const afterPrefix = bodyText.slice(pattern.prefix.length).trim();
1358
- if (!/^["“]/u.test(afterPrefix)) continue;
1359
- return {
1360
- action: pattern.action,
1361
- emoji: pattern.emoji,
1362
- targetText: afterPrefix.replace(/^["“]/u, "").replace(/["”]$/u, "").trim()
1363
- };
1364
- }
1365
- return null;
1366
- }
1367
- function resolveIMessageReactionContext(message, bodyText) {
1368
- if (message.is_reaction === true || message.is_tapback === true || typeof message.associated_message_type === "number" && Number.isFinite(message.associated_message_type) && message.associated_message_type >= 2e3 && message.associated_message_type < 4e3) {
1369
- const targetGuids = resolveReactionTargetGuidCandidates(message.reacted_to_guid, message.associated_message_guid);
1370
- return {
1371
- action: message.is_reaction_add === false ? "removed" : "added",
1372
- emoji: normalizeReactionValue(message.reaction_emoji) ?? normalizeReactionValue(message.reaction_type) ?? "reaction",
1373
- targetGuid: targetGuids[0],
1374
- targetGuids
1375
- };
1376
- }
1377
- return resolveTapbackTextContext(bodyText);
1378
- }
1379
- //#endregion
1380
- //#region extensions/imessage/src/approval-reactions.ts
1381
- var approval_reactions_exports = /* @__PURE__ */ __exportAll({
1382
- addIMessageApprovalReactionHintToStructuredPayload: () => addIMessageApprovalReactionHintToStructuredPayload,
1383
- addIMessageApprovalReactionHintToText: () => addIMessageApprovalReactionHintToText,
1384
- appendIMessageApprovalReactionHintForOutboundMessage: () => appendIMessageApprovalReactionHintForOutboundMessage,
1385
- buildIMessageApprovalConversationKeyForTarget: () => buildIMessageApprovalConversationKeyForTarget,
1386
- buildIMessageApprovalReactionHint: () => buildIMessageApprovalReactionHint,
1387
- clearIMessageApprovalReactionTargetsForTest: () => clearIMessageApprovalReactionTargetsForTest,
1388
- extractIMessageApprovalPromptBinding: () => extractIMessageApprovalPromptBinding,
1389
- handleIMessageApprovalReaction: () => handleIMessageApprovalReaction,
1390
- listPendingIMessageApprovalReactionPollTargets: () => listPendingIMessageApprovalReactionPollTargets,
1391
- maybeResolveIMessageApprovalReaction: () => maybeResolveIMessageApprovalReaction,
1392
- registerIMessageApprovalReactionTarget: () => registerIMessageApprovalReactionTarget,
1393
- registerIMessageApprovalReactionTargetForDeliveredPayload: () => registerIMessageApprovalReactionTargetForDeliveredPayload,
1394
- registerIMessageApprovalReactionTargetForOutboundMessage: () => registerIMessageApprovalReactionTargetForOutboundMessage,
1395
- resolveIMessageApprovalReactionTargetWithPersistence: () => resolveIMessageApprovalReactionTargetWithPersistence,
1396
- unregisterIMessageApprovalReactionTarget: () => unregisterIMessageApprovalReactionTarget
1397
- });
1398
- const PERSISTENT_NAMESPACE = "imessage.approval-reactions";
1399
- const PERSISTENT_MAX_ENTRIES = 1e3;
1400
- const DEFAULT_REACTION_TARGET_TTL_MS = 1440 * 60 * 1e3;
1401
- const loadResolveApprovalOverGateway = createLazyRuntimeSurface(() => import("openclaw/plugin-sdk/approval-gateway-runtime"), (runtime) => runtime.resolveApprovalOverGateway);
1402
- const pendingReactionPollTargets = /* @__PURE__ */ new Map();
1403
- function prunePendingReactionPollTargets(nowMs = Date.now()) {
1404
- for (const [key, target] of pendingReactionPollTargets.entries()) if (!isFutureDateTimestampMs(target.expiresAtMs, { nowMs })) pendingReactionPollTargets.delete(key);
1405
- }
1406
- function resolvePendingReactionPollExpiry(ttlMs) {
1407
- const nowMs = asDateTimestampMs(Date.now());
1408
- if (nowMs === void 0) return;
1409
- const expiresAtMs = resolveExpiresAtMsFromDurationMs(ttlMs ?? DEFAULT_REACTION_TARGET_TTL_MS, { nowMs }) ?? resolveExpiresAtMsFromDurationMs(DEFAULT_REACTION_TARGET_TTL_MS, { nowMs });
1410
- if (expiresAtMs === void 0) return;
1411
- return {
1412
- ttlMs: expiresAtMs - nowMs,
1413
- expiresAtMs
1414
- };
1415
- }
1416
- function mergePollTargetConversation(left, right) {
1417
- return {
1418
- chatGuid: left.chatGuid ?? right.chatGuid,
1419
- chatIdentifier: left.chatIdentifier ?? right.chatIdentifier,
1420
- chatId: left.chatId ?? right.chatId,
1421
- handle: left.handle ?? right.handle
1422
- };
1423
- }
1424
- function listPendingIMessageApprovalReactionPollTargets(params) {
1425
- const accountId = params.accountId.trim();
1426
- if (!accountId) return [];
1427
- prunePendingReactionPollTargets();
1428
- const targetByApprovalAndMessage = /* @__PURE__ */ new Map();
1429
- for (const target of pendingReactionPollTargets.values()) {
1430
- if (target.accountId !== accountId) continue;
1431
- const key = `${target.approvalId}:${normalizeIMessageGuid(target.messageId)}`;
1432
- const existing = targetByApprovalAndMessage.get(key);
1433
- if (!existing) {
1434
- targetByApprovalAndMessage.set(key, target);
1435
- continue;
1436
- }
1437
- targetByApprovalAndMessage.set(key, {
1438
- ...existing,
1439
- conversation: mergePollTargetConversation(existing.conversation, target.conversation),
1440
- expiresAtMs: Math.max(existing.expiresAtMs, target.expiresAtMs)
1441
- });
1442
- }
1443
- return [...targetByApprovalAndMessage.values()];
1444
- }
1445
- const reportPersistentApprovalReactionError = createPluginStateErrorReporter(getOptionalIMessageRuntime, "imessage", "approval-reaction-state", "iMessage persistent approval reaction state failed");
1446
- function reportApprovalBindingCorrelationMismatch(binding) {
1447
- try {
1448
- getOptionalIMessageRuntime()?.logging.getChildLogger({
1449
- plugin: "imessage",
1450
- feature: "approval-reaction-state"
1451
- }).warn("iMessage approval prompt text failed binding correlation; tapbacks disabled", {
1452
- approvalId: binding.approvalId,
1453
- approvalKind: binding.approvalKind
1454
- });
1455
- } catch {}
1456
- }
1457
- function readPersistedTarget(value) {
1458
- const target = value;
1459
- if (!target || typeof target.approvalId !== "string" || !Array.isArray(target.allowedDecisions) || target.approvalKind !== "exec" && target.approvalKind !== "plugin") return null;
1460
- const allowedDecisions = target.allowedDecisions.map((valueValue) => typeof valueValue === "string" ? normalizeApprovalReactionDecision(valueValue) : null).filter((valueLocal) => Boolean(valueLocal));
1461
- if (allowedDecisions.length === 0) return null;
1462
- return {
1463
- approvalId: target.approvalId,
1464
- approvalKind: target.approvalKind,
1465
- allowedDecisions
1466
- };
1467
- }
1468
- const imessageApprovalReactionTargets = createApprovalReactionTargetStore({
1469
- namespace: PERSISTENT_NAMESPACE,
1470
- maxEntries: PERSISTENT_MAX_ENTRIES,
1471
- defaultTtlMs: DEFAULT_REACTION_TARGET_TTL_MS,
1472
- openStore: (params) => getOptionalIMessageRuntime()?.state.openKeyedStore(params),
1473
- logPersistentError: reportPersistentApprovalReactionError,
1474
- readPersistedTarget
1475
- });
1476
- function listIMessageApprovalReactionBindings(allowedDecisions) {
1477
- return listApprovalReactionBindings({ allowedDecisions });
1478
- }
1479
- function buildIMessageApprovalReactionHint(allowedDecisions) {
1480
- return buildApprovalReactionHint({ allowedDecisions });
1481
- }
1482
- function addIMessageApprovalReactionHintToText(params) {
1483
- return addApprovalReactionHintToText(params);
1484
- }
1485
- function appendIMessageApprovalReactionHintForOutboundMessage(text) {
1486
- if (hasApprovalReactionHintText(text)) return text;
1487
- const binding = extractIMessageApprovalPromptBinding(text);
1488
- if (!binding) return text;
1489
- return addIMessageApprovalReactionHintToText({
1490
- text,
1491
- allowedDecisions: binding.allowedDecisions
1492
- });
1493
- }
1494
- const IMESSAGE_APPROVAL_DELIVERY_BINDING_KEY = "imessageApprovalReactionBindingV1";
1495
- function visibleApprovalBindingMatches(text, binding, options) {
1496
- if (!text) return false;
1497
- const lines = text.split(/\r?\n/).map((line) => line.replace(/\*\*/g, "").trim());
1498
- const normalizedHeaders = lines.map((line) => line.replace(/^[^A-Za-z0-9]*/, ""));
1499
- const hasKindHeader = binding.approvalKind === "exec" ? lines.includes("Approval required.") || normalizedHeaders.some((line) => /^Exec approval required$/i.test(line)) : normalizedHeaders.some((line) => /^Plugin approval required$/i.test(line));
1500
- const hasId = lines.includes(`ID: ${binding.approvalId}`) || lines.includes(`Full id: \`${binding.approvalId}\``) || lines.includes(`Full id: ${binding.approvalId}`);
1501
- if (!hasKindHeader || !hasId) return false;
1502
- const visibleDecisions = [];
1503
- for (const line of lines) {
1504
- const match = line.match(APPROVE_COMMAND_LINE_RE);
1505
- const approvalId = match?.[1];
1506
- const decisionsText = match?.[2];
1507
- if (!approvalId || !decisionsText || approvalId !== binding.approvalId && approvalId !== binding.approvalSlug) continue;
1508
- for (const token of decisionsText.split(/[\s|,]+/)) {
1509
- const decision = normalizeApprovalReactionDecision(token);
1510
- if (decision && !visibleDecisions.includes(decision)) visibleDecisions.push(decision);
1511
- }
1512
- }
1513
- if (!approvalReactionDecisionSetsMatch(binding.allowedDecisions, visibleDecisions)) return false;
1514
- if (!options.requireReactionHint) return true;
1515
- const hint = buildIMessageApprovalReactionHint(binding.allowedDecisions);
1516
- return Boolean(hint && text.includes(hint));
1517
- }
1518
- /** Preserve a validated typed approval binding until the iMessage GUID is known. */
1519
- function addIMessageApprovalReactionHintToStructuredPayload(params) {
1520
- const metadata = readApprovalReactionPresentationBinding({
1521
- payload: params.payload,
1522
- requireApprovalSlug: true,
1523
- trimApprovalId: true
1524
- });
1525
- const text = params.payload.text;
1526
- if (metadata?.approvalKind !== params.approvalKind || !text) return null;
1527
- if (!visibleApprovalBindingMatches(text, metadata, { requireReactionHint: false })) {
1528
- reportApprovalBindingCorrelationMismatch(metadata);
1529
- return null;
1530
- }
1531
- return {
1532
- ...params.payload,
1533
- text: addIMessageApprovalReactionHintToText({
1534
- text,
1535
- allowedDecisions: metadata.allowedDecisions
1536
- }),
1537
- channelData: {
1538
- ...params.payload.channelData,
1539
- [IMESSAGE_APPROVAL_DELIVERY_BINDING_KEY]: {
1540
- version: 1,
1541
- approvalId: metadata.approvalId,
1542
- approvalSlug: metadata.approvalSlug,
1543
- approvalKind: metadata.approvalKind,
1544
- allowedDecisions: metadata.allowedDecisions
1545
- }
1546
- }
1547
- };
1548
- }
1549
- const APPROVE_COMMAND_LINE_RE = /\/approve(?:@[^\s]+)?\s+([A-Za-z0-9][A-Za-z0-9._:-]*)\s+(.+)$/i;
1550
- function extractIMessageApprovalPromptBinding(text) {
1551
- return extractApprovalReactionPromptBinding({ text });
1552
- }
1553
- function registerIMessageApprovalReactionTarget(params) {
1554
- const approvalId = params.approvalId.trim();
1555
- const allowedDecisions = listIMessageApprovalReactionBindings(params.allowedDecisions).map((binding) => binding.decision);
1556
- if (!approvalId || params.approvalKind !== "exec" && params.approvalKind !== "plugin" || allowedDecisions.length === 0) return null;
1557
- const target = {
1558
- approvalId,
1559
- approvalKind: params.approvalKind,
1560
- allowedDecisions
1561
- };
1562
- const expiry = resolvePendingReactionPollExpiry(params.ttlMs);
1563
- if (!expiry) return null;
1564
- const keys = enumerateApprovalTargetKeys({
1565
- accountId: params.accountId,
1566
- conversation: params.conversation,
1567
- messageId: params.messageId
1568
- });
1569
- if (keys.length === 0) return null;
1570
- for (const key of keys) {
1571
- imessageApprovalReactionTargets.register(key, target, { ttlMs: expiry.ttlMs });
1572
- pendingReactionPollTargets.set(key, {
1573
- accountId: params.accountId,
1574
- conversation: params.conversation,
1575
- messageId: params.messageId,
1576
- approvalId,
1577
- approvalKind: params.approvalKind,
1578
- allowedDecisions,
1579
- expiresAtMs: expiry.expiresAtMs
1580
- });
1581
- }
1582
- prunePendingReactionPollTargets();
1583
- return target;
1584
- }
1585
- function registerIMessageApprovalReactionTargetForOutboundMessage(params) {
1586
- const binding = extractIMessageApprovalPromptBinding(params.text);
1587
- if (!binding || binding.approvalKind !== params.approvalKind) return false;
1588
- return Boolean(registerIMessageApprovalReactionTarget({
1589
- accountId: params.accountId,
1590
- conversation: params.conversation,
1591
- messageId: params.messageId,
1592
- approvalId: binding.approvalId,
1593
- approvalKind: params.approvalKind,
1594
- allowedDecisions: binding.allowedDecisions,
1595
- ttlMs: params.ttlMs
1596
- }));
1597
- }
1598
- function listDeliveredIMessageApprovalGuids(params) {
1599
- const deliveries = [];
1600
- const seen = /* @__PURE__ */ new Set();
1601
- for (const result of params.results) {
1602
- if (result.channel !== "imessage") continue;
1603
- const guid = typeof result.meta?.imessageMessageGuid === "string" ? result.meta.imessageMessageGuid.trim() : "";
1604
- const visibleText = result.meta?.imessageVisibleText;
1605
- if (!guid || /^\d+$/.test(guid) || seen.has(guid) || typeof visibleText !== "string") continue;
1606
- seen.add(guid);
1607
- deliveries.push({
1608
- guid,
1609
- visibleText
1610
- });
1611
- }
1612
- if (!visibleApprovalBindingMatches(deliveries.map((delivery) => delivery.visibleText).join("\n"), params.binding, { requireReactionHint: true })) {
1613
- if (params.results.some((result) => result.channel === "imessage")) reportApprovalBindingCorrelationMismatch(params.binding);
1614
- return [];
1615
- }
1616
- return deliveries.map((delivery) => delivery.guid);
1617
- }
1618
- /** Bind a typed forwarded approval after iMessage returns the stable tapback GUID. */
1619
- function registerIMessageApprovalReactionTargetForDeliveredPayload(params) {
1620
- if (params.target.channel.trim().toLowerCase() !== "imessage") return false;
1621
- const binding = readApprovalReactionDeliveredBinding({
1622
- payload: params.payload,
1623
- channelDataKey: IMESSAGE_APPROVAL_DELIVERY_BINDING_KEY,
1624
- requireApprovalSlug: true,
1625
- trimApprovalId: true
1626
- });
1627
- if (!binding) return false;
1628
- const conversation = buildIMessageApprovalConversationKeyForTarget(params.target.to);
1629
- if (!conversation) return false;
1630
- let registered = false;
1631
- for (const messageId of listDeliveredIMessageApprovalGuids({
1632
- binding,
1633
- results: params.results
1634
- })) registered = Boolean(registerIMessageApprovalReactionTarget({
1635
- accountId: params.accountId,
1636
- conversation,
1637
- messageId,
1638
- approvalId: binding.approvalId,
1639
- approvalKind: binding.approvalKind,
1640
- allowedDecisions: binding.allowedDecisions,
1641
- ttlMs: params.ttlMs
1642
- })) || registered;
1643
- return registered;
1644
- }
1645
- function unregisterIMessageApprovalReactionTarget(params) {
1646
- const keys = enumerateApprovalTargetKeys(params);
1647
- for (const key of keys) {
1648
- imessageApprovalReactionTargets.delete(key);
1649
- pendingReactionPollTargets.delete(key);
1650
- }
1651
- }
1652
- function resolveTarget(params) {
1653
- const target = resolveTypedApprovalReactionTarget(params);
1654
- return target ? {
1655
- approvalId: target.approvalId,
1656
- approvalKind: target.approvalKind,
1657
- decision: target.decision
1658
- } : null;
1659
- }
1660
- function formatCanonicalApprovalTerminalState(approval) {
1661
- const decision = approval.status === "allowed" || approval.status === "denied" ? ` decision=${approval.decision}` : "";
1662
- return `status=${approval.status}${decision} reason=${approval.reason}`;
1663
- }
1664
- async function resolveIMessageApprovalReactionTargetWithPersistence(params) {
1665
- const keys = enumerateApprovalTargetKeys(params);
1666
- for (const key of keys) {
1667
- const target = resolveTarget({
1668
- target: await imessageApprovalReactionTargets.lookup(key),
1669
- reactionKey: params.reactionKey
1670
- });
1671
- if (target) return target;
1672
- }
1673
- return null;
1674
- }
1675
- function readApprovalReactionEvent(message, bodyText) {
1676
- const reaction = resolveIMessageReactionContext(message, bodyText);
1677
- if (!reaction) return null;
1678
- const reactionKey = reaction.emoji.trim();
1679
- const candidates = (reaction.targetGuids ?? []).map((value) => value.trim()).filter((value) => value.length > 0);
1680
- const primary = reaction.targetGuid?.trim() || candidates[0] || "";
1681
- const messageIdCandidates = candidates.length > 0 ? candidates : primary ? [primary] : [];
1682
- const actorHandle = normalizeIMessageHandle$1((message.sender ?? "").trim());
1683
- if (!reactionKey || !primary || !actorHandle) return null;
1684
- const conversation = buildIMessageApprovalConversationKeyForInbound({
1685
- chatGuid: message.chat_guid,
1686
- chatIdentifier: message.chat_identifier,
1687
- chatId: message.chat_id,
1688
- isGroup: message.is_group,
1689
- actorHandle
1690
- });
1691
- if (!normalizeConversationKey(conversation)) return null;
1692
- return {
1693
- conversation,
1694
- messageId: primary,
1695
- messageIdCandidates,
1696
- actorHandle,
1697
- reactionKey,
1698
- action: reaction.action
1699
- };
1700
- }
1701
- async function handleIMessageApprovalReaction(params) {
1702
- const event = readApprovalReactionEvent(params.message, params.bodyText);
1703
- if (!event) return {
1704
- handled: false,
1705
- stopPolling: false
1706
- };
1707
- if (event.action === "removed") return {
1708
- handled: false,
1709
- stopPolling: false
1710
- };
1711
- let target = null;
1712
- let matchedMessageId = null;
1713
- for (const candidate of event.messageIdCandidates) {
1714
- target = await resolveIMessageApprovalReactionTargetWithPersistence({
1715
- accountId: params.accountId,
1716
- conversation: event.conversation,
1717
- messageId: candidate,
1718
- reactionKey: event.reactionKey
1719
- });
1720
- if (target) {
1721
- matchedMessageId = candidate;
1722
- break;
1723
- }
1724
- }
1725
- if (!target) return {
1726
- handled: false,
1727
- stopPolling: false
1728
- };
1729
- if (getIMessageApprovalApprovers({
1730
- cfg: params.cfg,
1731
- accountId: params.accountId
1732
- }).length === 0) {
1733
- params.logVerboseMessage?.(`imessage: approval reaction denied id=${target.approvalId}; reactions require explicit approvers`);
1734
- return {
1735
- handled: true,
1736
- stopPolling: false
1737
- };
1738
- }
1739
- if (!imessageApprovalAuth.authorizeActorAction({
1740
- cfg: params.cfg,
1741
- accountId: params.accountId,
1742
- senderId: event.actorHandle,
1743
- action: "approve",
1744
- approvalKind: target.approvalKind
1745
- }).authorized) {
1746
- params.logVerboseMessage?.(`imessage: approval reaction denied id=${target.approvalId} sender=${event.actorHandle}`);
1747
- return {
1748
- handled: true,
1749
- stopPolling: false
1750
- };
1751
- }
1752
- const resolveApprovalOverGateway = await loadResolveApprovalOverGateway();
1753
- try {
1754
- const result = await resolveApprovalOverGateway({
1755
- cfg: params.cfg,
1756
- approvalId: target.approvalId,
1757
- approvalKind: target.approvalKind,
1758
- decision: target.decision,
1759
- channel: "imessage",
1760
- accountId: params.accountId,
1761
- senderId: event.actorHandle,
1762
- gatewayUrl: params.gatewayUrl,
1763
- ...params.gatewayRuntime ? { gatewayRuntime: params.gatewayRuntime } : {}
1764
- });
1765
- for (const candidate of event.messageIdCandidates) unregisterIMessageApprovalReactionTarget({
1766
- accountId: params.accountId,
1767
- conversation: event.conversation,
1768
- messageId: candidate
1769
- });
1770
- const outcome = result.applied ? "resolved" : "already resolved";
1771
- params.logVerboseMessage?.(`imessage: approval reaction ${outcome} id=${target.approvalId} sender=${event.actorHandle} ${formatCanonicalApprovalTerminalState(result.approval)} via messageId=${matchedMessageId ?? event.messageId}`);
1772
- return {
1773
- handled: true,
1774
- stopPolling: true,
1775
- stopPollingReason: "resolved"
1776
- };
1777
- } catch (error) {
1778
- if (isApprovalNotFoundError(error)) {
1779
- for (const candidate of event.messageIdCandidates) unregisterIMessageApprovalReactionTarget({
1780
- accountId: params.accountId,
1781
- conversation: event.conversation,
1782
- messageId: candidate
1783
- });
1784
- params.logVerboseMessage?.(`imessage: approval reaction ignored for expired approval id=${target.approvalId} sender=${event.actorHandle}`);
1785
- return {
1786
- handled: true,
1787
- stopPolling: true,
1788
- stopPollingReason: "not-found"
1789
- };
1790
- }
1791
- try {
1792
- getOptionalIMessageRuntime()?.logging.getChildLogger({
1793
- plugin: "imessage",
1794
- feature: "approval-reactions"
1795
- }).warn("approval reaction failed", {
1796
- approvalId: target.approvalId,
1797
- senderId: event.actorHandle,
1798
- error: String(error)
1799
- });
1800
- } catch {}
1801
- params.logVerboseMessage?.(`imessage: approval reaction failed id=${target.approvalId} sender=${event.actorHandle}: ${String(error)}`);
1802
- return {
1803
- handled: true,
1804
- stopPolling: true,
1805
- stopPollingReason: "resolver-error"
1806
- };
1807
- }
1808
- }
1809
- async function maybeResolveIMessageApprovalReaction(params) {
1810
- return (await handleIMessageApprovalReaction(params)).handled;
1811
- }
1812
- function clearIMessageApprovalReactionTargetsForTest() {
1813
- imessageApprovalReactionTargets.clearForTest();
1814
- pendingReactionPollTargets.clear();
1815
- loadResolveApprovalOverGateway.clear();
1816
- }
1817
- //#endregion
1818
1196
  //#region extensions/imessage/src/normalize.ts
1819
1197
  const SERVICE_PREFIXES = [
1820
1198
  "imessage:",
@@ -1822,14 +1200,7 @@ const SERVICE_PREFIXES = [
1822
1200
  "auto:"
1823
1201
  ];
1824
1202
  const CHAT_TARGET_PREFIX_RE = /^(chat_id:|chatid:|chat:|chat_guid:|chatguid:|guid:|chat_identifier:|chatidentifier:|chatident:)/i;
1825
- function looksLikeHandleOrPhoneTarget(params) {
1826
- const trimmed = params.raw.trim();
1827
- if (!trimmed) return false;
1828
- if (params.prefixPattern.test(trimmed)) return true;
1829
- if (trimmed.includes("@")) return true;
1830
- return (params.phonePattern ?? /^\+?\d{3,}$/).test(trimmed);
1831
- }
1832
- function normalizeIMessageHandle(raw) {
1203
+ function normalizeIMessageHandle(raw, allowContactName = false) {
1833
1204
  const trimmed = raw.trim();
1834
1205
  if (!trimmed) return "";
1835
1206
  const lowered = normalizeLowercaseStringOrEmpty(trimmed);
@@ -1845,16 +1216,16 @@ function normalizeIMessageHandle(raw) {
1845
1216
  if (trimmed.includes("@")) return normalizeLowercaseStringOrEmpty(trimmed);
1846
1217
  const bareChatIdentifier = normalizeBareIMessageChatIdentifier(trimmed);
1847
1218
  if (bareChatIdentifier) return `chat_identifier:${bareChatIdentifier}`;
1848
- const normalized = normalizeE164(trimmed);
1219
+ const normalized = isIMessagePhoneLikeHandle(trimmed) ? normalizeE164(trimmed) : "";
1849
1220
  if (normalized) return normalized;
1850
- return trimmed.replace(/\s+/g, "");
1221
+ return allowContactName ? trimmed.replace(/\s+/g, "") : "";
1851
1222
  }
1852
1223
  function normalizeIMessageMessagingTarget(raw) {
1853
1224
  const trimmed = normalizeOptionalString(raw);
1854
1225
  if (!trimmed) return;
1855
1226
  const lower = normalizeLowercaseStringOrEmpty(trimmed);
1856
1227
  for (const prefix of SERVICE_PREFIXES) if (lower.startsWith(prefix)) {
1857
- const normalizedHandle = normalizeIMessageHandle(trimmed.slice(prefix.length).trim());
1228
+ const normalizedHandle = normalizeIMessageHandle(trimmed.slice(prefix.length).trim(), true);
1858
1229
  if (!normalizedHandle) return;
1859
1230
  if (CHAT_TARGET_PREFIX_RE.test(normalizedHandle)) return normalizedHandle;
1860
1231
  return `${prefix}${normalizedHandle}`;
@@ -1866,10 +1237,7 @@ function looksLikeIMessageTargetId(raw) {
1866
1237
  if (!trimmed) return false;
1867
1238
  if (CHAT_TARGET_PREFIX_RE.test(trimmed)) return true;
1868
1239
  if (normalizeBareIMessageChatIdentifier(trimmed)) return true;
1869
- return looksLikeHandleOrPhoneTarget({
1870
- raw: trimmed,
1871
- prefixPattern: /^(imessage:|sms:|auto:)/i
1872
- });
1240
+ return /^(imessage:|sms:|auto:)/i.test(trimmed) || trimmed.includes("@") || isIMessagePhoneLikeHandle(trimmed) && Boolean(normalizeE164(trimmed));
1873
1241
  }
1874
1242
  //#endregion
1875
1243
  //#region extensions/imessage/src/conversation-id-core.ts
@@ -1929,4 +1297,4 @@ function resolveIMessageGroupToolPolicy(params) {
1929
1297
  });
1930
1298
  }
1931
1299
  //#endregion
1932
- export { enumerateConversationKeyForms as A, imessageCompletionNote as B, registerIMessageApprovalReactionTarget as C, buildIMessageApprovalConversationKeyForInbound as D, resolveIMessageReactionContext as E, imessageMessageActions as F, normalizeIMessageCliPathForSetup as G, imessageSetupContract as H, probeIMessage as I, __exportAll as K, IMESSAGE_INSTALL_COMMAND as L, normalizeIMessageGuid as M, getIMessageApprovalApprovers as N, buildIMessageApprovalConversationKeyForTarget as O, imessageApprovalAuth as P, createIMessageCliPathTextInput as R, maybeResolveIMessageApprovalReaction as S, unregisterIMessageApprovalReactionTarget as T, imessageSetupStatusBase as U, imessageDmPolicy as V, isAutoManagedIMessageCliPath as W, appendIMessageApprovalReactionHintForOutboundMessage as _, normalizeIMessageAcpConversationId as a, handleIMessageApprovalReaction as b, PAIRING_APPROVED_MESSAGE as c, formatTrimmedAllowFromEntries$1 as d, getChatChannelMeta as f, addIMessageApprovalReactionHintToText as g, normalizeIMessageMessagingTarget as h, matchIMessageAcpConversation as i, normalizeConversationKey as j, enumerateApprovalTargetKeys as k, chunkTextForOutbound as l, looksLikeIMessageTargetId as m, resolveIMessageGroupToolPolicy as n, resolveIMessageConversationIdFromTarget as o, resolveChannelMediaMaxBytes as p, resolveIMessageInboundConversationId as r, DEFAULT_ACCOUNT_ID as s, resolveIMessageGroupRequireMention as t, collectStatusIssuesFromLastError as u, approval_reactions_exports as v, registerIMessageApprovalReactionTargetForOutboundMessage as w, listPendingIMessageApprovalReactionPollTargets as x, extractIMessageApprovalPromptBinding as y, createIMessageSetupWizardProxy as z };
1300
+ export { imessageDmPolicy as _, normalizeIMessageAcpConversationId as a, isAutoManagedIMessageCliPath as b, normalizeIMessageMessagingTarget as c, imessageMessageActions as d, probeIMessage as f, imessageCompletionNote as g, createIMessageSetupWizardProxy as h, matchIMessageAcpConversation as i, getIMessageApprovalApprovers as l, createIMessageCliPathTextInput as m, resolveIMessageGroupToolPolicy as n, resolveIMessageConversationIdFromTarget as o, IMESSAGE_INSTALL_COMMAND as p, resolveIMessageInboundConversationId as r, looksLikeIMessageTargetId as s, resolveIMessageGroupRequireMention as t, imessageApprovalAuth as u, imessageSetupContract as v, normalizeIMessageCliPathForSetup as x, imessageSetupStatusBase as y };