@openclaw/imessage 2026.9.1-beta.1 → 2026.9.2

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 (47) hide show
  1. package/dist/{accounts-DIpGOIiN.js → accounts-CCirBEIm.js} +2 -3
  2. package/dist/{actions.runtime-BhggncbG.js → actions.runtime-D5MAgeSs.js} +5 -5
  3. package/dist/api.js +5 -5
  4. package/dist/{approval-handler.runtime-BC-YsgAf.js → approval-handler.runtime-47rs6THN.js} +14 -9
  5. package/dist/{approval-reactions-Cvwmdlev.js → approval-reactions-sVpDno7d.js} +8 -16
  6. package/dist/{channel-CnKQ2MVB.js → channel-BxraMrmK.js} +21 -14
  7. package/dist/channel-config-api.js +1 -1
  8. package/dist/channel-plugin-api.js +1 -1
  9. package/dist/{channel.runtime-BQLCh7bE.js → channel.runtime-2jwkMPGR.js} +59 -14
  10. package/dist/{config-schema-DV0KP5nC.js → config-schema-DuGbA8Kp.js} +8 -7
  11. package/dist/contract-api.js +1 -1
  12. package/dist/doctor-contract-api.js +8 -281
  13. package/dist/{group-policy-BipELT2x.js → group-policy-Cp8SDG4G.js} +18 -12
  14. package/dist/media-contract-api.js +1 -1
  15. package/dist/{media-contract-BVXuQHG2.js → media-contract-pns3TSS5.js} +3 -2
  16. package/dist/{message-tool-api-BwIxJDoz.js → message-tool-api-CUoFESHj.js} +11 -6
  17. package/dist/message-tool-api.js +1 -1
  18. package/dist/{monitor-DRD_Dnp9.js → monitor-CESwxMQ4.js} +319 -48
  19. package/dist/{question-reactions-viP7ZcyG.js → question-reactions-9tBYB1_F.js} +4 -7
  20. package/dist/{reaction-context-BAYI7pz0.js → reaction-context-Br-vAJFp.js} +9 -3
  21. package/dist/{remote-file-CyTTuRAt.js → remote-file-Biz5PjXi.js} +5 -53
  22. package/dist/runtime-Cza4CY5T.js +8 -0
  23. package/dist/runtime-api.js +7 -7
  24. package/dist/{sanitize-outbound-g651fIhi.js → sanitize-outbound-Bvo4g1Mp.js} +470 -82
  25. package/dist/{send-DVQY6M5M.js → send-DC981dqK.js} +146 -23
  26. package/dist/state-contract-DvahEY4X.js +56 -0
  27. package/dist/state-migrations-D-fyHVcb.js +277 -0
  28. package/node_modules/typebox/build/format/email.mjs +1 -1
  29. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  30. package/node_modules/typebox/build/format/json_pointer.d.mts +2 -2
  31. package/node_modules/typebox/build/format/json_pointer.mjs +2 -2
  32. package/node_modules/typebox/build/format/json_pointer_uri_fragment.d.mts +2 -2
  33. package/node_modules/typebox/build/format/json_pointer_uri_fragment.mjs +2 -2
  34. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  35. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  36. package/node_modules/typebox/build/system/memory/assign.mjs +2 -1
  37. package/node_modules/typebox/build/system/memory/create.mjs +3 -4
  38. package/node_modules/typebox/build/system/memory/discard.mjs +2 -2
  39. package/node_modules/typebox/build/system/memory/freeze.d.mts +4 -0
  40. package/node_modules/typebox/build/system/memory/freeze.mjs +6 -0
  41. package/node_modules/typebox/build/system/memory/update.mjs +3 -2
  42. package/node_modules/typebox/package.json +1 -1
  43. package/openclaw.plugin.json +2 -7
  44. package/package.json +5 -5
  45. package/dist/catchup-Dh-Rv4Ur.js +0 -294
  46. package/dist/monitor-reply-cache-BdeUQaHO.js +0 -353
  47. package/dist/persisted-echo-cache-DGxy-J4t.js +0 -143
