@openclaw/imessage 2026.10.1 → 2026.10.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 (30) hide show
  1. package/dist/.setup/{accounts-evTpvJMv.mjs → accounts-DacCvDBt.mjs} +23 -45
  2. package/dist/.setup/{actions-DJqbUmbN.mjs → actions-Hxh12myO.mjs} +54 -101
  3. package/dist/.setup/{actions.runtime-DL5i-Y4J.mjs → actions.runtime-DOIX6Fkf.mjs} +29 -37
  4. package/dist/.setup/{api-oq_MryN7.mjs → api-BV8qHfLl.mjs} +7 -7
  5. package/dist/.setup/{api-SAVMfMoY.mjs → api-DC1yHVGj.mjs} +8 -8
  6. package/dist/.setup/{approval-handler.runtime-Bj2NGNXF.mjs → approval-handler.runtime-Dc3KzakG.mjs} +38 -66
  7. package/dist/.setup/{approval-reactions-L9Ul7PAu.mjs → approval-reactions-JvzJCJ4a.mjs} +26 -33
  8. package/dist/.setup/{channel-CL73qdMG.mjs → channel-9TWBUDkP.mjs} +14 -16
  9. package/dist/.setup/{channel.runtime-DY7JJ0_9.mjs → channel.runtime-DrLDEY4R.mjs} +198 -362
  10. package/dist/.setup/{client-12apu4Ip.mjs → client-HixFQQWY.mjs} +34 -38
  11. package/dist/.setup/{media-contract-DjQGZlfl.mjs → media-contract-BwWs5PM7.mjs} +1 -1
  12. package/dist/.setup/{message-tool-api-CqfRxLlT.mjs → message-tool-api-B5NfPnFL.mjs} +2 -2
  13. package/dist/.setup/{question-reactions-DJV-TnA8.mjs → question-reactions-9jrqVZgE.mjs} +20 -25
  14. package/dist/.setup/{reaction-context-By7kUMBC.mjs → reaction-context-CRXpeYAr.mjs} +1 -1
  15. package/dist/.setup/{remote-file-BU7pA-Zi.mjs → remote-file-Dq5Asi_F.mjs} +10 -16
  16. package/dist/.setup/{sanitize-outbound-C0x4BPky.mjs → sanitize-outbound-DpdQERYJ.mjs} +27 -62
  17. package/dist/.setup/{send-pkYwL6Rt.mjs → send-BZZzMbdi.mjs} +186 -251
  18. package/dist/.setup/{setup-core-DqOBe-n0.mjs → setup-core-CaRGbZOL.mjs} +15 -46
  19. package/dist/.setup/{setup-surface-zKhIinwY.mjs → setup-surface-BMWS7VuY.mjs} +2 -2
  20. package/dist/.setup/{targets-BicBiYsM.mjs → targets-B4oU7n-v.mjs} +47 -69
  21. package/dist/api.js +7 -7
  22. package/dist/channel-plugin-api.js +1 -1
  23. package/dist/contract-api.js +1 -1
  24. package/dist/doctor-contract-api.js +21 -45
  25. package/dist/media-contract-api.js +1 -1
  26. package/dist/message-tool-api.js +1 -1
  27. package/dist/runtime-api.js +1 -1
  28. package/dist/setup-entry.js +1 -1
  29. package/dist/src/chat-db.worker.js +1 -1
  30. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
