@openclaw/imessage 2026.10.10-beta.5 → 2026.11.5-beta.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 (142) hide show
  1. package/dist/.setup/{accounts-DacCvDBt.mjs → accounts-C1Ypv3Wn.mjs} +9 -13
  2. package/dist/.setup/{actions-762Azi-J.mjs → actions-qOuKy8To.mjs} +364 -116
  3. package/dist/.setup/{actions.runtime-DHiRiPHe.mjs → actions.runtime-Ccg9CARL.mjs} +12 -61
  4. package/dist/.setup/{api-Deyo8NDs.mjs → api-BXXuQQCS.mjs} +8 -9
  5. package/dist/.setup/{api-BFGXDHiC.mjs → api-DTbxSOPc.mjs} +9 -9
  6. package/dist/.setup/{approval-handler.runtime-fsSBf2jf.mjs → approval-handler.runtime-B6vrFfZx.mjs} +113 -133
  7. package/dist/.setup/{approval-reactions-CoAkCiwf.mjs → approval-reactions-DBBsqbRC.mjs} +156 -79
  8. package/dist/.setup/{channel-C61YdcZR.mjs → channel-CLaN4mQn.mjs} +151 -137
  9. package/dist/.setup/{channel.runtime-B5jle0g3.mjs → channel.runtime-XJGx1MIH.mjs} +236 -425
  10. package/dist/.setup/chat-context-fTfJVqAi.mjs +77 -0
  11. package/dist/.setup/chat-lookup-xtPsOBkl.mjs +50 -0
  12. package/dist/.setup/client-D_BaG8sC.mjs +367 -0
  13. package/dist/.setup/{config-schema-DXwa_3V5.mjs → config-schema-BjkQV5P5.mjs} +1 -4
  14. package/dist/.setup/{conversation-bindings-DR-dbHjs.mjs → conversation-bindings-8DjxoIYU.mjs} +10 -8
  15. package/dist/.setup/{media-contract-BwWs5PM7.mjs → media-contract-BErFBKV9.mjs} +2 -3
  16. package/dist/.setup/{message-tool-api-B5NfPnFL.mjs → message-tool-api-DtZ1wKbT.mjs} +6 -12
  17. package/dist/.setup/{outbound-send-deps-B-QEsLSM.mjs → outbound-send-deps-_da8jqeo.mjs} +1 -2
  18. package/dist/.setup/{remote-file-B94a787O.mjs → remote-file-DpK3GQFD.mjs} +12 -30
  19. package/dist/.setup/{rolldown-runtime-BBjsoOtd.mjs → rolldown-runtime-782esTHO.mjs} +1 -2
  20. package/dist/.setup/{sanitize-outbound-BtEY324R.mjs → sanitize-outbound-Dhjhz0a-.mjs} +25 -31
  21. package/dist/.setup/{send-BvxKNWzF.mjs → send-DhEW0gfe.mjs} +155 -236
  22. package/dist/.setup/{setup-core-BHyLkAEJ.mjs → setup-core-B1_P_t4T.mjs} +3 -4
  23. package/dist/.setup/{setup-surface-DPqiLGy0.mjs → setup-surface-CD28mXWK.mjs} +13 -29
  24. package/dist/.setup/{targets-B4oU7n-v.mjs → targets-C7CIWJ0k.mjs} +15 -9
  25. package/dist/.source-module-urls/929c518fa2986b0f85f66bceefead22868db0ab452dee914dc6a2bb86b2e60ad.json +1 -1
  26. package/dist/api.js +9 -9
  27. package/dist/channel-config-api.js +1 -1
  28. package/dist/channel-plugin-api.js +1 -1
  29. package/dist/contract-api.js +1 -1
  30. package/dist/doctor-contract-api.js +7 -13
  31. package/dist/index.js +1 -2
  32. package/dist/media-contract-api.js +1 -1
  33. package/dist/message-tool-api.js +1 -1
  34. package/dist/runtime-api.js +1 -3
  35. package/dist/secret-contract-api.js +1 -2
  36. package/dist/session-binding-contract-api.js +1 -1
  37. package/dist/setup-entry.js +2 -3
  38. package/dist/src/chat-db.worker.js +2 -3
  39. package/node_modules/typebox/build/format/duration.d.mts +2 -2
  40. package/node_modules/typebox/build/format/duration.mjs +2 -2
  41. package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
  42. package/node_modules/typebox/build/format/idn_email.mjs +1 -0
  43. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
  44. package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
  45. package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
  46. package/node_modules/typebox/build/format/ipv4.mjs +2 -2
  47. package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
  48. package/node_modules/typebox/build/format/ipv6.mjs +1 -1
  49. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  50. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  51. package/node_modules/typebox/build/schema/build.mjs +1 -0
  52. package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
  53. package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
  54. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
  55. package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
  56. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
  57. package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
  58. package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
  59. package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
  60. package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
  61. package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
  62. package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
  63. package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
  64. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
  65. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
  66. package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
  67. package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
  68. package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
  69. package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
  70. package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
  71. package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
  72. package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
  73. package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
  74. package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
  75. package/node_modules/typebox/build/system/memory/create.mjs +18 -13
  76. package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
  77. package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
  78. package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
  79. package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
  80. package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
  81. package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
  82. package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
  83. package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
  84. package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
  85. package/node_modules/typebox/build/system/memory/update.mjs +43 -16
  86. package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
  87. package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
  88. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
  89. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
  90. package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
  91. package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
  92. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
  93. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
  94. package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
  95. package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
  96. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
  97. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
  98. package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
  99. package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
  100. package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
  101. package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
  102. package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
  103. package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
  104. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
  105. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
  106. package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
  107. package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
  108. package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
  109. package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
  110. package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
  111. package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
  112. package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
  113. package/node_modules/typebox/package.json +1 -1
  114. package/node_modules/typebox/readme.md +1 -1
  115. package/node_modules/zod/package.json +1 -1
  116. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  117. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  118. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  119. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  120. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  121. package/node_modules/zod/src/v4/core/util.ts +13 -0
  122. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  123. package/node_modules/zod/v4/core/compile.cjs +8 -0
  124. package/node_modules/zod/v4/core/compile.js +8 -0
  125. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  126. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  127. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  128. package/node_modules/zod/v4/core/schemas.js +30 -0
  129. package/node_modules/zod/v4/core/util.cjs +15 -0
  130. package/node_modules/zod/v4/core/util.d.cts +2 -0
  131. package/node_modules/zod/v4/core/util.d.ts +2 -0
  132. package/node_modules/zod/v4/core/util.js +14 -0
  133. package/node_modules/zod/v4/core/versions.cjs +1 -1
  134. package/node_modules/zod/v4/core/versions.js +1 -1
  135. package/openclaw.plugin.json +0 -30
  136. package/package.json +6 -6
  137. package/dist/.setup/client-CcROCvRq.mjs +0 -746
  138. package/dist/.setup/question-reactions-BD06B1Lx.mjs +0 -68
  139. package/dist/.setup/reaction-context-Q26DYzQH.mjs +0 -106
  140. package/dist/.setup/runtime-Cza4CY5T.mjs +0 -8
  141. package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
  142. package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