@@ -1,284 +1,6 @@
1
- import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount } from "./accounts-DIpGOIiN.js";
2
- import { d as resolveIMessageReplyCacheEntryKey, i as IMESSAGE_REPLY_CACHE_NAMESPACE, n as IMESSAGE_REPLY_CACHE_COUNTER_NAMESPACE, r as IMESSAGE_REPLY_CACHE_MAX_ENTRIES, t as IMESSAGE_REPLY_CACHE_COUNTER_KEY } from "./monitor-reply-cache-BdeUQaHO.js";
3
- import { o as resolveIMessageCatchupCursorKey, r as capFailureRetriesMap, t as IMESSAGE_CATCHUP_CURSOR_NAMESPACE } from "./catchup-Dh-Rv4Ur.js";
4
- import { n as IMESSAGE_SENT_ECHOES_TTL_MS, s as resolveIMessageSentEchoEntryKey, t as IMESSAGE_SENT_ECHOES_NAMESPACE } from "./persisted-echo-cache-DGxy-J4t.js";
5
- import fs from "node:fs";
6
- import path from "node:path";
7
- import { asFiniteNumber, isRecord, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
8
- import { createHash } from "node:crypto";
1
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
9
2
  import { defineChannelAliasMigration, definePluginDoctorMigrationFromPlans } from "openclaw/plugin-sdk/runtime-doctor-migrations";
10
- import { fileExists } from "openclaw/plugin-sdk/security-runtime";
11
- import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
12
- //#region extensions/imessage/src/state-migrations.ts
13
- const REPLY_CACHE_TTL_MS = 360 * 60 * 1e3;
14
- function resolveMigrationStateDir(params) {
15
- return params.stateDir ?? resolveStateDir(params.env);
16
- }
17
- function remainingTtlMs(timestamp, ttlMs) {
18
- const remaining = ttlMs - Math.max(0, Date.now() - timestamp);
19
- return remaining > 0 ? remaining : void 0;
20
- }
21
- function readJsonl(pathValue) {
22
- try {
23
- return fs.readFileSync(pathValue, "utf8").split(/\n+/).flatMap((line) => {
24
- if (!line) return [];
25
- try {
26
- return [JSON.parse(line)];
27
- } catch {
28
- return [];
29
- }
30
- });
31
- } catch (err) {
32
- throw new Error(`Failed reading ${pathValue}: ${String(err)}`, { cause: err });
33
- }
34
- }
35
- function parseReplyCacheEntry(raw) {
36
- if (!raw || typeof raw !== "object") return null;
37
- const parsed = raw;
38
- if (typeof parsed.accountId !== "string" || typeof parsed.messageId !== "string" || typeof parsed.shortId !== "string" || typeof parsed.timestamp !== "number") return null;
39
- return {
40
- accountId: parsed.accountId,
41
- messageId: parsed.messageId,
42
- shortId: parsed.shortId,
43
- timestamp: parsed.timestamp,
44
- ...typeof parsed.chatGuid === "string" ? { chatGuid: parsed.chatGuid } : {},
45
- ...typeof parsed.chatIdentifier === "string" ? { chatIdentifier: parsed.chatIdentifier } : {},
46
- ...typeof parsed.chatId === "number" ? { chatId: parsed.chatId } : {},
47
- ...typeof parsed.isFromMe === "boolean" ? { isFromMe: parsed.isFromMe } : {}
48
- };
49
- }
50
- function readReplyCacheMaxShortId(sourcePath) {
51
- let max = 0;
52
- for (const raw of readJsonl(sourcePath)) {
53
- if (!raw || typeof raw !== "object") continue;
54
- const shortId = raw.shortId;
55
- if (typeof shortId !== "string") continue;
56
- const numeric = Number.parseInt(shortId, 10);
57
- if (Number.isFinite(numeric) && numeric > max) max = numeric;
58
- }
59
- return max;
60
- }
61
- function readReplyCounterValue(value) {
62
- if (!value || typeof value !== "object") return null;
63
- const counter = value.counter;
64
- return asFiniteNumber(counter) ?? null;
65
- }
66
- function shouldReplaceReplyCounter(existingValue, incomingValue) {
67
- const incomingCounter = readReplyCounterValue(incomingValue);
68
- if (incomingCounter === null) return false;
69
- const existingCounter = readReplyCounterValue(existingValue);
70
- return existingCounter === null || incomingCounter > existingCounter;
71
- }
72
- function parseSentEchoEntry(raw) {
73
- if (!raw || typeof raw !== "object") return null;
74
- const parsed = raw;
75
- if (typeof parsed.scope !== "string" || typeof parsed.timestamp !== "number") return null;
76
- return {
77
- scope: parsed.scope,
78
- timestamp: parsed.timestamp,
79
- ...typeof parsed.text === "string" ? { text: parsed.text } : {},
80
- ...typeof parsed.messageId === "string" ? { messageId: parsed.messageId } : {}
81
- };
82
- }
83
- function listReplyCacheEntries(sourcePath) {
84
- const entriesByKey = /* @__PURE__ */ new Map();
85
- for (const entry of readJsonl(sourcePath).map(parseReplyCacheEntry)) {
86
- if (!entry) continue;
87
- const ttlMs = remainingTtlMs(entry.timestamp, REPLY_CACHE_TTL_MS);
88
- if (!ttlMs) continue;
89
- const key = resolveIMessageReplyCacheEntryKey(entry.messageId);
90
- entriesByKey.delete(key);
91
- entriesByKey.set(key, {
92
- value: entry,
93
- ttlMs
94
- });
95
- }
96
- return [...entriesByKey.entries()].slice(-IMESSAGE_REPLY_CACHE_MAX_ENTRIES).map(([key, entry]) => ({
97
- key,
98
- value: entry.value,
99
- ttlMs: entry.ttlMs
100
- }));
101
- }
102
- function listSentEchoEntries(sourcePath) {
103
- return readJsonl(sourcePath).map(parseSentEchoEntry).filter((entry) => Boolean(entry)).slice(-256).flatMap((entry) => {
104
- const ttlMs = remainingTtlMs(entry.timestamp, IMESSAGE_SENT_ECHOES_TTL_MS);
105
- if (!ttlMs) return [];
106
- return [{
107
- key: resolveIMessageSentEchoEntryKey(entry),
108
- value: entry,
109
- ttlMs
110
- }];
111
- });
112
- }
113
- function resolveLegacyCatchupCursorPath(stateDir, accountId) {
114
- const safePrefix = accountId.replace(/[^a-zA-Z0-9_-]/g, "_") || "account";
115
- const hash = createHash("sha256").update(accountId, "utf8").digest("hex").slice(0, 12);
116
- return path.join(stateDir, "imessage", "catchup", `${safePrefix}__${hash}.json`);
117
- }
118
- function listLegacyCatchupCursorPaths(stateDir) {
119
- const dir = path.join(stateDir, "imessage", "catchup");
120
- try {
121
- return fs.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => path.join(dir, entry.name));
122
- } catch {
123
- return [];
124
- }
125
- }
126
- function normalizeCatchupCursor(raw) {
127
- if (!raw || typeof raw !== "object") return null;
128
- const value = raw;
129
- if (typeof value.lastSeenMs !== "number" || !Number.isFinite(value.lastSeenMs) || typeof value.lastSeenRowid !== "number" || !Number.isFinite(value.lastSeenRowid)) return null;
130
- const failureRetries = sanitizeCatchupFailureRetries(value.failureRetries);
131
- const hasRetries = Object.keys(failureRetries).length > 0;
132
- return {
133
- lastSeenMs: value.lastSeenMs,
134
- lastSeenRowid: value.lastSeenRowid,
135
- updatedAt: typeof value.updatedAt === "number" ? value.updatedAt : 0,
136
- ...hasRetries ? { failureRetries } : {}
137
- };
138
- }
139
- function readCatchupCursor(sourcePath) {
140
- let parsed;
141
- try {
142
- parsed = JSON.parse(fs.readFileSync(sourcePath, "utf8"));
143
- } catch (err) {
144
- throw new Error(`Failed reading ${sourcePath}: ${String(err)}`, { cause: err });
145
- }
146
- const cursor = normalizeCatchupCursor(parsed);
147
- if (!cursor) throw new Error(`Invalid iMessage catchup cursor: ${sourcePath}`);
148
- return cursor;
149
- }
150
- function sanitizeCatchupFailureRetries(raw) {
151
- if (!raw || typeof raw !== "object") return {};
152
- const out = {};
153
- for (const [guid, count] of Object.entries(raw)) if (typeof count === "number" && Number.isFinite(count) && count > 0) out[guid] = Math.floor(count);
154
- return capFailureRetriesMap(out);
155
- }
156
- function shouldReplaceCatchupCursor(existingValue, incomingValue) {
157
- const incoming = normalizeCatchupCursor(incomingValue);
158
- if (!incoming) return false;
159
- const existing = normalizeCatchupCursor(existingValue);
160
- return !existing || incoming.lastSeenRowid > existing.lastSeenRowid || incoming.lastSeenRowid === existing.lastSeenRowid && incoming.lastSeenMs > existing.lastSeenMs;
161
- }
162
- function detectReplyCacheMigration(params) {
163
- const stateDir = resolveMigrationStateDir(params);
164
- const sourcePath = path.join(stateDir, "imessage", "reply-cache.jsonl");
165
- if (!fileExists(sourcePath)) return [];
166
- const plans = [];
167
- plans.push({
168
- kind: "plugin-state-import",
169
- label: "iMessage reply short-id counter",
170
- sourcePath,
171
- targetPath: `plugin state:${IMESSAGE_REPLY_CACHE_COUNTER_NAMESPACE}`,
172
- pluginId: "imessage",
173
- namespace: IMESSAGE_REPLY_CACHE_COUNTER_NAMESPACE,
174
- maxEntries: 1,
175
- scopeKey: "",
176
- stateDir,
177
- preview: `- iMessage reply short-id counter: ${sourcePath} → plugin state (${IMESSAGE_REPLY_CACHE_COUNTER_NAMESPACE})`,
178
- readEntries: () => {
179
- const maxShortId = readReplyCacheMaxShortId(sourcePath);
180
- return maxShortId > 0 ? [{
181
- key: IMESSAGE_REPLY_CACHE_COUNTER_KEY,
182
- value: { counter: maxShortId }
183
- }] : [];
184
- },
185
- shouldReplaceExistingEntry: ({ existingValue, incomingValue }) => shouldReplaceReplyCounter(existingValue, incomingValue)
186
- });
187
- plans.push({
188
- kind: "plugin-state-import",
189
- label: "iMessage reply short-id cache",
190
- sourcePath,
191
- targetPath: `plugin state:${IMESSAGE_REPLY_CACHE_NAMESPACE}`,
192
- pluginId: "imessage",
193
- namespace: IMESSAGE_REPLY_CACHE_NAMESPACE,
194
- maxEntries: IMESSAGE_REPLY_CACHE_MAX_ENTRIES,
195
- scopeKey: "",
196
- stateDir,
197
- cleanupSource: "rename",
198
- cleanupWhenEmpty: true,
199
- preview: `- iMessage reply short-id cache: ${sourcePath} → plugin state (${IMESSAGE_REPLY_CACHE_NAMESPACE})`,
200
- readEntries: () => listReplyCacheEntries(sourcePath)
201
- });
202
- return plans;
203
- }
204
- function detectSentEchoMigration(params) {
205
- const stateDir = resolveMigrationStateDir(params);
206
- const sourcePath = path.join(stateDir, "imessage", "sent-echoes.jsonl");
207
- if (!fileExists(sourcePath)) return [];
208
- return [{
209
- kind: "plugin-state-import",
210
- label: "iMessage sent-echo dedupe cache",
211
- sourcePath,
212
- targetPath: `plugin state:${IMESSAGE_SENT_ECHOES_NAMESPACE}`,
213
- pluginId: "imessage",
214
- namespace: IMESSAGE_SENT_ECHOES_NAMESPACE,
215
- maxEntries: 256,
216
- scopeKey: "",
217
- stateDir,
218
- cleanupSource: "rename",
219
- cleanupWhenEmpty: true,
220
- preview: `- iMessage sent-echo dedupe cache: ${sourcePath} → plugin state (${IMESSAGE_SENT_ECHOES_NAMESPACE})`,
221
- readEntries: () => listSentEchoEntries(sourcePath)
222
- }];
223
- }
224
- function detectCatchupCursorMigrations(params) {
225
- const stateDir = resolveMigrationStateDir(params);
226
- const accountIds = uniqueStrings([resolveDefaultIMessageAccountId(params.cfg), ...listIMessageAccountIds(params.cfg)].map((accountId) => resolveIMessageAccount({
227
- cfg: params.cfg,
228
- accountId
229
- }).accountId));
230
- const configuredPaths = new Set(accountIds.map((accountId) => resolveLegacyCatchupCursorPath(stateDir, accountId)));
231
- const configuredPlans = accountIds.flatMap((accountId) => {
232
- const sourcePath = resolveLegacyCatchupCursorPath(stateDir, accountId);
233
- if (!fileExists(sourcePath)) return [];
234
- return {
235
- kind: "plugin-state-import",
236
- label: "iMessage catchup cursor",
237
- sourcePath,
238
- targetPath: `plugin state:${IMESSAGE_CATCHUP_CURSOR_NAMESPACE}`,
239
- pluginId: "imessage",
240
- namespace: IMESSAGE_CATCHUP_CURSOR_NAMESPACE,
241
- maxEntries: 256,
242
- scopeKey: "",
243
- stateDir,
244
- cleanupSource: "rename",
245
- preview: `- iMessage catchup cursor: ${sourcePath} → plugin state (${IMESSAGE_CATCHUP_CURSOR_NAMESPACE})`,
246
- readEntries: () => {
247
- const cursor = readCatchupCursor(sourcePath);
248
- return [{
249
- key: resolveIMessageCatchupCursorKey(accountId),
250
- value: cursor
251
- }];
252
- },
253
- shouldReplaceExistingEntry: (replaceParams) => shouldReplaceCatchupCursor(replaceParams.existingValue, replaceParams.incomingValue)
254
- };
255
- });
256
- const orphanPlans = listLegacyCatchupCursorPaths(stateDir).filter((sourcePath) => !configuredPaths.has(sourcePath)).map((sourcePath) => ({
257
- kind: "plugin-state-import",
258
- label: "iMessage orphan catchup cursor",
259
- sourcePath,
260
- targetPath: `plugin state:${IMESSAGE_CATCHUP_CURSOR_NAMESPACE}`,
261
- pluginId: "imessage",
262
- namespace: IMESSAGE_CATCHUP_CURSOR_NAMESPACE,
263
- maxEntries: 256,
264
- scopeKey: "",
265
- stateDir,
266
- cleanupSource: "rename",
267
- cleanupWhenEmpty: true,
268
- preview: `- iMessage orphan catchup cursor: ${sourcePath} → archived legacy state`,
269
- readEntries: () => []
270
- }));
271
- return [...configuredPlans, ...orphanPlans];
272
- }
273
- async function detectIMessageLegacyStateMigrations(params) {
274
- return [
275
- ...detectCatchupCursorMigrations(params),
276
- ...detectReplyCacheMigration(params),
277
- ...detectSentEchoMigration(params)
278
- ];
279
- }
280
- //#endregion
281
- //#region extensions/imessage/doctor-contract-api.ts
3
+ //#region extensions/imessage/config-doctor-api.ts
282
4
  function isEnabledCatchup(value) {
283
5
  return isRecord(value) && value.enabled === true;
284
6
  }
