@openclaw/imessage 2026.10.10-beta.5 → 2026.11.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/.setup/{accounts-DacCvDBt.mjs → accounts-C1Ypv3Wn.mjs} +9 -13
  2. package/dist/.setup/{actions-762Azi-J.mjs → actions-qOuKy8To.mjs} +364 -116
  3. package/dist/.setup/{actions.runtime-DHiRiPHe.mjs → actions.runtime-Ccg9CARL.mjs} +12 -61
  4. package/dist/.setup/{api-Deyo8NDs.mjs → api-BXXuQQCS.mjs} +8 -9
  5. package/dist/.setup/{api-BFGXDHiC.mjs → api-DTbxSOPc.mjs} +9 -9
  6. package/dist/.setup/{approval-handler.runtime-fsSBf2jf.mjs → approval-handler.runtime-B6vrFfZx.mjs} +113 -133
  7. package/dist/.setup/{approval-reactions-CoAkCiwf.mjs → approval-reactions-DBBsqbRC.mjs} +156 -79
  8. package/dist/.setup/{channel-C61YdcZR.mjs → channel-CLaN4mQn.mjs} +151 -137
  9. package/dist/.setup/{channel.runtime-B5jle0g3.mjs → channel.runtime-XJGx1MIH.mjs} +236 -425
  10. package/dist/.setup/chat-context-fTfJVqAi.mjs +77 -0
  11. package/dist/.setup/chat-lookup-xtPsOBkl.mjs +50 -0
  12. package/dist/.setup/client-D_BaG8sC.mjs +367 -0
  13. package/dist/.setup/{config-schema-DXwa_3V5.mjs → config-schema-BjkQV5P5.mjs} +1 -4
  14. package/dist/.setup/{conversation-bindings-DR-dbHjs.mjs → conversation-bindings-8DjxoIYU.mjs} +10 -8
  15. package/dist/.setup/{media-contract-BwWs5PM7.mjs → media-contract-BErFBKV9.mjs} +2 -3
  16. package/dist/.setup/{message-tool-api-B5NfPnFL.mjs → message-tool-api-DtZ1wKbT.mjs} +6 -12
  17. package/dist/.setup/{outbound-send-deps-B-QEsLSM.mjs → outbound-send-deps-_da8jqeo.mjs} +1 -2
  18. package/dist/.setup/{remote-file-B94a787O.mjs → remote-file-DpK3GQFD.mjs} +12 -30
  19. package/dist/.setup/{rolldown-runtime-BBjsoOtd.mjs → rolldown-runtime-782esTHO.mjs} +1 -2
  20. package/dist/.setup/{sanitize-outbound-BtEY324R.mjs → sanitize-outbound-Dhjhz0a-.mjs} +25 -31
  21. package/dist/.setup/{send-BvxKNWzF.mjs → send-DhEW0gfe.mjs} +155 -236
  22. package/dist/.setup/{setup-core-BHyLkAEJ.mjs → setup-core-B1_P_t4T.mjs} +3 -4
  23. package/dist/.setup/{setup-surface-DPqiLGy0.mjs → setup-surface-CD28mXWK.mjs} +13 -29
  24. package/dist/.setup/{targets-B4oU7n-v.mjs → targets-C7CIWJ0k.mjs} +15 -9
  25. package/dist/.source-module-urls/929c518fa2986b0f85f66bceefead22868db0ab452dee914dc6a2bb86b2e60ad.json +1 -1
  26. package/dist/api.js +9 -9
  27. package/dist/channel-config-api.js +1 -1
  28. package/dist/channel-plugin-api.js +1 -1
  29. package/dist/contract-api.js +1 -1
  30. package/dist/doctor-contract-api.js +7 -13
  31. package/dist/index.js +1 -2
  32. package/dist/media-contract-api.js +1 -1
  33. package/dist/message-tool-api.js +1 -1
  34. package/dist/runtime-api.js +1 -3
  35. package/dist/secret-contract-api.js +1 -2
  36. package/dist/session-binding-contract-api.js +1 -1
  37. package/dist/setup-entry.js +2 -3
  38. package/dist/src/chat-db.worker.js +2 -3
  39. package/node_modules/typebox/build/format/duration.d.mts +2 -2
  40. package/node_modules/typebox/build/format/duration.mjs +2 -2
  41. package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
  42. package/node_modules/typebox/build/format/idn_email.mjs +1 -0
  43. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
  44. package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
  45. package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
  46. package/node_modules/typebox/build/format/ipv4.mjs +2 -2
  47. package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
  48. package/node_modules/typebox/build/format/ipv6.mjs +1 -1
  49. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  50. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  51. package/node_modules/typebox/build/schema/build.mjs +1 -0
  52. package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
  53. package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
  54. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
  55. package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
  56. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
  57. package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
  58. package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
  59. package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
  60. package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
  61. package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
  62. package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
  63. package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
  64. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
  65. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
  66. package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
  67. package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
  68. package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
  69. package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
  70. package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
  71. package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
  72. package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
  73. package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
  74. package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
  75. package/node_modules/typebox/build/system/memory/create.mjs +18 -13
  76. package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
  77. package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
  78. package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
  79. package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
  80. package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
  81. package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
  82. package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
  83. package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
  84. package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
  85. package/node_modules/typebox/build/system/memory/update.mjs +43 -16
  86. package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
  87. package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
  88. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
  89. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
  90. package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
  91. package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
  92. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
  93. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
  94. package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
  95. package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
  96. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
  97. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
  98. package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
  99. package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
  100. package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
  101. package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
  102. package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
  103. package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
  104. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
  105. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
  106. package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
  107. package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
  108. package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
  109. package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
  110. package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
  111. package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
  112. package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
  113. package/node_modules/typebox/package.json +1 -1
  114. package/node_modules/typebox/readme.md +1 -1
  115. package/node_modules/zod/package.json +1 -1
  116. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  117. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  118. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  119. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  120. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  121. package/node_modules/zod/src/v4/core/util.ts +13 -0
  122. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  123. package/node_modules/zod/v4/core/compile.cjs +8 -0
  124. package/node_modules/zod/v4/core/compile.js +8 -0
  125. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  126. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  127. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  128. package/node_modules/zod/v4/core/schemas.js +30 -0
  129. package/node_modules/zod/v4/core/util.cjs +15 -0
  130. package/node_modules/zod/v4/core/util.d.cts +2 -0
  131. package/node_modules/zod/v4/core/util.d.ts +2 -0
  132. package/node_modules/zod/v4/core/util.js +14 -0
  133. package/node_modules/zod/v4/core/versions.cjs +1 -1
  134. package/node_modules/zod/v4/core/versions.js +1 -1
  135. package/openclaw.plugin.json +0 -30
  136. package/package.json +6 -6
  137. package/dist/.setup/client-CcROCvRq.mjs +0 -746
  138. package/dist/.setup/question-reactions-BD06B1Lx.mjs +0 -68
  139. package/dist/.setup/reaction-context-Q26DYzQH.mjs +0 -106
  140. package/dist/.setup/runtime-Cza4CY5T.mjs +0 -8
  141. package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
  142. package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
