@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.
- package/dist/.setup/{accounts-DacCvDBt.mjs → accounts-C1Ypv3Wn.mjs} +9 -13
- package/dist/.setup/{actions-762Azi-J.mjs → actions-qOuKy8To.mjs} +364 -116
- package/dist/.setup/{actions.runtime-DHiRiPHe.mjs → actions.runtime-Ccg9CARL.mjs} +12 -61
- package/dist/.setup/{api-Deyo8NDs.mjs → api-BXXuQQCS.mjs} +8 -9
- package/dist/.setup/{api-BFGXDHiC.mjs → api-DTbxSOPc.mjs} +9 -9
- package/dist/.setup/{approval-handler.runtime-fsSBf2jf.mjs → approval-handler.runtime-B6vrFfZx.mjs} +113 -133
- package/dist/.setup/{approval-reactions-CoAkCiwf.mjs → approval-reactions-DBBsqbRC.mjs} +156 -79
- package/dist/.setup/{channel-C61YdcZR.mjs → channel-CLaN4mQn.mjs} +151 -137
- package/dist/.setup/{channel.runtime-B5jle0g3.mjs → channel.runtime-XJGx1MIH.mjs} +236 -425
- package/dist/.setup/chat-context-fTfJVqAi.mjs +77 -0
- package/dist/.setup/chat-lookup-xtPsOBkl.mjs +50 -0
- package/dist/.setup/client-D_BaG8sC.mjs +367 -0
- package/dist/.setup/{config-schema-DXwa_3V5.mjs → config-schema-BjkQV5P5.mjs} +1 -4
- package/dist/.setup/{conversation-bindings-DR-dbHjs.mjs → conversation-bindings-8DjxoIYU.mjs} +10 -8
- package/dist/.setup/{media-contract-BwWs5PM7.mjs → media-contract-BErFBKV9.mjs} +2 -3
- package/dist/.setup/{message-tool-api-B5NfPnFL.mjs → message-tool-api-DtZ1wKbT.mjs} +6 -12
- package/dist/.setup/{outbound-send-deps-B-QEsLSM.mjs → outbound-send-deps-_da8jqeo.mjs} +1 -2
- package/dist/.setup/{remote-file-B94a787O.mjs → remote-file-DpK3GQFD.mjs} +12 -30
- package/dist/.setup/{rolldown-runtime-BBjsoOtd.mjs → rolldown-runtime-782esTHO.mjs} +1 -2
- package/dist/.setup/{sanitize-outbound-BtEY324R.mjs → sanitize-outbound-Dhjhz0a-.mjs} +25 -31
- package/dist/.setup/{send-BvxKNWzF.mjs → send-DhEW0gfe.mjs} +155 -236
- package/dist/.setup/{setup-core-BHyLkAEJ.mjs → setup-core-B1_P_t4T.mjs} +3 -4
- package/dist/.setup/{setup-surface-DPqiLGy0.mjs → setup-surface-CD28mXWK.mjs} +13 -29
- package/dist/.setup/{targets-B4oU7n-v.mjs → targets-C7CIWJ0k.mjs} +15 -9
- package/dist/.source-module-urls/929c518fa2986b0f85f66bceefead22868db0ab452dee914dc6a2bb86b2e60ad.json +1 -1
- package/dist/api.js +9 -9
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +7 -13
- package/dist/index.js +1 -2
- package/dist/media-contract-api.js +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +1 -3
- package/dist/secret-contract-api.js +1 -2
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/setup-entry.js +2 -3
- package/dist/src/chat-db.worker.js +2 -3
- package/node_modules/typebox/build/format/duration.d.mts +2 -2
- package/node_modules/typebox/build/format/duration.mjs +2 -2
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_email.mjs +1 -0
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
- package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
- package/node_modules/typebox/build/format/ipv4.mjs +2 -2
- package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
- package/node_modules/typebox/build/format/ipv6.mjs +1 -1
- package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
- package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
- package/node_modules/typebox/build/schema/build.mjs +1 -0
- package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
- package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
- package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
- package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
- package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
- package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
- package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
- package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
- package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
- package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
- package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
- package/node_modules/typebox/build/system/memory/create.mjs +18 -13
- package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
- package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
- package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
- package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
- package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
- package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
- package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
- package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
- package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
- package/node_modules/typebox/build/system/memory/update.mjs +43 -16
- package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
- package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
- package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
- package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
- package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
- package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
- package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
- package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
- package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
- package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
- package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
- package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +1 -1
- package/node_modules/zod/package.json +1 -1
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
- package/node_modules/zod/src/v4/core/compile.ts +9 -0
- package/node_modules/zod/src/v4/core/schemas.ts +35 -1
- package/node_modules/zod/src/v4/core/util.ts +13 -0
- package/node_modules/zod/src/v4/core/versions.ts +1 -1
- package/node_modules/zod/v4/core/compile.cjs +8 -0
- package/node_modules/zod/v4/core/compile.js +8 -0
- package/node_modules/zod/v4/core/schemas.cjs +30 -0
- package/node_modules/zod/v4/core/schemas.d.cts +3 -1
- package/node_modules/zod/v4/core/schemas.d.ts +3 -1
- package/node_modules/zod/v4/core/schemas.js +30 -0
- package/node_modules/zod/v4/core/util.cjs +15 -0
- package/node_modules/zod/v4/core/util.d.cts +2 -0
- package/node_modules/zod/v4/core/util.d.ts +2 -0
- package/node_modules/zod/v4/core/util.js +14 -0
- package/node_modules/zod/v4/core/versions.cjs +1 -1
- package/node_modules/zod/v4/core/versions.js +1 -1
- package/openclaw.plugin.json +0 -30
- package/package.json +6 -6
- package/dist/.setup/client-CcROCvRq.mjs +0 -746
- package/dist/.setup/question-reactions-BD06B1Lx.mjs +0 -68
- package/dist/.setup/reaction-context-Q26DYzQH.mjs +0 -106
- package/dist/.setup/runtime-Cza4CY5T.mjs +0 -8
- package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
- package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-
|
|
3
|
-
import { a as setCachedIMessagePrivateApiStatus, n as getCachedIMessagePrivateApiStatus, o as IMESSAGE_ACTIONS, r as imessageRpcSupportsMethod, s as IMESSAGE_ACTION_NAMES, t as describeIMessageMessageTool } from "./message-tool-api-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { l as parseIMessageTarget } from "./targets-C7CIWJ0k.mjs";
|
|
2
|
+
import { l as resolveIMessageRemoteHost, n as hasExclusiveIMessageLocalDatabase, o as resolveIMessageAccount, u as expandIMessageUserPath } from "./accounts-C1Ypv3Wn.mjs";
|
|
3
|
+
import { a as setCachedIMessagePrivateApiStatus, n as getCachedIMessagePrivateApiStatus, o as IMESSAGE_ACTIONS, r as imessageRpcSupportsMethod, s as IMESSAGE_ACTION_NAMES, t as describeIMessageMessageTool } from "./message-tool-api-DtZ1wKbT.mjs";
|
|
4
|
+
import { i as resolveIMessageChatMatch, t as chatContextFromIMessageTarget } from "./chat-context-fTfJVqAi.mjs";
|
|
5
|
+
import { n as createIMessageRpcClient } from "./client-D_BaG8sC.mjs";
|
|
6
|
+
import { l as isAutoManagedIMessageCliPath, n as IMESSAGE_UPDATE_COMMAND, t as IMESSAGE_INSTALL_COMMAND } from "./setup-core-B1_P_t4T.mjs";
|
|
7
|
+
import { filterStringEntries, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
8
|
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
|
|
10
11
|
import { createActionGate, jsonResult, readNonNegativeIntegerParam, readPositiveIntegerParam, readReactionParams, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/channel-actions";
|
|
11
12
|
import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
|
|
12
13
|
import { normalizePollInput } from "openclaw/plugin-sdk/poll-runtime";
|
|
13
|
-
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
14
|
+
import { createSubsystemLogger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
14
15
|
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
15
|
-
import {
|
|
16
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
16
18
|
import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
|
|
17
19
|
import { captureRuntimeConfigAsyncReader } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
18
20
|
import { detectBinary } from "openclaw/plugin-sdk/setup";
|
|
19
21
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
20
|
-
|
|
22
|
+
// extensions/imessage/src/message-action-reference.ts
|
|
21
23
|
async function resolveAuthorizedIMessageActionReference(params) {
|
|
22
24
|
const options = {
|
|
23
|
-
requireKnownShortId: true,
|
|
24
25
|
chatContext: params.inputChatContext,
|
|
25
26
|
...params.requireFromMe ? { requireFromMe: true } : {}
|
|
26
27
|
};
|
|
@@ -34,18 +35,14 @@ async function resolveAuthorizedIMessageActionReference(params) {
|
|
|
34
35
|
await authorize(messageId, params.inputChatContext);
|
|
35
36
|
const chatGuid = await params.resolveChatGuid();
|
|
36
37
|
const chatContext = { chatGuid };
|
|
37
|
-
const resolvedMessageId = await params.resolveMessageId(messageId, {
|
|
38
|
-
requireKnownShortId: true,
|
|
39
|
-
chatContext
|
|
40
|
-
});
|
|
38
|
+
const resolvedMessageId = await params.resolveMessageId(messageId, { chatContext });
|
|
41
39
|
await authorize(resolvedMessageId, chatContext);
|
|
42
40
|
return {
|
|
43
41
|
messageId: resolvedMessageId,
|
|
44
42
|
chatGuid
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
|
-
|
|
48
|
-
//#region extensions/imessage/src/message-guid.ts
|
|
45
|
+
// extensions/imessage/src/message-guid.ts
|
|
49
46
|
/** Strip the `p:<n>/` part prefix Messages puts on some GUIDs so keys match. */
|
|
50
47
|
function normalizeIMessageGuid(value) {
|
|
51
48
|
return value.trim().replace(/^p:\d+\//iu, "");
|
|
@@ -55,32 +52,312 @@ function normalizeIMessageMessageId(value) {
|
|
|
55
52
|
const id = value?.trim();
|
|
56
53
|
return id && id !== "ok" && id !== "unknown" ? id : void 0;
|
|
57
54
|
}
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
// extensions/imessage/src/persistence-failure.ts
|
|
56
|
+
function createPersistenceFailureReporter(cache) {
|
|
57
|
+
let reported = false;
|
|
58
|
+
return (scope, err) => {
|
|
59
|
+
if (reported) return;
|
|
60
|
+
reported = true;
|
|
61
|
+
logVerbose(`imessage ${cache}: ${scope} disabled after first failure: ${String(err)}`);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// extensions/imessage/src/runtime.ts
|
|
65
|
+
const { getRuntime: getIMessageRuntime, setRuntime: setIMessageRuntime, tryGetRuntime: getOptionalIMessageRuntime } = createPluginRuntimeStore({
|
|
66
|
+
pluginId: "imessage",
|
|
67
|
+
errorMessage: "iMessage runtime not initialized"
|
|
68
|
+
});
|
|
69
|
+
// extensions/imessage/src/state-contract.ts
|
|
70
|
+
const IMESSAGE_REPLY_CACHE_NAMESPACE = "imessage.reply-cache";
|
|
71
|
+
const IMESSAGE_REPLY_CACHE_MAX_ENTRIES = 2e3;
|
|
72
|
+
const IMESSAGE_REPLY_CACHE_COUNTER_NAMESPACE = "imessage.reply-cache-counter";
|
|
73
|
+
const IMESSAGE_REPLY_CACHE_COUNTER_KEY = "short-id-counter";
|
|
74
|
+
const IMESSAGE_REPLY_CACHE_TTL_MS = 216e5;
|
|
75
|
+
function resolveIMessageReplyCacheEntryKey(messageId) {
|
|
76
|
+
return createHash("sha256").update(messageId, "utf8").digest("hex").slice(0, 32);
|
|
77
|
+
}
|
|
78
|
+
const MAX_FAILURE_RETRY_MAP_SIZE = 512;
|
|
79
|
+
const textEncoder = new TextEncoder();
|
|
80
|
+
const IMESSAGE_CATCHUP_CURSOR_NAMESPACE = "imessage.catchup-cursors";
|
|
81
|
+
function resolveIMessageCatchupCursorKey(accountId) {
|
|
82
|
+
return createHash("sha256").update(accountId, "utf8").digest("hex").slice(0, 32);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Bound the retry map so a pathological storm of unique failing GUIDs
|
|
86
|
+
* cannot grow the cursor value without limit. Keeps the `maxSize` entries
|
|
87
|
+
* with the highest counts (closest to give-up) when over the bound.
|
|
88
|
+
*/
|
|
89
|
+
function capFailureRetriesMap(map, maxSize = MAX_FAILURE_RETRY_MAP_SIZE) {
|
|
90
|
+
const maxBytes = 48e3;
|
|
91
|
+
const entries = Object.entries(map);
|
|
92
|
+
if (entries.length <= maxSize && textEncoder.encode(JSON.stringify(map)).byteLength <= maxBytes) return map;
|
|
93
|
+
entries.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
94
|
+
const capped = {};
|
|
95
|
+
for (const [guid, count] of entries.slice(0, maxSize)) {
|
|
96
|
+
capped[guid] = count;
|
|
97
|
+
if (textEncoder.encode(JSON.stringify(capped)).byteLength > maxBytes) {
|
|
98
|
+
delete capped[guid];
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return capped;
|
|
103
|
+
}
|
|
104
|
+
const IMESSAGE_SENT_ECHOES_TTL_MS = 432e5;
|
|
105
|
+
const IMESSAGE_SENT_ECHOES_NAMESPACE = "imessage.sent-echoes";
|
|
106
|
+
function resolveIMessageSentEchoEntryKey(entry) {
|
|
107
|
+
return createHash("sha256").update(JSON.stringify([
|
|
108
|
+
entry.scope,
|
|
109
|
+
entry.text ?? "",
|
|
110
|
+
resolveIMessageEchoMediaKey(entry.media) ?? "",
|
|
111
|
+
entry.messageId ?? "",
|
|
112
|
+
entry.timestamp
|
|
113
|
+
])).digest("hex").slice(0, 32);
|
|
114
|
+
}
|
|
115
|
+
function resolveIMessageEchoMediaKey(media) {
|
|
116
|
+
const contentType = media?.contentType?.trim().toLowerCase() || void 0;
|
|
117
|
+
const kind = media?.kind && media.kind !== "unknown" ? media.kind : void 0;
|
|
118
|
+
if (kind) return `kind:${kind}`;
|
|
119
|
+
const normalizedContentType = contentType?.split(";", 1)[0]?.trim();
|
|
120
|
+
return normalizedContentType ? `mime:${normalizedContentType}` : void 0;
|
|
121
|
+
}
|
|
122
|
+
// extensions/imessage/src/monitor-reply-cache.ts
|
|
123
|
+
/** Recency window for the "react to the latest message" fallback. */
|
|
124
|
+
const LATEST_FALLBACK_MS = 6e5;
|
|
125
|
+
const reportPersistenceFailure = createPersistenceFailureReporter("reply-cache");
|
|
126
|
+
const imessageReplyCacheByMessageId = /* @__PURE__ */ new Map();
|
|
127
|
+
const imessageShortIdToUuid = /* @__PURE__ */ new Map();
|
|
128
|
+
let imessageShortIdCounter = 0;
|
|
129
|
+
function openReplyCacheStore() {
|
|
130
|
+
return getIMessageRuntime().state.openKeyedStoreV2({
|
|
131
|
+
namespace: IMESSAGE_REPLY_CACHE_NAMESPACE,
|
|
132
|
+
maxEntries: IMESSAGE_REPLY_CACHE_MAX_ENTRIES
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function openReplyCacheCounterStore() {
|
|
136
|
+
return getIMessageRuntime().state.openKeyedStoreV2({
|
|
137
|
+
namespace: IMESSAGE_REPLY_CACHE_COUNTER_NAMESPACE,
|
|
138
|
+
maxEntries: 1
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function remainingTtlMs(timestamp) {
|
|
142
|
+
const remaining = IMESSAGE_REPLY_CACHE_TTL_MS - Math.max(0, Date.now() - timestamp);
|
|
143
|
+
return remaining > 0 ? remaining : void 0;
|
|
144
|
+
}
|
|
145
|
+
let hydrated = false;
|
|
146
|
+
let hydration;
|
|
147
|
+
let persistence = Promise.resolve();
|
|
148
|
+
function hydrateCounter(counter) {
|
|
149
|
+
if (counter && Number.isSafeInteger(counter.counter) && counter.counter > 0) imessageShortIdCounter = Math.max(imessageShortIdCounter, counter.counter);
|
|
150
|
+
}
|
|
151
|
+
function hydrateRows(entries) {
|
|
152
|
+
const cutoff = Date.now() - IMESSAGE_REPLY_CACHE_TTL_MS;
|
|
153
|
+
for (const entry of entries.filter((cached) => cached.timestamp >= cutoff).toSorted((a, b) => a.timestamp - b.timestamp).slice(-2e3)) {
|
|
154
|
+
const numeric = Number.parseInt(entry.shortId, 10);
|
|
155
|
+
if (Number.isFinite(numeric) && numeric > imessageShortIdCounter) imessageShortIdCounter = numeric;
|
|
156
|
+
imessageReplyCacheByMessageId.set(entry.messageId, entry);
|
|
157
|
+
imessageShortIdToUuid.set(entry.shortId, entry.messageId);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function hydrateFromStoreOnce() {
|
|
161
|
+
if (hydrated) return;
|
|
162
|
+
hydration ??= (async () => {
|
|
163
|
+
try {
|
|
164
|
+
hydrateCounter(await openReplyCacheCounterStore().lookup(IMESSAGE_REPLY_CACHE_COUNTER_KEY));
|
|
165
|
+
hydrateRows((await openReplyCacheStore().entries()).map(({ value }) => value));
|
|
166
|
+
} catch (err) {
|
|
167
|
+
reportPersistenceFailure("read", err);
|
|
168
|
+
} finally {
|
|
169
|
+
hydrated = true;
|
|
170
|
+
}
|
|
171
|
+
})();
|
|
172
|
+
await hydration;
|
|
173
|
+
}
|
|
174
|
+
async function persistReplyCacheEntry(entry) {
|
|
175
|
+
const ttlMs = remainingTtlMs(entry.timestamp);
|
|
176
|
+
if (!ttlMs) return;
|
|
177
|
+
try {
|
|
178
|
+
await openReplyCacheStore().register(resolveIMessageReplyCacheEntryKey(entry.messageId), entry, { ttlMs });
|
|
179
|
+
} catch (err) {
|
|
180
|
+
reportPersistenceFailure("write", err);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async function deleteReplyCacheEntry(messageId) {
|
|
184
|
+
try {
|
|
185
|
+
await openReplyCacheStore().delete(resolveIMessageReplyCacheEntryKey(messageId));
|
|
186
|
+
} catch (err) {
|
|
187
|
+
reportPersistenceFailure("delete", err);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function persistReplyCacheCounter(counter) {
|
|
191
|
+
try {
|
|
192
|
+
await openReplyCacheCounterStore().register(IMESSAGE_REPLY_CACHE_COUNTER_KEY, { counter });
|
|
193
|
+
} catch (err) {
|
|
194
|
+
reportPersistenceFailure("counter", err);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function buildReplyCacheEntry(entry, messageId, shortId) {
|
|
198
|
+
return {
|
|
199
|
+
accountId: entry.accountId,
|
|
200
|
+
messageId,
|
|
201
|
+
shortId,
|
|
202
|
+
timestamp: entry.timestamp,
|
|
203
|
+
...entry.chatGuid !== void 0 ? { chatGuid: entry.chatGuid } : {},
|
|
204
|
+
...entry.chatIdentifier !== void 0 ? { chatIdentifier: entry.chatIdentifier } : {},
|
|
205
|
+
...entry.chatId !== void 0 ? { chatId: entry.chatId } : {},
|
|
206
|
+
...entry.isFromMe !== void 0 ? { isFromMe: entry.isFromMe } : {}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function rememberIMessageReplyCache(entry) {
|
|
210
|
+
await hydrateFromStoreOnce();
|
|
211
|
+
const messageId = entry.messageId.trim();
|
|
212
|
+
if (!messageId) return {
|
|
213
|
+
...entry,
|
|
214
|
+
shortId: ""
|
|
215
|
+
};
|
|
216
|
+
let shortId = imessageReplyCacheByMessageId.get(messageId)?.shortId;
|
|
217
|
+
const isNewMessage = !shortId;
|
|
218
|
+
if (!shortId) {
|
|
219
|
+
shortId = String(++imessageShortIdCounter);
|
|
220
|
+
imessageShortIdToUuid.set(shortId, messageId);
|
|
221
|
+
}
|
|
222
|
+
const fullEntry = buildReplyCacheEntry(entry, messageId, shortId);
|
|
223
|
+
imessageReplyCacheByMessageId.delete(messageId);
|
|
224
|
+
imessageReplyCacheByMessageId.set(messageId, fullEntry);
|
|
225
|
+
const cutoff = Date.now() - IMESSAGE_REPLY_CACHE_TTL_MS;
|
|
226
|
+
const deletedMessageIds = [];
|
|
227
|
+
const pruneUntil = (retain) => {
|
|
228
|
+
for (const [key, cached] of imessageReplyCacheByMessageId) {
|
|
229
|
+
if (retain(key, cached)) break;
|
|
230
|
+
imessageReplyCacheByMessageId.delete(key);
|
|
231
|
+
deletedMessageIds.push(key);
|
|
232
|
+
if (cached.shortId) imessageShortIdToUuid.delete(cached.shortId);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
pruneUntil((_key, cached) => cached.timestamp >= cutoff);
|
|
236
|
+
pruneUntil((key) => !key || imessageReplyCacheByMessageId.size <= 2e3);
|
|
237
|
+
const counter = imessageShortIdCounter;
|
|
238
|
+
persistence = persistence.then(async () => {
|
|
239
|
+
if (isNewMessage) await persistReplyCacheCounter(counter);
|
|
240
|
+
for (const messageIdToDelete of deletedMessageIds) await deleteReplyCacheEntry(messageIdToDelete);
|
|
241
|
+
await persistReplyCacheEntry(fullEntry);
|
|
242
|
+
});
|
|
243
|
+
await persistence;
|
|
244
|
+
return fullEntry;
|
|
245
|
+
}
|
|
246
|
+
function hasChatScope(ctx) {
|
|
247
|
+
if (!ctx) return false;
|
|
248
|
+
return Boolean(normalizeOptionalString(ctx.chatGuid) || normalizeOptionalString(ctx.chatIdentifier) || typeof ctx.chatId === "number");
|
|
249
|
+
}
|
|
250
|
+
function describeChatForError(values) {
|
|
251
|
+
const parts = [];
|
|
252
|
+
if (normalizeOptionalString(values.chatGuid)) parts.push("chatGuid=<redacted>");
|
|
253
|
+
if (normalizeOptionalString(values.chatIdentifier)) parts.push("chatIdentifier=<redacted>");
|
|
254
|
+
if (typeof values.chatId === "number") parts.push("chatId=<redacted>");
|
|
255
|
+
return parts.length === 0 ? "<unknown chat>" : parts.join(", ");
|
|
256
|
+
}
|
|
257
|
+
function describeMessageIdForError(inputId, inputKind) {
|
|
258
|
+
if (inputKind === "short") return `<short:${inputId.length}-digit>`;
|
|
259
|
+
return `<uuid:${inputId.slice(0, 8)}...>`;
|
|
260
|
+
}
|
|
261
|
+
function buildCrossChatError(inputId, inputKind, cached, ctx) {
|
|
262
|
+
const remediation = inputKind === "short" ? "Use a message ID from the current chat target; MessageSidFull from another chat is rejected." : "Retry with the correct chat target.";
|
|
263
|
+
return /* @__PURE__ */ new Error(`iMessage message id ${describeMessageIdForError(inputId, inputKind)} belongs to a different chat (${describeChatForError(cached)}) than the current call target (${describeChatForError(ctx)}). ${remediation}`);
|
|
264
|
+
}
|
|
265
|
+
async function resolveIMessageMessageId(shortOrUuid, opts) {
|
|
266
|
+
const trimmed = shortOrUuid.trim();
|
|
267
|
+
if (!trimmed) return trimmed;
|
|
268
|
+
await hydrateFromStoreOnce();
|
|
269
|
+
const inputKind = /^\d+$/.test(trimmed) ? "short" : "uuid";
|
|
270
|
+
const messageId = inputKind === "short" ? imessageShortIdToUuid.get(trimmed) : trimmed;
|
|
271
|
+
if (!messageId) {
|
|
272
|
+
if (!hasChatScope(opts?.chatContext)) throw new Error(`iMessage short message id ${describeMessageIdForError(trimmed, "short")} requires a chat scope (chatGuid / chatIdentifier / chatId or a target).`);
|
|
273
|
+
throw new Error(`iMessage short message id ${describeMessageIdForError(trimmed, "short")} is no longer available. Use MessageSidFull.`);
|
|
274
|
+
}
|
|
275
|
+
const cached = imessageReplyCacheByMessageId.get(messageId);
|
|
276
|
+
if (cached && opts?.chatContext && (inputKind === "uuid" || hasChatScope(opts.chatContext)) && resolveIMessageChatMatch(cached, opts.chatContext) === "mismatch") throw buildCrossChatError(trimmed, inputKind, cached, opts.chatContext);
|
|
277
|
+
if (opts?.requireFromMe && cached?.isFromMe !== true) throw buildFromMeError(trimmed, inputKind);
|
|
278
|
+
return messageId;
|
|
279
|
+
}
|
|
280
|
+
async function isKnownFromMeIMessageMessageId(messageId, ctx) {
|
|
281
|
+
const trimmed = normalizeOptionalString(messageId);
|
|
282
|
+
if (!trimmed || !ctx.accountId || !hasChatScope(ctx)) return false;
|
|
283
|
+
await hydrateFromStoreOnce();
|
|
284
|
+
const cached = imessageReplyCacheByMessageId.get(trimmed);
|
|
285
|
+
if (!cached || cached.isFromMe !== true) return false;
|
|
286
|
+
return resolveCachedResourceBinding(trimmed, {
|
|
287
|
+
...ctx,
|
|
288
|
+
accountId: ctx.accountId
|
|
289
|
+
}) === "match";
|
|
290
|
+
}
|
|
291
|
+
async function isKnownFromMeIMessageTarget(params) {
|
|
292
|
+
const { accountId, chatId, chatGuid, chatIdentifier } = params;
|
|
293
|
+
const ctx = {
|
|
294
|
+
accountId,
|
|
295
|
+
chatId,
|
|
296
|
+
chatGuid,
|
|
297
|
+
chatIdentifier
|
|
298
|
+
};
|
|
299
|
+
for (const messageId of params.messageIds) if (await isKnownFromMeIMessageMessageId(messageId, ctx)) return true;
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
function buildFromMeError(inputId, inputKind) {
|
|
303
|
+
return /* @__PURE__ */ new Error(`iMessage message id ${describeMessageIdForError(inputId, inputKind)} is not one this agent sent. edit and unsend can only target messages the gateway delivered itself; messages received from other participants cannot be modified.`);
|
|
304
|
+
}
|
|
305
|
+
/** Latest recent entry with a positive same-account conversation match; never guess a chat. */
|
|
306
|
+
function findLatestIMessageEntryForChat(ctx) {
|
|
307
|
+
if (!hasChatScope(ctx) || !ctx.accountId) return;
|
|
308
|
+
const cutoff = Date.now() - LATEST_FALLBACK_MS;
|
|
309
|
+
let best;
|
|
310
|
+
for (const entry of imessageReplyCacheByMessageId.values()) {
|
|
311
|
+
if (entry.accountId !== ctx.accountId) continue;
|
|
312
|
+
if (entry.timestamp < cutoff) continue;
|
|
313
|
+
if (resolveIMessageChatMatch(entry, ctx) !== "match") continue;
|
|
314
|
+
if (!best || entry.timestamp > best.timestamp) best = entry;
|
|
315
|
+
}
|
|
316
|
+
return best;
|
|
317
|
+
}
|
|
318
|
+
async function resolveIMessageCachedResourceBinding(messageId, ctx) {
|
|
319
|
+
await hydrateFromStoreOnce();
|
|
320
|
+
return resolveCachedResourceBinding(messageId, ctx);
|
|
321
|
+
}
|
|
322
|
+
function resolveCachedResourceBinding(messageId, ctx) {
|
|
323
|
+
const entry = imessageReplyCacheByMessageId.get(messageId.trim());
|
|
324
|
+
if (!entry) return "unknown";
|
|
325
|
+
if (Date.now() - entry.timestamp > 216e5) return "unknown";
|
|
326
|
+
if (entry.accountId !== ctx.accountId) return "mismatch";
|
|
327
|
+
return resolveIMessageChatMatch(entry, ctx);
|
|
328
|
+
}
|
|
329
|
+
async function isIMessageCurrentMessageInChatAsync(params) {
|
|
330
|
+
await hydrateFromStoreOnce();
|
|
331
|
+
return isCurrentMessageInChat(params);
|
|
332
|
+
}
|
|
333
|
+
function isCurrentMessageInChat(params) {
|
|
334
|
+
if (!params.accountId || !hasChatScope(params.chatContext)) return false;
|
|
335
|
+
const currentMessageId = normalizeOptionalString(String(params.currentMessageId));
|
|
336
|
+
if (!currentMessageId) return false;
|
|
337
|
+
const fullMessageId = /^\d+$/.test(currentMessageId) ? imessageShortIdToUuid.get(currentMessageId) : currentMessageId;
|
|
338
|
+
if (!fullMessageId) return false;
|
|
339
|
+
return resolveCachedResourceBinding(fullMessageId, {
|
|
340
|
+
...params.chatContext,
|
|
341
|
+
accountId: params.accountId
|
|
342
|
+
}) === "match";
|
|
343
|
+
}
|
|
344
|
+
// extensions/imessage/src/probe.ts
|
|
60
345
|
const RPC_SUPPORT_CACHE_TTL_MS = 3e5;
|
|
61
346
|
const PRIVATE_API_NEGATIVE_TTL_MS = 1e4;
|
|
62
347
|
const rpcSupportCache = /* @__PURE__ */ new Map();
|
|
63
348
|
function cacheIMessagePrivateApiStatus(cliPath, status) {
|
|
64
|
-
|
|
65
|
-
setCachedIMessagePrivateApiStatus(cliPath, status, 0);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const expiresAt = resolveExpiresAtMsFromDurationMs(PRIVATE_API_NEGATIVE_TTL_MS);
|
|
69
|
-
if (expiresAt !== void 0) setCachedIMessagePrivateApiStatus(cliPath, status, expiresAt);
|
|
349
|
+
setCachedIMessagePrivateApiStatus(cliPath, status, status.available ? 0 : Date.now() + PRIVATE_API_NEGATIVE_TTL_MS);
|
|
70
350
|
}
|
|
71
351
|
function setCachedRpcSupport(cliPath, result) {
|
|
72
|
-
const expiresAt = resolveExpiresAtMsFromDurationMs(RPC_SUPPORT_CACHE_TTL_MS);
|
|
73
|
-
if (expiresAt === void 0) return;
|
|
74
352
|
rpcSupportCache.set(cliPath, {
|
|
75
353
|
result,
|
|
76
|
-
expiresAt
|
|
354
|
+
expiresAt: Date.now() + RPC_SUPPORT_CACHE_TTL_MS
|
|
77
355
|
});
|
|
78
356
|
}
|
|
79
357
|
async function probeRpcSupport(cliPath, timeoutMs) {
|
|
80
358
|
const cached = rpcSupportCache.get(cliPath);
|
|
81
359
|
if (cached) {
|
|
82
|
-
|
|
83
|
-
if (now !== void 0 && cached.expiresAt > now) return cached.result;
|
|
360
|
+
if (cached.expiresAt > Date.now()) return cached.result;
|
|
84
361
|
rpcSupportCache.delete(cliPath);
|
|
85
362
|
}
|
|
86
363
|
try {
|
|
@@ -136,6 +413,21 @@ async function probeIMessagePrivateApi(cliPath, timeoutMs, options = {}) {
|
|
|
136
413
|
const cached = getCachedIMessagePrivateApiStatus(key);
|
|
137
414
|
if (cached) return cached;
|
|
138
415
|
}
|
|
416
|
+
const unavailable = (error) => {
|
|
417
|
+
const status = {
|
|
418
|
+
available: false,
|
|
419
|
+
v2Ready: false,
|
|
420
|
+
selectors: {},
|
|
421
|
+
rpcMethods: [],
|
|
422
|
+
cliCapabilities: {
|
|
423
|
+
sendRichSupportsAttachment: false,
|
|
424
|
+
pollSendSupportsNoComment: false
|
|
425
|
+
},
|
|
426
|
+
error
|
|
427
|
+
};
|
|
428
|
+
cacheIMessagePrivateApiStatus(key, status);
|
|
429
|
+
return status;
|
|
430
|
+
};
|
|
139
431
|
try {
|
|
140
432
|
const result = await runCommandWithTimeout([
|
|
141
433
|
expandIMessageUserPath(key),
|
|
@@ -144,21 +436,7 @@ async function probeIMessagePrivateApi(cliPath, timeoutMs, options = {}) {
|
|
|
144
436
|
], { timeoutMs });
|
|
145
437
|
const combined = `${result.stdout}\n${result.stderr}`.trim();
|
|
146
438
|
const normalized = normalizeLowercaseStringOrEmpty(combined);
|
|
147
|
-
if (result.code !== 0 && normalized.includes("unknown subcommand") && normalized.includes("status")) {
|
|
148
|
-
const status = {
|
|
149
|
-
available: false,
|
|
150
|
-
v2Ready: false,
|
|
151
|
-
selectors: {},
|
|
152
|
-
rpcMethods: [],
|
|
153
|
-
cliCapabilities: {
|
|
154
|
-
sendRichSupportsAttachment: false,
|
|
155
|
-
pollSendSupportsNoComment: false
|
|
156
|
-
},
|
|
157
|
-
error: `imsg CLI does not support the "status" subcommand. Update imsg on the Messages Mac: ${IMESSAGE_UPDATE_COMMAND}`
|
|
158
|
-
};
|
|
159
|
-
cacheIMessagePrivateApiStatus(key, status);
|
|
160
|
-
return status;
|
|
161
|
-
}
|
|
439
|
+
if (result.code !== 0 && normalized.includes("unknown subcommand") && normalized.includes("status")) return unavailable(`imsg CLI does not support the "status" subcommand. Update imsg on the Messages Mac: ${IMESSAGE_UPDATE_COMMAND}`);
|
|
162
440
|
const lines = normalizeStringEntries(result.stdout.split(/\r?\n/));
|
|
163
441
|
let payload = null;
|
|
164
442
|
for (const line of lines.toReversed()) try {
|
|
@@ -195,19 +473,7 @@ async function probeIMessagePrivateApi(cliPath, timeoutMs, options = {}) {
|
|
|
195
473
|
cacheIMessagePrivateApiStatus(key, status);
|
|
196
474
|
return status;
|
|
197
475
|
} catch (err) {
|
|
198
|
-
|
|
199
|
-
available: false,
|
|
200
|
-
v2Ready: false,
|
|
201
|
-
selectors: {},
|
|
202
|
-
rpcMethods: [],
|
|
203
|
-
cliCapabilities: {
|
|
204
|
-
sendRichSupportsAttachment: false,
|
|
205
|
-
pollSendSupportsNoComment: false
|
|
206
|
-
},
|
|
207
|
-
error: String(err)
|
|
208
|
-
};
|
|
209
|
-
cacheIMessagePrivateApiStatus(key, status);
|
|
210
|
-
return status;
|
|
476
|
+
return unavailable(String(err));
|
|
211
477
|
}
|
|
212
478
|
}
|
|
213
479
|
async function probeIMessage(timeoutMs, opts = {}) {
|
|
@@ -258,9 +524,8 @@ async function probeIMessage(timeoutMs, opts = {}) {
|
|
|
258
524
|
await client.stop();
|
|
259
525
|
}
|
|
260
526
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-DHiRiPHe.mjs"), "imessageActionsRuntime");
|
|
527
|
+
// extensions/imessage/src/actions.ts
|
|
528
|
+
const loadIMessageActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-Ccg9CARL.mjs"), "imessageActionsRuntime");
|
|
264
529
|
const log = createSubsystemLogger("channels/imessage");
|
|
265
530
|
const providerId = "imessage";
|
|
266
531
|
const SUPPORTED_ACTIONS = /* @__PURE__ */ new Set([...IMESSAGE_ACTION_NAMES, "upload-file"]);
|
|
@@ -332,32 +597,9 @@ function readMessageIdWithChatFallback(params, chatContext) {
|
|
|
332
597
|
if (latest?.messageId) return latest.messageId;
|
|
333
598
|
return readStringParam(params, "messageId", { required: true });
|
|
334
599
|
}
|
|
335
|
-
async function resolveChatGuid(params) {
|
|
336
|
-
const target = resolveIMessageActionTarget(params);
|
|
337
|
-
if (!target) throw new Error(`iMessage ${params.action} requires chatGuid, chatId, chatIdentifier, or a chat target.`);
|
|
338
|
-
if (target.kind === "chat_guid") return target.chatGuid;
|
|
339
|
-
const synthesizedIdentifier = target.kind === "handle" ? `${target.service === "sms" ? "SMS" : "iMessage"};-;${target.to}` : "";
|
|
340
|
-
const lookupTarget = target.kind === "handle" ? {
|
|
341
|
-
kind: "chat_identifier",
|
|
342
|
-
chatIdentifier: synthesizedIdentifier
|
|
343
|
-
} : target;
|
|
344
|
-
const resolved = await params.runtime.resolveChatGuidForTarget({
|
|
345
|
-
target: lookupTarget,
|
|
346
|
-
options: params.options,
|
|
347
|
-
conversationReadOrigin: params.conversationReadOrigin
|
|
348
|
-
});
|
|
349
|
-
if (resolved) return resolved;
|
|
350
|
-
if (target.kind !== "handle") throw new Error(`iMessage ${params.action} failed: chatGuid not found for ${formatUnresolvedTarget(target)}.`);
|
|
351
|
-
if (params.action === "react" || params.action === "edit" || params.action === "unsend") throw new Error(`iMessage ${params.action} requires a known chat. No registered chat for the supplied target; send a message first or pass an explicit chatGuid.`);
|
|
352
|
-
return synthesizedIdentifier;
|
|
353
|
-
}
|
|
354
600
|
function formatUnresolvedTarget(target) {
|
|
355
601
|
return target.kind === "chat_id" ? "chat_id:<redacted>" : "chat_identifier:<redacted>";
|
|
356
602
|
}
|
|
357
|
-
function buildChatContextFromActionParams(params) {
|
|
358
|
-
const target = resolveIMessageActionTarget(params);
|
|
359
|
-
return target ? chatContextFromIMessageTarget(target, params.service) : {};
|
|
360
|
-
}
|
|
361
603
|
function mapTapbackReaction(emoji) {
|
|
362
604
|
const value = normalizeOptionalLowercaseString(emoji)?.replace(/\ufe0f/g, "");
|
|
363
605
|
return value ? [
|
|
@@ -402,7 +644,7 @@ function decodeBase64Buffer(params, action) {
|
|
|
402
644
|
if (!base64Buffer) throw new Error(`iMessage ${action} requires buffer (base64) parameter.`);
|
|
403
645
|
const canonical = canonicalizeBase64(base64Buffer.replaceAll("-", "+").replaceAll("_", "/"));
|
|
404
646
|
if (!canonical) throw new Error(`iMessage ${action} buffer must be valid base64.`);
|
|
405
|
-
return
|
|
647
|
+
return Buffer.from(canonical, "base64");
|
|
406
648
|
}
|
|
407
649
|
const REPLY_ATTACHMENT_PATH_PARAM_NAMES = [
|
|
408
650
|
"filePath",
|
|
@@ -411,21 +653,6 @@ const REPLY_ATTACHMENT_PATH_PARAM_NAMES = [
|
|
|
411
653
|
"mediaUrl",
|
|
412
654
|
"fileUrl"
|
|
413
655
|
];
|
|
414
|
-
function extractReplyAttachment(params) {
|
|
415
|
-
if (readStringParam(params, "buffer")) {
|
|
416
|
-
const filename = readStringParam(params, "filename") ?? "attachment.bin";
|
|
417
|
-
return { spec: {
|
|
418
|
-
kind: "buffer",
|
|
419
|
-
buffer: decodeBase64Buffer(params, "reply attachment"),
|
|
420
|
-
filename
|
|
421
|
-
} };
|
|
422
|
-
}
|
|
423
|
-
for (const name of REPLY_ATTACHMENT_PATH_PARAM_NAMES) if (readStringParam(params, name)) return {
|
|
424
|
-
spec: null,
|
|
425
|
-
bypassParam: name
|
|
426
|
-
};
|
|
427
|
-
return null;
|
|
428
|
-
}
|
|
429
656
|
const EFFECT_ALIASES = {
|
|
430
657
|
slam: "com.apple.MobileSMS.expressivesend.impact",
|
|
431
658
|
impact: "com.apple.MobileSMS.expressivesend.impact",
|
|
@@ -512,20 +739,35 @@ const imessageMessageActions = {
|
|
|
512
739
|
timeoutMs: account.config.probeTimeoutMs
|
|
513
740
|
};
|
|
514
741
|
const attestedConversationReadOrigin = conversationReadOrigin ?? "delegated";
|
|
515
|
-
const chatGuid = async () =>
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
742
|
+
const chatGuid = async () => {
|
|
743
|
+
const target = resolveIMessageActionTarget({
|
|
744
|
+
actionParams: params,
|
|
745
|
+
currentChannelId: toolContext?.currentChannelId
|
|
746
|
+
});
|
|
747
|
+
if (!target) throw new Error(`iMessage ${action} requires chatGuid, chatId, chatIdentifier, or a chat target.`);
|
|
748
|
+
if (target.kind === "chat_guid") return target.chatGuid;
|
|
749
|
+
const synthesizedIdentifier = target.kind === "handle" ? `${target.service === "sms" ? "SMS" : "iMessage"};-;${target.to}` : "";
|
|
750
|
+
const lookupTarget = target.kind === "handle" ? {
|
|
751
|
+
kind: "chat_identifier",
|
|
752
|
+
chatIdentifier: synthesizedIdentifier
|
|
753
|
+
} : target;
|
|
754
|
+
const resolved = await runtime.resolveChatGuidForTarget({
|
|
755
|
+
target: lookupTarget,
|
|
756
|
+
options: opts,
|
|
757
|
+
conversationReadOrigin: attestedConversationReadOrigin
|
|
758
|
+
});
|
|
759
|
+
if (resolved) return resolved;
|
|
760
|
+
if (target.kind !== "handle") throw new Error(`iMessage ${action} failed: chatGuid not found for ${formatUnresolvedTarget(target)}.`);
|
|
761
|
+
if (action === "react" || action === "edit" || action === "unsend") throw new Error(`iMessage ${action} requires a known chat. No registered chat for the supplied target; send a message first or pass an explicit chatGuid.`);
|
|
762
|
+
return synthesizedIdentifier;
|
|
763
|
+
};
|
|
523
764
|
const messageReference = async (input) => {
|
|
524
|
-
const
|
|
765
|
+
const service = account.config.service;
|
|
766
|
+
const target = resolveIMessageActionTarget({
|
|
525
767
|
actionParams: params,
|
|
526
|
-
currentChannelId: toolContext?.currentChannelId
|
|
527
|
-
service: account.config.service
|
|
768
|
+
currentChannelId: toolContext?.currentChannelId
|
|
528
769
|
});
|
|
770
|
+
const inputChatContext = target ? chatContextFromIMessageTarget(target, service) : {};
|
|
529
771
|
return await resolveAuthorizedIMessageActionReference({
|
|
530
772
|
messageId: input?.messageId,
|
|
531
773
|
inputChatContext,
|
|
@@ -583,7 +825,7 @@ const imessageMessageActions = {
|
|
|
583
825
|
if (!remove && (isEmpty || !reaction)) throw new Error("iMessage react supports love, like, dislike, laugh, emphasize, and question tapbacks.");
|
|
584
826
|
const partIndex = readNonNegativeIntegerParam(params, "partIndex");
|
|
585
827
|
const reference = await messageReference();
|
|
586
|
-
const reactionsToSend = remove && !reaction ?
|
|
828
|
+
const reactionsToSend = remove && !reaction ? TAPBACK_KINDS : reaction ? [reaction] : [];
|
|
587
829
|
for (const kind of reactionsToSend) await runtime.sendReaction({
|
|
588
830
|
chatGuid: reference.chatGuid,
|
|
589
831
|
messageId: reference.messageId,
|
|
@@ -634,9 +876,16 @@ const imessageMessageActions = {
|
|
|
634
876
|
const text = readMessageText(params);
|
|
635
877
|
if (!text) throw new Error("iMessage reply requires text or message.");
|
|
636
878
|
const reference = await messageReference();
|
|
637
|
-
|
|
879
|
+
let attachment;
|
|
880
|
+
if (readStringParam(params, "buffer")) {
|
|
881
|
+
const filename = readStringParam(params, "filename") ?? "attachment.bin";
|
|
882
|
+
attachment = {
|
|
883
|
+
kind: "buffer",
|
|
884
|
+
buffer: decodeBase64Buffer(params, "reply attachment"),
|
|
885
|
+
filename
|
|
886
|
+
};
|
|
887
|
+
} else for (const name of REPLY_ATTACHMENT_PATH_PARAM_NAMES) if (readStringParam(params, name)) throw new Error(`iMessage reply rejected \`${name}\` because it did not pass through the outbound media resolver. Pass a base64 \`buffer\` + \`filename\` directly, or invoke message(action: "reply") through the runner so the resolver can validate the path against mediaLocalRoots/sandbox/size before sending.`);
|
|
638
888
|
if (attachment) {
|
|
639
|
-
if (attachment.spec === null) throw new Error(`iMessage reply rejected \`${attachment.bypassParam}\` because it did not pass through the outbound media resolver. Pass a base64 \`buffer\` + \`filename\` directly, or invoke message(action: "reply") through the runner so the resolver can validate the path against mediaLocalRoots/sandbox/size before sending.`);
|
|
640
889
|
if (!opts.remoteHost && privateApiStatus?.cliCapabilities?.sendRichSupportsAttachment !== true) throw new Error("iMessage reply with an attachment needs an imsg build that exposes `send-rich --file` (openclaw/imsg#114). Upgrade imsg, or use action 'upload-file' (with filePath/filename) or action 'send' (with media) to deliver the file plus a separate 'reply' for any text.");
|
|
641
890
|
}
|
|
642
891
|
const partIndex = readNonNegativeIntegerParam(params, "partIndex");
|
|
@@ -645,7 +894,7 @@ const imessageMessageActions = {
|
|
|
645
894
|
text,
|
|
646
895
|
replyToMessageId: reference.messageId,
|
|
647
896
|
partIndex,
|
|
648
|
-
attachment
|
|
897
|
+
attachment,
|
|
649
898
|
options: opts
|
|
650
899
|
}), reference.chatGuid, { repliedTo: reference.messageId });
|
|
651
900
|
}
|
|
@@ -776,5 +1025,4 @@ const imessageMessageActions = {
|
|
|
776
1025
|
throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
|
|
777
1026
|
}
|
|
778
1027
|
};
|
|
779
|
-
|
|
780
|
-
export { normalizeIMessageMessageId as a, normalizeIMessageGuid as i, probeIMessage as n, probeIMessagePrivateApi as r, imessageMessageActions as t };
|
|
1028
|
+
export { setIMessageRuntime as _, rememberIMessageReplyCache as a, normalizeIMessageMessageId as b, IMESSAGE_CATCHUP_CURSOR_NAMESPACE as c, capFailureRetriesMap as d, resolveIMessageCatchupCursorKey as f, getOptionalIMessageRuntime as g, getIMessageRuntime as h, isKnownFromMeIMessageTarget as i, IMESSAGE_SENT_ECHOES_NAMESPACE as l, resolveIMessageSentEchoEntryKey as m, probeIMessage as n, resolveIMessageCachedResourceBinding as o, resolveIMessageEchoMediaKey as p, probeIMessagePrivateApi as r, resolveIMessageMessageId as s, imessageMessageActions as t, IMESSAGE_SENT_ECHOES_TTL_MS as u, createPersistenceFailureReporter as v, normalizeIMessageGuid as y };
|