@@ -1,22 +1,20 @@
1
- import { c as parseIMessageTarget, o as normalizeIMessageHandle, r as isAllowedIMessageReplyContextSender, s as parseIMessageAllowTarget, t as formatIMessageChatTarget } from "./targets-B4oU7n-v.mjs";
2
- import { d as resolveIMessageChatDbLookupPath, f as resolveIMessageHomeDir, l as resolveIMessageRemoteHost, o as resolveIMessageAccount, r as listEnabledIMessageAccounts, s as resolveIMessageDuplicateSourceOwner } from "./accounts-DacCvDBt.mjs";
3
- import { r as imessageRpcSupportsMethod } from "./message-tool-api-B5NfPnFL.mjs";
4
- import { S as resolveIMessageDirectChatService, h as resolveIMessageEchoMediaKey, m as resolveIMessageCatchupCursorKey, n as createIMessageRpcClient, o as isKnownFromMeIMessageTarget, p as capFailureRetriesMap, s as rememberIMessageReplyCache, u as IMESSAGE_CATCHUP_CURSOR_NAMESPACE } from "./client-CcROCvRq.mjs";
5
- import { a as normalizeIMessageMessageId, i as normalizeIMessageGuid, n as probeIMessage, r as probeIMessagePrivateApi } from "./actions-762Azi-J.mjs";
6
- import { t as getIMessageRuntime } from "./runtime-Cza4CY5T.mjs";
7
- import { a as resolveIMessageGroupSystemPrompt, s as resolveIMessageInboundConversationId } from "./channel-C61YdcZR.mjs";
8
- import { r as sanitizeOutboundText } from "./sanitize-outbound-BtEY324R.mjs";
9
- import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-BwWs5PM7.mjs";
10
- import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-send-deps-B-QEsLSM.mjs";
11
- import { i as resolveIMessageStartupRowidWatermark } from "./remote-file-B94a787O.mjs";
12
- import { i as registerIMessageApprovalReactionTarget, n as handleIMessageApprovalReaction, o as listPendingIMessageApprovalReactionPollTargets, r as maybeResolveIMessageApprovalReaction } from "./approval-reactions-CoAkCiwf.mjs";
13
- import { n as hasPersistedIMessageEcho, r as normalizeIMessageEchoText, s as maybeResolveIMessageApprovalPollVote, t as sendMessageIMessage } from "./send-BvxKNWzF.mjs";
14
- import { t as resolveIMessageReactionContext } from "./reaction-context-Q26DYzQH.mjs";
15
- import { n as maybeResolveIMessageQuestionReaction, t as hasIMessageQuestionReactionTarget } from "./question-reactions-BD06B1Lx.mjs";
16
- import { imessageSetupWizard } from "./setup-surface-DPqiLGy0.mjs";
1
+ import { c as parseIMessageAllowTarget, i as isAllowedIMessageReplyContextSender, l as parseIMessageTarget, n as iMessageTargetRpcParams, s as normalizeIMessageHandle, t as formatIMessageChatTarget } from "./targets-C7CIWJ0k.mjs";
2
+ import { d as resolveIMessageChatDbLookupPath, f as resolveIMessageHomeDir, l as resolveIMessageRemoteHost, o as resolveIMessageAccount, r as listEnabledIMessageAccounts, s as resolveIMessageDuplicateSourceOwner } from "./accounts-C1Ypv3Wn.mjs";
3
+ import { r as imessageRpcSupportsMethod } from "./message-tool-api-DtZ1wKbT.mjs";
4
+ import { a as resolveIMessageDirectChatService } from "./chat-context-fTfJVqAi.mjs";
5
+ import { n as createIMessageRpcClient, r as normalizeIMessageFullDiskAccessError } from "./client-D_BaG8sC.mjs";
6
+ import { a as rememberIMessageReplyCache, b as normalizeIMessageMessageId, c as IMESSAGE_CATCHUP_CURSOR_NAMESPACE, d as capFailureRetriesMap, f as resolveIMessageCatchupCursorKey, h as getIMessageRuntime, i as isKnownFromMeIMessageTarget, n as probeIMessage, p as resolveIMessageEchoMediaKey, r as probeIMessagePrivateApi, y as normalizeIMessageGuid } from "./actions-qOuKy8To.mjs";
7
+ import { a as resolveIMessageGroupSystemPrompt, s as resolveIMessageInboundConversationId } from "./channel-CLaN4mQn.mjs";
8
+ import { r as sanitizeOutboundText } from "./sanitize-outbound-Dhjhz0a-.mjs";
9
+ import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-BErFBKV9.mjs";
10
+ import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-send-deps-_da8jqeo.mjs";
11
+ import { i as resolveIMessageStartupRowidWatermark } from "./remote-file-DpK3GQFD.mjs";
12
+ import { a as resolveIMessageReactionContext, n as handleIMessageApprovalReaction, o as listPendingIMessageApprovalReactionPollTargets, r as registerIMessageApprovalReactionTarget } from "./approval-reactions-DBBsqbRC.mjs";
13
+ import { n as hasPersistedIMessageEcho, r as normalizeIMessageEchoText, s as maybeResolveIMessageApprovalPollVote, t as sendMessageIMessage } from "./send-DhEW0gfe.mjs";
17
14
  import { asSafeIntegerInRange, hasNonEmptyString, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
18
15
  import { normalizeChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-helpers";
19
16
  import { bindIngressLifecycleToReplyOptions, createAccountStatusSink, createChannelDeliveryAccumulator, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, resolveChannelStreamingBlockEnabled, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
17
+ import { resolveChannelGroupPolicy, resolveChannelGroups, resolveChannelGroupsConfigPath, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
20
18
  import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
21
19
  import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
22
20
  import path from "node:path";
@@ -24,17 +22,16 @@ import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers
24
22
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
25
23
  import fs from "node:fs/promises";
26
24
  import { isInboundPathAllowed, kindFromMime } from "openclaw/plugin-sdk/media-runtime";
27
- import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, sleepWithAbort, waitForAbortSignal, warn } from "openclaw/plugin-sdk/runtime-env";
28
- import { asDateTimestampMs, asPositiveFiniteNumber, parseDateStringTimestampMs, resolveIntegerOption, resolvePromptHistoryLimit, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
25
+ import { createNonExitingRuntime, danger, logVerbose, sleepWithAbort, waitForAbortSignal, warn } from "openclaw/plugin-sdk/runtime-env";
29
26
  import { createHash } from "node:crypto";
30
27
  import { captureRuntimeConfigAsyncReader, createRuntimeConfigReader } from "openclaw/plugin-sdk/runtime-config-snapshot";
31
28
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
32
29
  import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
33
- import { resolveChannelGroupPolicy, resolveChannelGroups, resolveChannelGroupsConfigPath, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
34
- import { convertMarkdownTables, findCodeRegions, isInsideCode, sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
30
+ import { convertMarkdownTables, findCodeRegions, isInsideCode } from "openclaw/plugin-sdk/text-chunking";
35
31
  import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, formatMediaPlaceholderText, logInboundDrop, matchesMentionPatterns, resolveEnvelopeFormatOptions, resolveInboundDebounceMs, resolveInboundMentionDecision, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
36
32
  import { FsSafeError, openLocalFileSafely, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
37
33
  import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
34
+ import { asDateTimestampMs, asPositiveFiniteNumber, parseDateStringTimestampMs, resolveIntegerOption, resolvePromptHistoryLimit, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
38
35
  import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime";
39
36
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
40
37
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -44,15 +41,16 @@ import { defineStableChannelIngressIdentity, fanInChannelIngressLifecycles } fro
44
41
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
45
42
  import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
46
43
  import { ensureConfiguredBindingRouteReady, readChannelAllowFromStore, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
44
+ import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
47
45
  import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
48
46
  import { redactIdentifier } from "openclaw/plugin-sdk/logging-core";
49
47
  import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
50
48
  import { getSessionEntryAsync, readSessionUpdatedAtAsync, resolveSendPolicy, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
51
49
  import { waitForTransportReady } from "openclaw/plugin-sdk/transport-ready-runtime";
52
50
  import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
51
+ import { isStringArray } from "openclaw/plugin-sdk/collection-input-runtime";
53
52
  import { chunkMarkdownTextWithMode, resolveChunkMode } from "openclaw/plugin-sdk/reply-chunking";
54
53
  import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
55
- import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
56
54
  import { hasControlCommand } from "openclaw/plugin-sdk/command-auth-native";
57
55
  import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
58
56
  import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
@@ -62,112 +60,43 @@ import { readFileHandleBounded } from "openclaw/plugin-sdk/file-access-runtime";
62
60
  import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
63
61
  import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
64
62
  import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
65
- //#region extensions/imessage/src/approval-reaction-poller.ts
63
+ import { sha256Hex } from "openclaw/plugin-sdk/node-crypto-runtime";
64
+ // extensions/imessage/src/approval-reaction-poller.ts
66
65
  const RECENT_CHAT_LIMIT = 50;
67
66
  const PER_CHAT_HISTORY_LIMIT$1 = 30;
68
67
  function normalizeChatId(value) {
69
68
  return asPositiveFiniteNumber(value) ?? null;
70
69
  }
71
- function listTargetChatIds(targets) {
72
- const chatIds = /* @__PURE__ */ new Set();
73
- for (const target of targets) {
74
- const chatId = normalizeChatId(target.conversation.chatId);
75
- if (chatId !== null) chatIds.add(chatId);
76
- }
77
- return [...chatIds];
78
- }
79
- function hasUnscopedTarget(targets) {
80
- return targets.some((target) => normalizeChatId(target.conversation.chatId) === null);
81
- }
82
70
  function enumerateMessageGuidCandidates(value) {
83
71
  const trimmed = value.trim();
84
72
  if (!trimmed) return [];
85
73
  return [trimmed, normalizeIMessageGuid(trimmed)].filter((candidate, index, candidates) => candidate.length > 0 && candidates.indexOf(candidate) === index);
86
74
  }
87
- function buildPendingTargetsByMessageId(targets) {
88
- const pendingByMessageId = /* @__PURE__ */ new Map();
89
- for (const target of targets) for (const candidate of enumerateMessageGuidCandidates(target.messageId)) pendingByMessageId.set(candidate, target);
90
- return pendingByMessageId;
91
- }
92
75
  async function listRecentChatIds(client) {
93
76
  return ((await client.request("chats.list", { limit: RECENT_CHAT_LIMIT }, { timeoutMs: 1e4 })).chats ?? []).map((chat) => normalizeChatId(chat.id)).filter((chatId) => chatId !== null);
94
77
  }
95
- async function fetchRecentHistory(params) {
96
- return ((await params.client.request("messages.history", {
97
- chat_id: params.chatId,
98
- limit: PER_CHAT_HISTORY_LIMIT$1
99
- }, { timeoutMs: 1e4 })).messages ?? []).filter((message) => Boolean(message && typeof message === "object"));
100
- }
101
- function buildReactionPayload(params) {
102
- const emoji = params.reaction.emoji?.trim();
103
- const sender = params.reaction.sender?.trim();
104
- const targetGuid = params.targetMessage.guid?.trim();
105
- if (!emoji || !sender || !targetGuid) return null;
106
- const reactionId = normalizeChatId(params.reaction.id);
107
- return {
108
- ...reactionId !== null ? { id: reactionId } : {},
109
- guid: `reaction:${targetGuid}:${sender}:${emoji}:${params.reaction.created_at ?? ""}`,
110
- chat_id: params.targetMessage.chat_id,
111
- chat_guid: params.targetMessage.chat_guid,
112
- chat_identifier: params.targetMessage.chat_identifier,
113
- chat_name: params.targetMessage.chat_name,
114
- participants: params.targetMessage.participants,
115
- is_group: params.targetMessage.is_group,
116
- sender,
117
- destination_caller_id: params.targetMessage.destination_caller_id,
118
- is_from_me: params.reaction.is_from_me,
119
- text: `${params.reaction.type ?? "reaction"} "${params.targetMessage.text ?? ""}"`,
120
- created_at: params.reaction.created_at,
121
- is_reaction: true,
122
- is_tapback: true,
123
- associated_message_guid: targetGuid,
124
- associated_message_type: 2e3,
125
- reaction_type: params.reaction.type ?? void 0,
126
- reaction_emoji: emoji,
127
- is_reaction_add: true,
128
- reacted_to_guid: targetGuid
129
- };
130
- }
131
- function buildConversationKeyFromMessage(message) {
132
- return {
133
- ...message.chat_guid?.trim() ? { chatGuid: message.chat_guid.trim() } : {},
134
- ...message.chat_identifier?.trim() ? { chatIdentifier: message.chat_identifier.trim() } : {},
135
- ...normalizeChatId(message.chat_id) !== null ? { chatId: message.chat_id } : {}
136
- };
137
- }
138
- async function bindObservedConversation(params) {
139
- const nowMs = asDateTimestampMs(Date.now());
140
- const expiresAtMs = asDateTimestampMs(params.target.expiresAtMs);
141
- if (nowMs === void 0 || expiresAtMs === void 0 || expiresAtMs <= nowMs) return;
142
- const ttlMs = expiresAtMs - nowMs;
143
- const conversation = buildConversationKeyFromMessage(params.message);
144
- const messageIds = /* @__PURE__ */ new Set([...enumerateMessageGuidCandidates(params.target.messageId), ...enumerateMessageGuidCandidates(params.message.guid ?? "")]);
145
- await Promise.all([...messageIds].map((messageId) => registerIMessageApprovalReactionTarget({
146
- accountId: params.target.accountId,
147
- conversation,
148
- messageId,
149
- approvalId: params.target.approvalId,
150
- approvalKind: params.target.approvalKind,
151
- allowedDecisions: params.target.allowedDecisions,
152
- ttlMs
153
- })));
154
- }
155
78
  async function pollPendingIMessageApprovalReactions(params) {
156
79
  const targets = await listPendingIMessageApprovalReactionPollTargets({ accountId: params.accountId });
157
80
  if (params.signal?.aborted || targets.length === 0) return;
158
- const pendingByMessageId = buildPendingTargetsByMessageId(targets);
159
- const explicitChatIds = listTargetChatIds(targets);
160
- const chatIds = params.allowRecentChatDiscovery === true && hasUnscopedTarget(targets) ? [.../* @__PURE__ */ new Set([...explicitChatIds, ...await listRecentChatIds(params.client)])] : explicitChatIds;
81
+ const pendingByMessageId = /* @__PURE__ */ new Map();
82
+ for (const target of targets) for (const candidate of enumerateMessageGuidCandidates(target.messageId)) pendingByMessageId.set(candidate, target);
83
+ const targetChatIds = /* @__PURE__ */ new Set();
84
+ for (const target of targets) {
85
+ const chatId = normalizeChatId(target.conversation.chatId);
86
+ if (chatId !== null) targetChatIds.add(chatId);
87
+ }
88
+ const explicitChatIds = [...targetChatIds];
89
+ const chatIds = params.allowRecentChatDiscovery === true && targets.some((target) => normalizeChatId(target.conversation.chatId) === null) ? [.../* @__PURE__ */ new Set([...explicitChatIds, ...await listRecentChatIds(params.client)])] : explicitChatIds;
161
90
  for (const chatId of chatIds) {
162
91
  if (params.signal?.aborted) return;
163
92
  let messages;
164
93
  try {
165
- messages = await fetchRecentHistory({
166
- client: params.client,
167
- chatId
168
- });
94
+ messages = ((await params.client.request("messages.history", {
95
+ chat_id: chatId,
96
+ limit: PER_CHAT_HISTORY_LIMIT$1
97
+ }, { timeoutMs: 1e4 })).messages ?? []).filter((message) => Boolean(message && typeof message === "object"));
169
98
  } catch (err) {
170
- params.logVerboseMessage?.(`imessage: approval reaction poll skipped chat_id=${chatId}: ${String(err)}`);
99
+ logVerbose(`imessage: approval reaction poll skipped chat_id=${chatId}: ${String(err)}`);
171
100
  continue;
172
101
  }
173
102
  for (const message of messages) {
@@ -176,46 +105,83 @@ async function pollPendingIMessageApprovalReactions(params) {
176
105
  if (!targetGuid) continue;
177
106
  const target = pendingByMessageId.get(targetGuid) ?? pendingByMessageId.get(normalizeIMessageGuid(targetGuid));
178
107
  if (!target) continue;
179
- await bindObservedConversation({
180
- target,
181
- message
182
- });
108
+ await (async () => {
109
+ const nowMs = asDateTimestampMs(Date.now());
110
+ const expiresAtMs = asDateTimestampMs(target.expiresAtMs);
111
+ if (nowMs === void 0 || expiresAtMs === void 0 || expiresAtMs <= nowMs) return;
112
+ const ttlMs = expiresAtMs - nowMs;
113
+ const conversation = {
114
+ ...message.chat_guid?.trim() ? { chatGuid: message.chat_guid.trim() } : {},
115
+ ...message.chat_identifier?.trim() ? { chatIdentifier: message.chat_identifier.trim() } : {},
116
+ ...normalizeChatId(message.chat_id) !== null ? { chatId: message.chat_id } : {}
117
+ };
118
+ const messageIds = /* @__PURE__ */ new Set([...enumerateMessageGuidCandidates(target.messageId), ...enumerateMessageGuidCandidates(message.guid ?? "")]);
119
+ await Promise.all([...messageIds].map((messageId) => registerIMessageApprovalReactionTarget({
120
+ accountId: target.accountId,
121
+ conversation,
122
+ messageId,
123
+ approvalId: target.approvalId,
124
+ approvalKind: target.approvalKind,
125
+ allowedDecisions: target.allowedDecisions,
126
+ ttlMs
127
+ })));
128
+ })();
183
129
  for (const reaction of message.reactions ?? []) {
184
130
  if (params.signal?.aborted) return;
185
- const reactionPayload = buildReactionPayload({
186
- targetMessage: message,
187
- reaction
188
- });
131
+ const reactionPayload = (() => {
132
+ const emoji = reaction.emoji?.trim();
133
+ const sender = reaction.sender?.trim();
134
+ const reactionTargetGuid = message.guid?.trim();
135
+ if (!emoji || !sender || !reactionTargetGuid) return null;
136
+ const reactionId = normalizeChatId(reaction.id);
137
+ return {
138
+ ...reactionId !== null ? { id: reactionId } : {},
139
+ guid: `reaction:${reactionTargetGuid}:${sender}:${emoji}:${reaction.created_at ?? ""}`,
140
+ chat_id: message.chat_id,
141
+ chat_guid: message.chat_guid,
142
+ chat_identifier: message.chat_identifier,
143
+ chat_name: message.chat_name,
144
+ participants: message.participants,
145
+ is_group: message.is_group,
146
+ sender,
147
+ destination_caller_id: message.destination_caller_id,
148
+ is_from_me: reaction.is_from_me,
149
+ text: `${reaction.type ?? "reaction"} "${message.text ?? ""}"`,
150
+ created_at: reaction.created_at,
151
+ is_reaction: true,
152
+ is_tapback: true,
153
+ associated_message_guid: reactionTargetGuid,
154
+ associated_message_type: 2e3,
155
+ reaction_type: reaction.type ?? void 0,
156
+ reaction_emoji: emoji,
157
+ is_reaction_add: true,
158
+ reacted_to_guid: reactionTargetGuid
159
+ };
160
+ })();
189
161
  if (!reactionPayload) continue;
190
162
  if ((await handleIMessageApprovalReaction({
191
163
  cfg: params.cfg,
192
164
  accountId: params.accountId,
193
165
  message: reactionPayload,
194
166
  bodyText: reactionPayload.text ?? "",
195
- gatewayRuntime: params.gatewayRuntime,
196
- logVerboseMessage: params.logVerboseMessage
167
+ gatewayRuntime: params.gatewayRuntime
197
168
  })).stopPolling) return;
198
169
  }
199
170
  }
200
171
  }
201
172
  }
202
- //#endregion
203
- //#region extensions/imessage/src/chat.ts
173
+ // extensions/imessage/src/chat.ts
204
174
  async function runChatAction(method, to, opts, isTyping) {
205
175
  const cfg = requireRuntimeConfig(opts.cfg, "iMessage chat action");
206
- const account = opts.account ?? resolveIMessageAccount({
176
+ const account = resolveIMessageAccount({
207
177
  cfg,
208
178
  accountId: opts.accountId
209
179
  });
210
- const target = parseIMessageTarget(opts.chatId ? formatIMessageChatTarget(opts.chatId) : to);
211
- const params = {};
212
- if (target.kind === "chat_id") params.chat_id = target.chatId;
213
- else if (target.kind === "chat_guid") params.chat_guid = target.chatGuid;
214
- else if (target.kind === "chat_identifier") params.chat_identifier = target.chatIdentifier;
215
- else params.to = target.to;
180
+ const target = parseIMessageTarget(to);
181
+ const params = iMessageTargetRpcParams(target);
216
182
  if (method === "typing") {
217
183
  params.typing = isTyping;
218
- const service = opts.service ?? (target.kind === "handle" ? target.service : void 0) ?? account.config.service;
184
+ const service = (target.kind === "handle" ? target.service : void 0) ?? account.config.service;
219
185
  if (service) params.service = service;
220
186
  }
221
187
  const cliPath = opts.cliPath?.trim() || account.config.cliPath?.trim() || "imsg";
@@ -231,7 +197,7 @@ async function runChatAction(method, to, opts, isTyping) {
231
197
  });
232
198
  const shouldClose = !opts.client;
233
199
  try {
234
- await client.request(method, params, { timeoutMs: opts.timeoutMs });
200
+ await client.request(method, params);
235
201
  } finally {
236
202
  if (shouldClose) await client.stop();
237
203
  }
@@ -242,8 +208,7 @@ async function sendIMessageTyping(to, isTyping, opts) {
242
208
  async function markIMessageChatRead(to, opts) {
243
209
  await runChatAction("read", to, opts);
244
210
  }
245
- //#endregion
246
- //#region extensions/imessage/src/monitor/abort-handler.ts
211
+ // extensions/imessage/src/monitor/abort-handler.ts
247
212
  function attachIMessageMonitorAbortHandler(params) {
248
213
  const abort = params.abortSignal;
249
214
  if (!abort) return () => {};
@@ -255,8 +220,7 @@ function attachIMessageMonitorAbortHandler(params) {
255
220
  abort.addEventListener("abort", onAbort, { once: true });
256
221
  return () => abort.removeEventListener("abort", onAbort);
257
222
  }
258
- //#endregion
259
- //#region extensions/imessage/src/monitor/catchup.ts
223
+ // extensions/imessage/src/monitor/catchup.ts
260
224
  const DEFAULT_MAX_AGE_MINUTES = 120;
261
225
  const MAX_MAX_AGE_MINUTES = 720;
262
226
  const DEFAULT_PER_RUN_LIMIT = 50;
@@ -361,13 +325,12 @@ async function advanceIMessageCatchupCursor(accountId, next, config) {
361
325
  return await updateIMessageCatchupCursor(accountId, (existing) => decideLiveCatchupCursorAdvance(existing, cursor, config.maxFailureRetries));
362
326
  }
363
327
  async function performIMessageCatchup(params) {
364
- const now = params.now ?? Date.now();
328
+ const now = Date.now();
365
329
  const cfg = params.config;
366
330
  const cursor = await loadIMessageCatchupCursor(params.accountId);
367
331
  const lookbackMs = cursor === null ? cfg.firstRunLookbackMinutes * 6e4 : cfg.maxAgeMinutes * 6e4;
368
332
  const ageBoundMs = now - cfg.maxAgeMinutes * 6e4;
369
333
  const windowStartMs = Math.max(cursor?.lastSeenMs ?? now - lookbackMs, ageBoundMs);
370
- const windowEndMs = now;
371
334
  const sinceRowid = cursor?.lastSeenRowid ?? 0;
372
335
  const summary = {
373
336
  querySucceeded: false,
@@ -375,20 +338,9 @@ async function performIMessageCatchup(params) {
375
338
  fetchedCount: 0,
376
339
  replayed: 0,
377
340
  skippedFromMe: 0,
378
- skippedPreCursor: 0,
379
341
  skippedGivenUp: 0,
380
342
  failed: 0,
381
- givenUp: 0,
382
- cursorBefore: cursor ? {
383
- lastSeenMs: cursor.lastSeenMs,
384
- lastSeenRowid: cursor.lastSeenRowid
385
- } : null,
386
- cursorAfter: {
387
- lastSeenMs: cursor?.lastSeenMs ?? windowStartMs,
388
- lastSeenRowid: cursor?.lastSeenRowid ?? 0
389
- },
390
- windowStartMs,
391
- windowEndMs
343
+ givenUp: 0
392
344
  };
393
345
  let fetchResult;
394
346
  try {
@@ -416,16 +368,10 @@ async function performIMessageCatchup(params) {
416
368
  let highWatermarkRowid = cursorBeforeRowid;
417
369
  let earliestHeldFailureRow = null;
418
370
  for (const row of rows) {
419
- if (row.rowid <= sinceRowid) {
420
- summary.skippedPreCursor += 1;
421
- continue;
422
- }
371
+ if (row.rowid <= sinceRowid) continue;
423
372
  highWatermarkMs = Math.max(highWatermarkMs, row.date);
424
373
  highWatermarkRowid = Math.max(highWatermarkRowid, row.rowid);
425
- if (row.date < ageBoundMs) {
426
- summary.skippedPreCursor += 1;
427
- continue;
428
- }
374
+ if (row.date < ageBoundMs) continue;
429
375
  if (row.isFromMe) {
430
376
  try {
431
377
  await params.observeSkippedFromMe?.(row);
@@ -476,10 +422,6 @@ async function performIMessageCatchup(params) {
476
422
  lastSeenRowid = highWatermarkRowid;
477
423
  }
478
424
  const capped = capFailureRetriesMap(failureRetries);
479
- summary.cursorAfter = {
480
- lastSeenMs,
481
- lastSeenRowid
482
- };
483
425
  const next = buildIMessageCatchupCursor({
484
426
  lastSeenMs,
485
427
  lastSeenRowid,
@@ -489,8 +431,7 @@ async function performIMessageCatchup(params) {
489
431
  if (summary.replayed > 0 || summary.failed > 0 || summary.givenUp > 0) params.log?.(`imessage catchup: replayed=${summary.replayed} skippedFromMe=${summary.skippedFromMe} skippedGivenUp=${summary.skippedGivenUp} failed=${summary.failed} givenUp=${summary.givenUp} fetchedCount=${summary.fetchedCount}`);
490
432
  return summary;
491
433
  }
492
- //#endregion
493
- //#region extensions/imessage/src/monitor/strip-imsg-length-prefixed-text.ts
434
+ // extensions/imessage/src/monitor/strip-imsg-length-prefixed-text.ts
494
435
  const utf8Decoder = new TextDecoder();
495
436
  function readVarint(buf, start) {
496
437
  let offset = start;
@@ -525,8 +466,7 @@ function stripImessageLengthPrefixedUtf8Text(text) {
525
466
  const inner = utf8Decoder.decode(stripped);
526
467
  return inner.length > 0 ? inner : text;
527
468
  }
528
- //#endregion
529
- //#region extensions/imessage/src/monitor/parse-notification.ts
469
+ // extensions/imessage/src/monitor/parse-notification.ts
530
470
  function isOptionalString(value) {
531
471
  return value === void 0 || value === null || typeof value === "string";
532
472
  }
@@ -537,7 +477,7 @@ function isOptionalBoolean(value) {
537
477
  return value === void 0 || value === null || typeof value === "boolean";
538
478
  }
539
479
  function isOptionalStringArray(value) {
540
- return value === void 0 || value === null || Array.isArray(value) && value.every((entry) => typeof entry === "string");
480
+ return value === void 0 || value === null || isStringArray(value);
541
481
  }
542
482
  function isOptionalAttachments(value) {
543
483
  if (value === void 0 || value === null) return true;
@@ -559,8 +499,7 @@ function parseIMessageNotification(raw) {
559
499
  reply_to_text: typeof message.reply_to_text === "string" ? stripImessageLengthPrefixedUtf8Text(message.reply_to_text) : message.reply_to_text
560
500
  };
561
501
  }
562
- //#endregion
563
- //#region extensions/imessage/src/monitor/catchup-bridge.ts
502
+ // extensions/imessage/src/monitor/catchup-bridge.ts
564
503
  const PER_CHAT_HISTORY_LIMIT = 500;
565
504
  const CATCHUP_CHATS_LIST_LIMIT = 200;
566
505
  const CATCHUP_RPC_TIMEOUT_MS = 3e4;
@@ -681,12 +620,10 @@ async function runIMessageCatchup(params) {
681
620
  await params.observeSkippedFromMePayload?.(entry.message);
682
621
  },
683
622
  log,
684
- warn: warnLog,
685
- ...params.now ? { now: params.now() } : {}
623
+ warn: warnLog
686
624
  });
687
625
  }
688
- //#endregion
689
- //#region extensions/imessage/src/monitor/coalesce.ts
626
+ // extensions/imessage/src/monitor/coalesce.ts
690
627
  const MAX_COALESCED_TEXT_CHARS = 4e3;
691
628
  const MAX_COALESCED_ATTACHMENTS = 20;
692
629
  /**
@@ -714,7 +651,7 @@ function combineIMessagePayloads(payloads) {
714
651
  const keepContent = payloadIndex < 9 || payloadIndex === payloads.length - 1;
715
652
  payloadIndex += 1;
716
653
  const createdAt = payload.created_at;
717
- if (typeof createdAt === "string" && createdAt.length > 0 && (latestCreatedAt === void 0 || createdAt > latestCreatedAt)) latestCreatedAt = createdAt;
654
+ if (createdAt && (latestCreatedAt === void 0 || createdAt > latestCreatedAt)) latestCreatedAt = createdAt;
718
655
  if (!reply && (payload.thread_originator_guid != null || payload.reply_to_guid != null)) reply = payload;
719
656
  if (!keepContent) continue;
720
657
  const text = textLength <= MAX_COALESCED_TEXT_CHARS ? (payload.text ?? "").trim() : "";
@@ -747,8 +684,7 @@ function combineIMessagePayloads(payloads) {
747
684
  reply_to_sender: reply.reply_to_sender ?? null
748
685
  };
749
686
  }
750
- //#endregion
751
- //#region extensions/imessage/src/monitor/conversation-repair.ts
687
+ // extensions/imessage/src/monitor/conversation-repair.ts
752
688
  const DEFAULT_CHATS_LIMIT = 20;
753
689
  const DEFAULT_PER_CHAT_HISTORY_LIMIT = 50;
754
690
  const DEFAULT_RPC_TIMEOUT_MS = 5e3;
@@ -778,7 +714,7 @@ function extractAuthoritativeRecoveryProjection(entry) {
778
714
  if (hasNonEmptyString(entry.chat_guid)) projection.chat_guid = entry.chat_guid;
779
715
  if (hasNonEmptyString(entry.chat_identifier)) projection.chat_identifier = entry.chat_identifier;
780
716
  if (typeof entry.chat_name === "string") projection.chat_name = entry.chat_name;
781
- if (Array.isArray(entry.participants) && entry.participants.every((participant) => typeof participant === "string")) projection.participants = entry.participants;
717
+ if (isStringArray(entry.participants)) projection.participants = entry.participants;
782
718
  return hasUsableConversationAnchor(projection) ? projection : null;
783
719
  }
784
720
  function projectionConflictKey(projection) {
@@ -856,8 +792,7 @@ async function repairIMessageConversationAnchor(params) {
856
792
  runtime?.log?.(`imessage: recovered anchorless message GUID=${guid} chat_id=${repaired.chat_id ?? "unknown"} is_group=${repaired.is_group}`);
857
793
  return repaired;
858
794
  }
859
- //#endregion
860
- //#region extensions/imessage/src/monitor/deliver.ts
795
+ // extensions/imessage/src/monitor/deliver.ts
861
796
  async function deliverIMessageReply(params) {
862
797
  const { payload, target, runtime, maxBytes, textLimit, accountId, sentMessageCache } = params;
863
798
  const scope = `${accountId ?? ""}:${target}`;
@@ -920,8 +855,7 @@ function createIMessageEchoCachingSend(params) {
920
855
  return sent;
921
856
  };
922
857
  }
923
- //#endregion
924
- //#region extensions/imessage/src/monitor/dm-history.ts
858
+ // extensions/imessage/src/monitor/dm-history.ts
925
859
  const DM_HISTORY_RPC_TIMEOUT_MS = 1e4;
926
860
  function resolveIMessageDmHistoryLimit(params) {
927
861
  const senderCandidates = [
@@ -940,14 +874,6 @@ function historyRowSortValue(message) {
940
874
  const createdAtMs = typeof message.created_at === "string" ? Date.parse(message.created_at) : NaN;
941
875
  return Number.isFinite(createdAtMs) ? createdAtMs : 0;
942
876
  }
943
- function isBeforeCurrentMessage(params) {
944
- const { message, currentMessage } = params;
945
- if (typeof message.id === "number" && typeof currentMessage.id === "number" && Number.isFinite(message.id) && Number.isFinite(currentMessage.id)) return message.id < currentMessage.id;
946
- const guid = normalizeOptionalString(message.guid);
947
- const currentGuid = normalizeOptionalString(currentMessage.guid);
948
- if (guid && currentGuid) return guid !== currentGuid;
949
- return true;
950
- }
951
877
  function historyEntryFromMessage(message, fallbackSender) {
952
878
  const body = normalizeOptionalString(message.text);
953
879
  if (!body) return null;
@@ -970,13 +896,17 @@ async function resolveIMessageDmHistoryContext(params) {
970
896
  attachments: false
971
897
  }, { timeoutMs: DM_HISTORY_RPC_TIMEOUT_MS });
972
898
  } catch (err) {
973
- params.logVerbose?.(`imessage: DM history fetch failed for chat_id=${chatId}: ${String(err)}`);
899
+ logVerbose(`imessage: DM history fetch failed for chat_id=${chatId}: ${String(err)}`);
974
900
  return {};
975
901
  }
976
- const history = (Array.isArray(result?.messages) ? result.messages : []).map((row) => parseIMessageNotification({ message: row })).filter((message) => Boolean(message)).filter((message) => message.is_group !== true).filter((message) => isBeforeCurrentMessage({
977
- message,
978
- currentMessage: params.message
979
- })).toSorted((a, b) => historyRowSortValue(a) - historyRowSortValue(b)).map((message) => historyEntryFromMessage(message, params.senderNormalized)).filter((entry) => Boolean(entry)).slice(-maxMessages);
902
+ const history = (Array.isArray(result?.messages) ? result.messages : []).map((row) => parseIMessageNotification({ message: row })).filter((message) => Boolean(message)).filter((message) => message.is_group !== true).filter((message) => {
903
+ const currentMessage = params.message;
904
+ if (typeof message.id === "number" && typeof currentMessage.id === "number" && Number.isFinite(message.id) && Number.isFinite(currentMessage.id)) return message.id < currentMessage.id;
905
+ const guid = normalizeOptionalString(message.guid);
906
+ const currentGuid = normalizeOptionalString(currentMessage.guid);
907
+ if (guid && currentGuid) return guid !== currentGuid;
908
+ return true;
909
+ }).toSorted((a, b) => historyRowSortValue(a) - historyRowSortValue(b)).map((message) => historyEntryFromMessage(message, params.senderNormalized)).filter((entry) => Boolean(entry)).slice(-maxMessages);
980
910
  if (history.length === 0) return {};
981
911
  return {
982
912
  inboundHistory: history,
@@ -991,91 +921,63 @@ async function resolveIMessageDmHistoryContext(params) {
991
921
  })).join("\n\n")
992
922
  };
993
923
  }
994
- //#endregion
995
- //#region extensions/imessage/src/monitor/drop-diagnostic-cache.ts
996
- const THROTTLED_DROP_DIAGNOSTIC_CACHE_MAX_SIZE = 512;
997
- function createIMessageThrottledDropDiagnosticCache() {
998
- return createDedupeCache({
999
- maxSize: THROTTLED_DROP_DIAGNOSTIC_CACHE_MAX_SIZE,
1000
- ttlMs: 0
1001
- });
1002
- }
1003
- //#endregion
1004
- //#region extensions/imessage/src/monitor/echo-cache.ts
924
+ // extensions/imessage/src/monitor/echo-cache.ts
1005
925
  const SENT_MESSAGE_TEXT_TTL_MS = 4e3;
1006
926
  const SENT_MESSAGE_ID_TTL_MS = 6e4;
1007
927
  function createSentMessageCache() {
1008
928
  const textCache = /* @__PURE__ */ new Map();
1009
- const textBackedByIdCache = /* @__PURE__ */ new Map();
1010
929
  const mediaCache = /* @__PURE__ */ new Map();
1011
- const mediaBackedByIdCache = /* @__PURE__ */ new Map();
1012
930
  const messageIdCache = /* @__PURE__ */ new Map();
1013
931
  function remember(scope, lookup) {
1014
- const textKey = normalizeIMessageEchoText(lookup.text);
1015
- if (textKey) textCache.set(`${scope}:${textKey}`, Date.now());
1016
- const mediaKey = resolveIMessageEchoMediaKey(lookup.media);
1017
- if (mediaKey) mediaCache.set(`${scope}:${mediaKey}`, Date.now());
932
+ const now = Date.now();
1018
933
  const messageIdKey = normalizeIMessageMessageId(lookup.messageId);
1019
- if (messageIdKey) {
1020
- messageIdCache.set(`${scope}:${messageIdKey}`, Date.now());
1021
- if (textKey) textBackedByIdCache.set(`${scope}:${textKey}`, Date.now());
1022
- if (mediaKey) mediaBackedByIdCache.set(`${scope}:${mediaKey}`, Date.now());
934
+ if (messageIdKey) messageIdCache.set(`${scope}:${messageIdKey}`, now);
935
+ for (const [cache, value] of [[textCache, normalizeIMessageEchoText(lookup.text)], [mediaCache, resolveIMessageEchoMediaKey(lookup.media)]]) if (value) {
936
+ const key = `${scope}:${value}`;
937
+ cache.set(key, {
938
+ timestamp: now,
939
+ idTimestamp: messageIdKey ? now : cache.get(key)?.idTimestamp
940
+ });
1023
941
  }
1024
942
  cleanup();
1025
943
  }
1026
- async function has(scope, lookup, options = false) {
1027
- cleanup();
1028
- const resolvedOptions = typeof options === "boolean" ? { skipIdShortCircuit: options } : options;
944
+ async function has(scope, lookup, options = {}) {
1029
945
  if (await hasPersistedIMessageEcho({
1030
946
  scope,
1031
947
  text: lookup.text,
1032
948
  media: lookup.media,
1033
949
  messageId: lookup.messageId,
1034
- skipIdShortCircuit: resolvedOptions.skipIdShortCircuit,
1035
- includePendingText: resolvedOptions.includePendingText
950
+ skipIdShortCircuit: options.skipIdShortCircuit,
951
+ includePendingText: options.includePendingText
1036
952
  })) return true;
1037
- const matchesWithin = (cache, key, ttlMs) => {
1038
- const timestamp = key ? cache.get(`${scope}:${key}`) : void 0;
1039
- return Boolean(timestamp && Date.now() - timestamp <= ttlMs);
1040
- };
1041
- const hasContentOnlyMatch = (cache, backedById, key) => {
1042
- const timestamp = key ? cache.get(`${scope}:${key}`) : void 0;
1043
- const idTimestamp = key ? backedById.get(`${scope}:${key}`) : void 0;
1044
- return typeof timestamp === "number" && (!idTimestamp || timestamp > idTimestamp);
1045
- };
953
+ cleanup();
1046
954
  const textKey = normalizeIMessageEchoText(lookup.text);
1047
955
  const mediaKey = resolveIMessageEchoMediaKey(lookup.media);
956
+ const text = textKey ? textCache.get(`${scope}:${textKey}`) : void 0;
957
+ const media = mediaKey ? mediaCache.get(`${scope}:${mediaKey}`) : void 0;
958
+ const hasContentOnlyMatch = (entry) => Boolean(entry && (!entry.idTimestamp || entry.timestamp > entry.idTimestamp));
1048
959
  const messageIdKey = normalizeIMessageMessageId(lookup.messageId);
1049
960
  let canUseMediaFallback = !messageIdKey;
1050
961
  if (messageIdKey) {
1051
- if (matchesWithin(messageIdCache, messageIdKey, SENT_MESSAGE_ID_TTL_MS)) return true;
1052
- const hasTextOnlyMatch = hasContentOnlyMatch(textCache, textBackedByIdCache, textKey);
1053
- const hasMediaOnlyMatch = hasContentOnlyMatch(mediaCache, mediaBackedByIdCache, mediaKey);
962
+ if (messageIdCache.has(`${scope}:${messageIdKey}`)) return true;
963
+ const hasTextOnlyMatch = hasContentOnlyMatch(text);
964
+ const hasMediaOnlyMatch = hasContentOnlyMatch(media);
1054
965
  canUseMediaFallback = hasMediaOnlyMatch;
1055
- if (!resolvedOptions.skipIdShortCircuit && !hasTextOnlyMatch && !hasMediaOnlyMatch) return false;
966
+ if (!options.skipIdShortCircuit && !hasTextOnlyMatch && !hasMediaOnlyMatch) return false;
1056
967
  }
1057
- return matchesWithin(textCache, textKey, SENT_MESSAGE_TEXT_TTL_MS) || canUseMediaFallback && matchesWithin(mediaCache, mediaKey, SENT_MESSAGE_TEXT_TTL_MS);
968
+ return Boolean(text || canUseMediaFallback && media);
1058
969
  }
1059
970
  function cleanup() {
1060
971
  const now = Date.now();
1061
- for (const cache of [
1062
- textCache,
1063
- textBackedByIdCache,
1064
- mediaCache,
1065
- mediaBackedByIdCache,
1066
- messageIdCache
1067
- ]) {
1068
- const ttlMs = cache === messageIdCache ? SENT_MESSAGE_ID_TTL_MS : SENT_MESSAGE_TEXT_TTL_MS;
1069
- for (const [key, timestamp] of cache) if (now - timestamp > ttlMs) cache.delete(key);
1070
- }
972
+ for (const cache of [textCache, mediaCache]) for (const [key, entry] of cache) if (now - entry.timestamp > SENT_MESSAGE_TEXT_TTL_MS) cache.delete(key);
973
+ for (const [key, timestamp] of messageIdCache) if (now - timestamp > SENT_MESSAGE_ID_TTL_MS) messageIdCache.delete(key);
1071
974
  }
1072
975
  return {
1073
976
  remember,
1074
977
  has
1075
978
  };
1076
979
  }
1077
- //#endregion
1078
- //#region extensions/imessage/src/monitor/group-allowlist-warnings.ts
980
+ // extensions/imessage/src/monitor/group-allowlist-warnings.ts
1079
981
  const PER_CHAT_WARNING_CACHE_MAX_SIZE = 512;
1080
982
  const startupWarned = /* @__PURE__ */ new Set();
1081
983
  const perChatWarned = createDedupeCache({
@@ -1111,8 +1013,7 @@ function warnGroupAllowlistDropPerChatOnce(params) {
1111
1013
  params.log(`imessage: dropping group message from chat_id=${chat} (account "${params.accountId}") — not in channels.imessage.groups allowlist. Add channels.imessage.groups["${chat}"] or channels.imessage.groups["*"] to allow it.`);
1112
1014
  return true;
1113
1015
  }
1114
- //#endregion
1115
- //#region extensions/imessage/src/monitor/inbound-dedupe.ts
1016
+ // extensions/imessage/src/monitor/inbound-dedupe.ts
1116
1017
  const IMESSAGE_STALE_INBOUND_THRESHOLD_MS = 9e5;
1117
1018
  const IMESSAGE_RECOVERY_MAX_AGE_MS = 72e5;
1118
1019
  /**
@@ -1128,8 +1029,7 @@ function isStaleIMessageBacklog(message, nowMs, thresholdMs = IMESSAGE_STALE_INB
1128
1029
  if (!Number.isFinite(sentMs)) return false;
1129
1030
  return nowMs - sentMs > thresholdMs;
1130
1031
  }
1131
- //#endregion
1132
- //#region extensions/imessage/src/conversation-route.ts
1032
+ // extensions/imessage/src/conversation-route.ts
1133
1033
  async function resolveIMessageConversationRoute(params) {
1134
1034
  const routeInput = {
1135
1035
  channel: "imessage",
@@ -1181,15 +1081,12 @@ async function resolveIMessageConversationRoute(params) {
1181
1081
  }
1182
1082
  });
1183
1083
  if (runtimeRoute.bindingRecord) await service.touchAsync(runtimeRoute.bindingRecord.bindingId, void 0, runtimeRoute.bindingRecord.conversation);
1184
- if (runtimeRoute.bindingRecord && !runtimeRoute.boundSessionKey) logVerbose(`imessage: plugin-bound conversation ${conversationId}`);
1185
- else if (runtimeRoute.boundSessionKey) logVerbose(`imessage: routed via bound conversation ${conversationId} -> ${runtimeRoute.boundSessionKey}`);
1186
1084
  return {
1187
1085
  route: runtimeRoute.route,
1188
1086
  bindingResolution: runtimeRoute.bindingRecord ? null : bindingResolution
1189
1087
  };
1190
1088
  }
1191
- //#endregion
1192
- //#region src/channels/mention-gating.ts
1089
+ // src/channels/mention-gating.ts
1193
1090
  function resolveBotThreadMentionPolicy(params) {
1194
1091
  if (!params.isBotOwnedThread || params.requireMentionInBotThreads === void 0) return {
1195
1092
  requireMention: params.requireMention,
@@ -1200,8 +1097,7 @@ function resolveBotThreadMentionPolicy(params) {
1200
1097
  implicitMentionKinds: params.requireMentionInBotThreads ? params.implicitMentionKinds?.filter((kind) => kind === "native") : params.implicitMentionKinds
1201
1098
  };
1202
1099
  }
1203
- //#endregion
1204
- //#region extensions/imessage/src/monitor/mention-policy.ts
1100
+ // extensions/imessage/src/monitor/mention-policy.ts
1205
1101
  async function resolveIMessageInboundMentionPolicy(params) {
1206
1102
  const groups = resolveChannelGroups(params.cfg, "imessage", params.accountId);
1207
1103
  const { "*": defaults, ...scopes } = groups ?? {};
@@ -1221,8 +1117,7 @@ async function resolveIMessageInboundMentionPolicy(params) {
1221
1117
  accountId: params.accountId,
1222
1118
  chatId: params.message.chat_id ?? void 0,
1223
1119
  chatGuid: params.message.chat_guid ?? void 0,
1224
- chatIdentifier: params.message.chat_identifier ?? void 0,
1225
- isKnownFromMeMessageId: params.isKnownFromMeMessageId
1120
+ chatIdentifier: params.message.chat_identifier ?? void 0
1226
1121
  }));
1227
1122
  return {
1228
1123
  ...resolveBotThreadMentionPolicy({
@@ -1233,8 +1128,7 @@ async function resolveIMessageInboundMentionPolicy(params) {
1233
1128
  enforceMentionRequirement: isBotOwnedThread && requireMentionInBotThreads === true
1234
1129
  };
1235
1130
  }
1236
- //#endregion
1237
- //#region extensions/imessage/src/monitor/reflection-guard.ts
1131
+ // extensions/imessage/src/monitor/reflection-guard.ts
1238
1132
  const REFLECTION_PATTERNS = [
1239
1133
  {
1240
1134
  re: /(?:#\+){2,}#?/,
@@ -1287,8 +1181,7 @@ function detectReflectedContent(text) {
1287
1181
  matchedLabels
1288
1182
  };
1289
1183
  }
1290
- //#endregion
1291
- //#region extensions/imessage/src/monitor/inbound-processing.ts
1184
+ // extensions/imessage/src/monitor/inbound-processing.ts
1292
1185
  const normalizeNonEmpty = (value) => value.trim() || null;
1293
1186
  const imessageConversationIdentityKinds = /* @__PURE__ */ new Set([
1294
1187
  "plugin:imessage-chat-id",
@@ -1498,12 +1391,13 @@ async function resolveIMessageInboundDecision(params) {
1498
1391
  sender,
1499
1392
  chatId
1500
1393
  });
1394
+ let storeAllowFrom;
1501
1395
  const ingressResolver = getIMessageRuntime().channel.inbound.ingress.createResolver({
1502
1396
  channelId: "imessage",
1503
1397
  accountId: params.accountId,
1504
1398
  identity: imessageIngressIdentity,
1505
1399
  cfg: params.cfg,
1506
- readStoreAllowFrom: async () => params.storeAllowFrom
1400
+ readStoreAllowFrom: () => storeAllowFrom ??= params.readStoreAllowFrom()
1507
1401
  });
1508
1402
  const resolveChannelIngress = (contextBinding) => ingressResolver.message({
1509
1403
  subject: {
@@ -1535,27 +1429,27 @@ async function resolveIMessageInboundDecision(params) {
1535
1429
  if (senderAccess.decision !== "allow") {
1536
1430
  if (isGroup) {
1537
1431
  if (senderAccess.reasonCode === "group_policy_disabled") {
1538
- params.logVerbose?.("Blocked iMessage group message (groupPolicy: disabled)");
1432
+ logVerbose("Blocked iMessage group message (groupPolicy: disabled)");
1539
1433
  return {
1540
1434
  kind: "drop",
1541
1435
  reason: "groupPolicy disabled"
1542
1436
  };
1543
1437
  }
1544
1438
  if (senderAccess.reasonCode === "group_policy_empty_allowlist") {
1545
- params.logVerbose?.("Blocked iMessage group message (groupPolicy: allowlist, no groupAllowFrom)");
1439
+ logVerbose("Blocked iMessage group message (groupPolicy: allowlist, no groupAllowFrom)");
1546
1440
  return {
1547
1441
  kind: "drop",
1548
1442
  reason: "groupPolicy allowlist (empty groupAllowFrom)"
1549
1443
  };
1550
1444
  }
1551
1445
  if (senderAccess.reasonCode === "group_policy_not_allowlisted") {
1552
- params.logVerbose?.(`Blocked iMessage sender ${sender} (not in groupAllowFrom)`);
1446
+ logVerbose(`Blocked iMessage sender ${sender} (not in groupAllowFrom)`);
1553
1447
  return {
1554
1448
  kind: "drop",
1555
1449
  reason: "not in groupAllowFrom"
1556
1450
  };
1557
1451
  }
1558
- params.logVerbose?.(`Blocked iMessage group message (${senderAccess.reasonCode})`);
1452
+ logVerbose(`Blocked iMessage group message (${senderAccess.reasonCode})`);
1559
1453
  return {
1560
1454
  kind: "drop",
1561
1455
  reason: senderAccess.reasonCode
@@ -1569,14 +1463,14 @@ async function resolveIMessageInboundDecision(params) {
1569
1463
  kind: "pairing",
1570
1464
  senderId: senderNormalized
1571
1465
  };
1572
- params.logVerbose?.(`Blocked iMessage sender ${sender} (dmPolicy=${params.dmPolicy})`);
1466
+ logVerbose(`Blocked iMessage sender ${sender} (dmPolicy=${params.dmPolicy})`);
1573
1467
  return {
1574
1468
  kind: "drop",
1575
1469
  reason: "dmPolicy blocked"
1576
1470
  };
1577
1471
  }
1578
1472
  if (isGroup && groupListPolicy.allowlistEnabled && !groupListPolicy.allowed) {
1579
- params.logVerbose?.(`imessage: skipping group message (${groupId ?? "unknown"}) not in allowlist`);
1473
+ logVerbose(`imessage: skipping group message (${groupId ?? "unknown"}) not in allowlist`);
1580
1474
  return {
1581
1475
  kind: "drop",
1582
1476
  reason: "group id not in allowlist"
@@ -1599,8 +1493,7 @@ async function resolveIMessageInboundDecision(params) {
1599
1493
  accountId: params.accountId,
1600
1494
  chatId,
1601
1495
  chatGuid,
1602
- chatIdentifier,
1603
- isKnownFromMeMessageId: params.isKnownFromMeMessageId
1496
+ chatIdentifier
1604
1497
  })));
1605
1498
  if (notificationMode === "own" && !targetIsOwn) return {
1606
1499
  kind: "drop",
@@ -1638,7 +1531,7 @@ async function resolveIMessageInboundDecision(params) {
1638
1531
  ...selfChatLookup,
1639
1532
  text: bodyText
1640
1533
  })) {
1641
- params.logVerbose?.("imessage: dropping self-chat reflected duplicate");
1534
+ logVerbose("imessage: dropping self-chat reflected duplicate");
1642
1535
  return {
1643
1536
  kind: "drop",
1644
1537
  reason: "self-chat echo"
@@ -1653,7 +1546,7 @@ async function resolveIMessageInboundDecision(params) {
1653
1546
  messageIds: inboundMessageIds,
1654
1547
  includePendingText: isSelfChat
1655
1548
  })) {
1656
- params.logVerbose?.(`imessage: skipping echo message${inboundMessageId ? ` id=${inboundMessageId}` : ""}`);
1549
+ logVerbose(`imessage: skipping echo message${inboundMessageId ? ` id=${inboundMessageId}` : ""}`);
1657
1550
  return {
1658
1551
  kind: "drop",
1659
1552
  reason: "echo"
@@ -1662,7 +1555,7 @@ async function resolveIMessageInboundDecision(params) {
1662
1555
  }
1663
1556
  const reflection = detectReflectedContent(messageText);
1664
1557
  if (reflection.isReflection) {
1665
- params.logVerbose?.(`imessage: dropping reflected assistant content (markers: ${reflection.matchedLabels.join(", ")})`);
1558
+ logVerbose(`imessage: dropping reflected assistant content (markers: ${reflection.matchedLabels.join(", ")})`);
1666
1559
  return {
1667
1560
  kind: "drop",
1668
1561
  reason: "reflected assistant content"
@@ -1703,7 +1596,7 @@ async function resolveIMessageInboundDecision(params) {
1703
1596
  body: visibleReply.body ?? "",
1704
1597
  sender: visibleReply.sender
1705
1598
  } : null;
1706
- if (replyContext && !filteredReplyContext && isGroup) params.logVerbose?.(`imessage: drop reply context (mode=${contextVisibilityMode}, sender_allowed=${replySenderAllowed ? "yes" : "no"})`);
1599
+ if (replyContext && !filteredReplyContext && isGroup) logVerbose(`imessage: drop reply context (mode=${contextVisibilityMode}, sender_allowed=${replySenderAllowed ? "yes" : "no"})`);
1707
1600
  const historyKey = isGroup ? String(chatId ?? chatGuid ?? chatIdentifier ?? "unknown") : void 0;
1708
1601
  const mentioned = isGroup ? matchesMentionPatterns(messageText, mentionRegexes) : true;
1709
1602
  const { requireMention, implicitMentionKinds, enforceMentionRequirement } = await resolveIMessageInboundMentionPolicy({
@@ -1712,14 +1605,13 @@ async function resolveIMessageInboundDecision(params) {
1712
1605
  groupId,
1713
1606
  isGroup,
1714
1607
  message: params.message,
1715
- requireMentionOverride: params.opts?.requireMention,
1716
- isKnownFromMeMessageId: params.isKnownFromMeMessageId
1608
+ requireMentionOverride: params.opts?.requireMention
1717
1609
  });
1718
1610
  const canDetectMention = mentionRegexes.length > 0 || enforceMentionRequirement;
1719
1611
  const commandAuthorized = commandAccess.authorized;
1720
1612
  if (commandAccess.shouldBlockControlCommand) {
1721
- if (params.logVerbose) logInboundDrop({
1722
- log: params.logVerbose,
1613
+ logInboundDrop({
1614
+ log: logVerbose,
1723
1615
  channel: "imessage",
1724
1616
  reason: "control command (unauthorized)",
1725
1617
  target: sender
@@ -1746,7 +1638,7 @@ async function resolveIMessageInboundDecision(params) {
1746
1638
  });
1747
1639
  const effectiveWasMentioned = mentionDecision.effectiveWasMentioned;
1748
1640
  if (isGroup && requireMention && canDetectMention && mentionDecision.shouldSkip) {
1749
- params.logVerbose?.(`imessage: skipping group message (no mention)`);
1641
+ logVerbose(`imessage: skipping group message (no mention)`);
1750
1642
  createChannelHistoryWindow({ historyMap: params.groupHistories }).record({
1751
1643
  historyKey: historyKey ?? "",
1752
1644
  limit: params.historyLimit,
@@ -1789,7 +1681,7 @@ async function resolveIMessageInboundDecision(params) {
1789
1681
  };
1790
1682
  }
1791
1683
  async function buildIMessageInboundContext(params) {
1792
- const envelopeOptions = params.envelopeOptions ?? resolveEnvelopeFormatOptions(params.cfg);
1684
+ const envelopeOptions = resolveEnvelopeFormatOptions(params.cfg);
1793
1685
  const { decision } = params;
1794
1686
  const chatId = decision.chatId;
1795
1687
  const chatTarget = decision.isGroup && chatId != null ? formatIMessageChatTarget(chatId) : void 0;
@@ -1926,8 +1818,7 @@ async function buildIMessageInboundContext(params) {
1926
1818
  inboundHistory
1927
1819
  };
1928
1820
  }
1929
- //#endregion
1930
- //#region extensions/imessage/src/monitor/ingress.ts
1821
+ // extensions/imessage/src/monitor/ingress.ts
1931
1822
  const IMESSAGE_INGRESS_PAYLOAD_VERSION = 1;
1932
1823
  const IMESSAGE_INGRESS_DRAIN_INTERVAL_MS = 1e3;
1933
1824
  const IMessageIngressPayloadError = createChannelIngressError("IMessageIngressPayloadError");
@@ -1999,7 +1890,6 @@ function resolveIMessageIngressNonRetryableFailure(error) {
1999
1890
  }
2000
1891
  function createIMessageDurableIngress(options) {
2001
1892
  const queue = options.queue ?? getIMessageRuntime().state.openChannelIngressQueue({ accountId: options.accountId });
2002
- const now = options.now ?? Date.now;
2003
1893
  const dispatchAdmissionQueue = new KeyedAsyncQueue();
2004
1894
  const priorityDispatchQueue = new KeyedAsyncQueue();
2005
1895
  const monitor = createChannelIngressMonitor({
@@ -2056,7 +1946,6 @@ function createIMessageDurableIngress(options) {
2056
1946
  resolveNonRetryableFailure: resolveIMessageIngressNonRetryableFailure,
2057
1947
  onLog: (message) => options.runtime.log?.(`imessage ${message}`)
2058
1948
  },
2059
- now,
2060
1949
  onError: (error) => options.runtime.error?.(`imessage: ingress drain failed: ${formatErrorMessage(error)}`)
2061
1950
  });
2062
1951
  let stopTask;
@@ -2078,8 +1967,7 @@ function createIMessageDurableIngress(options) {
2078
1967
  waitForIdle: monitor.waitForIdle
2079
1968
  };
2080
1969
  }
2081
- //#endregion
2082
- //#region extensions/imessage/src/monitor/loop-rate-limiter.ts
1970
+ // extensions/imessage/src/monitor/loop-rate-limiter.ts
2083
1971
  /**
2084
1972
  * Per-conversation rate limiter that detects rapid-fire identical echo
2085
1973
  * patterns and suppresses them before they amplify into queue overflow.
@@ -2121,8 +2009,7 @@ function createLoopRateLimiter() {
2121
2009
  }
2122
2010
  };
2123
2011
  }
2124
- //#endregion
2125
- //#region extensions/imessage/src/monitor/media-staging.ts
2012
+ // extensions/imessage/src/monitor/media-staging.ts
2126
2013
  function createTypeOnlyIMessageAttachment(attachment) {
2127
2014
  const contentType = attachment.mime_type?.trim() || void 0;
2128
2015
  return {
@@ -2172,7 +2059,7 @@ async function readAttachmentBuffer(params) {
2172
2059
  originalFilename: `${path.parse(params.attachmentPath).name || "imessage-attachment"}.jpg`
2173
2060
  };
2174
2061
  } catch (err) {
2175
- params.deps.logVerbose?.(`imessage: HEIC attachment conversion failed; staging original instead: ${String(err)}`);
2062
+ logVerbose(`imessage: HEIC attachment conversion failed; staging original instead: ${String(err)}`);
2176
2063
  }
2177
2064
  return {
2178
2065
  buffer,
@@ -2181,7 +2068,6 @@ async function readAttachmentBuffer(params) {
2181
2068
  };
2182
2069
  }
2183
2070
  async function stageIMessageAttachments(attachments, params) {
2184
- const deps = params.deps ?? {};
2185
2071
  const staged = [];
2186
2072
  let unavailableCount = 0;
2187
2073
  for (const attachment of attachments) {
@@ -2196,8 +2082,7 @@ async function stageIMessageAttachments(attachments, params) {
2196
2082
  attachmentPath,
2197
2083
  mimeType: attachment.mime_type,
2198
2084
  maxBytes: params.maxBytes,
2199
- allowedRoots: params.allowedRoots,
2200
- deps
2085
+ allowedRoots: params.allowedRoots
2201
2086
  });
2202
2087
  const saved = await saveMediaBuffer(media.buffer, media.contentType, "inbound", params.maxBytes, media.originalFilename);
2203
2088
  const contentType = saved.contentType ?? media.contentType;
@@ -2209,7 +2094,7 @@ async function stageIMessageAttachments(attachments, params) {
2209
2094
  } catch (err) {
2210
2095
  unavailableCount += 1;
2211
2096
  staged.push(createTypeOnlyIMessageAttachment(attachment));
2212
- deps.logVerbose?.(`imessage: failed to stage inbound attachment: ${String(err)}`);
2097
+ logVerbose(`imessage: failed to stage inbound attachment: ${String(err)}`);
2213
2098
  }
2214
2099
  }
2215
2100
  return {
@@ -2217,14 +2102,12 @@ async function stageIMessageAttachments(attachments, params) {
2217
2102
  unavailableCount
2218
2103
  };
2219
2104
  }
2220
- //#endregion
2221
- //#region extensions/imessage/src/monitor/poll-comment.ts
2222
- const DEFAULT_COMMENT_WINDOW_MS = 15e3;
2223
- function createPollCommentFolder(options) {
2224
- const windowMs = options?.windowMs ?? DEFAULT_COMMENT_WINDOW_MS;
2105
+ // extensions/imessage/src/monitor/poll-comment.ts
2106
+ const COMMENT_WINDOW_MS = 15e3;
2107
+ function createPollCommentFolder() {
2225
2108
  const seenPolls = /* @__PURE__ */ new Map();
2226
2109
  function prune(referenceMs) {
2227
- for (const [key, seen] of seenPolls) if (referenceMs - seen.atMs > windowMs) seenPolls.delete(key);
2110
+ for (const [key, seen] of seenPolls) if (referenceMs - seen.atMs > COMMENT_WINDOW_MS) seenPolls.delete(key);
2228
2111
  }
2229
2112
  return {
2230
2113
  rememberPoll(guid, atMs, sender) {
@@ -2240,14 +2123,13 @@ function createPollCommentFolder(options) {
2240
2123
  const key = replyToGuid?.trim();
2241
2124
  if (!key || !Number.isFinite(atMs)) return false;
2242
2125
  const seen = seenPolls.get(key);
2243
- if (!seen || atMs < seen.atMs || atMs - seen.atMs > windowMs) return false;
2126
+ if (!seen || atMs < seen.atMs || atMs - seen.atMs > COMMENT_WINDOW_MS) return false;
2244
2127
  const replySender = normalizeLowercaseStringOrEmpty(sender);
2245
2128
  return seen.sender.length > 0 && replySender.length > 0 && seen.sender === replySender;
2246
2129
  }
2247
2130
  };
2248
2131
  }
2249
- //#endregion
2250
- //#region extensions/imessage/src/monitor/poll-render.ts
2132
+ // extensions/imessage/src/monitor/poll-render.ts
2251
2133
  function renderIMessagePollBody(poll, sender, renderOptions) {
2252
2134
  const options = poll.options ?? [];
2253
2135
  if (poll.kind === "vote" || poll.vote && options.length === 0) {
@@ -2288,17 +2170,15 @@ function renderIMessagePollBody(poll, sender, renderOptions) {
2288
2170
  const selector = renderOptions?.preferOptionId ? "pollOptionId = the stable option id shown above" : "pollOptionIndex = the option number";
2289
2171
  return `\u{1F4CA} Poll${question ? `: ${question}` : ""} — options: ${optionList}. Cast your vote on this poll with the poll-vote action (${selector}); do not answer in a text reply.`;
2290
2172
  }
2291
- //#endregion
2292
- //#region extensions/imessage/src/monitor/reaction-system-event.ts
2173
+ // extensions/imessage/src/monitor/reaction-system-event.ts
2293
2174
  function enqueueIMessageReactionSystemEvent(params) {
2294
2175
  const { decision, runtime } = params;
2295
2176
  const queued = enqueueRoutedSystemEvent(decision.text, decision.route, { contextKey: decision.contextKey });
2296
2177
  runtime.log?.(`imessage: reaction system event ${queued ? "queued" : "deduped"} session=${decision.route.sessionKey} target=${decision.reaction.targetGuid ?? "unknown"} action=${decision.reaction.action} emoji=${decision.reaction.emoji}`);
2297
- params.logVerbose?.("imessage: reaction event enqueued");
2178
+ logVerbose("imessage: reaction event enqueued");
2298
2179
  return queued;
2299
2180
  }
2300
- //#endregion
2301
- //#region extensions/imessage/src/monitor/recovery-cursor.ts
2181
+ // extensions/imessage/src/monitor/recovery-cursor.ts
2302
2182
  const RECOVERY_CURSOR_STORE_OPTIONS = {
2303
2183
  namespace: "imessage.recovery-cursor",
2304
2184
  maxEntries: 64
@@ -2358,36 +2238,28 @@ function applyRecoveryCursorUpdate(key, update) {
2358
2238
  return write;
2359
2239
  }
2360
2240
  async function readRecoveryCursor(accountId, dbIdentity) {
2361
- try {
2362
- const store = openRecoveryCursorStore();
2363
- const key = recoveryCursorStoreKey(accountId, dbIdentity);
2364
- const value = await store.lookup(key);
2365
- if (value) return Number.isFinite(value.lastRowid) ? value.lastRowid : null;
2366
- const legacy = await store.consume(accountId);
2367
- if (legacy && Number.isFinite(legacy.lastRowid)) {
2368
- await store.registerIfAbsent(key, { lastRowid: legacy.lastRowid });
2369
- const adopted = await store.lookup(key);
2370
- return adopted && Number.isFinite(adopted.lastRowid) ? adopted.lastRowid : null;
2371
- }
2372
- return null;
2373
- } catch {
2374
- return null;
2241
+ const store = openRecoveryCursorStore();
2242
+ const key = recoveryCursorStoreKey(accountId, dbIdentity);
2243
+ const value = await store.lookup(key);
2244
+ if (value) return Number.isFinite(value.lastRowid) ? value.lastRowid : null;
2245
+ const legacy = await store.consume(accountId);
2246
+ if (legacy && Number.isFinite(legacy.lastRowid)) {
2247
+ await store.registerIfAbsent(key, { lastRowid: legacy.lastRowid });
2248
+ const adopted = await store.lookup(key);
2249
+ return adopted && Number.isFinite(adopted.lastRowid) ? adopted.lastRowid : null;
2375
2250
  }
2251
+ return null;
2376
2252
  }
2377
2253
  async function migrateLegacyCatchupCursor(accountId, dbIdentity) {
2378
- try {
2379
- const legacy = getIMessageRuntime().state.openKeyedStoreV2({
2380
- namespace: LEGACY_CATCHUP_CURSOR_NAMESPACE,
2381
- maxEntries: LEGACY_CATCHUP_CURSOR_MAX_ENTRIES
2382
- });
2383
- const key = createHash("sha256").update(accountId, "utf8").digest("hex").slice(0, 32);
2384
- const value = await legacy.consume(key);
2385
- const rowid = typeof value?.lastSeenRowid === "number" && Number.isFinite(value.lastSeenRowid) ? value.lastSeenRowid : null;
2386
- if (rowid !== null) await advanceIMessageRecoveryCursor(accountId, dbIdentity, rowid);
2387
- return rowid;
2388
- } catch {
2389
- return null;
2390
- }
2254
+ const legacy = getIMessageRuntime().state.openKeyedStoreV2({
2255
+ namespace: LEGACY_CATCHUP_CURSOR_NAMESPACE,
2256
+ maxEntries: LEGACY_CATCHUP_CURSOR_MAX_ENTRIES
2257
+ });
2258
+ const key = createHash("sha256").update(accountId, "utf8").digest("hex").slice(0, 32);
2259
+ const value = await legacy.consume(key);
2260
+ const rowid = typeof value?.lastSeenRowid === "number" && Number.isFinite(value.lastSeenRowid) ? value.lastSeenRowid : null;
2261
+ if (rowid !== null) await advanceIMessageRecoveryCursor(accountId, dbIdentity, rowid);
2262
+ return rowid;
2391
2263
  }
2392
2264
  async function reconcileRecoveryCursorToWatermark(accountId, dbIdentity, cursorRowid, watermarkRowid) {
2393
2265
  if (cursorRowid === null || watermarkRowid === null || cursorRowid <= watermarkRowid) return cursorRowid;
@@ -2410,7 +2282,6 @@ async function loadIMessageRecoveryCursor(accountId, dbIdentity, options = {}) {
2410
2282
  const watermarkRowid = typeof options.watermarkRowid === "number" && Number.isFinite(options.watermarkRowid) ? options.watermarkRowid : null;
2411
2283
  const current = await readRecoveryCursor(accountId, dbIdentity);
2412
2284
  if (current !== null) return await reconcileRecoveryCursorToWatermark(accountId, dbIdentity, current, watermarkRowid);
2413
- if (options.migrateLegacyCatchup === false) return null;
2414
2285
  return await reconcileRecoveryCursorToWatermark(accountId, dbIdentity, await migrateLegacyCatchupCursor(accountId, dbIdentity), watermarkRowid);
2415
2286
  }
2416
2287
  /** Advance the cursor forward to `rowid` (monotonic per database; never rewinds). */
@@ -2423,11 +2294,9 @@ async function advanceIMessageRecoveryCursor(accountId, dbIdentity, rowid) {
2423
2294
  });
2424
2295
  } catch {}
2425
2296
  }
2426
- //#endregion
2427
- //#region extensions/imessage/src/monitor/self-chat-cache.ts
2297
+ // extensions/imessage/src/monitor/self-chat-cache.ts
2428
2298
  const SELF_CHAT_TTL_MS = 1e4;
2429
2299
  const SELF_CHAT_CREATED_AT_TOLERANCE_MS = 1e3;
2430
- const MAX_SELF_CHAT_CACHE_ENTRIES = 512;
2431
2300
  const CLEANUP_MIN_INTERVAL_MS = 1e3;
2432
2301
  function normalizeText(text) {
2433
2302
  if (!text) return null;
@@ -2437,87 +2306,62 @@ function normalizeText(text) {
2437
2306
  function isUsableTimestamp(createdAt) {
2438
2307
  return typeof createdAt === "number" && Number.isFinite(createdAt);
2439
2308
  }
2440
- function digestText(text) {
2441
- return createHash("sha256").update(text).digest("hex");
2442
- }
2443
2309
  function buildScope(parts) {
2444
2310
  if (!parts.isGroup) return `${parts.accountId}:imessage:${parts.sender}`;
2445
2311
  const chatTarget = formatIMessageChatTarget(parts.chatId) || "chat_id:unknown";
2446
2312
  return `${parts.accountId}:${chatTarget}:imessage:${parts.sender}`;
2447
2313
  }
2448
- var DefaultSelfChatCache = class {
2314
+ var SelfChatCache = class {
2449
2315
  constructor() {
2450
- this.cache = /* @__PURE__ */ new Map();
2451
- this.insertionOrder = /* @__PURE__ */ new Map();
2316
+ this.entries = [];
2452
2317
  this.lastCleanupAt = 0;
2453
2318
  }
2454
2319
  buildBucketKey(lookup) {
2455
2320
  const text = normalizeText(lookup.text);
2456
2321
  if (!text) return null;
2457
- return `${buildScope(lookup)}:${digestText(text)}`;
2322
+ return `${buildScope(lookup)}:${sha256Hex(text)}`;
2458
2323
  }
2459
2324
  remember(lookup) {
2460
2325
  const key = this.buildBucketKey(lookup);
2461
2326
  if (!key || !isUsableTimestamp(lookup.createdAt)) return;
2462
- const entries = this.cache.get(key) ?? /* @__PURE__ */ new Set();
2463
- const entry = {
2327
+ this.entries.push({
2328
+ key,
2464
2329
  createdAt: lookup.createdAt,
2465
2330
  createdAtSkewToleranceMs: lookup.allowCreatedAtSkew ? SELF_CHAT_CREATED_AT_TOLERANCE_MS : 0,
2466
2331
  rememberedAt: Date.now()
2467
- };
2468
- entries.add(entry);
2469
- this.cache.set(key, entries);
2470
- this.insertionOrder.set(entry, key);
2332
+ });
2471
2333
  this.maybeCleanup();
2472
2334
  }
2473
2335
  has(lookup) {
2474
2336
  this.maybeCleanup();
2475
2337
  const key = this.buildBucketKey(lookup);
2476
2338
  if (!key || !isUsableTimestamp(lookup.createdAt)) return false;
2477
- const entries = this.cache.get(key);
2478
- if (!entries) return false;
2479
2339
  const now = Date.now();
2480
2340
  const createdAt = lookup.createdAt;
2481
- return [...entries.values()].some((entry) => {
2341
+ return this.entries.some((entry) => {
2482
2342
  const createdAtDelta = Math.abs(entry.createdAt - createdAt);
2483
- return now - entry.rememberedAt <= SELF_CHAT_TTL_MS && (createdAtDelta === 0 || createdAtDelta < entry.createdAtSkewToleranceMs);
2343
+ return entry.key === key && now - entry.rememberedAt <= SELF_CHAT_TTL_MS && (createdAtDelta === 0 || createdAtDelta < entry.createdAtSkewToleranceMs);
2484
2344
  });
2485
2345
  }
2486
- removeEntry(entry, key) {
2487
- this.insertionOrder.delete(entry);
2488
- const entries = this.cache.get(key);
2489
- entries?.delete(entry);
2490
- if (entries?.size === 0) this.cache.delete(key);
2491
- }
2492
2346
  maybeCleanup() {
2493
2347
  const now = Date.now();
2494
2348
  if (now - this.lastCleanupAt < CLEANUP_MIN_INTERVAL_MS) return;
2495
2349
  this.lastCleanupAt = now;
2496
- for (const [entry, key] of this.insertionOrder) if (now - entry.rememberedAt > SELF_CHAT_TTL_MS) this.removeEntry(entry, key);
2497
- while (this.insertionOrder.size > MAX_SELF_CHAT_CACHE_ENTRIES) {
2498
- const [entry, key] = expectDefined(this.insertionOrder.entries().next().value, "oldest iMessage self-chat cache entry");
2499
- this.removeEntry(entry, key);
2500
- }
2350
+ this.entries = this.entries.filter((entry) => now - entry.rememberedAt <= SELF_CHAT_TTL_MS).slice(-512);
2501
2351
  }
2502
2352
  };
2503
- function createSelfChatCache() {
2504
- return new DefaultSelfChatCache();
2505
- }
2506
- //#endregion
2507
- //#region extensions/imessage/src/monitor/watch-error-log.ts
2508
- const MAX_WATCH_ERROR_MESSAGE_CHARS = 200;
2353
+ // extensions/imessage/src/monitor/watch-error-log.ts
2509
2354
  function sanitizeIMessageWatchErrorPayload(payload) {
2510
2355
  if (!isRecord(payload)) return {};
2511
2356
  const safe = {};
2512
2357
  if (typeof payload.code === "number" && Number.isFinite(payload.code)) safe.code = payload.code;
2513
2358
  if (typeof payload.message === "string") {
2514
- const sanitizedMessage = sanitizeTerminalText(payload.message);
2515
- if (sanitizedMessage) safe.message = sanitizedMessage.length > MAX_WATCH_ERROR_MESSAGE_CHARS ? `${truncateUtf16Safe(sanitizedMessage, 199)}…` : sanitizedMessage;
2359
+ const guidance = normalizeIMessageFullDiskAccessError(payload.message);
2360
+ if (guidance) safe.message = guidance;
2516
2361
  }
2517
2362
  return safe;
2518
2363
  }
2519
- //#endregion
2520
- //#region extensions/imessage/src/monitor/monitor-provider.ts
2364
+ // extensions/imessage/src/monitor/monitor-provider.ts
2521
2365
  const WATCH_SUBSCRIBE_MAX_ATTEMPTS = 3;
2522
2366
  const WATCH_SUBSCRIBE_RETRY_DELAY_MS = 1e3;
2523
2367
  const CHANNEL_APPROVAL_GATEWAY_RUNTIME_CONTEXT_CAPABILITY = "approval.gateway";
@@ -2576,7 +2420,7 @@ async function monitorIMessageProvider(opts) {
2576
2420
  const historyLimit = resolvePromptHistoryLimit(imessageCfg.historyLimit ?? cfg.messages?.groupChat?.historyLimit);
2577
2421
  const groupHistories = /* @__PURE__ */ new Map();
2578
2422
  const sentMessageCache = createSentMessageCache();
2579
- const selfChatCache = createSelfChatCache();
2423
+ const selfChatCache = new SelfChatCache();
2580
2424
  const loopRateLimiter = createLoopRateLimiter();
2581
2425
  const textLimit = resolveTextChunkLimit(cfg, "imessage", accountInfo.accountId);
2582
2426
  const allowFrom = normalizeStringEntries(imessageCfg.allowFrom);
@@ -2640,7 +2484,10 @@ async function monitorIMessageProvider(opts) {
2640
2484
  error
2641
2485
  });
2642
2486
  let staleBacklogSuppressed = 0;
2643
- const loggedThrottledDropDiagnostics = createIMessageThrottledDropDiagnosticCache();
2487
+ const loggedThrottledDropDiagnostics = createDedupeCache({
2488
+ maxSize: 512,
2489
+ ttlMs: 0
2490
+ });
2644
2491
  const watchSourceDbPath = resolveIMessageChatDbLookupPath({
2645
2492
  cliPath,
2646
2493
  dbPath,
@@ -2652,10 +2499,7 @@ async function monitorIMessageProvider(opts) {
2652
2499
  dbPath,
2653
2500
  remoteHost
2654
2501
  });
2655
- const recoveryCursorRowid = await loadIMessageRecoveryCursor(accountInfo.accountId, recoveryCursorDbIdentity, {
2656
- migrateLegacyCatchup: !catchupCfg.enabled,
2657
- watermarkRowid: recoveryBoundaryRowid
2658
- });
2502
+ const recoveryCursorRowid = catchupCfg.enabled ? null : await loadIMessageRecoveryCursor(accountInfo.accountId, recoveryCursorDbIdentity, { watermarkRowid: recoveryBoundaryRowid });
2659
2503
  const reconciledWatchSinceRowid = catchupCfg.enabled ? null : recoveryCursorRowid !== null ? recoveryBoundaryRowid !== null ? Math.max(recoveryCursorRowid, recoveryBoundaryRowid - 500) : recoveryCursorRowid : recoveryBoundaryRowid;
2660
2504
  const watchSinceRowid = reconciledWatchSinceRowid === 0 ? -1 : reconciledWatchSinceRowid;
2661
2505
  let latestAdvancedRecoveryCursorRowid = recoveryCursorRowid ?? -1;
@@ -2718,14 +2562,7 @@ async function monitorIMessageProvider(opts) {
2718
2562
  await abandon();
2719
2563
  return;
2720
2564
  }
2721
- const combined = entries.length === 1 ? expectDefined(entries[0], "single iMessage dispatch entry").message : combineIMessagePayloads(entries.map((entry) => entry.message));
2722
- if (entries.length > 1 && shouldLogVerbose()) {
2723
- const text = combined.text ?? "";
2724
- const preview = sliceUtf16Safe(text, 0, 50);
2725
- const ellipsis = text.length > 50 ? "..." : "";
2726
- logVerbose(`[imessage] merged ${entries.length} debounced messages: "${preview}${ellipsis}"`);
2727
- }
2728
- await handleMessageNow(combined, admissionLifecycle);
2565
+ await handleMessageNow(entries.length === 1 ? expectDefined(entries[0], "single iMessage dispatch entry").message : combineIMessagePayloads(entries.map((entry) => entry.message)), admissionLifecycle);
2729
2566
  await settle();
2730
2567
  } catch (err) {
2731
2568
  await abandon();
@@ -2831,12 +2668,6 @@ async function monitorIMessageProvider(opts) {
2831
2668
  return;
2832
2669
  }
2833
2670
  const { messageText, bodyText, mediaFacts, mediaCandidates, rawMediaAttachments, effectiveAttachmentRoots } = resolveIMessageInboundBodyText(message);
2834
- const storeAllowFrom = await readChannelAllowFromStore("imessage", process.env, accountInfo.accountId).catch(() => []);
2835
- const isQuestionReaction = hasIMessageQuestionReactionTarget({
2836
- accountId: accountInfo.accountId,
2837
- message,
2838
- bodyText
2839
- });
2840
2671
  const decision = await resolveIMessageInboundDecision({
2841
2672
  cfg,
2842
2673
  accountId: accountInfo.accountId,
@@ -2850,13 +2681,12 @@ async function monitorIMessageProvider(opts) {
2850
2681
  allowLegacyConversationAllowFromForGroup,
2851
2682
  groupPolicy,
2852
2683
  dmPolicy,
2853
- storeAllowFrom,
2684
+ readStoreAllowFrom: () => readChannelAllowFromStore("imessage", process.env, accountInfo.accountId),
2854
2685
  historyLimit,
2855
2686
  groupHistories,
2856
2687
  echoCache: sentMessageCache,
2857
2688
  selfChatCache,
2858
- reactionNotifications: isQuestionReaction ? "all" : imessageCfg.reactionNotifications,
2859
- logVerbose
2689
+ reactionNotifications: imessageCfg.reactionNotifications
2860
2690
  });
2861
2691
  const chatId = message.chat_id ?? void 0;
2862
2692
  const senderForKey = (message.sender ?? "").trim();
@@ -2923,18 +2753,9 @@ async function monitorIMessageProvider(opts) {
2923
2753
  return;
2924
2754
  }
2925
2755
  if (decision.kind === "reaction") {
2926
- if (await maybeResolveIMessageQuestionReaction({
2927
- cfg,
2928
- accountId: accountInfo.accountId,
2929
- message,
2930
- bodyText,
2931
- senderId: decision.senderNormalized,
2932
- logDebug: logVerbose
2933
- })) return;
2934
2756
  enqueueIMessageReactionSystemEvent({
2935
2757
  decision,
2936
- runtime,
2937
- logVerbose
2758
+ runtime
2938
2759
  });
2939
2760
  return;
2940
2761
  }
@@ -2993,8 +2814,7 @@ async function monitorIMessageProvider(opts) {
2993
2814
  unavailableCount: rawMediaAttachments.filter((attachment) => !attachment.path).length
2994
2815
  } : await stageIMessageAttachments(mediaCandidates, {
2995
2816
  maxBytes: mediaMaxBytes,
2996
- allowedRoots: effectiveAttachmentRoots,
2997
- deps: { logVerbose }
2817
+ allowedRoots: effectiveAttachmentRoots
2998
2818
  });
2999
2819
  const mediaAttachments = staged.attachments;
3000
2820
  const unavailableCount = staged.unavailableCount;
@@ -3019,8 +2839,7 @@ async function monitorIMessageProvider(opts) {
3019
2839
  message,
3020
2840
  senderNormalized: decision.senderNormalized,
3021
2841
  limit: dmHistoryLimit,
3022
- envelopeOptions: resolveEnvelopeFormatOptions(cfg),
3023
- logVerbose
2842
+ envelopeOptions: resolveEnvelopeFormatOptions(cfg)
3024
2843
  }) : void 0;
3025
2844
  const pluginChannelRuntime = opts.channelRuntime;
3026
2845
  const { ctxPayload, chatTarget, imessageTo } = await buildIMessageInboundContext({
@@ -3042,10 +2861,6 @@ async function monitorIMessageProvider(opts) {
3042
2861
  allowFrom,
3043
2862
  normalizeEntry: normalizeIMessageHandle
3044
2863
  });
3045
- if (shouldLogVerbose()) {
3046
- const preview = truncateUtf16Safe(ctxPayload.Body ?? "", 200).replace(/\n/g, "\\n");
3047
- logVerbose(`imessage inbound: chatId=${chatId ?? "unknown"} from=${ctxPayload.From} len=${(ctxPayload.Body ?? "").length} preview="${preview}"`);
3048
- }
3049
2864
  const sendReadReceipts = imessageCfg.sendReadReceipts !== false;
3050
2865
  const typingTarget = ctxPayload.To;
3051
2866
  const readTarget = !decision.isGroup && decision.chatGuid ? `chat_guid:${decision.chatGuid}` : typingTarget;
@@ -3211,14 +3026,13 @@ async function monitorIMessageProvider(opts) {
3211
3026
  message,
3212
3027
  gatewayRuntime: approvalGatewayRuntime
3213
3028
  })) return true;
3214
- return await maybeResolveIMessageApprovalReaction({
3029
+ return (await handleIMessageApprovalReaction({
3215
3030
  cfg,
3216
3031
  accountId: accountInfo.accountId,
3217
3032
  message,
3218
3033
  bodyText: resolveIMessageInboundBodyText(message).bodyText,
3219
- gatewayRuntime: approvalGatewayRuntime,
3220
- logVerboseMessage: logVerbose
3221
- });
3034
+ gatewayRuntime: approvalGatewayRuntime
3035
+ })).handled;
3222
3036
  };
3223
3037
  const ingress = createIMessageDurableIngress({
3224
3038
  accountId: accountInfo.accountId,
@@ -3385,8 +3199,7 @@ async function monitorIMessageProvider(opts) {
3385
3199
  cfg,
3386
3200
  accountId: accountInfo.accountId,
3387
3201
  allowRecentChatDiscovery,
3388
- gatewayRuntime: approvalGatewayRuntime,
3389
- logVerboseMessage: logVerbose
3202
+ gatewayRuntime: approvalGatewayRuntime
3390
3203
  }).catch((err) => {
3391
3204
  logVerbose(`imessage: approval reaction poll failed: ${String(err)}`);
3392
3205
  });
@@ -3439,8 +3252,7 @@ async function monitorIMessageProvider(opts) {
3439
3252
  await ingress.stop();
3440
3253
  }
3441
3254
  }
3442
- //#endregion
3443
- //#region extensions/imessage/src/channel.runtime.ts
3255
+ // extensions/imessage/src/channel.runtime.ts
3444
3256
  async function sendIMessageOutbound(params) {
3445
3257
  const send = resolveOutboundSendDep(params.deps, "imessage", { legacyKeys: IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageIMessage;
3446
3258
  const maxBytes = resolveChannelMediaMaxBytes({
@@ -3455,8 +3267,8 @@ async function sendIMessageOutbound(params) {
3455
3267
  ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {},
3456
3268
  ...params.audioAsVoice ? { audioAsVoice: true } : {},
3457
3269
  maxBytes,
3458
- accountId: params.accountId ?? void 0,
3459
- replyToId: params.replyToId ?? void 0,
3270
+ accountId: params.accountId,
3271
+ replyToId: params.replyToId,
3460
3272
  conversationReadOrigin: params.conversationReadOrigin,
3461
3273
  assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
3462
3274
  onPlatformSendDispatch: params.onPlatformSendDispatch,
@@ -3520,5 +3332,4 @@ async function startIMessageGatewayAccount(ctx) {
3520
3332
  statusSink
3521
3333
  });
3522
3334
  }
3523
- //#endregion
3524
- export { imessageSetupWizard, probeIMessageAccount, sendIMessageOutbound, startIMessageGatewayAccount };
3335
+ export { probeIMessageAccount, sendIMessageOutbound, startIMessageGatewayAccount };