1
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
2
  import { normalizeAccountId, resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
3
3
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
4
4
  import { accessSync, constants, readFileSync, realpathSync, statSync } from "node:fs";
@@ -184,12 +184,7 @@ async function resolveIMessageRemoteHost(params) {
184
184
  const { listAccountIds, resolveDefaultAccountId, resolveAccountConfig: resolveMergedIMessageAccountConfig } = createAccountListHelpers("imessage", { implicitDefaultAccount: { channelKeys: ["cliPath", "dbPath"] } });
185
185
  const listIMessageAccountIds = listAccountIds;
186
186
  const resolveDefaultIMessageAccountId = resolveDefaultAccountId;
187
- function asStreamingConfigObject(value) {
188
- return asOptionalRecord(value);
189
- }
190
- function mergeIMessageStreamingConfig(base, account) {
191
- const baseConfig = asStreamingConfigObject(base);
192
- const accountConfig = asStreamingConfigObject(account);
187
+ function mergeIMessageStreamingConfig(baseConfig, accountConfig) {
193
188
  if (!baseConfig || !accountConfig) return accountConfig ?? baseConfig;
194
189
  return {
195
190
  ...baseConfig,
@@ -207,7 +202,7 @@ function mergeIMessageStreamingConfig(base, account) {
207
202
  function mergeIMessageAccountConfig(cfg, accountId) {
208
203
  const accountConfig = resolveAccountEntry(cfg.channels?.imessage?.accounts, accountId);
209
204
  const merged = resolveMergedIMessageAccountConfig(cfg, accountId);
210
- const streaming = mergeIMessageStreamingConfig((cfg.channels?.imessage)?.streaming, accountConfig?.streaming);
205
+ const streaming = mergeIMessageStreamingConfig(cfg.channels?.imessage?.streaming, accountConfig?.streaming);
211
206
  return streaming !== void 0 ? {
212
207
  ...merged,
213
208
  streaming
@@ -253,22 +248,23 @@ function resolveIMessageAccountSourceSignature(account) {
253
248
  ""
254
249
  ]);
255
250
  }
256
- function resolveIMessageAccountSourceOwner(params) {
257
- let defaultOwner;
258
- for (const candidateAccountId of listIMessageAccountIds(params.cfg)) {
259
- const candidate = resolveIMessageAccount({
260
- cfg: params.cfg,
261
- accountId: candidateAccountId
251
+ function groupIMessageAccountsBySource(cfg) {
252
+ const groups = /* @__PURE__ */ new Map();
253
+ for (const accountId of listIMessageAccountIds(cfg)) {
254
+ const account = resolveIMessageAccount({
255
+ cfg,
256
+ accountId
262
257
  });
263
- if (!candidate.enabled || !candidate.configured) continue;
264
- if (resolveIMessageAccountSourceSignature(candidate) !== params.signature) continue;
265
- if (candidate.accountId === DEFAULT_ACCOUNT_ID) {
266
- defaultOwner ??= candidate.accountId;
267
- continue;
268
- }
269
- return candidate.accountId;
258
+ if (!account.enabled || !account.configured) continue;
259
+ const signature = resolveIMessageAccountSourceSignature(account);
260
+ const accounts = groups.get(signature) ?? [];
261
+ accounts.push(account);
262
+ groups.set(signature, accounts);
270
263
  }
271
- return defaultOwner;
264
+ return groups;
265
+ }
266
+ function resolveIMessageAccountSourceOwner(accounts) {
267
+ return accounts.find((account) => account.accountId !== DEFAULT_ACCOUNT_ID) ?? accounts[0];
272
268
  }
273
269
  function resolveIMessageDatabaseFileIdentity(dbPath) {
274
270
  try {
@@ -288,11 +284,9 @@ function resolveIMessageDatabaseFileIdentity(dbPath) {
288
284
  */
289
285
  function resolveIMessageDuplicateSourceOwner(params) {
290
286
  if (!params.account.enabled || !params.account.configured) return;
291
- const owner = resolveIMessageAccountSourceOwner({
292
- cfg: params.cfg,
293
- signature: resolveIMessageAccountSourceSignature(params.account)
294
- });
295
- return owner && owner !== params.account.accountId ? owner : void 0;
287
+ const signature = resolveIMessageAccountSourceSignature(params.account);
288
+ const owner = resolveIMessageAccountSourceOwner(groupIMessageAccountsBySource(params.cfg).get(signature) ?? []);
289
+ return owner && owner.accountId !== params.account.accountId ? owner.accountId : void 0;
296
290
  }
297
291
  function listEnabledIMessageAccounts(cfg) {
298
292
  return listIMessageAccountIds(cfg).map((accountId) => resolveIMessageAccount({
@@ -325,27 +319,11 @@ function hasExclusiveIMessageLocalDatabase(params) {
325
319
  return true;
326
320
  }
327
321
  function collectIMessageDuplicateAccountSourceWarnings(params) {
328
- const groups = /* @__PURE__ */ new Map();
329
- for (const accountId of listIMessageAccountIds(params.cfg)) {
330
- const account = resolveIMessageAccount({
331
- cfg: params.cfg,
332
- accountId
333
- });
334
- if (!account.enabled || !account.configured) continue;
335
- const signature = resolveIMessageAccountSourceSignature(account);
336
- const existing = groups.get(signature);
337
- if (existing) existing.push(account);
338
- else groups.set(signature, [account]);
339
- }
322
+ const groups = groupIMessageAccountsBySource(params.cfg);
340
323
  const warnings = [];
341
324
  for (const collisions of groups.values()) {
342
325
  if (collisions.length < 2) continue;
343
- const firstCollision = expectDefined(collisions[0], "duplicate iMessage account source");
344
- const ownerId = resolveIMessageAccountSourceOwner({
345
- cfg: params.cfg,
346
- signature: resolveIMessageAccountSourceSignature(firstCollision)
347
- });
348
- const owner = collisions.find((a) => a.accountId === ownerId) ?? firstCollision;
326
+ const owner = expectDefined(resolveIMessageAccountSourceOwner(collisions), "duplicate iMessage account source");
349
327
  const dupIds = collisions.filter((a) => a.accountId !== owner.accountId).map((a) => `"${a.accountId}"`).join(", ");
350
328
  const cliPath = normalizeIMessageCliPath(owner.config.cliPath);
351
329
  const dbPath = normalizeIMessageDbPath(owner.config.dbPath);
@@ -1,8 +1,8 @@
1
- import { c as parseIMessageTarget } from "./targets-BicBiYsM.mjs";
2
- import { l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-evTpvJMv.mjs";
3
- import { a as setCachedIMessagePrivateApiStatus, n as getCachedIMessagePrivateApiStatus, o as IMESSAGE_ACTIONS, r as imessageRpcSupportsMethod, s as IMESSAGE_ACTION_NAMES, t as describeIMessageMessageTool } from "./message-tool-api-CqfRxLlT.mjs";
4
- import { a as isIMessageCurrentMessageInChat, b as chatContextFromIMessageTarget, c as rememberIMessageReplyCache, i as findLatestIMessageEntryForChat, n as createIMessageRpcClient, o as isIMessageCurrentMessageInChatAsync } from "./client-12apu4Ip.mjs";
5
- import { l as isAutoManagedIMessageCliPath, n as IMESSAGE_UPDATE_COMMAND, t as IMESSAGE_INSTALL_COMMAND } from "./setup-core-DqOBe-n0.mjs";
1
+ import { c as parseIMessageTarget } from "./targets-B4oU7n-v.mjs";
2
+ import { l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-DacCvDBt.mjs";
3
+ import { a as setCachedIMessagePrivateApiStatus, n as getCachedIMessagePrivateApiStatus, o as IMESSAGE_ACTIONS, r as imessageRpcSupportsMethod, s as IMESSAGE_ACTION_NAMES, t as describeIMessageMessageTool } from "./message-tool-api-B5NfPnFL.mjs";
4
+ import { a as isIMessageCurrentMessageInChat, b as chatContextFromIMessageTarget, c as rememberIMessageReplyCache, i as findLatestIMessageEntryForChat, n as createIMessageRpcClient, o as isIMessageCurrentMessageInChatAsync } from "./client-HixFQQWY.mjs";
5
+ import { l as isAutoManagedIMessageCliPath, n as IMESSAGE_UPDATE_COMMAND, t as IMESSAGE_INSTALL_COMMAND } from "./setup-core-CaRGbZOL.mjs";
6
6
  import { filterStringEntries, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
8
8
  import path from "node:path";
@@ -68,16 +68,6 @@ function cacheIMessagePrivateApiStatus(cliPath, status) {
68
68
  const expiresAt = resolveExpiresAtMsFromDurationMs(PRIVATE_API_NEGATIVE_TTL_MS);
69
69
  if (expiresAt !== void 0) setCachedIMessagePrivateApiStatus(cliPath, status, expiresAt);
70
70
  }
71
- function getCachedRpcSupport(cliPath) {
72
- const cached = rpcSupportCache.get(cliPath);
73
- if (!cached) return;
74
- const now = asDateTimestampMs(Date.now());
75
- if (now === void 0 || cached.expiresAt <= now) {
76
- rpcSupportCache.delete(cliPath);
77
- return;
78
- }
79
- return cached.result;
80
- }
81
71
  function setCachedRpcSupport(cliPath, result) {
82
72
  const expiresAt = resolveExpiresAtMsFromDurationMs(RPC_SUPPORT_CACHE_TTL_MS);
83
73
  if (expiresAt === void 0) return;
@@ -86,17 +76,13 @@ function setCachedRpcSupport(cliPath, result) {
86
76
  expiresAt
87
77
  });
88
78
  }
89
- function isDefaultLocalIMessageCliPath(cliPath) {
90
- const trimmed = cliPath.trim();
91
- return trimmed === "imsg" || !trimmed.includes("/") && path.basename(trimmed) === "imsg";
92
- }
93
- function resolveIMessageNonMacHostError(cliPath, platform = process.platform) {
94
- if (platform === "darwin" || !isDefaultLocalIMessageCliPath(cliPath)) return;
95
- return "iMessage via the default imsg CLI must run on macOS. Run OpenClaw on the signed-in Messages Mac, or set channels.imessage.cliPath to an SSH wrapper that runs imsg on that Mac.";
96
- }
97
79
  async function probeRpcSupport(cliPath, timeoutMs) {
98
- const cached = getCachedRpcSupport(cliPath);
99
- if (cached) return cached;
80
+ const cached = rpcSupportCache.get(cliPath);
81
+ if (cached) {
82
+ const now = asDateTimestampMs(Date.now());
83
+ if (now !== void 0 && cached.expiresAt > now) return cached.result;
84
+ rpcSupportCache.delete(cliPath);
85
+ }
100
86
  try {
101
87
  const result = await runCommandWithTimeout([
102
88
  expandIMessageUserPath(cliPath),
@@ -130,24 +116,6 @@ async function probeRpcSupport(cliPath, timeoutMs) {
130
116
  };
131
117
  }
132
118
  }
133
- function parseStatusPayload(stdout) {
134
- const lines = normalizeStringEntries(stdout.split(/\r?\n/));
135
- for (const line of lines.toReversed()) try {
136
- const value = JSON.parse(line);
137
- if (value && typeof value === "object" && !Array.isArray(value)) return { payload: value };
138
- } catch {}
139
- return {
140
- payload: null,
141
- firstLineSnippet: lines[0] ? truncateUtf16Safe(lines[0], 120) : void 0
142
- };
143
- }
144
- function selectorsFromPayload(payload) {
145
- const raw = payload.selectors;
146
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
147
- const selectors = {};
148
- for (const [key, value] of Object.entries(raw)) if (typeof value === "boolean") selectors[key] = value;
149
- return selectors;
150
- }
151
119
  async function probeIMessageCliFlag(cliPath, timeoutMs, command, flag) {
152
120
  try {
153
121
  const result = await runCommandWithTimeout([
@@ -191,8 +159,21 @@ async function probeIMessagePrivateApi(cliPath, timeoutMs, options = {}) {
191
159
  cacheIMessagePrivateApiStatus(key, status);
192
160
  return status;
193
161
  }
194
- const { payload, firstLineSnippet } = parseStatusPayload(result.stdout);
195
- const selectors = payload ? selectorsFromPayload(payload) : {};
162
+ const lines = normalizeStringEntries(result.stdout.split(/\r?\n/));
163
+ let payload = null;
164
+ for (const line of lines.toReversed()) try {
165
+ const value = JSON.parse(line);
166
+ if (value && typeof value === "object" && !Array.isArray(value)) {
167
+ payload = value;
168
+ break;
169
+ }
170
+ } catch {}
171
+ const firstLineSnippet = !payload && lines[0] ? truncateUtf16Safe(lines[0], 120) : void 0;
172
+ const rawSelectors = payload?.selectors;
173
+ const selectors = {};
174
+ if (rawSelectors && typeof rawSelectors === "object" && !Array.isArray(rawSelectors)) {
175
+ for (const [selector, value] of Object.entries(rawSelectors)) if (typeof value === "boolean") selectors[selector] = value;
176
+ }
196
177
  const rpcMethods = filterStringEntries(payload?.rpc_methods);
197
178
  const advancedFeatures = payload?.advanced_features === true;
198
179
  const v2Ready = payload?.v2_ready === true;
@@ -239,11 +220,10 @@ async function probeIMessage(timeoutMs, opts = {}) {
239
220
  remoteHost: opts.remoteHost ?? cfg?.channels?.imessage?.remoteHost
240
221
  });
241
222
  const effectiveTimeout = timeoutMs ?? cfg?.channels?.imessage?.probeTimeoutMs ?? 1e4;
242
- const nonMacHostError = resolveIMessageNonMacHostError(cliPath, opts.platform);
243
- if (nonMacHostError) return {
223
+ if ((opts.platform ?? process.platform) !== "darwin" && (cliPath === "imsg" || !cliPath.includes("/") && path.basename(cliPath) === "imsg")) return {
244
224
  ok: false,
245
225
  fatal: true,
246
- error: nonMacHostError
226
+ error: "iMessage via the default imsg CLI must run on macOS. Run OpenClaw on the signed-in Messages Mac, or set channels.imessage.cliPath to an SSH wrapper that runs imsg on that Mac."
247
227
  };
248
228
  if (!await detectBinary(expandIMessageUserPath(cliPath))) return {
249
229
  ok: false,
@@ -280,7 +260,7 @@ async function probeIMessage(timeoutMs, opts = {}) {
280
260
  }
281
261
  //#endregion
282
262
  //#region extensions/imessage/src/actions.ts
283
- const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-DL5i-Y4J.mjs"), "imessageActionsRuntime");
263
+ const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-DOIX6Fkf.mjs"), "imessageActionsRuntime");
284
264
  const log = createSubsystemLogger("channels/imessage");
285
265
  const providerId = "imessage";
286
266
  const SUPPORTED_ACTIONS = /* @__PURE__ */ new Set([...IMESSAGE_ACTION_NAMES, "upload-file"]);
@@ -348,21 +328,6 @@ function createIMessageTargetAliases(resourceAliases = []) {
348
328
  }
349
329
  };
350
330
  }
351
- async function completeOutboundBridgeMessage(params) {
352
- const messageId = normalizeIMessageMessageId(params.messageId);
353
- if (messageId) await rememberIMessageReplyCache({
354
- accountId: params.accountId,
355
- messageId,
356
- chatGuid: params.chatGuid,
357
- timestamp: Date.now(),
358
- isFromMe: true
359
- });
360
- return jsonResult({
361
- ok: true,
362
- messageId: params.messageId,
363
- ...params.details
364
- });
365
- }
366
331
  /** An omitted action reference targets the most recent inbound in the same chat. */
367
332
  function readMessageIdWithChatFallback(params, chatContext) {
368
333
  const explicit = readStringParam(params, "messageId");
@@ -545,7 +510,7 @@ const imessageMessageActions = {
545
510
  }
546
511
  };
547
512
  const opts = {
548
- cliPath: account.config.cliPath?.trim() || "imsg",
513
+ cliPath: cliPathForProbe,
549
514
  dbPath: account.config.dbPath?.trim() || void 0,
550
515
  remoteHost,
551
516
  timeoutMs: account.config.probeTimeoutMs
@@ -592,6 +557,21 @@ const imessageMessageActions = {
592
557
  }
593
558
  });
594
559
  };
560
+ const completeOutboundBridgeMessage = async (result, targetChatGuid, details) => {
561
+ const messageId = normalizeIMessageMessageId(result.messageId);
562
+ if (messageId) await rememberIMessageReplyCache({
563
+ accountId: account.accountId,
564
+ messageId,
565
+ chatGuid: targetChatGuid,
566
+ timestamp: Date.now(),
567
+ isFromMe: true
568
+ });
569
+ return jsonResult({
570
+ ok: true,
571
+ messageId: result.messageId,
572
+ ...details
573
+ });
574
+ };
595
575
  await assertPrivateApiEnabled();
596
576
  if (action === "react") {
597
577
  const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove an iMessage reaction." });
@@ -664,38 +644,26 @@ const imessageMessageActions = {
664
644
  if (!opts.remoteHost && privateApiStatus?.cliCapabilities?.sendRichSupportsAttachment !== true) throw new Error("iMessage reply with an attachment needs an imsg build that exposes `send-rich --file` (openclaw/imsg#114). Upgrade imsg, or use action 'upload-file' (with filePath/filename) or action 'send' (with media) to deliver the file plus a separate 'reply' for any text.");
665
645
  }
666
646
  const partIndex = readNonNegativeIntegerParam(params, "partIndex");
667
- const result = await runtime.sendRichMessage({
647
+ return await completeOutboundBridgeMessage(await runtime.sendRichMessage({
668
648
  chatGuid: reference.chatGuid,
669
649
  text,
670
650
  replyToMessageId: reference.messageId,
671
651
  partIndex,
672
652
  attachment: attachment?.spec ?? void 0,
673
653
  options: opts
674
- });
675
- return await completeOutboundBridgeMessage({
676
- accountId: account.accountId,
677
- messageId: result.messageId,
678
- chatGuid: reference.chatGuid,
679
- details: { repliedTo: reference.messageId }
680
- });
654
+ }), reference.chatGuid, { repliedTo: reference.messageId });
681
655
  }
682
656
  if (action === "sendWithEffect") {
683
657
  const text = readMessageText(params);
684
658
  const effectId = effectIdFromParam(readStringParam(params, "effectId") ?? readStringParam(params, "effect"));
685
659
  if (!text || !effectId) throw new Error("iMessage sendWithEffect requires text/message and effect/effectId.");
686
660
  const resolvedChatGuid = await chatGuid();
687
- const result = await runtime.sendRichMessage({
661
+ return await completeOutboundBridgeMessage(await runtime.sendRichMessage({
688
662
  chatGuid: resolvedChatGuid,
689
663
  text,
690
664
  effectId,
691
665
  options: opts
692
- });
693
- return await completeOutboundBridgeMessage({
694
- accountId: account.accountId,
695
- messageId: result.messageId,
696
- chatGuid: resolvedChatGuid,
697
- details: { effect: effectId }
698
- });
666
+ }), resolvedChatGuid, { effect: effectId });
699
667
  }
700
668
  if (action === "renameGroup") {
701
669
  const displayName = readStringParam(params, "displayName") ?? readStringParam(params, "name");
@@ -757,18 +725,13 @@ const imessageMessageActions = {
757
725
  const filename = readStringParam(params, "filename", { required: true });
758
726
  const asVoice = readBooleanParam(params, "asVoice");
759
727
  const resolvedChatGuid = await chatGuid();
760
- const result = await runtime.sendAttachment({
728
+ return await completeOutboundBridgeMessage(await runtime.sendAttachment({
761
729
  chatGuid: resolvedChatGuid,
762
730
  buffer: decodeBase64Buffer(params, action),
763
731
  filename,
764
732
  asVoice: asVoice ?? void 0,
765
733
  options: opts
766
- });
767
- return await completeOutboundBridgeMessage({
768
- accountId: account.accountId,
769
- messageId: result.messageId,
770
- chatGuid: resolvedChatGuid
771
- });
734
+ }), resolvedChatGuid);
772
735
  }
773
736
  if (action === "poll") {
774
737
  if (privateApiStatus?.selectors?.pollPayloadMessage !== true) await probePrivateApiStatus(true);
@@ -780,17 +743,12 @@ const imessageMessageActions = {
780
743
  options: rawChoices
781
744
  }, { maxOptions: 12 });
782
745
  const resolvedChatGuid = await chatGuid();
783
- const result = await runtime.sendPoll({
746
+ return await completeOutboundBridgeMessage(await runtime.sendPoll({
784
747
  chatGuid: resolvedChatGuid,
785
748
  question: poll.question,
786
749
  choices: poll.options,
787
750
  options: opts
788
- });
789
- return await completeOutboundBridgeMessage({
790
- accountId: account.accountId,
791
- messageId: result.messageId,
792
- chatGuid: resolvedChatGuid
793
- });
751
+ }), resolvedChatGuid);
794
752
  }
795
753
  if (action === "poll-vote") {
796
754
  if (privateApiStatus?.selectors?.pollVoteMessage !== true || !imessageRpcSupportsMethod(privateApiStatus, "poll.vote")) await probePrivateApiStatus(true);
@@ -817,12 +775,7 @@ const imessageMessageActions = {
817
775
  optionText: optionText ?? void 0,
818
776
  options: opts
819
777
  });
820
- return await completeOutboundBridgeMessage({
821
- accountId: account.accountId,
822
- messageId: result.messageId,
823
- chatGuid: pollReference.chatGuid,
824
- details: result.optionText ? { pollVotedOption: result.optionText } : void 0
825
- });
778
+ return await completeOutboundBridgeMessage(result, pollReference.chatGuid, result.optionText ? { pollVotedOption: result.optionText } : void 0);
826
779
  }
827
780
  throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
828
781
  }
@@ -1,42 +1,19 @@
1
- import { S as normalizeDirectChatIdentifier, n as createIMessageRpcClient, r as runIMessageCliJsonCommand, u as resolveIMessageMessageId } from "./client-12apu4Ip.mjs";
2
- import { n as sanitizeIMessageFinalOutboundText } from "./sanitize-outbound-C0x4BPky.mjs";
3
- import { n as authorizeIMessageResourceReference, t as withIMessageRemoteFile } from "./remote-file-BU7pA-Zi.mjs";
1
+ import { S as normalizeDirectChatIdentifier, n as createIMessageRpcClient, r as runIMessageCliJsonCommand, u as resolveIMessageMessageId } from "./client-HixFQQWY.mjs";
2
+ import { n as sanitizeIMessageFinalOutboundText } from "./sanitize-outbound-DpdQERYJ.mjs";
3
+ import { n as authorizeIMessageResourceReference, t as withIMessageRemoteFile } from "./remote-file-Dq5Asi_F.mjs";
4
4
  import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { basename, parse, win32 } from "node:path";
6
6
  import { asDateTimestampMs, parseStrictInteger, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
7
7
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
8
+ import { captureChannelReadAuthority, captureEffectAuthority } from "openclaw/plugin-sdk/fetch-runtime";
8
9
  import { sanitizeUntrustedFileName } from "openclaw/plugin-sdk/security-runtime";
9
10
  import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
10
11
  //#region extensions/imessage/src/actions-chat-guid.ts
11
12
  const CHAT_LIST_CACHE_TTL_MS = 3e4;
12
13
  const chatListCache = /* @__PURE__ */ new Map();
13
- function asChatList(value) {
14
- if (!isRecord(value)) return [];
15
- return Array.isArray(value.chats) ? value.chats.filter(isRecord) : [];
16
- }
17
14
  function numberFromUnknown(value) {
18
15
  return typeof value === "number" && Number.isFinite(value) ? value : parseStrictInteger(value);
19
16
  }
20
- function chatListCacheKey(options) {
21
- return `${options.cliPath}\0${options.dbPath ?? ""}\0${options.remoteHost ?? ""}`;
22
- }
23
- function chatListCacheGet(options) {
24
- const key = chatListCacheKey(options);
25
- const entry = chatListCache.get(key);
26
- const now = asDateTimestampMs(Date.now());
27
- if (!entry || now === void 0 || entry.expiresAt <= now) {
28
- chatListCache.delete(key);
29
- return null;
30
- }
31
- return entry.list;
32
- }
33
- function chatListCacheSet(options, list) {
34
- const expiresAt = resolveExpiresAtMsFromDurationMs(CHAT_LIST_CACHE_TTL_MS);
35
- if (expiresAt !== void 0) chatListCache.set(chatListCacheKey(options), {
36
- list,
37
- expiresAt
38
- });
39
- }
40
17
  function findChatGuid(chats, target) {
41
18
  if (target.kind === "chat_id") {
42
19
  for (const chat of chats) {
@@ -55,12 +32,21 @@ function findChatGuid(chats, target) {
55
32
  return null;
56
33
  }
57
34
  async function resolveIMessageActionChatGuid(params) {
58
- const cached = chatListCacheGet(params.options);
59
- if (cached) return findChatGuid(cached, params.target);
35
+ const { cliPath, dbPath, remoteHost } = params.options;
36
+ const key = `${cliPath}\0${dbPath ?? ""}\0${remoteHost ?? ""}`;
37
+ const cached = chatListCache.get(key);
38
+ const now = asDateTimestampMs(Date.now());
39
+ if (cached && now !== void 0 && cached.expiresAt > now) return findChatGuid(cached.list, params.target);
40
+ chatListCache.delete(key);
60
41
  const client = await createIMessageRpcClient(params.options);
61
42
  try {
62
- const list = asChatList(await client.request("chats.list", { limit: 1e3 }, { timeoutMs: params.options.timeoutMs }));
63
- chatListCacheSet(params.options, list);
43
+ const result = await client.request("chats.list", { limit: 1e3 }, { timeoutMs: params.options.timeoutMs });
44
+ const list = isRecord(result) && Array.isArray(result.chats) ? result.chats.filter(isRecord) : [];
45
+ const expiresAt = resolveExpiresAtMsFromDurationMs(CHAT_LIST_CACHE_TTL_MS);
46
+ if (expiresAt !== void 0) chatListCache.set(key, {
47
+ list,
48
+ expiresAt
49
+ });
64
50
  return findChatGuid(list, params.target);
65
51
  } finally {
66
52
  await client.stop();
@@ -79,12 +65,18 @@ function throwIMessageRemoteUnsupported(message) {
79
65
  throw new IMessageRemoteUnsupportedError(`iMessage Remote Mac limitation: ${message}`);
80
66
  }
81
67
  async function runIMessageAction(options, method, params, args) {
82
- if (!options.remoteHost) return await runIMessageCliJsonCommand({
83
- args,
84
- cliPath: options.cliPath,
85
- dbPath: options.dbPath,
86
- timeoutMs: options.timeoutMs
87
- });
68
+ if (!options.remoteHost) {
69
+ const assertReadAuthority = captureChannelReadAuthority();
70
+ return await captureEffectAuthority().initiate(() => {
71
+ assertReadAuthority?.();
72
+ return runIMessageCliJsonCommand({
73
+ args,
74
+ cliPath: options.cliPath,
75
+ dbPath: options.dbPath,
76
+ timeoutMs: options.timeoutMs
77
+ });
78
+ });
79
+ }
88
80
  const client = await createIMessageRpcClient({
89
81
  cliPath: options.cliPath,
90
82
  dbPath: options.dbPath,
@@ -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-BicBiYsM.mjs";
2
- import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, r as listEnabledIMessageAccounts } from "./accounts-evTpvJMv.mjs";
3
- import { o as IMESSAGE_ACTIONS, s as IMESSAGE_ACTION_NAMES } from "./message-tool-api-CqfRxLlT.mjs";
4
- import { v as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./client-12apu4Ip.mjs";
5
- import { n as probeIMessage } from "./actions-DJqbUmbN.mjs";
6
- import { c as matchIMessageAcpConversation, i as resolveIMessageGroupRequireMention, l as normalizeIMessageAcpConversationId, o as resolveIMessageGroupToolPolicy, s as resolveIMessageInboundConversationId, t as imessagePlugin, u as resolveIMessageConversationIdFromTarget } from "./channel-CL73qdMG.mjs";
1
+ import { a as looksLikeIMessageExplicitTargetId, c as parseIMessageTarget, d as normalizeIMessageMessagingTarget, i as isAllowedIMessageSender, n as inferIMessageTargetChatType, o as normalizeIMessageHandle, s as parseIMessageAllowTarget, t as formatIMessageChatTarget, u as looksLikeIMessageTargetId } from "./targets-B4oU7n-v.mjs";
2
+ import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, r as listEnabledIMessageAccounts } from "./accounts-DacCvDBt.mjs";
3
+ import { o as IMESSAGE_ACTIONS, s as IMESSAGE_ACTION_NAMES } from "./message-tool-api-B5NfPnFL.mjs";
4
+ import { v as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./client-HixFQQWY.mjs";
5
+ import { n as probeIMessage } from "./actions-Hxh12myO.mjs";
6
+ import { c as matchIMessageAcpConversation, i as resolveIMessageGroupRequireMention, l as normalizeIMessageAcpConversationId, o as resolveIMessageGroupToolPolicy, s as resolveIMessageInboundConversationId, t as imessagePlugin, u as resolveIMessageConversationIdFromTarget } from "./channel-9TWBUDkP.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-SAVMfMoY.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-DC1yHVGj.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,15 +1,15 @@
1
- import "./targets-BicBiYsM.mjs";
2
- import "./accounts-evTpvJMv.mjs";
3
- import "./message-tool-api-CqfRxLlT.mjs";
4
- import "./actions-DJqbUmbN.mjs";
5
- import { s as imessageSetupContract } from "./setup-core-DqOBe-n0.mjs";
6
- import { n as createIMessagePluginBase, r as imessageSetupWizard } from "./channel-CL73qdMG.mjs";
1
+ import "./targets-B4oU7n-v.mjs";
2
+ import "./accounts-DacCvDBt.mjs";
3
+ import "./message-tool-api-B5NfPnFL.mjs";
4
+ import "./actions-Hxh12myO.mjs";
5
+ import { s as imessageSetupContract } from "./setup-core-CaRGbZOL.mjs";
6
+ import { n as createIMessagePluginBase, r as imessageSetupWizard } from "./channel-9TWBUDkP.mjs";
7
7
  import "./conversation-bindings-GDQ_Laxj.mjs";
8
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";
9
9
  //#region extensions/imessage/src/channel.setup.ts
10
- const imessageSetupPlugin = { ...createIMessagePluginBase({
10
+ const imessageSetupPlugin = createIMessagePluginBase({
11
11
  setupWizard: imessageSetupWizard,
12
12
  setupContract: imessageSetupContract
13
- }) };
13
+ });
14
14
  //#endregion
15
15
  export { resolveServicePrefixedChatTarget$1 as a, imessageSetupPlugin as c, resolveServicePrefixedAllowTarget as i, parseChatAllowTargetPrefixes as n, resolveServicePrefixedOrChatAllowTarget$1 as o, parseChatTargetPrefixesOrThrow$1 as r, resolveServicePrefixedTarget as s, createAllowedChatSenderMatcher$1 as t };