@@ -0,0 +1,77 @@
1
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
+ import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
3
+ // extensions/imessage/src/chat-context.ts
4
+ const EMAIL_HANDLE_PATTERN = /^[^\s@]+@[^\s@]+$/u;
5
+ function parseDirectChatIdentity(raw) {
6
+ const trimmed = raw.trim();
7
+ const parts = trimmed.split(";");
8
+ if (parts.length === 3 && parts[1] === "-" && parts[2]) {
9
+ const service = parts[0]?.toLowerCase();
10
+ if (service === "imessage" || service === "sms" || service === "any") {
11
+ const identifier = parts[2];
12
+ return {
13
+ service,
14
+ identifier: EMAIL_HANDLE_PATTERN.test(identifier) ? identifier.toLowerCase() : identifier
15
+ };
16
+ }
17
+ }
18
+ if (parts.length !== 1) return;
19
+ if (trimmed.startsWith("+") || EMAIL_HANDLE_PATTERN.test(trimmed)) return { identifier: trimmed.toLowerCase() };
20
+ }
21
+ function resolveIMessageDirectChatService(configuredService, chatGuid) {
22
+ if (configuredService === "imessage" || configuredService === "sms") return configuredService;
23
+ const observedService = chatGuid ? parseDirectChatIdentity(chatGuid)?.service : void 0;
24
+ return observedService === "imessage" || observedService === "sms" ? observedService : void 0;
25
+ }
26
+ function isIMessageEmailChatIdentifier(raw) {
27
+ const identity = parseDirectChatIdentity(raw);
28
+ return Boolean(identity && EMAIL_HANDLE_PATTERN.test(identity.identifier));
29
+ }
30
+ /**
31
+ * Strip the `iMessage;-;` / `SMS;-;` / `any;-;` service prefix that Messages
32
+ * uses for direct chats. Different layers report direct DMs in different
33
+ * forms, so raw comparison would falsely treat one DM as different chats.
34
+ */
35
+ function normalizeDirectChatIdentifier(raw) {
36
+ const trimmed = raw.trim();
37
+ return parseDirectChatIdentity(trimmed)?.identifier ?? trimmed;
38
+ }
39
+ function chatContextFromIMessageTarget(target, effectiveService) {
40
+ if (target.kind === "chat_id") return { chatId: target.chatId };
41
+ if (target.kind === "chat_guid") return { chatGuid: target.chatGuid };
42
+ if (target.kind === "chat_identifier") return { chatIdentifier: target.chatIdentifier };
43
+ const trimmedHandle = target.to.trim();
44
+ const canonicalHandle = trimmedHandle.startsWith("+") ? normalizeE164(trimmedHandle) : EMAIL_HANDLE_PATTERN.test(trimmedHandle) ? trimmedHandle.toLowerCase() : void 0;
45
+ if (!canonicalHandle) return {};
46
+ const service = target.service === "auto" ? effectiveService : target.service;
47
+ if (service !== "imessage" && service !== "sms") return {};
48
+ return { chatIdentifier: `${service === "sms" ? "SMS" : "iMessage"};-;${canonicalHandle}` };
49
+ }
50
+ function compareOptional(left, right) {
51
+ return left === void 0 || right === void 0 ? void 0 : left === right;
52
+ }
53
+ function compareChatSelector(cachedRaw, currentRaw, crossKind = false) {
54
+ const cached = normalizeOptionalString(cachedRaw);
55
+ const current = normalizeOptionalString(currentRaw);
56
+ if (!cached || !current) return;
57
+ if (cached === current) return true;
58
+ const cachedDirect = parseDirectChatIdentity(cached);
59
+ const currentDirect = parseDirectChatIdentity(current);
60
+ if (!cachedDirect || !currentDirect) return crossKind ? void 0 : false;
61
+ if (cachedDirect.identifier !== currentDirect.identifier) return false;
62
+ if (cachedDirect.service === "any") return true;
63
+ if (!cachedDirect.service || !currentDirect.service) return;
64
+ return cachedDirect.service === currentDirect.service;
65
+ }
66
+ function resolveIMessageChatMatch(cached, current) {
67
+ const comparisons = [
68
+ compareChatSelector(cached.chatGuid, current.chatGuid),
69
+ compareChatSelector(cached.chatIdentifier, current.chatIdentifier),
70
+ compareOptional(cached.chatId, current.chatId),
71
+ compareChatSelector(cached.chatGuid, current.chatIdentifier, true),
72
+ compareChatSelector(cached.chatIdentifier, current.chatGuid, true)
73
+ ].filter((comparison) => comparison !== void 0);
74
+ if (comparisons.length === 0) return "unknown";
75
+ return comparisons.every(Boolean) ? "match" : "mismatch";
76
+ }
77
+ export { resolveIMessageDirectChatService as a, resolveIMessageChatMatch as i, isIMessageEmailChatIdentifier as n, normalizeDirectChatIdentifier as r, chatContextFromIMessageTarget as t };
@@ -0,0 +1,50 @@
1
+ import { r as normalizeDirectChatIdentifier } from "./chat-context-fTfJVqAi.mjs";
2
+ import { n as createIMessageRpcClient } from "./client-D_BaG8sC.mjs";
3
+ import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
+ import { parseStrictInteger } from "openclaw/plugin-sdk/number-runtime";
5
+ // extensions/imessage/src/chat-lookup.ts
6
+ const CHAT_LIST_CACHE_TTL_MS = 3e4;
7
+ const chatListCache = /* @__PURE__ */ new Map();
8
+ function numberFromUnknown(value) {
9
+ return typeof value === "number" && Number.isFinite(value) ? value : parseStrictInteger(value);
10
+ }
11
+ function findChat(chats, target) {
12
+ if (target.kind === "chat_id") return chats.find((chat) => chat.id === target.chatId) ?? null;
13
+ if (target.kind === "chat_guid") return chats.find((chat) => chat.guid === target.chatGuid) ?? null;
14
+ const wanted = normalizeDirectChatIdentifier(target.chatIdentifier);
15
+ for (const chat of chats) {
16
+ const { identifier, guid } = chat;
17
+ if (identifier === target.chatIdentifier || guid === target.chatIdentifier || identifier && normalizeDirectChatIdentifier(identifier) === wanted || normalizeDirectChatIdentifier(guid) === wanted) return chat;
18
+ }
19
+ return null;
20
+ }
21
+ async function resolveIMessageChat(params) {
22
+ const { cliPath, dbPath, remoteHost } = params.options;
23
+ const key = `${cliPath}\0${dbPath ?? ""}\0${remoteHost ?? ""}`;
24
+ const cached = chatListCache.get(key);
25
+ if (cached && cached.expiresAt > Date.now()) return findChat(cached.list, params.target);
26
+ chatListCache.delete(key);
27
+ const client = await createIMessageRpcClient(params.options);
28
+ try {
29
+ const result = await client.request("chats.list", { limit: 1e3 }, { timeoutMs: params.options.timeoutMs });
30
+ const list = [];
31
+ for (const chat of isRecord(result) && Array.isArray(result.chats) ? result.chats : []) {
32
+ if (!isRecord(chat)) continue;
33
+ const id = numberFromUnknown(chat.id);
34
+ const guid = normalizeOptionalString(chat.guid);
35
+ if (id !== void 0 && guid) list.push({
36
+ id,
37
+ guid,
38
+ identifier: normalizeOptionalString(chat.identifier)
39
+ });
40
+ }
41
+ chatListCache.set(key, {
42
+ list,
43
+ expiresAt: Date.now() + CHAT_LIST_CACHE_TTL_MS
44
+ });
45
+ return findChat(list, params.target);
46
+ } finally {
47
+ await client.stop();
48
+ }
49
+ }
50
+ export { resolveIMessageChat };
@@ -0,0 +1,367 @@
1
+ import { u as expandIMessageUserPath } from "./accounts-C1Ypv3Wn.mjs";
2
+ import { i as invalidateCachedIMessagePrivateApiStatus } from "./message-tool-api-DtZ1wKbT.mjs";
3
+ import { asNullableRecord, isRecord, normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
4
+ import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
5
+ import { resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
6
+ import { spawn } from "node:child_process";
7
+ import { StringDecoder } from "node:string_decoder";
8
+ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
9
+ import { captureChannelReadAuthority, captureEffectAuthority } from "openclaw/plugin-sdk/fetch-runtime";
10
+ import { raceWithTimeout } from "openclaw/plugin-sdk/time-runtime";
11
+ // extensions/imessage/src/constants.ts
12
+ const DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS = 1e4;
13
+ const DEFAULT_IMESSAGE_SEND_TIMEOUT_MS = 18e4;
14
+ // extensions/imessage/src/cli-output.ts
15
+ const IMESSAGE_CLI_STDOUT_MAX_BYTES = 8388608;
16
+ const IMESSAGE_CLI_STDERR_TAIL_BYTES = 65536;
17
+ function parseLastJsonObject(stdout) {
18
+ const last = stdout.split(/\r?\n/u).findLast((line) => line.trim().length > 0)?.trim();
19
+ if (!last) return null;
20
+ try {
21
+ return asNullableRecord(JSON.parse(last));
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ async function runIMessageCliJsonCommand(params) {
27
+ const dbPath = params.dbPath?.trim();
28
+ const argv = [
29
+ expandIMessageUserPath(params.cliPath),
30
+ ...params.args,
31
+ ...dbPath ? ["--db", dbPath] : [],
32
+ "--json"
33
+ ];
34
+ const result = await runCommandWithTimeout(argv, {
35
+ killProcessTree: true,
36
+ maxOutputBytes: {
37
+ stdout: IMESSAGE_CLI_STDOUT_MAX_BYTES,
38
+ stderr: IMESSAGE_CLI_STDERR_TAIL_BYTES
39
+ },
40
+ outputCapture: {
41
+ stdout: "head",
42
+ stderr: "tail"
43
+ },
44
+ terminateOnOutputLimit: { stdout: true },
45
+ timeoutMs: params.timeoutMs
46
+ });
47
+ if (result.termination === "timeout") throw new Error(`iMessage action timed out after ${params.timeoutMs}ms`);
48
+ if (result.outputLimitExceeded || result.stdoutTruncatedBytes) throw new Error(`imsg stdout exceeded ${IMESSAGE_CLI_STDOUT_MAX_BYTES} bytes`);
49
+ const parsed = parseLastJsonObject(result.stdout);
50
+ if (result.code !== 0) {
51
+ const detail = typeof parsed?.error === "string" && parsed.error.trim() || result.stderr.trim() || result.stdout.trim() || `imsg exited with code ${result.code}`;
52
+ throw new Error(detail);
53
+ }
54
+ if (!parsed) throw new Error(`imsg returned non-JSON output: ${result.stdout.trim() || result.stderr.trim()}`);
55
+ if (parsed.success === false) {
56
+ const detail = typeof parsed.error === "string" && parsed.error.trim() ? parsed.error.trim() : "iMessage action failed";
57
+ throw new Error(detail);
58
+ }
59
+ return parsed;
60
+ }
61
+ // extensions/imessage/src/bridge-recovery.ts
62
+ const BRIDGE_RECOVERY_TIMEOUT_MS = 3e4;
63
+ const recoveries = /* @__PURE__ */ new Map();
64
+ /**
65
+ * Re-inject the private bridge after imsg has positively identified it as
66
+ * unresponsive. This deliberately does not retry the failed mutation: imsg may
67
+ * still reconcile a published send, so replaying it could duplicate a message.
68
+ */
69
+ function recoverIMessageBridge(cliPath) {
70
+ const existing = recoveries.get(cliPath);
71
+ if (existing) return existing;
72
+ const recovery = runIMessageCliJsonCommand({
73
+ cliPath,
74
+ args: ["launch"],
75
+ timeoutMs: BRIDGE_RECOVERY_TIMEOUT_MS
76
+ }).then(() => void 0).finally(() => {
77
+ recoveries.delete(cliPath);
78
+ });
79
+ recoveries.set(cliPath, recovery);
80
+ return recovery;
81
+ }
82
+ // extensions/imessage/src/process-diagnostics.ts
83
+ const PUBLIC_IMESSAGE_FULL_DISK_ACCESS_ERROR = "imsg cannot access ~/Library/Messages/chat.db. Grant Full Disk Access to the Gateway/launcher process and restart Gateway.";
84
+ function normalizeIMessageFullDiskAccessError(message) {
85
+ const normalized = normalizeLowercaseStringOrEmpty(message);
86
+ return normalized.includes("full disk access") && normalized.includes("chat.db") ? PUBLIC_IMESSAGE_FULL_DISK_ACCESS_ERROR : void 0;
87
+ }
88
+ // extensions/imessage/src/client.ts
89
+ const IMSG_APPLE_FRAMEWORK_STDERR_PATTERN = /^(?:\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+ imsg\[\d+:\d+\] )?Could not fetch group for change type \d+ with identifier [^:]+:ABGroup, making it a delete change type\.$/u;
90
+ var IMessageRpcRequestError = class extends Error {
91
+ constructor(message, code, data) {
92
+ super(message);
93
+ this.code = code;
94
+ this.data = data;
95
+ this.name = "IMessageRpcRequestError";
96
+ }
97
+ };
98
+ function isIMessageBridgeStall(error) {
99
+ if (error instanceof IMessageRpcRequestError && isRecord(error.data)) {
100
+ const { transport, detail } = error.data;
101
+ if (transport === "bridge_v2" && typeof detail === "string" && detail.startsWith("The bridge response deadline expired.")) return true;
102
+ }
103
+ return error instanceof Error && error.message.includes("Timed out waiting for response");
104
+ }
105
+ const BRIDGE_STALL_GUIDANCE = "The imsg private API bridge stopped responding. Run `imsg launch` to re-inject the dylib, then `openclaw channels status --probe` to refresh capability detection.";
106
+ function describeIMessageBridgeStall(error) {
107
+ if (error instanceof IMessageRpcRequestError) return new IMessageRpcRequestError(`${error.message} ${BRIDGE_STALL_GUIDANCE}`, error.code, error.data);
108
+ if (error instanceof Error) return new Error(`${error.message} ${BRIDGE_STALL_GUIDANCE}`, { cause: error });
109
+ return error;
110
+ }
111
+ const IMESSAGE_RPC_CLOSE_GRACE_MS = 500;
112
+ function isTestEnv() {
113
+ const vitest = normalizeLowercaseStringOrEmpty(process.env.VITEST);
114
+ return Boolean(vitest);
115
+ }
116
+ function createLfLineFramer(onLine) {
117
+ const decoder = new StringDecoder("utf8");
118
+ let buffer = "";
119
+ return {
120
+ write(chunk) {
121
+ buffer += typeof chunk === "string" ? chunk : decoder.write(chunk);
122
+ let newlineIndex = buffer.indexOf("\n");
123
+ while (newlineIndex !== -1) {
124
+ const line = buffer.slice(0, newlineIndex);
125
+ buffer = buffer.slice(newlineIndex + 1);
126
+ onLine(line);
127
+ newlineIndex = buffer.indexOf("\n");
128
+ }
129
+ },
130
+ flush() {
131
+ buffer += decoder.end();
132
+ if (!buffer) return;
133
+ const line = buffer;
134
+ buffer = "";
135
+ onLine(line);
136
+ }
137
+ };
138
+ }
139
+ var IMessageRpcClient = class {
140
+ constructor(opts = {}) {
141
+ this.pending = /* @__PURE__ */ new Map();
142
+ this.terminalResolve = null;
143
+ this.reapedResolve = null;
144
+ this.child = null;
145
+ this.stopPromise = null;
146
+ this.stdoutFramer = createLfLineFramer((line) => this.handleStdoutLine(line));
147
+ this.stderrFramer = createLfLineFramer((line) => this.handleStderrLine(line));
148
+ this.nextId = 1;
149
+ this.publicProcessError = null;
150
+ this.configuredCliPath = opts.cliPath?.trim() || "imsg";
151
+ this.cliPath = expandIMessageUserPath(this.configuredCliPath);
152
+ const dbPath = opts.dbPath?.trim();
153
+ this.dbPath = dbPath ? opts.remoteHost?.trim() ? dbPath : resolveUserPath(dbPath) : void 0;
154
+ this.runtime = opts.runtime;
155
+ this.onNotification = opts.onNotification;
156
+ this.terminal = new Promise((resolve) => {
157
+ this.terminalResolve = resolve;
158
+ });
159
+ this.reaped = new Promise((resolve) => {
160
+ this.reapedResolve = resolve;
161
+ });
162
+ }
163
+ async start() {
164
+ if (this.child) return;
165
+ if (isTestEnv()) throw new Error("Refusing to start imsg rpc in test environment; mock iMessage RPC client");
166
+ const args = ["rpc", "--json"];
167
+ if (this.dbPath) args.push("--db", this.dbPath);
168
+ const child = spawn(this.cliPath, args, { stdio: [
169
+ "pipe",
170
+ "pipe",
171
+ "pipe"
172
+ ] });
173
+ this.child = child;
174
+ for (const [stream, framer] of [[child.stdout, this.stdoutFramer], [child.stderr, this.stderrFramer]]) stream.on("data", (chunk) => {
175
+ if (this.child === child) framer.write(chunk);
176
+ });
177
+ const failFromProcessError = (err) => this.failTransport(err, child);
178
+ child.on("error", failFromProcessError);
179
+ for (const stream of [
180
+ child.stdin,
181
+ child.stdout,
182
+ child.stderr
183
+ ]) {
184
+ stream.on("error", failFromProcessError);
185
+ stream.once("close", () => {
186
+ const error = stream.errored;
187
+ if (error) failFromProcessError(error);
188
+ });
189
+ }
190
+ child.on("close", (code, signal) => {
191
+ if (this.child === child) {
192
+ this.stdoutFramer.flush();
193
+ this.stderrFramer.flush();
194
+ this.child = null;
195
+ }
196
+ this.finish(this.buildCloseError(code, signal));
197
+ const resolve = this.reapedResolve;
198
+ this.reapedResolve = null;
199
+ resolve?.();
200
+ });
201
+ }
202
+ async stop() {
203
+ if (this.stopPromise) return await this.stopPromise;
204
+ const child = this.child;
205
+ if (!child) return;
206
+ this.stopPromise = this.stopChild(child);
207
+ return await this.stopPromise;
208
+ }
209
+ async waitForClose() {
210
+ throw await this.terminal;
211
+ }
212
+ async request(method, params, opts) {
213
+ const child = this.child;
214
+ const stdin = child?.stdin;
215
+ const assertReadAuthority = captureChannelReadAuthority();
216
+ return captureEffectAuthority().initiate(() => {
217
+ if (child !== this.child || stdin !== this.child?.stdin) throw new Error("imsg rpc process changed before request initiation");
218
+ assertReadAuthority?.();
219
+ opts?.assertCurrent?.();
220
+ return this.initiateRequest(method, params, opts);
221
+ });
222
+ }
223
+ async initiateRequest(method, params, opts) {
224
+ if (!this.child || !this.child.stdin) throw new Error("imsg rpc not running");
225
+ const id = this.nextId++;
226
+ const line = `${JSON.stringify({
227
+ jsonrpc: "2.0",
228
+ id,
229
+ method,
230
+ params: params ?? {}
231
+ })}\n`;
232
+ const timeoutMs = opts?.timeoutMs ?? 1e4;
233
+ const key = String(id);
234
+ const pendingResponse = new Promise((resolve, reject) => {
235
+ this.pending.set(key, {
236
+ resolve: (value) => resolve(value),
237
+ reject
238
+ });
239
+ });
240
+ const response = timeoutMs > 0 ? raceWithTimeout(pendingResponse, timeoutMs, () => {
241
+ this.pending.delete(key);
242
+ throw new Error(`imsg rpc timeout (${method})`);
243
+ }) : pendingResponse;
244
+ try {
245
+ this.child.stdin.write(line, (err) => {
246
+ if (err) this.failTransport(err, this.child);
247
+ });
248
+ } catch (err) {
249
+ this.failTransport(err, this.child);
250
+ }
251
+ try {
252
+ return await response;
253
+ } catch (err) {
254
+ if (isIMessageBridgeStall(err)) {
255
+ invalidateCachedIMessagePrivateApiStatus(this.configuredCliPath);
256
+ try {
257
+ await recoverIMessageBridge(this.configuredCliPath);
258
+ } catch (recoveryError) {
259
+ this.runtime?.error?.(normalizeIMessageFullDiskAccessError(formatErrorMessage(recoveryError)) ?? `imessage: automatic bridge recovery failed. ${BRIDGE_STALL_GUIDANCE}`);
260
+ }
261
+ throw describeIMessageBridgeStall(err);
262
+ }
263
+ throw err;
264
+ }
265
+ }
266
+ async stopChild(child) {
267
+ try {
268
+ child.stdin.end();
269
+ } catch (err) {
270
+ this.failTransport(err, child);
271
+ }
272
+ if (await this.waitForReap(IMESSAGE_RPC_CLOSE_GRACE_MS)) return;
273
+ this.signalChild(child, "SIGTERM");
274
+ if (await this.waitForReap(IMESSAGE_RPC_CLOSE_GRACE_MS)) return;
275
+ this.signalChild(child, "SIGKILL");
276
+ if (!await this.waitForReap(IMESSAGE_RPC_CLOSE_GRACE_MS)) throw new Error("imsg rpc did not exit after SIGKILL");
277
+ }
278
+ async waitForReap(timeoutMs) {
279
+ if (!this.reapedResolve) return true;
280
+ return await raceWithTimeout(this.reaped.then(() => true), timeoutMs, () => false);
281
+ }
282
+ signalChild(child, signal) {
283
+ try {
284
+ child.kill(signal);
285
+ } catch {}
286
+ }
287
+ failTransport(err, child) {
288
+ if (!this.finish(err instanceof Error ? err : new Error(String(err)))) return;
289
+ if (child) this.signalChild(child, "SIGTERM");
290
+ }
291
+ handleStdoutLine(line) {
292
+ const trimmed = line.trim();
293
+ if (!trimmed) return;
294
+ this.handleLine(trimmed);
295
+ }
296
+ handleStderrLine(line) {
297
+ const trimmed = line.trim();
298
+ if (!trimmed) return;
299
+ this.recordProcessDiagnostic(trimmed);
300
+ if (IMSG_APPLE_FRAMEWORK_STDERR_PATTERN.test(trimmed)) return;
301
+ this.runtime?.error?.(normalizeIMessageFullDiskAccessError(trimmed) ?? "imsg rpc: stderr diagnostic received");
302
+ }
303
+ handleLine(line) {
304
+ let parsed;
305
+ try {
306
+ parsed = JSON.parse(line);
307
+ } catch {
308
+ this.recordProcessDiagnostic(line);
309
+ this.runtime?.error?.("imsg rpc: failed to parse JSON response");
310
+ return;
311
+ }
312
+ if (parsed.id !== void 0 && parsed.id !== null) {
313
+ const key = String(parsed.id);
314
+ const pending = this.pending.get(key);
315
+ if (!pending) return;
316
+ this.pending.delete(key);
317
+ if (parsed.error) {
318
+ const baseMessage = parsed.error.message ?? "imsg rpc error";
319
+ const details = parsed.error.data;
320
+ const code = parsed.error.code;
321
+ const suffixes = [];
322
+ if (typeof code === "number") suffixes.push(`code=${code}`);
323
+ if (details !== void 0) {
324
+ const detailText = typeof details === "string" ? details : JSON.stringify(details, null, 2);
325
+ if (detailText) suffixes.push(detailText);
326
+ }
327
+ const msg = suffixes.length > 0 ? `${baseMessage}: ${suffixes.join(" ")}` : baseMessage;
328
+ pending.reject(new IMessageRpcRequestError(msg, typeof code === "number" ? code : void 0, details));
329
+ return;
330
+ }
331
+ pending.resolve(parsed.result);
332
+ return;
333
+ }
334
+ if (parsed.method) this.onNotification?.({
335
+ method: parsed.method,
336
+ params: parsed.params
337
+ });
338
+ }
339
+ recordProcessDiagnostic(line) {
340
+ this.publicProcessError ??= normalizeIMessageFullDiskAccessError(line) ?? null;
341
+ }
342
+ buildCloseError(code, signal) {
343
+ if (this.publicProcessError) return new Error(this.publicProcessError);
344
+ if (code !== 0 && code !== null) {
345
+ const reason = signal ? `signal ${signal}` : `code ${code}`;
346
+ return /* @__PURE__ */ new Error(`imsg rpc exited (${reason})`);
347
+ }
348
+ return /* @__PURE__ */ new Error("imsg rpc closed");
349
+ }
350
+ finish(err) {
351
+ const resolve = this.terminalResolve;
352
+ if (!resolve) return false;
353
+ this.terminalResolve = null;
354
+ for (const [key, pending] of this.pending.entries()) {
355
+ pending.reject(err);
356
+ this.pending.delete(key);
357
+ }
358
+ resolve(err);
359
+ return true;
360
+ }
361
+ };
362
+ async function createIMessageRpcClient(opts = {}) {
363
+ const client = new IMessageRpcClient(opts);
364
+ await client.start();
365
+ return client;
366
+ }
367
+ export { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS as a, runIMessageCliJsonCommand as i, createIMessageRpcClient as n, DEFAULT_IMESSAGE_SEND_TIMEOUT_MS as o, normalizeIMessageFullDiskAccessError as r, IMessageRpcRequestError as t };
@@ -1,7 +1,7 @@
1
1
  import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
2
2
  import { ChannelDeliveryStreamingConfigSchema, ChannelSendReadReceiptsSchema, ExecutableTokenSchema, buildChannelAccountSchemaParts, buildChannelConfigSchema, buildChannelReactionShape, buildGroupEntrySchema, isSafeScpRemoteHost, isValidInboundPathRootPattern, refineChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-schema";
3
3
  import { z } from "zod";
4
- //#region extensions/imessage/src/config-ui-hints.ts
4
+ // extensions/imessage/src/config-schema.ts
5
5
  const iMessageChannelConfigUiHints = {
6
6
  "": {
7
7
  label: "iMessage",
@@ -35,8 +35,6 @@ const iMessageChannelConfigUiHints = {
35
35
  help: "Preferred imsg RPC send transport for normal outbound replies. \"auto\" uses the IMCore bridge when available, \"bridge\" requires it, and \"applescript\" forces Messages automation."
36
36
  }
37
37
  };
38
- //#endregion
39
- //#region extensions/imessage/src/config-schema.ts
40
38
  const IMessageActionSchema = z.object({
41
39
  reactions: z.boolean().optional(),
42
40
  edit: z.boolean().optional(),
@@ -118,5 +116,4 @@ const IMessageConfigSchema = IMessageAccountSchemaBase.extend({
118
116
  }
119
117
  });
120
118
  const IMessageChannelConfigSchema = buildChannelConfigSchema(IMessageConfigSchema, { uiHints: iMessageChannelConfigUiHints });
121
- //#endregion
122
119
  export { IMessageChannelConfigSchema as t };
@@ -1,5 +1,6 @@
1
- import { createAccountScopedConversationBindingManager, createAccountScopedConversationBindingManagerV2, resetAccountScopedConversationBindingsForTests } from "openclaw/plugin-sdk/thread-bindings-runtime";
2
- //#region extensions/imessage/src/conversation-bindings.ts
1
+ import { createAccountScopedConversationBindingManager, createAccountScopedConversationBindingManagerV2 } from "openclaw/plugin-sdk/thread-bindings-runtime";
2
+ import { warnPluginSdkDeprecation } from "openclaw/plugin-sdk/thread-bindings-session-runtime";
3
+ // extensions/imessage/src/conversation-bindings.ts
3
4
  const IMESSAGE_CONVERSATION_BINDINGS_STATE_KEY = Symbol.for("openclaw.imessageConversationBindingsState");
4
5
  function toSessionBindingTargetKind(raw) {
5
6
  return raw === "subagent" ? "subagent" : "session";
@@ -7,8 +8,13 @@ function toSessionBindingTargetKind(raw) {
7
8
  function toIMessageTargetKind(raw) {
8
9
  return raw === "subagent" ? "subagent" : "acp";
9
10
  }
10
- /** @deprecated Use createIMessageConversationBindingManagerV2; final compatibility day: 2026-12-31. */
11
+ /** @deprecated Use createIMessageConversationBindingManagerV2; final compatibility day: 2026-12-31. Removal in the first January 2027 stable release. */
11
12
  function createIMessageConversationBindingManager(params) {
13
+ warnPluginSdkDeprecation({
14
+ family: "conversation-bindings",
15
+ method: "createIMessageConversationBindingManager",
16
+ replacement: "createIMessageConversationBindingManagerV2"
17
+ });
12
18
  return createAccountScopedConversationBindingManager({
13
19
  channel: "imessage",
14
20
  cfg: params.cfg,
@@ -29,8 +35,4 @@ function createIMessageConversationBindingManagerV2(params) {
29
35
  toSessionBindingTargetKind
30
36
  });
31
37
  }
32
- const testing = { resetIMessageConversationBindingsForTests() {
33
- resetAccountScopedConversationBindingsForTests({ stateKey: IMESSAGE_CONVERSATION_BINDINGS_STATE_KEY });
34
- } };
35
- //#endregion
36
- export { createIMessageConversationBindingManagerV2 as n, testing as r, createIMessageConversationBindingManager as t };
38
+ export { createIMessageConversationBindingManagerV2 as n, createIMessageConversationBindingManager as t };
@@ -1,6 +1,6 @@
1
- import { o as resolveIMessageAccount } from "./accounts-DacCvDBt.mjs";
1
+ import { o as resolveIMessageAccount } from "./accounts-C1Ypv3Wn.mjs";
2
2
  import { mergeInboundPathRoots } from "openclaw/plugin-sdk/channel-inbound";
3
- //#region extensions/imessage/src/media-contract.ts
3
+ // extensions/imessage/src/media-contract.ts
4
4
  const DEFAULT_IMESSAGE_ATTACHMENT_ROOTS = ["/Users/*/Library/Messages/Attachments"];
5
5
  function resolveIMessageAttachmentRoots(params) {
6
6
  const account = resolveIMessageAccount(params);
@@ -10,5 +10,4 @@ function resolveIMessageRemoteAttachmentRoots(params) {
10
10
  const account = resolveIMessageAccount(params);
11
11
  return mergeInboundPathRoots(account.config.remoteAttachmentRoots, params.cfg.channels?.imessage?.remoteAttachmentRoots, account.config.attachmentRoots, params.cfg.channels?.imessage?.attachmentRoots, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS);
12
12
  }
13
- //#endregion
14
13
  export { resolveIMessageAttachmentRoots as n, resolveIMessageRemoteAttachmentRoots as r, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS as t };
@@ -1,9 +1,8 @@
1
- import { n as inferIMessageTargetChatType } from "./targets-B4oU7n-v.mjs";
2
- import { c as getCachedIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-DacCvDBt.mjs";
1
+ import { r as inferIMessageTargetChatType } from "./targets-C7CIWJ0k.mjs";
2
+ import { c as getCachedIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-C1Ypv3Wn.mjs";
3
3
  import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
4
4
  import { Type } from "typebox";
5
- import { asDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
6
- //#region extensions/imessage/src/actions-contract.ts
5
+ // extensions/imessage/src/actions-contract.ts
7
6
  const IMESSAGE_ACTIONS = {
8
7
  react: { gate: "reactions" },
9
8
  edit: { gate: "edit" },
@@ -35,8 +34,7 @@ const IMESSAGE_ACTIONS = {
35
34
  "poll-vote": { gate: "polls" }
36
35
  };
37
36
  const IMESSAGE_ACTION_NAMES = Object.keys(IMESSAGE_ACTIONS);
38
- //#endregion
39
- //#region extensions/imessage/src/private-api-status.ts
37
+ // extensions/imessage/src/private-api-status.ts
40
38
  const FOUNDATIONAL_RPC_METHODS = /* @__PURE__ */ new Set([
41
39
  "chats.list",
42
40
  "messages.history",
@@ -58,8 +56,7 @@ function getCachedIMessagePrivateApiStatus(cliPath) {
58
56
  const entry = bridgeStatusCache.get(key);
59
57
  if (!entry) return;
60
58
  if (entry.expiresAt === 0) return entry.status;
61
- const now = asDateTimestampMs(Date.now());
62
- if (now === void 0 || entry.expiresAt <= now) {
59
+ if (entry.expiresAt <= Date.now()) {
63
60
  bridgeStatusCache.delete(key);
64
61
  return;
65
62
  }
@@ -69,14 +66,12 @@ function invalidateCachedIMessagePrivateApiStatus(cliPath) {
69
66
  bridgeStatusCache.delete(normalizeCliPath(cliPath));
70
67
  }
71
68
  function setCachedIMessagePrivateApiStatus(cliPath, status, expiresAt = 0) {
72
- if (expiresAt !== 0 && asDateTimestampMs(expiresAt) === void 0) return;
73
69
  bridgeStatusCache.set(normalizeCliPath(cliPath), {
74
70
  status,
75
71
  expiresAt
76
72
  });
77
73
  }
78
- //#endregion
79
- //#region extensions/imessage/src/message-tool-api.ts
74
+ // extensions/imessage/src/message-tool-api.ts
80
75
  function isGroupTarget(raw, chatType) {
81
76
  if (chatType) return chatType !== "direct";
82
77
  if (!raw) return false;
@@ -129,5 +124,4 @@ function describeIMessageMessageTool({ cfg, accountId, chatType, currentChannelI
129
124
  } } : {}
130
125
  };
131
126
  }
132
- //#endregion
133
127
  export { setCachedIMessagePrivateApiStatus as a, invalidateCachedIMessagePrivateApiStatus as i, getCachedIMessagePrivateApiStatus as n, IMESSAGE_ACTIONS as o, imessageRpcSupportsMethod as r, IMESSAGE_ACTION_NAMES as s, describeIMessageMessageTool as t };
@@ -1,4 +1,3 @@
1
- //#region extensions/imessage/src/outbound-send-deps.ts
1
+ // extensions/imessage/src/outbound-send-deps.ts
2
2
  const IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS = ["sendIMessage"];
3
- //#endregion
4
3
  export { IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS as t };