@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
@@ -0,0 +1,226 @@
1
+ import { o as normalizeIMessageHandle } from "./targets-BicBiYsM.mjs";
2
+ import { a as resolveDefaultIMessageAccountId, o as resolveIMessageAccount } from "./accounts-nzcU0cq2.mjs";
3
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
4
+ import { parseAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
5
+ import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
6
+ import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
7
+ import { createCliPathTextInput, createDelegatedSetupWizardProxy, createDelegatedTextInputShouldPrompt, createPatchedAccountSetupAdapter, createSetupTranslator, promptParsedAllowFromForAccount, setAccountAllowFromForChannel, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup-runtime";
8
+ import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
9
+ //#region extensions/imessage/src/setup-core.ts
10
+ const t = createSetupTranslator();
11
+ const channel = "imessage";
12
+ const IMESSAGE_INSTALL_COMMAND = "brew install steipete/tap/imsg";
13
+ const IMESSAGE_UPDATE_COMMAND = "brew update && brew upgrade imsg";
14
+ const HOMEBREW_IMSG_PATHS = /* @__PURE__ */ new Set([
15
+ "/opt/homebrew/bin/imsg",
16
+ "/opt/homebrew/opt/imsg/bin/imsg",
17
+ "/usr/local/bin/imsg",
18
+ "/usr/local/opt/imsg/bin/imsg"
19
+ ]);
20
+ function normalizeIMessageCliPathForSetup(cliPath) {
21
+ return cliPath?.trim() || "imsg";
22
+ }
23
+ function isAutoManagedIMessageCliPath(cliPath, opts) {
24
+ const normalized = normalizeIMessageCliPathForSetup(cliPath);
25
+ return !opts?.explicit && normalized === "imsg" || HOMEBREW_IMSG_PATHS.has(normalized);
26
+ }
27
+ const CHAT_TARGET_ALLOWFROM_PREFIXES = [
28
+ "chat_id:",
29
+ "chatid:",
30
+ "chat:",
31
+ "chat_guid:",
32
+ "chatguid:",
33
+ "guid:",
34
+ "chat_identifier:",
35
+ "chatidentifier:",
36
+ "chatident:"
37
+ ];
38
+ const SERVICE_ALLOWFROM_PREFIXES = [
39
+ "imessage:",
40
+ "sms:",
41
+ "auto:"
42
+ ];
43
+ function normalizeAllowFromEntryForPrefixCheck(entry) {
44
+ let lower = normalizeLowercaseStringOrEmpty(entry);
45
+ let stripped = true;
46
+ while (stripped) {
47
+ stripped = false;
48
+ for (const prefix of SERVICE_ALLOWFROM_PREFIXES) if (lower.startsWith(prefix)) {
49
+ lower = lower.slice(prefix.length).trim();
50
+ stripped = true;
51
+ }
52
+ }
53
+ return lower;
54
+ }
55
+ function parseIMessageAllowFromEntries(raw) {
56
+ return parseAllowFromEntries(raw, (entry) => {
57
+ const lower = normalizeAllowFromEntryForPrefixCheck(entry);
58
+ if (CHAT_TARGET_ALLOWFROM_PREFIXES.some((prefix) => lower.startsWith(prefix))) return { error: `iMessage allowFrom entries must be sender handles: ${entry}` };
59
+ if (!normalizeIMessageHandle(entry)) return { error: `Invalid handle: ${entry}` };
60
+ return { value: entry };
61
+ });
62
+ }
63
+ function buildIMessageSetupPatch(input) {
64
+ return {
65
+ ...input.cliPath ? { cliPath: input.cliPath } : {},
66
+ ...input.dbPath ? { dbPath: input.dbPath } : {},
67
+ ...input.service ? { service: input.service } : {},
68
+ ...input.region ? { region: input.region } : {}
69
+ };
70
+ }
71
+ async function promptIMessageAllowFrom(params) {
72
+ return promptParsedAllowFromForAccount({
73
+ cfg: params.cfg,
74
+ accountId: params.accountId,
75
+ defaultAccountId: resolveDefaultIMessageAccountId(params.cfg),
76
+ prompter: params.prompter,
77
+ noteTitle: "iMessage allowlist",
78
+ noteLines: [
79
+ "Allowlist iMessage DMs by sender handle.",
80
+ "Examples:",
81
+ "- +15555550123",
82
+ "- user@example.com",
83
+ "Multiple entries: comma-separated.",
84
+ `Docs: ${formatDocsLink("/imessage", "imessage")}`
85
+ ],
86
+ message: "iMessage allowFrom (sender handle)",
87
+ placeholder: "+15555550123, user@example.com",
88
+ parseEntries: parseIMessageAllowFromEntries,
89
+ getExistingAllowFrom: ({ cfg, accountId }) => resolveIMessageAccount({
90
+ cfg,
91
+ accountId
92
+ }).config.allowFrom ?? [],
93
+ applyAllowFrom: ({ cfg, accountId, allowFrom }) => setAccountAllowFromForChannel({
94
+ cfg,
95
+ channel,
96
+ accountId,
97
+ allowFrom,
98
+ setupSurface: imessageSetupAdapter
99
+ })
100
+ });
101
+ }
102
+ const imessageDmPolicy = createChannelDmPolicy({
103
+ label: "iMessage",
104
+ channel,
105
+ resolveAccount: (cfg, accountId) => resolveIMessageAccount({
106
+ cfg,
107
+ accountId: accountId ?? resolveDefaultIMessageAccountId(cfg)
108
+ }),
109
+ setupSurface: () => imessageSetupAdapter,
110
+ promptAllowFrom: promptIMessageAllowFrom
111
+ });
112
+ function createIMessageCliPathTextInput(shouldPrompt) {
113
+ return createCliPathTextInput({
114
+ inputKey: "cliPath",
115
+ message: "imsg CLI path",
116
+ resolvePath: ({ cfg, accountId }) => resolveIMessageAccount({
117
+ cfg,
118
+ accountId
119
+ }).config.cliPath ?? "imsg",
120
+ shouldPrompt,
121
+ helpTitle: "iMessage",
122
+ helpLines: [
123
+ "imsg CLI path required to enable iMessage.",
124
+ `Install imsg on the Messages Mac: ${IMESSAGE_INSTALL_COMMAND}`,
125
+ `Update imsg when channel probes report missing RPC or private API capabilities: ${IMESSAGE_UPDATE_COMMAND}`
126
+ ]
127
+ });
128
+ }
129
+ const imessageCompletionNote = {
130
+ title: "iMessage next steps",
131
+ lines: [
132
+ "For the usual setup, run OpenClaw on the Mac signed into Messages.",
133
+ "If the Gateway runs elsewhere, set cliPath to a transparent SSH wrapper that runs imsg on the Messages Mac.",
134
+ `Install imsg on the Messages Mac: ${IMESSAGE_INSTALL_COMMAND}`,
135
+ `Update imsg after imsg fixes or missing-capability errors: ${IMESSAGE_UPDATE_COMMAND}`,
136
+ "Private API mode is strongly encouraged for replies, tapbacks, effects, polls, attachments, and group actions.",
137
+ "After Private API setup, run `imsg launch`, then `openclaw channels status --probe`.",
138
+ "Ensure OpenClaw has Full Disk Access to Messages DB.",
139
+ "Grant Automation permission for Messages when prompted.",
140
+ "List chats with: imsg chats --limit 20",
141
+ `Docs: ${formatDocsLink("/imessage", "imessage")}`
142
+ ]
143
+ };
144
+ const imessageSetupAdapter = {
145
+ ...createPatchedAccountSetupAdapter({
146
+ channelKey: channel,
147
+ buildPatch: (input) => buildIMessageSetupPatch(input)
148
+ }),
149
+ singleAccountKeysToMove: [
150
+ "cliPath",
151
+ "dbPath",
152
+ "service",
153
+ "region"
154
+ ]
155
+ };
156
+ const imessageSetupContract = defineChannelSetupContract({
157
+ fields: {
158
+ cliPath: {
159
+ kind: "string",
160
+ cli: {
161
+ flags: "--cli-path <path>",
162
+ description: "iMessage CLI path"
163
+ }
164
+ },
165
+ dbPath: {
166
+ kind: "string",
167
+ cli: {
168
+ flags: "--db-path <path>",
169
+ description: "iMessage database path"
170
+ }
171
+ },
172
+ service: {
173
+ kind: "choice",
174
+ choices: [
175
+ "imessage",
176
+ "sms",
177
+ "auto"
178
+ ],
179
+ cli: {
180
+ flags: "--service <service>",
181
+ description: "iMessage service"
182
+ }
183
+ },
184
+ region: {
185
+ kind: "string",
186
+ cli: {
187
+ flags: "--region <region>",
188
+ description: "SMS region"
189
+ }
190
+ }
191
+ },
192
+ legacyAdapter: imessageSetupAdapter
193
+ });
194
+ const imessageSetupStatusLabels = {
195
+ configuredLabel: t("wizard.channels.statusConfigured"),
196
+ unconfiguredLabel: t("wizard.channels.statusNeedsSetup"),
197
+ configuredHint: t("wizard.imessage.imsgFound"),
198
+ unconfiguredHint: t("wizard.imessage.imsgMissing"),
199
+ configuredScore: 1,
200
+ unconfiguredScore: 0
201
+ };
202
+ const imessageSetupStatusBase = {
203
+ ...imessageSetupStatusLabels,
204
+ resolveConfigured: ({ cfg, accountId }) => resolveIMessageAccount({
205
+ cfg,
206
+ accountId
207
+ }).configured
208
+ };
209
+ function createIMessageSetupWizardProxy(loadWizard) {
210
+ return createDelegatedSetupWizardProxy({
211
+ channel,
212
+ loadWizard,
213
+ status: imessageSetupStatusLabels,
214
+ delegatePrepare: true,
215
+ credentials: [],
216
+ textInputs: [createIMessageCliPathTextInput(createDelegatedTextInputShouldPrompt({
217
+ loadWizard,
218
+ inputKey: "cliPath"
219
+ }))],
220
+ completionNote: imessageCompletionNote,
221
+ dmPolicy: imessageDmPolicy,
222
+ disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
223
+ });
224
+ }
225
+ //#endregion
226
+ export { imessageCompletionNote as a, imessageSetupStatusBase as c, parseIMessageAllowFromEntries as d, createIMessageSetupWizardProxy as i, isAutoManagedIMessageCliPath as l, IMESSAGE_UPDATE_COMMAND as n, imessageDmPolicy as o, createIMessageCliPathTextInput as r, imessageSetupContract as s, IMESSAGE_INSTALL_COMMAND as t, normalizeIMessageCliPathForSetup as u };
@@ -1,22 +1,14 @@
1
- import { l as resolveIMessageRemoteHost, o as resolveIMessageAccount, r as listEnabledIMessageAccounts, s as resolveIMessageDuplicateSourceOwner } from "./accounts-CUxZrTcY.mjs";
2
- import { _ as imessageDmPolicy, b as isAutoManagedIMessageCliPath, d as probeIMessage, g as imessageCompletionNote, m as createIMessageCliPathTextInput, p as IMESSAGE_INSTALL_COMMAND, x as normalizeIMessageCliPathForSetup, y as imessageSetupStatusBase } from "./group-policy-Cjztkquv.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-odAfTQ2J.mjs";
5
- import { t as monitorIMessageProvider } from "./monitor-BJ3Ozi6I.mjs";
6
- import { createAccountStatusSink, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
1
+ import { o as resolveIMessageAccount } from "./accounts-nzcU0cq2.mjs";
2
+ import { a as imessageCompletionNote, c as imessageSetupStatusBase, l as isAutoManagedIMessageCliPath, o as imessageDmPolicy, r as createIMessageCliPathTextInput, t as IMESSAGE_INSTALL_COMMAND, u as normalizeIMessageCliPathForSetup } from "./setup-core-8MDdYHj5.mjs";
7
3
  import path from "node:path";
8
- import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
9
4
  import fs from "node:fs/promises";
10
5
  import { createDetectedBinaryStatus, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
11
6
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
12
7
  import { detectBinary as detectBinary$1, resolveBrewExecutable } from "openclaw/plugin-sdk/setup-tools";
8
+ import { isPathStrictlyInside } from "openclaw/plugin-sdk/file-access-runtime";
13
9
  import { runPluginCommandWithTimeout } from "openclaw/plugin-sdk/run-command";
14
10
  //#region extensions/imessage/src/install-imsg.ts
15
11
  const IMESSAGE_BREW_FORMULA = "steipete/tap/imsg";
16
- function isPathInside(parentPath, candidatePath) {
17
- const relative = path.relative(parentPath, candidatePath);
18
- return relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
19
- }
20
12
  async function resolveBrewManagedIMessageCliPath(brewExe, cliPath) {
21
13
  try {
22
14
  const formulae = await runPluginCommandWithTimeout({
@@ -49,7 +41,7 @@ async function resolveBrewManagedIMessageCliPath(brewExe, cliPath) {
49
41
  });
50
42
  if (cellar.code !== 0 || !cellar.stdout.trim()) return null;
51
43
  const [realCliPath, realFormulaPath] = await Promise.all([fs.realpath(resolvedCliPath), fs.realpath(path.join(cellar.stdout.trim(), "imsg"))]);
52
- return isPathInside(realFormulaPath, realCliPath) ? resolvedCliPath : null;
44
+ return isPathStrictlyInside(realFormulaPath, realCliPath) ? resolvedCliPath : null;
53
45
  } catch {
54
46
  return null;
55
47
  }
@@ -126,13 +118,7 @@ const channel = "imessage";
126
118
  const imessageDetectedBinaryStatus = createDetectedBinaryStatus({
127
119
  channelLabel: "iMessage",
128
120
  binaryLabel: "imsg",
129
- configuredLabel: imessageSetupStatusBase.configuredLabel,
130
- unconfiguredLabel: imessageSetupStatusBase.unconfiguredLabel,
131
- configuredHint: imessageSetupStatusBase.configuredHint,
132
- unconfiguredHint: imessageSetupStatusBase.unconfiguredHint,
133
- configuredScore: imessageSetupStatusBase.configuredScore,
134
- unconfiguredScore: imessageSetupStatusBase.unconfiguredScore,
135
- resolveConfigured: imessageSetupStatusBase.resolveConfigured,
121
+ ...imessageSetupStatusBase,
136
122
  resolveBinaryPath: ({ cfg, accountId }) => resolveIMessageAccount({
137
123
  cfg,
138
124
  accountId
@@ -195,87 +181,4 @@ const imessageSetupWizard = {
195
181
  disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
196
182
  };
197
183
  //#endregion
198
- //#region extensions/imessage/src/channel.runtime.ts
199
- async function sendIMessageOutbound(params) {
200
- const send = resolveOutboundSendDep(params.deps, "imessage", { legacyKeys: IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageIMessage;
201
- const maxBytes = resolveChannelMediaMaxBytes({
202
- cfg: params.cfg,
203
- resolveChannelLimitMb: () => resolveIMessageAccount(params).config.mediaMaxMb
204
- });
205
- const result = await send(params.to, params.text, {
206
- config: params.cfg,
207
- ...params.mediaUrl ? { mediaUrl: params.mediaUrl } : {},
208
- ...params.mediaAccess ? { mediaAccess: params.mediaAccess } : {},
209
- ...params.mediaLocalRoots?.length ? { mediaLocalRoots: params.mediaLocalRoots } : {},
210
- ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {},
211
- ...params.audioAsVoice ? { audioAsVoice: true } : {},
212
- maxBytes,
213
- accountId: params.accountId ?? void 0,
214
- replyToId: params.replyToId ?? void 0,
215
- conversationReadOrigin: params.conversationReadOrigin,
216
- assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
217
- onPlatformSendDispatch: params.onPlatformSendDispatch,
218
- ...params.onDeliveryResult ? { onDeliveryResult: params.onDeliveryResult } : {}
219
- });
220
- const meta = {
221
- ...result.meta,
222
- ...result.guid ? { imessageMessageGuid: result.guid } : {},
223
- ...result.sentText ? { imessageVisibleText: result.sentText } : {}
224
- };
225
- return Object.keys(meta).length > 0 ? {
226
- ...result,
227
- meta
228
- } : result;
229
- }
230
- async function probeIMessageAccount(params) {
231
- return await probeIMessage(params?.timeoutMs, {
232
- cliPath: params?.cliPath,
233
- dbPath: params?.dbPath,
234
- remoteHost: params?.remoteHost,
235
- forceRefresh: true
236
- });
237
- }
238
- async function startIMessageGatewayAccount(ctx) {
239
- const account = ctx.account;
240
- const cliPath = account.config.cliPath?.trim() || "imsg";
241
- const dbPath = account.config.dbPath?.trim();
242
- ctx.setStatus({
243
- accountId: account.accountId,
244
- cliPath,
245
- dbPath: dbPath ?? null
246
- });
247
- await Promise.all(listEnabledIMessageAccounts(ctx.cfg).map(async (candidate) => {
248
- await resolveIMessageRemoteHost({
249
- cliPath: candidate.config.cliPath?.trim() || "imsg",
250
- remoteHost: candidate.config.remoteHost
251
- });
252
- }));
253
- const ownerAccountId = resolveIMessageDuplicateSourceOwner({
254
- cfg: ctx.cfg,
255
- account
256
- });
257
- if (ownerAccountId) {
258
- ctx.log?.info?.(`[${account.accountId}] skipping watcher: duplicate iMessage source; using account "${ownerAccountId}"`);
259
- if (ctx.abortSignal.aborted) return;
260
- await new Promise((resolve) => {
261
- ctx.abortSignal.addEventListener("abort", () => resolve(), { once: true });
262
- });
263
- return;
264
- }
265
- const statusSink = createAccountStatusSink({
266
- accountId: account.accountId,
267
- setStatus: ctx.setStatus
268
- });
269
- statusSink({ lifecycle: "starting" });
270
- ctx.log?.info?.(`[${account.accountId}] starting provider (${cliPath}${dbPath ? ` db=${dbPath}` : ""})`);
271
- return await monitorIMessageProvider({
272
- accountId: account.accountId,
273
- config: ctx.cfg,
274
- runtime: ctx.runtime,
275
- abortSignal: ctx.abortSignal,
276
- channelRuntime: ctx.channelRuntime,
277
- statusSink
278
- });
279
- }
280
- //#endregion
281
- export { imessageSetupWizard, probeIMessageAccount, sendIMessageOutbound, startIMessageGatewayAccount };
184
+ export { imessageSetupWizard };
@@ -0,0 +1,47 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+ import { extractErrorCode } from "openclaw/plugin-sdk/error-runtime";
4
+ //#region extensions/imessage/src/state-migrations.ts
5
+ async function retiredSourceWarnings(stateDir) {
6
+ const imessageDir = path.join(stateDir, "imessage");
7
+ const catchupDir = path.join(imessageDir, "catchup");
8
+ let catchupFiles;
9
+ try {
10
+ catchupFiles = await fs.readdir(catchupDir);
11
+ } catch (error) {
12
+ if (extractErrorCode(error) !== "ENOENT") throw error;
13
+ catchupFiles = [];
14
+ }
15
+ const candidates = [
16
+ path.join(imessageDir, "reply-cache.jsonl"),
17
+ path.join(imessageDir, "sent-echoes.jsonl"),
18
+ ...catchupFiles.filter((name) => name.endsWith(".json")).toSorted().map((name) => path.join(catchupDir, name))
19
+ ];
20
+ const warnings = [];
21
+ for (const sourcePath of candidates) {
22
+ try {
23
+ await fs.lstat(sourcePath);
24
+ } catch (error) {
25
+ if (extractErrorCode(error) === "ENOENT") continue;
26
+ throw error;
27
+ }
28
+ warnings.push(`Preserved retired iMessage state at ${sourcePath}. Install OpenClaw 2026.9.5, run "openclaw doctor --fix", then upgrade to latest. See https://docs.openclaw.ai/install/updating#upgrading-very-old-versions.`);
29
+ }
30
+ return warnings;
31
+ }
32
+ const imessageRetiredStateMigration = {
33
+ id: "imessage-legacy-state",
34
+ label: "iMessage legacy state",
35
+ async detectLegacyState({ stateDir }) {
36
+ const preview = await retiredSourceWarnings(stateDir);
37
+ return preview.length > 0 ? { preview } : null;
38
+ },
39
+ async migrateLegacyState({ stateDir }) {
40
+ return {
41
+ changes: [],
42
+ warnings: await retiredSourceWarnings(stateDir)
43
+ };
44
+ }
45
+ };
46
+ //#endregion
47
+ export { imessageRetiredStateMigration };
@@ -30,12 +30,9 @@ function normalizeIMessageHandle$1(raw, allowContactName = false) {
30
30
  const trimmed = raw.trim();
31
31
  if (!trimmed) return "";
32
32
  const lowered = normalizeLowercaseStringOrEmpty(trimmed);
33
- if (lowered.startsWith("imessage:")) return normalizeIMessageHandle$1(trimmed.slice(9));
34
- if (lowered.startsWith("sms:")) return normalizeIMessageHandle$1(trimmed.slice(4));
35
- if (lowered.startsWith("auto:")) return normalizeIMessageHandle$1(trimmed.slice(5));
36
- if (CHAT_TARGET_PREFIX_RE.test(trimmed)) {
37
- const prefix = trimmed.match(CHAT_TARGET_PREFIX_RE)?.[0];
38
- if (!prefix) return "";
33
+ for (const prefix of SERVICE_PREFIXES$1) if (lowered.startsWith(prefix)) return normalizeIMessageHandle$1(trimmed.slice(prefix.length));
34
+ const prefix = trimmed.match(CHAT_TARGET_PREFIX_RE)?.[0];
35
+ if (prefix) {
39
36
  const value = trimmed.slice(prefix.length).trim();
40
37
  return `${normalizeLowercaseStringOrEmpty(prefix)}${value}`;
41
38
  }
@@ -105,12 +102,12 @@ function normalizeIMessageHandle(raw) {
105
102
  const trimmed = raw.trim();
106
103
  if (!trimmed) return "";
107
104
  const lowered = normalizeLowercaseStringOrEmpty(trimmed);
108
- if (lowered.startsWith("imessage:")) return normalizeIMessageHandle(trimmed.slice(9));
109
- if (lowered.startsWith("sms:")) return normalizeIMessageHandle(trimmed.slice(4));
110
- if (lowered.startsWith("auto:")) return normalizeIMessageHandle(trimmed.slice(5));
111
- for (const prefix of CHAT_ID_PREFIXES) if (lowered.startsWith(prefix)) return `chat_id:${trimmed.slice(prefix.length).trim()}`;
112
- for (const prefix of CHAT_GUID_PREFIXES) if (lowered.startsWith(prefix)) return `chat_guid:${trimmed.slice(prefix.length).trim()}`;
113
- for (const prefix of CHAT_IDENTIFIER_PREFIXES) if (lowered.startsWith(prefix)) return `chat_identifier:${trimmed.slice(prefix.length).trim()}`;
105
+ for (const { prefix } of SERVICE_PREFIXES) if (lowered.startsWith(prefix)) return normalizeIMessageHandle(trimmed.slice(prefix.length));
106
+ for (const [kind, prefixes] of [
107
+ ["chat_id", CHAT_ID_PREFIXES],
108
+ ["chat_guid", CHAT_GUID_PREFIXES],
109
+ ["chat_identifier", CHAT_IDENTIFIER_PREFIXES]
110
+ ]) for (const prefix of prefixes) if (lowered.startsWith(prefix)) return `${kind}:${trimmed.slice(prefix.length).trim()}`;
114
111
  return normalizeIMessageHandleValue(trimmed) ?? trimmed.replace(/\s+/g, "");
115
112
  }
116
113
  function parseIMessageTarget(raw) {
@@ -205,14 +202,11 @@ function isAllowedIMessageSender(params) {
205
202
  allowConversationTargets: false
206
203
  });
207
204
  }
208
- const isAllowedIMessageReplyContextSenderMatcher = createAllowedChatSenderMatcher({
205
+ const isAllowedIMessageReplyContextSender = createAllowedChatSenderMatcher({
209
206
  normalizeSender: normalizeIMessageHandle,
210
207
  parseAllowTarget: parseIMessageAllowTarget,
211
208
  allowConversationTargets: true
212
209
  });
213
- function isAllowedIMessageReplyContextSender(params) {
214
- return isAllowedIMessageReplyContextSenderMatcher(params);
215
- }
216
210
  function formatIMessageChatTarget(chatId) {
217
211
  if (!chatId || !Number.isFinite(chatId)) return "";
218
212
  return `chat_id:${chatId}`;
package/dist/api.js CHANGED
@@ -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 "./.setup/targets-Cc9vthzI.mjs";
2
- import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, r as listEnabledIMessageAccounts } from "./.setup/accounts-CUxZrTcY.mjs";
3
- import { o as IMESSAGE_ACTIONS, s as IMESSAGE_ACTION_NAMES } from "./.setup/message-tool-api-pvlcOJPG.mjs";
4
- import { h as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./.setup/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 "./.setup/group-policy-Cjztkquv.mjs";
6
- import { t as imessagePlugin } from "./.setup/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 "./.setup/targets-BicBiYsM.mjs";
2
+ import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, r as listEnabledIMessageAccounts } from "./.setup/accounts-nzcU0cq2.mjs";
3
+ import { o as IMESSAGE_ACTIONS, s as IMESSAGE_ACTION_NAMES } from "./.setup/message-tool-api-D032l82H.mjs";
4
+ import { S as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./.setup/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 "./.setup/group-policy-90pw4tyG.mjs";
6
+ import { t as imessagePlugin } from "./.setup/channel-9fyvuN_p.mjs";
7
7
  import { t as createIMessageConversationBindingManager } from "./.setup/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 "./.setup/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 "./.setup/api-B9Qx21G-.mjs";
9
9
  import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./.setup/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,2 +1,2 @@
1
- import { t as IMessageChannelConfigSchema } from "./.setup/config-schema-CCbTcJEV.mjs";
1
+ import { t as IMessageChannelConfigSchema } from "./.setup/config-schema-4Q3_EqYt.mjs";
2
2
  export { IMessageChannelConfigSchema };
@@ -1,2 +1,2 @@
1
- import { t as imessagePlugin } from "./.setup/channel-BLTaKdSK.mjs";
1
+ import { t as imessagePlugin } from "./.setup/channel-9fyvuN_p.mjs";
2
2
  export { imessagePlugin };
@@ -1,3 +1,3 @@
1
- import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots, t as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS } from "./.setup/media-contract-DKJK7rh3.mjs";
1
+ import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots, t as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS } from "./.setup/media-contract-CagwSMvo.mjs";
2
2
  import "./media-contract-api.js";
3
3
  export { DEFAULT_IMESSAGE_ATTACHMENT_ROOTS, resolveIMessageAttachmentRoots, resolveIMessageAttachmentRoots as resolveInboundAttachmentRoots, resolveIMessageRemoteAttachmentRoots, resolveIMessageRemoteAttachmentRoots as resolveRemoteInboundAttachmentRoots };