@@ -348,10 +70,15 @@ function normalizeCompatibilityConfig({ cfg }) {
348
70
  changes
349
71
  };
350
72
  }
73
+ //#endregion
74
+ //#region extensions/imessage/doctor-contract-api.ts
351
75
  const stateMigrations = [definePluginDoctorMigrationFromPlans({
352
76
  id: "imessage-legacy-state",
353
77
  label: "iMessage legacy state",
354
- resolvePlans: detectIMessageLegacyStateMigrations
78
+ resolvePlans: async (params) => {
79
+ const { detectIMessageLegacyStateMigrations } = await import("./state-migrations-D-fyHVcb.js");
80
+ return detectIMessageLegacyStateMigrations(params);
81
+ }
355
82
  })];
356
83
  //#endregion
357
84
  export { legacyConfigRules, normalizeCompatibilityConfig, stateMigrations };
@@ -1,7 +1,6 @@
1
- import { a as resolveDefaultIMessageAccountId, l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-DIpGOIiN.js";
2
- import { d as normalizeBareIMessageChatIdentifier, f as getCachedIMessagePrivateApiStatus, g as IMESSAGE_ACTION_NAMES, h as IMESSAGE_ACTIONS, l as parseIMessageTarget, m as setCachedIMessagePrivateApiStatus, p as imessageRpcSupportsMethod, s as normalizeIMessageHandle$1, t as describeIMessageMessageTool, u as isIMessagePhoneLikeHandle } from "./message-tool-api-BwIxJDoz.js";
3
- import { a as findLatestIMessageEntryForChat, c as rememberIMessageReplyCache, h as chatContextFromIMessageTarget, o as isIMessageCurrentMessageInChat } from "./monitor-reply-cache-BdeUQaHO.js";
4
- import { o as createIMessageRpcClient } from "./sanitize-outbound-g651fIhi.js";
1
+ import { a as resolveDefaultIMessageAccountId, l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-CCirBEIm.js";
2
+ import { _ as IMESSAGE_ACTION_NAMES, d as normalizeBareIMessageChatIdentifier, f as getCachedIMessagePrivateApiStatus, g as IMESSAGE_ACTIONS, h as setCachedIMessagePrivateApiStatus, l as parseIMessageTarget, p as imessageRpcSupportsMethod, s as normalizeIMessageHandle$1, t as describeIMessageMessageTool, u as isIMessagePhoneLikeHandle } from "./message-tool-api-CUoFESHj.js";
3
+ import { c as findLatestIMessageEntryForChat, d as rememberIMessageReplyCache, g as chatContextFromIMessageTarget, l as isIMessageCurrentMessageInChat, o as createIMessageRpcClient } from "./sanitize-outbound-Bvo4g1Mp.js";
5
4
  import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
6
5
  import path from "node:path";
7
6
  import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
@@ -277,8 +276,8 @@ function createIMessageSetupWizardProxy(loadWizard) {
277
276
  }
278
277
  //#endregion
279
278
  //#region extensions/imessage/src/probe.ts
280
- const RPC_SUPPORT_CACHE_TTL_MS = 300 * 1e3;
281
- const PRIVATE_API_NEGATIVE_TTL_MS = 10 * 1e3;
279
+ const RPC_SUPPORT_CACHE_TTL_MS = 3e5;
280
+ const PRIVATE_API_NEGATIVE_TTL_MS = 1e4;
282
281
  const rpcSupportCache = /* @__PURE__ */ new Map();
283
282
  function cacheIMessagePrivateApiStatus(cliPath, status) {
284
283
  if (status.available) {
@@ -520,7 +519,7 @@ async function probeIMessage(timeoutMs, opts = {}) {
520
519
  }
521
520
  //#endregion
522
521
  //#region extensions/imessage/src/actions.ts
523
- const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-BhggncbG.js"), "imessageActionsRuntime");
522
+ const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-D5MAgeSs.js"), "imessageActionsRuntime");
524
523
  const log = createSubsystemLogger("channels/imessage");
525
524
  const providerId = "imessage";
526
525
  const SUPPORTED_ACTIONS = /* @__PURE__ */ new Set([...IMESSAGE_ACTION_NAMES, "upload-file"]);
@@ -534,10 +533,14 @@ const GROUP_MANAGEMENT_ACTIONS = /* @__PURE__ */ new Set([
534
533
  function readMessageText(params) {
535
534
  return readStringParam(params, "text") ?? readStringParam(params, "message");
536
535
  }
536
+ function rejectRedactedIMessageTarget(value) {
537
+ if (value === "***") throw new Error("iMessage action target is a redacted display value. Omit the target to use the current conversation.");
538
+ return value;
539
+ }
537
540
  function resolveIMessageDeliveryTarget(args) {
538
- const chatGuid = readStringParam(args, "chatGuid");
541
+ const chatGuid = rejectRedactedIMessageTarget(readStringParam(args, "chatGuid"));
539
542
  const chatId = readPositiveIntegerParam(args, "chatId");
540
- const chatIdentifier = readStringParam(args, "chatIdentifier");
543
+ const chatIdentifier = rejectRedactedIMessageTarget(readStringParam(args, "chatIdentifier"));
541
544
  const targets = [
542
545
  chatGuid ? `chat_guid:${chatGuid}` : void 0,
543
546
  chatId !== void 0 ? `chat_id:${chatId}` : void 0,
@@ -548,6 +551,7 @@ function resolveIMessageDeliveryTarget(args) {
548
551
  }
549
552
  function resolveIMessageActionTarget(params) {
550
553
  const rawTarget = resolveIMessageDeliveryTarget(params.actionParams) ?? readStringParam(params.actionParams, "to") ?? readStringParam(params.actionParams, "target") ?? (params.currentChannelId?.trim() || void 0);
554
+ rejectRedactedIMessageTarget(rawTarget);
551
555
  return rawTarget ? parseIMessageTarget(rawTarget) : null;
552
556
  }
553
557
  const IMESSAGE_DELIVERY_TARGET_ALIASES = [
@@ -1074,7 +1078,7 @@ const imessageMessageActions = {
1074
1078
  if (action === "sendAttachment" || action === "upload-file") {
1075
1079
  await assertPrivateApiEnabled();
1076
1080
  const filename = readStringParam(params, "filename", { required: true });
1077
- const asVoice = readBooleanParam(params, "asVoice") ?? readBooleanParam(params, "as_voice");
1081
+ const asVoice = readBooleanParam(params, "asVoice");
1078
1082
  const resolvedChatGuid = await chatGuid();
1079
1083
  const result = await runtime.sendAttachment({
1080
1084
  chatGuid: resolvedChatGuid,
@@ -1100,9 +1104,11 @@ const imessageMessageActions = {
1100
1104
  await assertPrivateApiEnabled();
1101
1105
  if (privateApiStatus?.selectors?.pollPayloadMessage !== true) await probePrivateApiStatus(true);
1102
1106
  if (privateApiStatus?.selectors?.pollPayloadMessage !== true) throw new Error("iMessage poll requires an imsg bridge that advertises the pollPayloadMessage selector. Update imsg, run imsg launch to re-inject the bridge, then run openclaw channels status --probe to refresh capability detection.");
1107
+ const question = readStringParam(params, "pollQuestion", { required: true });
1108
+ const rawChoices = readStringArrayParam(params, "pollOption", { required: true });
1103
1109
  const poll = normalizePollInput({
1104
- question: readStringParam(params, "pollQuestion", { required: true }),
1105
- options: readStringArrayParam(params, "pollOption", { required: true })
1110
+ question,
1111
+ options: rawChoices
1106
1112
  }, { maxOptions: 12 });
1107
1113
  const resolvedChatGuid = await chatGuid();
1108
1114
  const result = await runtime.sendPoll({
@@ -1,2 +1,2 @@
1
- import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots, t as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS } from "./media-contract-BVXuQHG2.js";
1
+ import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots, t as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS } from "./media-contract-pns3TSS5.js";
2
2
  export { DEFAULT_IMESSAGE_ATTACHMENT_ROOTS, resolveIMessageAttachmentRoots, resolveIMessageAttachmentRoots as resolveInboundAttachmentRoots, resolveIMessageRemoteAttachmentRoots, resolveIMessageRemoteAttachmentRoots as resolveRemoteInboundAttachmentRoots };
@@ -1,9 +1,10 @@
1
- import { o as resolveIMessageAccount } from "./accounts-DIpGOIiN.js";
1
+ import { o as resolveIMessageAccount } from "./accounts-CCirBEIm.js";
2
2
  import { mergeInboundPathRoots } from "openclaw/plugin-sdk/channel-inbound";
3
3
  //#region extensions/imessage/src/media-contract.ts
4
4
  const DEFAULT_IMESSAGE_ATTACHMENT_ROOTS = ["/Users/*/Library/Messages/Attachments"];
5
5
  function resolveIMessageAttachmentRoots(params) {
6
- return mergeInboundPathRoots(resolveIMessageAccount(params).config.attachmentRoots, params.cfg.channels?.imessage?.attachmentRoots, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS);
6
+ const account = resolveIMessageAccount(params);
7
+ return mergeInboundPathRoots(account.config.attachmentRoots, params.cfg.channels?.imessage?.attachmentRoots, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS);
7
8
  }
8
9
  function resolveIMessageRemoteAttachmentRoots(params) {
9
10
  const account = resolveIMessageAccount(params);
@@ -1,4 +1,4 @@
1
- import { c as getCachedIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-DIpGOIiN.js";
1
+ import { c as getCachedIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-CCirBEIm.js";
2
2
  import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
3
3
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
@@ -67,6 +67,9 @@ function getCachedIMessagePrivateApiStatus(cliPath) {
67
67
  }
68
68
  return entry.status;
69
69
  }
70
+ function invalidateCachedIMessagePrivateApiStatus(cliPath) {
71
+ bridgeStatusCache.delete(normalizeCliPath(cliPath));
72
+ }
70
73
  function setCachedIMessagePrivateApiStatus(cliPath, status, expiresAt = 0) {
71
74
  if (expiresAt !== 0 && asDateTimestampMs(expiresAt) === void 0) return;
72
75
  bridgeStatusCache.set(normalizeCliPath(cliPath), {
@@ -208,9 +211,10 @@ function parseIMessageAllowTarget(raw) {
208
211
  kind: "handle",
209
212
  handle: ""
210
213
  };
214
+ const lower = normalizeLowercaseStringOrEmpty(trimmed);
211
215
  const servicePrefixed = resolveServicePrefixedOrChatAllowTarget({
212
216
  trimmed,
213
- lower: normalizeLowercaseStringOrEmpty(trimmed),
217
+ lower,
214
218
  servicePrefixes: SERVICE_PREFIXES,
215
219
  parseAllowTarget: parseIMessageAllowTarget,
216
220
  chatIdPrefixes: CHAT_ID_PREFIXES,
@@ -263,11 +267,12 @@ const PRIVATE_API_ACTIONS = /* @__PURE__ */ new Set([
263
267
  "poll",
264
268
  "poll-vote"
265
269
  ]);
266
- function isGroupTarget(raw) {
270
+ function isGroupTarget(raw, chatType) {
271
+ if (chatType) return chatType !== "direct";
267
272
  if (!raw) return false;
268
273
  return inferIMessageTargetChatType(raw) === "group";
269
274
  }
270
- function describeIMessageMessageTool({ cfg, accountId, currentChannelId }) {
275
+ function describeIMessageMessageTool({ cfg, accountId, chatType, currentChannelId }) {
271
276
  const account = resolveIMessageAccount({
272
277
  cfg,
273
278
  accountId
@@ -292,7 +297,7 @@ function describeIMessageMessageTool({ cfg, accountId, currentChannelId }) {
292
297
  if (action === "poll-vote" && privateApiStatus && !imessageRpcSupportsMethod(privateApiStatus, "poll.vote")) continue;
293
298
  actions.add(action);
294
299
  }
295
- if (!isGroupTarget(currentChannelId)) {
300
+ if (!isGroupTarget(currentChannelId, chatType)) {
296
301
  for (const action of IMESSAGE_ACTION_NAMES) if ("groupOnly" in IMESSAGE_ACTIONS[action] && IMESSAGE_ACTIONS[action].groupOnly) actions.delete(action);
297
302
  }
298
303
  if (actions.delete("sendAttachment")) actions.add("upload-file");
@@ -315,4 +320,4 @@ function describeIMessageMessageTool({ cfg, accountId, currentChannelId }) {
315
320
  };
316
321
  }
317
322
  //#endregion
318
- export { isAllowedIMessageSender as a, parseIMessageAllowTarget as c, normalizeBareIMessageChatIdentifier as d, getCachedIMessagePrivateApiStatus as f, IMESSAGE_ACTION_NAMES as g, IMESSAGE_ACTIONS as h, isAllowedIMessageReplyContextSender as i, parseIMessageTarget as l, setCachedIMessagePrivateApiStatus as m, formatIMessageChatTarget as n, looksLikeIMessageExplicitTargetId as o, imessageRpcSupportsMethod as p, inferIMessageTargetChatType as r, normalizeIMessageHandle as s, describeIMessageMessageTool as t, isIMessagePhoneLikeHandle as u };
323
+ export { IMESSAGE_ACTION_NAMES as _, isAllowedIMessageSender as a, parseIMessageAllowTarget as c, normalizeBareIMessageChatIdentifier as d, getCachedIMessagePrivateApiStatus as f, IMESSAGE_ACTIONS as g, setCachedIMessagePrivateApiStatus as h, isAllowedIMessageReplyContextSender as i, parseIMessageTarget as l, invalidateCachedIMessagePrivateApiStatus as m, formatIMessageChatTarget as n, looksLikeIMessageExplicitTargetId as o, imessageRpcSupportsMethod as p, inferIMessageTargetChatType as r, normalizeIMessageHandle as s, describeIMessageMessageTool as t, isIMessagePhoneLikeHandle as u };
@@ -1,2 +1,2 @@
1
- import { t as describeIMessageMessageTool } from "./message-tool-api-BwIxJDoz.js";
1
+ import { t as describeIMessageMessageTool } from "./message-tool-api-CUoFESHj.js";
2
2
  export { describeIMessageMessageTool as describeMessageTool };