@openclaw/imessage 2026.9.6 → 2026.9.7

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 (81) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{accounts-CUxZrTcY.mjs → accounts-nzcU0cq2.mjs} +3 -6
  3. package/dist/.setup/{actions.runtime-D0zG_96v.mjs → actions.runtime-DdBN29zj.mjs} +3 -5
  4. package/dist/.setup/{api-RZv6yXul.mjs → api-B9Qx21G-.mjs} +6 -5
  5. package/dist/.setup/{api-VLVcFh7r.mjs → api-D2S6FhGw.mjs} +7 -7
  6. package/dist/.setup/{approval-handler.runtime-Bv5_XgNr.mjs → approval-handler.runtime-DKSq0DWq.mjs} +8 -8
  7. package/dist/.setup/{approval-reactions-D6RFg6lU.mjs → approval-reactions-Bp33xc83.mjs} +5 -5
  8. package/dist/.setup/{channel-BLTaKdSK.mjs → channel-9fyvuN_p.mjs} +97 -152
  9. package/dist/.setup/channel.runtime-n-MPKL8k.mjs +92 -0
  10. package/dist/.setup/{config-schema-CCbTcJEV.mjs → config-schema-4Q3_EqYt.mjs} +9 -1
  11. package/dist/.setup/{group-policy-Cjztkquv.mjs → group-policy-90pw4tyG.mjs} +48 -334
  12. package/dist/.setup/{media-contract-DKJK7rh3.mjs → media-contract-CagwSMvo.mjs} +1 -1
  13. package/dist/.setup/{message-tool-api-pvlcOJPG.mjs → message-tool-api-D032l82H.mjs} +3 -18
  14. package/dist/.setup/{monitor-BJ3Ozi6I.mjs → monitor-fv9nRuTH.mjs} +211 -280
  15. package/dist/.setup/{question-reactions-lm8OxWbb.mjs → question-reactions-Cy-dmU_j.mjs} +1 -1
  16. package/dist/.setup/{remote-file-Bye99O-C.mjs → remote-file-DRPCaVmg.mjs} +70 -21
  17. package/dist/.setup/rolldown-runtime-BBjsoOtd.mjs +27 -0
  18. package/dist/.setup/{sanitize-outbound-sJPF2DVM.mjs → sanitize-outbound-3MLljgtY.mjs} +86 -24
  19. package/dist/.setup/{send-odAfTQ2J.mjs → send-Cu9nl757.mjs} +28 -112
  20. package/dist/.setup/setup-core-8MDdYHj5.mjs +226 -0
  21. package/dist/.setup/{channel.runtime---s2k4YN.mjs → setup-surface-tGXFDdWh.mjs} +6 -103
  22. package/dist/.setup/state-migrations-B-Q7bO0Y.mjs +47 -0
  23. package/dist/.setup/{targets-Cc9vthzI.mjs → targets-BicBiYsM.mjs} +10 -16
  24. package/dist/api.js +7 -7
  25. package/dist/channel-config-api.js +1 -1
  26. package/dist/channel-plugin-api.js +1 -1
  27. package/dist/contract-api.js +1 -1
  28. package/dist/doctor-contract-api.js +168 -7
  29. package/dist/media-contract-api.js +1 -1
  30. package/dist/message-tool-api.js +1 -1
  31. package/dist/runtime-api.js +6 -6
  32. package/dist/setup-entry.js +1 -1
  33. package/dist/src/chat-db.worker.js +6 -1
  34. package/node_modules/typebox/build/compile/code.mjs +1 -2
  35. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  36. package/node_modules/typebox/build/format/iri.mjs +16 -9
  37. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  38. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  39. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  40. package/node_modules/typebox/build/guard/index.mjs +6 -0
  41. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  42. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  43. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  44. package/node_modules/typebox/build/schema/build.mjs +2 -3
  45. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  46. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  47. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  48. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  49. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  50. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  51. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  52. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  53. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  54. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  55. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  56. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  57. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  58. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  59. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  60. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  61. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  62. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  63. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  64. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  65. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  66. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  67. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  68. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  69. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  70. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  71. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  72. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  73. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  74. package/node_modules/typebox/package.json +1 -1
  75. package/node_modules/typebox/readme.md +3 -1
  76. package/openclaw.plugin.json +14 -0
  77. package/package.json +5 -5
  78. package/dist/.setup/rolldown-runtime-D7D4PA-g.mjs +0 -13
  79. package/dist/.setup/state-contract-DvahEY4X.mjs +0 -56
  80. package/dist/.setup/state-migrations-DIDzI99d.mjs +0 -277
  81. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
package/assets/icon.png CHANGED
Binary file
@@ -6,7 +6,7 @@ import path from "node:path";
6
6
  import { createAccountListHelpers } from "openclaw/plugin-sdk/account-helpers";
7
7
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
8
8
  import os from "node:os";
9
- import fs$1 from "node:fs/promises";
9
+ import fs from "node:fs/promises";
10
10
  import { normalizeScpRemoteHost } from "openclaw/plugin-sdk/host-runtime";
11
11
  //#region extensions/imessage/src/cli-path.ts
12
12
  const localCliPathCache = /* @__PURE__ */ new Map();
@@ -167,7 +167,7 @@ async function resolveIMessageRemoteHost(params) {
167
167
  const lookup = (async () => {
168
168
  let detected;
169
169
  try {
170
- detected = parseRemoteHost(await fs$1.readFile(key, "utf8"));
170
+ detected = parseRemoteHost(await fs.readFile(key, "utf8"));
171
171
  } catch (error) {
172
172
  const code = error?.code;
173
173
  if (code !== "ENOENT" && code !== "ENOTDIR") logVerbose(`imessage: failed to inspect cliPath ${params.cliPath}: ${String(error)}`);
@@ -190,9 +190,6 @@ async function resolveIMessageRemoteHost(params) {
190
190
  const { listAccountIds, resolveDefaultAccountId, resolveAccountConfig: resolveMergedIMessageAccountConfig } = createAccountListHelpers("imessage", { implicitDefaultAccount: { channelKeys: ["cliPath", "dbPath"] } });
191
191
  const listIMessageAccountIds = listAccountIds;
192
192
  const resolveDefaultIMessageAccountId = resolveDefaultAccountId;
193
- function resolveIMessageAccountConfig(cfg, accountId) {
194
- return resolveAccountEntry(cfg.channels?.imessage?.accounts, accountId);
195
- }
196
193
  function asStreamingConfigObject(value) {
197
194
  return asOptionalRecord(value);
198
195
  }
@@ -214,7 +211,7 @@ function mergeIMessageStreamingConfig(base, account) {
214
211
  };
215
212
  }
216
213
  function mergeIMessageAccountConfig(cfg, accountId) {
217
- const accountConfig = resolveIMessageAccountConfig(cfg, accountId);
214
+ const accountConfig = resolveAccountEntry(cfg.channels?.imessage?.accounts, accountId);
218
215
  const merged = resolveMergedIMessageAccountConfig(cfg, accountId);
219
216
  const streaming = mergeIMessageStreamingConfig((cfg.channels?.imessage)?.streaming, accountConfig?.streaming);
220
217
  return streaming !== void 0 ? {
@@ -1,5 +1,5 @@
1
- import { m as resolveIMessageMessageId, n as sanitizeIMessageFinalOutboundText, o as createIMessageRpcClient, s as runIMessageCliJsonCommand, y as normalizeDirectChatIdentifier } from "./sanitize-outbound-sJPF2DVM.mjs";
2
- import { n as authorizeIMessageResourceReference, t as withIMessageRemoteFile } from "./remote-file-Bye99O-C.mjs";
1
+ import { E as normalizeDirectChatIdentifier, m as resolveIMessageMessageId, n as sanitizeIMessageFinalOutboundText, o as createIMessageRpcClient, s as runIMessageCliJsonCommand } from "./sanitize-outbound-3MLljgtY.mjs";
2
+ import { n as authorizeIMessageResourceReference, t as withIMessageRemoteFile } from "./remote-file-DRPCaVmg.mjs";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { basename, parse, win32 } from "node:path";
5
5
  import { asDateTimestampMs, parseStrictInteger, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
@@ -144,9 +144,7 @@ async function withTempFile(input, options, fn) {
144
144
  }
145
145
  const imessageActionsRuntime = {
146
146
  resolveIMessageMessageId,
147
- async authorizeMessageReference(params) {
148
- await authorizeIMessageResourceReference(params);
149
- },
147
+ authorizeMessageReference: authorizeIMessageResourceReference,
150
148
  resolveChatGuidForTarget: resolveIMessageActionChatGuid,
151
149
  async sendReaction(params) {
152
150
  await runIMessageAction(params.options, "tapback", {
@@ -1,8 +1,9 @@
1
- import "./targets-Cc9vthzI.mjs";
2
- import "./accounts-CUxZrTcY.mjs";
3
- import "./message-tool-api-pvlcOJPG.mjs";
4
- import { v as imessageSetupContract } from "./group-policy-Cjztkquv.mjs";
5
- import { n as createIMessagePluginBase, r as imessageSetupWizard } from "./channel-BLTaKdSK.mjs";
1
+ import "./targets-BicBiYsM.mjs";
2
+ import "./accounts-nzcU0cq2.mjs";
3
+ import "./message-tool-api-D032l82H.mjs";
4
+ import "./group-policy-90pw4tyG.mjs";
5
+ import { s as imessageSetupContract } from "./setup-core-8MDdYHj5.mjs";
6
+ import { n as createIMessagePluginBase, r as imessageSetupWizard } from "./channel-9fyvuN_p.mjs";
6
7
  import "./conversation-bindings-GDQ_Laxj.mjs";
7
8
  import { createAllowedChatSenderMatcher as createAllowedChatSenderMatcher$1, parseChatAllowTargetPrefixes, parseChatTargetPrefixesOrThrow as parseChatTargetPrefixesOrThrow$1, resolveServicePrefixedAllowTarget, resolveServicePrefixedChatTarget as resolveServicePrefixedChatTarget$1, resolveServicePrefixedOrChatAllowTarget as resolveServicePrefixedOrChatAllowTarget$1, resolveServicePrefixedTarget } from "openclaw/plugin-sdk/channel-targets";
8
9
  //#region extensions/imessage/src/channel.setup.ts
@@ -1,10 +1,10 @@
1
- import { a as looksLikeIMessageExplicitTargetId, c as parseIMessageTarget, i as isAllowedIMessageSender, l as looksLikeIMessageTargetId, n as inferIMessageTargetChatType, o as normalizeIMessageHandle, s as parseIMessageAllowTarget, t as formatIMessageChatTarget, u as normalizeIMessageMessagingTarget } from "./targets-Cc9vthzI.mjs";
2
- import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, r as listEnabledIMessageAccounts } from "./accounts-CUxZrTcY.mjs";
3
- import { o as IMESSAGE_ACTIONS, s as IMESSAGE_ACTION_NAMES } from "./message-tool-api-pvlcOJPG.mjs";
4
- import { h as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./sanitize-outbound-sJPF2DVM.mjs";
5
- import { a as matchIMessageAcpConversation, d as probeIMessage, i as resolveIMessageInboundConversationId, o as normalizeIMessageAcpConversationId, r as resolveIMessageGroupToolPolicy, s as resolveIMessageConversationIdFromTarget, t as resolveIMessageGroupRequireMention } from "./group-policy-Cjztkquv.mjs";
6
- import { t as imessagePlugin } from "./channel-BLTaKdSK.mjs";
1
+ import { a as looksLikeIMessageExplicitTargetId, c as parseIMessageTarget, i as isAllowedIMessageSender, l as looksLikeIMessageTargetId, n as inferIMessageTargetChatType, o as normalizeIMessageHandle, s as parseIMessageAllowTarget, t as formatIMessageChatTarget, u as normalizeIMessageMessagingTarget } from "./targets-BicBiYsM.mjs";
2
+ import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, r as listEnabledIMessageAccounts } from "./accounts-nzcU0cq2.mjs";
3
+ import { o as IMESSAGE_ACTIONS, s as IMESSAGE_ACTION_NAMES } from "./message-tool-api-D032l82H.mjs";
4
+ import { S as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./sanitize-outbound-3MLljgtY.mjs";
5
+ import { a as matchIMessageAcpConversation, d as probeIMessage, i as resolveIMessageInboundConversationId, o as normalizeIMessageAcpConversationId, r as resolveIMessageGroupToolPolicy, s as resolveIMessageConversationIdFromTarget, t as resolveIMessageGroupRequireMention } from "./group-policy-90pw4tyG.mjs";
6
+ import { t as imessagePlugin } from "./channel-9fyvuN_p.mjs";
7
7
  import { t as createIMessageConversationBindingManager } from "./conversation-bindings-GDQ_Laxj.mjs";
8
- import { a as resolveServicePrefixedChatTarget, c as imessageSetupPlugin, i as resolveServicePrefixedAllowTarget, n as parseChatAllowTargetPrefixes, o as resolveServicePrefixedOrChatAllowTarget, r as parseChatTargetPrefixesOrThrow, s as resolveServicePrefixedTarget, t as createAllowedChatSenderMatcher } from "./api-RZv6yXul.mjs";
8
+ import { a as resolveServicePrefixedChatTarget, c as imessageSetupPlugin, i as resolveServicePrefixedAllowTarget, n as parseChatAllowTargetPrefixes, o as resolveServicePrefixedOrChatAllowTarget, r as parseChatTargetPrefixesOrThrow, s as resolveServicePrefixedTarget, t as createAllowedChatSenderMatcher } from "./api-B9Qx21G-.mjs";
9
9
  import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-send-deps-B-QEsLSM.mjs";
10
10
  export { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS, IMESSAGE_ACTIONS, IMESSAGE_ACTION_NAMES, IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS, createAllowedChatSenderMatcher, createIMessageConversationBindingManager, formatIMessageChatTarget, imessagePlugin, imessageSetupPlugin, inferIMessageTargetChatType, isAllowedIMessageSender, listEnabledIMessageAccounts, listIMessageAccountIds, looksLikeIMessageExplicitTargetId, looksLikeIMessageTargetId, matchIMessageAcpConversation, normalizeIMessageAcpConversationId, normalizeIMessageHandle, normalizeIMessageMessagingTarget, parseChatAllowTargetPrefixes, parseChatTargetPrefixesOrThrow, parseIMessageAllowTarget, parseIMessageTarget, probeIMessage, resolveDefaultIMessageAccountId, resolveIMessageAccount, resolveIMessageConversationIdFromTarget, resolveIMessageGroupRequireMention, resolveIMessageGroupToolPolicy, resolveIMessageInboundConversationId, resolveServicePrefixedAllowTarget, resolveServicePrefixedChatTarget, resolveServicePrefixedOrChatAllowTarget, resolveServicePrefixedTarget };
@@ -1,10 +1,10 @@
1
- import { c as parseIMessageTarget, u as normalizeIMessageMessagingTarget } from "./targets-Cc9vthzI.mjs";
2
- import { o as resolveIMessageAccount } from "./accounts-CUxZrTcY.mjs";
3
- import { n as getCachedIMessagePrivateApiStatus } from "./message-tool-api-pvlcOJPG.mjs";
4
- import { i as extractMarkdownFormatRuns } from "./sanitize-outbound-sJPF2DVM.mjs";
5
- import { c as getIMessageApprovalApprovers } from "./group-policy-Cjztkquv.mjs";
6
- import { a as unregisterIMessageApprovalReactionTarget, c as buildIMessageApprovalConversationKeyForTarget, i as registerIMessageApprovalReactionTarget } from "./approval-reactions-D6RFg6lU.mjs";
7
- import { a as buildApprovalPollOptions, l as iMessageApprovalControlBindings, o as iMessageApprovalPollTargets, s as mapSentPollOptionsToDecisions, t as sendMessageIMessage } from "./send-odAfTQ2J.mjs";
1
+ import { c as parseIMessageTarget, u as normalizeIMessageMessagingTarget } from "./targets-BicBiYsM.mjs";
2
+ import { o as resolveIMessageAccount } from "./accounts-nzcU0cq2.mjs";
3
+ import { n as getCachedIMessagePrivateApiStatus } from "./message-tool-api-D032l82H.mjs";
4
+ import { i as extractMarkdownFormatRuns } from "./sanitize-outbound-3MLljgtY.mjs";
5
+ import { c as getIMessageApprovalApprovers } from "./group-policy-90pw4tyG.mjs";
6
+ import { a as unregisterIMessageApprovalReactionTarget, c as buildIMessageApprovalConversationKeyForTarget, i as registerIMessageApprovalReactionTarget } from "./approval-reactions-Bp33xc83.mjs";
7
+ import { a as iMessageApprovalPollTargets, c as iMessageApprovalControlBindings, i as buildApprovalPollOptions, o as mapSentPollOptionsToDecisions, t as sendMessageIMessage } from "./send-Cu9nl757.mjs";
8
8
  import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
9
9
  import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
10
10
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
@@ -14,7 +14,7 @@ import { buildChannelApprovalExpiredText, buildChannelApprovalResolvedText, crea
14
14
  import { setTimeout } from "node:timers/promises";
15
15
  //#region extensions/imessage/src/approval-handler.runtime.ts
16
16
  const log = createSubsystemLogger("imessage/approvals");
17
- const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-D0zG_96v.mjs"), "imessageActionsRuntime");
17
+ const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-DdBN29zj.mjs"), "imessageActionsRuntime");
18
18
  const DEFAULT_PROBE_TIMEOUT_MS = 5e3;
19
19
  const APPROVAL_POLL_ORDERING_DELAY_MS = 1100;
20
20
  function buildPendingPayload(params) {
@@ -1,6 +1,6 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { c as parseIMessageTarget, o as normalizeIMessageHandle } from "./targets-Cc9vthzI.mjs";
3
- import { c as getIMessageApprovalApprovers, l as imessageApprovalAuth } from "./group-policy-Cjztkquv.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.mjs";
2
+ import { c as parseIMessageTarget, o as normalizeIMessageHandle } from "./targets-BicBiYsM.mjs";
3
+ import { c as getIMessageApprovalApprovers, l as imessageApprovalAuth } from "./group-policy-90pw4tyG.mjs";
4
4
  import { n as getOptionalIMessageRuntime } from "./runtime-Cza4CY5T.mjs";
5
5
  import { n as normalizeIMessageGuid, t as resolveIMessageReactionContext } from "./reaction-context-Br-vAJFp.mjs";
6
6
  import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -128,7 +128,7 @@ function readPersistedPollTarget(value) {
128
128
  ...typeof rawConversation.chatId === "string" || typeof rawConversation.chatId === "number" ? { chatId: rawConversation.chatId } : {},
129
129
  ...typeof rawConversation.handle === "string" ? { handle: rawConversation.handle.trim() } : {}
130
130
  };
131
- if (!accountId || !messageId || !approvalId || expiresAtMs === void 0 || !allowedDecisions || target.approvalKind !== "exec" && target.approvalKind !== "plugin" || !normalizeConversationKey(conversation)) return null;
131
+ if (!accountId || !messageId || !approvalId || expiresAtMs === void 0 || !allowedDecisions || target.approvalKind !== "exec" && target.approvalKind !== "plugin" && target.approvalKind !== "system-agent" || !normalizeConversationKey(conversation)) return null;
132
132
  return {
133
133
  accountId,
134
134
  conversation,
@@ -305,7 +305,7 @@ async function registerIMessageApprovalReactionTarget(params) {
305
305
  const messageId = params.messageId.trim();
306
306
  const approvalId = params.approvalId.trim();
307
307
  const allowedDecisions = listApprovalReactionBindings({ allowedDecisions: params.allowedDecisions }).map((binding) => binding.decision);
308
- if (!accountId || !messageId || !approvalId || params.approvalKind !== "exec" && params.approvalKind !== "plugin" || allowedDecisions.length === 0) return null;
308
+ if (!accountId || !messageId || !approvalId || params.approvalKind !== "exec" && params.approvalKind !== "plugin" && params.approvalKind !== "system-agent" || allowedDecisions.length === 0) return null;
309
309
  const target = {
310
310
  approvalId,
311
311
  approvalKind: params.approvalKind,
@@ -1,10 +1,11 @@
1
- import { a as looksLikeIMessageExplicitTargetId, c as parseIMessageTarget, d as isIMessagePhoneLikeHandle, n as inferIMessageTargetChatType, o as normalizeIMessageHandle, u as normalizeIMessageMessagingTarget } from "./targets-Cc9vthzI.mjs";
2
- import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, t as collectIMessageDuplicateAccountSourceWarnings } from "./accounts-CUxZrTcY.mjs";
3
- import { b as resolveIMessageDirectChatService, n as sanitizeIMessageFinalOutboundText, r as sanitizeOutboundText } from "./sanitize-outbound-sJPF2DVM.mjs";
4
- import { a as matchIMessageAcpConversation, c as getIMessageApprovalApprovers, h as createIMessageSetupWizardProxy, l as imessageApprovalAuth, o as normalizeIMessageAcpConversationId, r as resolveIMessageGroupToolPolicy, s as resolveIMessageConversationIdFromTarget, t as resolveIMessageGroupRequireMention, u as imessageMessageActions, v as imessageSetupContract } from "./group-policy-Cjztkquv.mjs";
1
+ import { a as looksLikeIMessageExplicitTargetId, c as parseIMessageTarget, d as isIMessagePhoneLikeHandle, n as inferIMessageTargetChatType, o as normalizeIMessageHandle, u as normalizeIMessageMessagingTarget } from "./targets-BicBiYsM.mjs";
2
+ import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, t as collectIMessageDuplicateAccountSourceWarnings } from "./accounts-nzcU0cq2.mjs";
3
+ import { D as resolveIMessageDirectChatService, n as sanitizeIMessageFinalOutboundText, r as sanitizeOutboundText } from "./sanitize-outbound-3MLljgtY.mjs";
4
+ import { a as matchIMessageAcpConversation, c as getIMessageApprovalApprovers, l as imessageApprovalAuth, o as normalizeIMessageAcpConversationId, r as resolveIMessageGroupToolPolicy, s as resolveIMessageConversationIdFromTarget, t as resolveIMessageGroupRequireMention, u as imessageMessageActions } from "./group-policy-90pw4tyG.mjs";
5
+ import { i as createIMessageSetupWizardProxy, s as imessageSetupContract } from "./setup-core-8MDdYHj5.mjs";
5
6
  import { t as createIMessageConversationBindingManager } from "./conversation-bindings-GDQ_Laxj.mjs";
6
- import { t as IMessageChannelConfigSchema } from "./config-schema-CCbTcJEV.mjs";
7
- import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-DKJK7rh3.mjs";
7
+ import { t as IMessageChannelConfigSchema } from "./config-schema-4Q3_EqYt.mjs";
8
+ import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-CagwSMvo.mjs";
8
9
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
9
10
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
10
11
  import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
@@ -29,8 +30,7 @@ import { createRestrictSendersChannelSecurity } from "openclaw/plugin-sdk/channe
29
30
  import { createChannelPluginBase, getChatChannelMeta } from "openclaw/plugin-sdk/core";
30
31
  //#region extensions/imessage/src/approval-text.ts
31
32
  function replaceApprovalIdPlaceholder(text, approvalId) {
32
- const safeApprovalId = approvalId.replace(/\$/g, "$$$$");
33
- return (text ?? "").replace(/\/approve\s+<id>/g, `/approve ${safeApprovalId}`);
33
+ return (text ?? "").replace(/\/approve\s+<id>/g, () => `/approve ${approvalId}`);
34
34
  }
35
35
  //#endregion
36
36
  //#region extensions/imessage/src/approval-native.ts
@@ -92,7 +92,7 @@ const imessageApproval = createApproverRestrictedNativeApprovalCapabilityFromFor
92
92
  approvalKind,
93
93
  request
94
94
  }),
95
- load: async () => (await import("./approval-handler.runtime-Bv5_XgNr.mjs")).imessageApprovalNativeRuntime
95
+ load: async () => (await import("./approval-handler.runtime-DKSq0DWq.mjs")).imessageApprovalNativeRuntime
96
96
  })
97
97
  });
98
98
  const imessageApprovalRouting = imessageApproval.routing;
@@ -146,12 +146,6 @@ function shouldSuppressLocalIMessageExecApprovalPrompt(params) {
146
146
  nativeSessionOnly: true
147
147
  });
148
148
  }
149
- function appendIMessageReactionHint(params) {
150
- return addApprovalReactionHintToText({
151
- text: params.text ?? "",
152
- allowedDecisions: params.allowedDecisions
153
- });
154
- }
155
149
  function buildIMessageExecPendingPayload(params) {
156
150
  const allowedDecisions = resolveExecApprovalRequestAllowedDecisions(params.request.request);
157
151
  const command = resolveExecApprovalCommandDisplay(params.request.request).commandText;
@@ -174,7 +168,7 @@ function buildIMessageExecPendingPayload(params) {
174
168
  });
175
169
  return {
176
170
  ...payload,
177
- text: appendIMessageReactionHint({
171
+ text: addApprovalReactionHintToText({
178
172
  text: replaceApprovalIdPlaceholder(payload.text, params.request.id),
179
173
  allowedDecisions
180
174
  })
@@ -190,7 +184,7 @@ function buildIMessagePluginPendingPayload(params) {
190
184
  });
191
185
  return {
192
186
  ...payload,
193
- text: appendIMessageReactionHint({
187
+ text: addApprovalReactionHintToText({
194
188
  text: replaceApprovalIdPlaceholder(payload.text, params.request.id),
195
189
  allowedDecisions
196
190
  })
@@ -206,10 +200,7 @@ const imessageDoctor = {
206
200
  //#endregion
207
201
  //#region extensions/imessage/src/shared.ts
208
202
  const IMESSAGE_CHANNEL = "imessage";
209
- async function loadIMessageChannelRuntime$1() {
210
- return await import("./channel.runtime---s2k4YN.mjs");
211
- }
212
- const imessageSetupWizard = createIMessageSetupWizardProxy(async () => (await loadIMessageChannelRuntime$1()).imessageSetupWizard);
203
+ const imessageSetupWizard = createIMessageSetupWizardProxy(async () => (await import("./setup-surface-tGXFDdWh.mjs")).imessageSetupWizard);
213
204
  const imessageConfigAdapter = createScopedChannelConfigAdapter({
214
205
  sectionKey: IMESSAGE_CHANNEL,
215
206
  listAccountIds: listIMessageAccountIds,
@@ -223,7 +214,7 @@ const imessageConfigAdapter = createScopedChannelConfigAdapter({
223
214
  "name"
224
215
  ],
225
216
  resolveAllowFrom: (account) => account.config.allowFrom,
226
- formatAllowFrom: (allowFrom) => formatTrimmedAllowFromEntries(allowFrom),
217
+ formatAllowFrom: formatTrimmedAllowFromEntries,
227
218
  resolveDefaultTo: (account) => account.config.defaultTo
228
219
  });
229
220
  const imessageSecurityAdapter = createRestrictSendersChannelSecurity({
@@ -249,51 +240,45 @@ function createIMessagePluginBase(params) {
249
240
  exposure: { configured: false }
250
241
  },
251
242
  setupWizard: params.setupWizard,
252
- capabilities: {
253
- chatTypes: ["direct", "group"],
254
- media: true,
255
- tts: { voice: {
256
- synthesisTarget: "audio-file",
257
- audioFileFormats: [
258
- "mp3",
259
- "caf",
260
- "audio/mpeg",
261
- "audio/x-caf"
262
- ],
263
- preferAudioFileFormat: "caf"
264
- } },
265
- reactions: true,
266
- edit: true,
267
- unsend: true,
268
- reply: true,
269
- effects: true,
270
- groupManagement: true
271
- },
272
243
  reload: {
273
244
  configPrefixes: ["channels.imessage"],
274
245
  noopPrefixes: ["messages.inbound"]
275
246
  },
276
247
  configSchema: IMessageChannelConfigSchema,
277
- config: {
278
- ...imessageConfigAdapter,
279
- isConfigured: (account) => account.configured,
280
- describeAccount: (account) => describeAccountSnapshot({
281
- account,
282
- configured: account.configured
283
- })
284
- },
285
248
  security: imessageSecurityAdapter,
286
249
  setupContract: params.setupContract
287
250
  }),
288
- messaging: {
289
- resolveInboundAttachmentRoots: (paramsValue) => resolveIMessageAttachmentRoots({
290
- accountId: paramsValue.accountId,
291
- cfg: paramsValue.cfg
292
- }),
293
- resolveRemoteInboundAttachmentRoots: (paramsLocal) => resolveIMessageRemoteAttachmentRoots({
294
- accountId: paramsLocal.accountId,
295
- cfg: paramsLocal.cfg
251
+ capabilities: {
252
+ chatTypes: ["direct", "group"],
253
+ media: true,
254
+ tts: { voice: {
255
+ synthesisTarget: "audio-file",
256
+ audioFileFormats: [
257
+ "mp3",
258
+ "caf",
259
+ "audio/mpeg",
260
+ "audio/x-caf"
261
+ ],
262
+ preferAudioFileFormat: "caf"
263
+ } },
264
+ reactions: true,
265
+ edit: true,
266
+ unsend: true,
267
+ reply: true,
268
+ effects: true,
269
+ groupManagement: true
270
+ },
271
+ config: {
272
+ ...imessageConfigAdapter,
273
+ isConfigured: (account) => account.configured,
274
+ describeAccount: (account) => describeAccountSnapshot({
275
+ account,
276
+ configured: account.configured
296
277
  })
278
+ },
279
+ messaging: {
280
+ resolveInboundAttachmentRoots: resolveIMessageAttachmentRoots,
281
+ resolveRemoteInboundAttachmentRoots: resolveIMessageRemoteAttachmentRoots
297
282
  }
298
283
  };
299
284
  }
@@ -309,7 +294,27 @@ async function probeIMessageStatusAccount(params) {
309
294
  }
310
295
  //#endregion
311
296
  //#region extensions/imessage/src/channel.ts
312
- const loadIMessageChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime---s2k4YN.mjs"));
297
+ const loadIMessageChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-n-MPKL8k.mjs"));
298
+ async function sendIMessageOutbound(ctx, kind, options = {}) {
299
+ return await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
300
+ cfg: ctx.cfg,
301
+ to: ctx.to,
302
+ text: ctx.text,
303
+ accountId: ctx.accountId ?? void 0,
304
+ deps: ctx.deps,
305
+ replyToId: ctx.replyToId ?? void 0,
306
+ assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff,
307
+ onPlatformSendDispatch: ctx.onPlatformSendDispatch,
308
+ ...options,
309
+ ...kind === "media" ? {
310
+ mediaUrl: ctx.mediaUrl,
311
+ mediaAccess: ctx.mediaAccess,
312
+ mediaLocalRoots: ctx.mediaLocalRoots,
313
+ mediaReadFile: ctx.mediaReadFile,
314
+ audioAsVoice: ctx.audioAsVoice
315
+ } : {}
316
+ });
317
+ }
313
318
  function toIMessageMessageSendResult(result, kind, replyToId) {
314
319
  const receipt = result.receipt ?? createMessageReceiptFromOutboundResults({
315
320
  results: result.messageId ? [{
@@ -325,8 +330,8 @@ function toIMessageMessageSendResult(result, kind, replyToId) {
325
330
  ...result.meta && Object.keys(result.meta).length > 0 ? { meta: result.meta } : {}
326
331
  };
327
332
  }
328
- const loadIMessageApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-D6RFg6lU.mjs").then((n) => n.t));
329
- const loadIMessageQuestionReactionsModule = createLazyRuntimeModule(() => import("./question-reactions-lm8OxWbb.mjs").then((n) => n.r));
333
+ const loadIMessageApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-Bp33xc83.mjs").then((n) => n.t));
334
+ const loadIMessageQuestionReactionsModule = createLazyRuntimeModule(() => import("./question-reactions-Cy-dmU_j.mjs").then((n) => n.r));
330
335
  async function prepareForwardedIMessageApprovalPayload(params) {
331
336
  const prepared = (await loadIMessageApprovalReactionsModule()).addIMessageApprovalReactionHintToStructuredPayload(params);
332
337
  if (prepared) Object.assign(params.payload, prepared);
@@ -359,33 +364,10 @@ const imessageMessageAdapter = defineChannelMessageAdapter({
359
364
  } },
360
365
  send: {
361
366
  text: async (ctx) => {
362
- return toIMessageMessageSendResult(await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
363
- cfg: ctx.cfg,
364
- to: ctx.to,
365
- text: ctx.text,
366
- accountId: ctx.accountId ?? void 0,
367
- deps: ctx.deps,
368
- replyToId: ctx.replyToId ?? void 0,
369
- assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff,
370
- onPlatformSendDispatch: ctx.onPlatformSendDispatch,
371
- conversationReadOrigin: ctx.conversationReadOrigin
372
- }), "text", ctx.replyToId);
367
+ return toIMessageMessageSendResult(await sendIMessageOutbound(ctx, "text", { conversationReadOrigin: ctx.conversationReadOrigin }), "text", ctx.replyToId);
373
368
  },
374
369
  media: async (ctx) => {
375
- return toIMessageMessageSendResult(await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
376
- cfg: ctx.cfg,
377
- to: ctx.to,
378
- text: ctx.text,
379
- mediaUrl: ctx.mediaUrl,
380
- mediaAccess: ctx.mediaAccess,
381
- mediaLocalRoots: ctx.mediaLocalRoots,
382
- mediaReadFile: ctx.mediaReadFile,
383
- audioAsVoice: ctx.audioAsVoice,
384
- accountId: ctx.accountId ?? void 0,
385
- deps: ctx.deps,
386
- replyToId: ctx.replyToId ?? void 0,
387
- assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff,
388
- onPlatformSendDispatch: ctx.onPlatformSendDispatch,
370
+ return toIMessageMessageSendResult(await sendIMessageOutbound(ctx, "media", {
389
371
  conversationReadOrigin: ctx.conversationReadOrigin,
390
372
  ...ctx.onDeliveryResult ? { onDeliveryResult: async (acceptedResult) => {
391
373
  await ctx.onDeliveryResult?.(toIMessageMessageSendResult(acceptedResult, ctx.audioAsVoice ? "voice" : "media", ctx.replyToId));
@@ -394,12 +376,6 @@ const imessageMessageAdapter = defineChannelMessageAdapter({
394
376
  }
395
377
  }
396
378
  });
397
- function buildIMessageBaseSessionKey(params) {
398
- return buildOutboundBaseSessionKey({
399
- ...params,
400
- channel: "imessage"
401
- });
402
- }
403
379
  function isCanonicalIMessageDirectHandle(raw, normalized) {
404
380
  const trimmed = raw.trim();
405
381
  if (!trimmed || !normalized) return false;
@@ -408,6 +384,10 @@ function isCanonicalIMessageDirectHandle(raw, normalized) {
408
384
  }
409
385
  function resolveIMessageOutboundSessionRoute(params) {
410
386
  const parsed = parseIMessageTarget(params.target);
387
+ let peer;
388
+ let from;
389
+ let to;
390
+ let recipientSessionExact = false;
411
391
  if (parsed.kind === "handle") {
412
392
  const handle = normalizeIMessageHandle(parsed.to);
413
393
  if (!handle) return null;
@@ -415,48 +395,37 @@ function resolveIMessageOutboundSessionRoute(params) {
415
395
  cfg: params.cfg,
416
396
  accountId: params.accountId
417
397
  });
418
- const directTarget = `${resolveIMessageDirectChatService(parsed.serviceExplicit ? parsed.service : account.config.service) ?? "auto"}:${handle}`;
419
- const peer = {
398
+ from = to = `${resolveIMessageDirectChatService(parsed.serviceExplicit ? parsed.service : account.config.service) ?? "auto"}:${handle}`;
399
+ peer = {
420
400
  kind: "direct",
421
401
  id: handle
422
402
  };
423
- const baseSessionKey = buildIMessageBaseSessionKey({
424
- cfg: params.cfg,
425
- agentId: params.agentId,
426
- accountId: params.accountId,
427
- peer
428
- });
429
- return {
430
- sessionKey: baseSessionKey,
431
- baseSessionKey,
432
- recipientSessionExact: isCanonicalIMessageDirectHandle(parsed.to, handle),
433
- peer,
434
- chatType: "direct",
435
- from: directTarget,
436
- to: directTarget
403
+ recipientSessionExact = isCanonicalIMessageDirectHandle(parsed.to, handle);
404
+ } else {
405
+ const peerId = parsed.kind === "chat_id" ? String(parsed.chatId) : parsed.kind === "chat_guid" ? parsed.chatGuid : parsed.chatIdentifier;
406
+ if (!peerId) return null;
407
+ peer = {
408
+ kind: "group",
409
+ id: peerId
437
410
  };
411
+ from = `imessage:group:${peerId}`;
412
+ to = `${parsed.kind}:${peerId}`;
438
413
  }
439
- const peerId = parsed.kind === "chat_id" ? String(parsed.chatId) : parsed.kind === "chat_guid" ? parsed.chatGuid : parsed.chatIdentifier;
440
- if (!peerId) return null;
441
- const peer = {
442
- kind: "group",
443
- id: peerId
444
- };
445
- const baseSessionKey = buildIMessageBaseSessionKey({
414
+ const baseSessionKey = buildOutboundBaseSessionKey({
446
415
  cfg: params.cfg,
416
+ channel: "imessage",
447
417
  agentId: params.agentId,
448
418
  accountId: params.accountId,
449
419
  peer
450
420
  });
451
- const toPrefix = parsed.kind === "chat_id" ? "chat_id" : parsed.kind === "chat_guid" ? "chat_guid" : "chat_identifier";
452
421
  return {
453
422
  sessionKey: baseSessionKey,
454
423
  baseSessionKey,
455
- recipientSessionExact: false,
424
+ recipientSessionExact,
456
425
  peer,
457
- chatType: "group",
458
- from: `imessage:group:${peerId}`,
459
- to: `${toPrefix}:${peerId}`
426
+ chatType: peer.kind,
427
+ from,
428
+ to
460
429
  };
461
430
  }
462
431
  const imessagePlugin = createChatChannelPlugin({
@@ -623,38 +592,14 @@ const imessagePlugin = createChatChannelPlugin({
623
592
  },
624
593
  attachedResults: {
625
594
  channel: "imessage",
626
- sendText: async ({ cfg, to, text, accountId, deps, replyToId, assertDirectAdapterHandoff, onPlatformSendDispatch }) => await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
627
- cfg,
628
- to,
629
- text,
630
- accountId: accountId ?? void 0,
631
- deps,
632
- replyToId: replyToId ?? void 0,
633
- assertDirectAdapterHandoff,
634
- onPlatformSendDispatch
635
- }),
636
- sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, audioAsVoice, accountId, deps, replyToId, onDeliveryResult, assertDirectAdapterHandoff, onPlatformSendDispatch }) => await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
637
- cfg,
638
- to,
639
- text,
640
- mediaUrl,
641
- mediaAccess,
642
- mediaLocalRoots,
643
- mediaReadFile,
644
- audioAsVoice,
645
- accountId: accountId ?? void 0,
646
- deps,
647
- replyToId: replyToId ?? void 0,
648
- assertDirectAdapterHandoff,
649
- onPlatformSendDispatch,
650
- ...onDeliveryResult ? { onDeliveryResult: async (result) => {
651
- await onDeliveryResult({
652
- channel: "imessage",
653
- ...toIMessageMessageSendResult(result, audioAsVoice ? "voice" : "media", replyToId),
654
- messageId: result.messageId
655
- });
656
- } } : {}
657
- })
595
+ sendText: (ctx) => sendIMessageOutbound(ctx, "text"),
596
+ sendMedia: (ctx) => sendIMessageOutbound(ctx, "media", ctx.onDeliveryResult ? { onDeliveryResult: async (result) => {
597
+ await ctx.onDeliveryResult?.({
598
+ channel: "imessage",
599
+ ...toIMessageMessageSendResult(result, ctx.audioAsVoice ? "voice" : "media", ctx.replyToId),
600
+ messageId: result.messageId
601
+ });
602
+ } } : {})
658
603
  }
659
604
  }
660
605
  });
@@ -0,0 +1,92 @@
1
+ import { l as resolveIMessageRemoteHost, o as resolveIMessageAccount, r as listEnabledIMessageAccounts, s as resolveIMessageDuplicateSourceOwner } from "./accounts-nzcU0cq2.mjs";
2
+ import { d as probeIMessage } from "./group-policy-90pw4tyG.mjs";
3
+ import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-send-deps-B-QEsLSM.mjs";
4
+ import { t as sendMessageIMessage } from "./send-Cu9nl757.mjs";
5
+ import { t as monitorIMessageProvider } from "./monitor-fv9nRuTH.mjs";
6
+ import { imessageSetupWizard } from "./setup-surface-tGXFDdWh.mjs";
7
+ import { createAccountStatusSink, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
8
+ import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
9
+ //#region extensions/imessage/src/channel.runtime.ts
10
+ async function sendIMessageOutbound(params) {
11
+ const send = resolveOutboundSendDep(params.deps, "imessage", { legacyKeys: IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageIMessage;
12
+ const maxBytes = resolveChannelMediaMaxBytes({
13
+ cfg: params.cfg,
14
+ resolveChannelLimitMb: () => resolveIMessageAccount(params).config.mediaMaxMb
15
+ });
16
+ const result = await send(params.to, params.text, {
17
+ config: params.cfg,
18
+ ...params.mediaUrl ? { mediaUrl: params.mediaUrl } : {},
19
+ ...params.mediaAccess ? { mediaAccess: params.mediaAccess } : {},
20
+ ...params.mediaLocalRoots?.length ? { mediaLocalRoots: params.mediaLocalRoots } : {},
21
+ ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {},
22
+ ...params.audioAsVoice ? { audioAsVoice: true } : {},
23
+ maxBytes,
24
+ accountId: params.accountId ?? void 0,
25
+ replyToId: params.replyToId ?? void 0,
26
+ conversationReadOrigin: params.conversationReadOrigin,
27
+ assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
28
+ onPlatformSendDispatch: params.onPlatformSendDispatch,
29
+ ...params.onDeliveryResult ? { onDeliveryResult: params.onDeliveryResult } : {}
30
+ });
31
+ const meta = {
32
+ ...result.meta,
33
+ ...result.guid ? { imessageMessageGuid: result.guid } : {},
34
+ ...result.sentText ? { imessageVisibleText: result.sentText } : {}
35
+ };
36
+ return Object.keys(meta).length > 0 ? {
37
+ ...result,
38
+ meta
39
+ } : result;
40
+ }
41
+ async function probeIMessageAccount(params) {
42
+ return await probeIMessage(params?.timeoutMs, {
43
+ cliPath: params?.cliPath,
44
+ dbPath: params?.dbPath,
45
+ remoteHost: params?.remoteHost,
46
+ forceRefresh: true
47
+ });
48
+ }
49
+ async function startIMessageGatewayAccount(ctx) {
50
+ const account = ctx.account;
51
+ const cliPath = account.config.cliPath?.trim() || "imsg";
52
+ const dbPath = account.config.dbPath?.trim();
53
+ ctx.setStatus({
54
+ accountId: account.accountId,
55
+ cliPath,
56
+ dbPath: dbPath ?? null
57
+ });
58
+ await Promise.all(listEnabledIMessageAccounts(ctx.cfg).map(async (candidate) => {
59
+ await resolveIMessageRemoteHost({
60
+ cliPath: candidate.config.cliPath?.trim() || "imsg",
61
+ remoteHost: candidate.config.remoteHost
62
+ });
63
+ }));
64
+ const ownerAccountId = resolveIMessageDuplicateSourceOwner({
65
+ cfg: ctx.cfg,
66
+ account
67
+ });
68
+ if (ownerAccountId) {
69
+ ctx.log?.info?.(`[${account.accountId}] skipping watcher: duplicate iMessage source; using account "${ownerAccountId}"`);
70
+ if (ctx.abortSignal.aborted) return;
71
+ await new Promise((resolve) => {
72
+ ctx.abortSignal.addEventListener("abort", () => resolve(), { once: true });
73
+ });
74
+ return;
75
+ }
76
+ const statusSink = createAccountStatusSink({
77
+ accountId: account.accountId,
78
+ setStatus: ctx.setStatus
79
+ });
80
+ statusSink({ lifecycle: "starting" });
81
+ ctx.log?.info?.(`[${account.accountId}] starting provider (${cliPath}${dbPath ? ` db=${dbPath}` : ""})`);
82
+ return await monitorIMessageProvider({
83
+ accountId: account.accountId,
84
+ config: ctx.cfg,
85
+ runtime: ctx.runtime,
86
+ abortSignal: ctx.abortSignal,
87
+ channelRuntime: ctx.channelRuntime,
88
+ statusSink
89
+ });
90
+ }
91
+ //#endregion
92
+ export { imessageSetupWizard, probeIMessageAccount, sendIMessageOutbound, startIMessageGatewayAccount };
@@ -15,6 +15,14 @@ const iMessageChannelConfigUiHints = {
15
15
  allowFrom: { presentation: "phone-number" },
16
16
  defaultTo: { presentation: "phone-number" },
17
17
  groupAllowFrom: { presentation: "phone-number" },
18
+ "groups.*.requireMentionInBotThreads": {
19
+ label: "iMessage Bot Thread Mention Requirement",
20
+ help: "Override mention gating in native reply threads started by this account. False allows unmentioned replies; true requires a mention and keeps threads quiet when mention patterns are disabled. Omit to preserve normal gating. Ownership uses the bounded cache of messages OpenClaw sent; sender restrictions still apply."
21
+ },
22
+ "accounts.*.groups.*.requireMentionInBotThreads": {
23
+ label: "iMessage Account Bot Thread Mention Requirement",
24
+ help: "Override mention gating in native reply threads whose root this account sent. Unknown or evicted roots keep the group's normal mention requirement."
25
+ },
18
26
  "accounts.*.allowFrom.*": { presentation: "phone-number" },
19
27
  "accounts.*.defaultTo": { presentation: "phone-number" },
20
28
  "accounts.*.groupAllowFrom.*": { presentation: "phone-number" },
@@ -82,7 +90,7 @@ const IMessageAccountSchemaBase = z.object({
82
90
  firstRunLookbackMinutes: z.number().int().min(1).max(720).optional(),
83
91
  maxFailureRetries: z.number().int().min(1).max(1e3).optional()
84
92
  }).strict().optional(),
85
- groups: z.record(z.string(), buildGroupEntrySchema(void 0, { omit: [
93
+ groups: z.record(z.string(), buildGroupEntrySchema({ requireMentionInBotThreads: z.boolean().optional() }, { omit: [
86
94
  "skills",
87
95
  "enabled",
88
96
  "allowFrom"