@openclaw/imessage 2026.8.1-beta.2 → 2026.8.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/{accounts-D00Njxg2.js → accounts-CCirBEIm.js} +4 -5
- package/dist/{actions.runtime-DTFKDN5p.js → actions.runtime-CAl3WcqD.js} +2 -3
- package/dist/api.js +6 -5
- package/dist/{approval-handler.runtime-BtLs4gho.js → approval-handler.runtime-UBd1j2Sg.js} +15 -9
- package/dist/approval-reactions-LL5yn1Rc.js +562 -0
- package/dist/{channel-lppmI51h.js → channel-DNI9DKGN.js} +26 -21
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-5wpCKQb7.js → channel.runtime-HSkrmWfW.js} +58 -11
- package/dist/{config-schema-DV0KP5nC.js → config-schema-DuGbA8Kp.js} +8 -7
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +8 -281
- package/dist/{group-policy-DF9xSdik.js → group-policy-Dvc-BcWo.js} +19 -651
- package/dist/{media-contract-BEgdvYhW.js → media-contract-D-FhGE98.js} +1 -1
- package/dist/media-contract-api.js +1 -1
- package/dist/{message-tool-api-CPDfJJoE.js → message-tool-api-CvIgJpOo.js} +7 -4
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-DnxJ8pW9.js → monitor-BywJn1QW.js} +343 -111
- package/dist/{question-reactions-DVe50UhB.js → question-reactions-viP7ZcyG.js} +2 -1
- package/dist/reaction-context-BAYI7pz0.js +105 -0
- package/dist/{remote-file-DLwO9ved.js → remote-file-6mCj2ZBy.js} +7 -3
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/runtime-Cza4CY5T.js +8 -0
- package/dist/runtime-api.js +10 -9
- package/dist/{sanitize-outbound-CoTZLXMw.js → sanitize-outbound-Du-r1lNQ.js} +345 -58
- package/dist/{send-BUXW76tw.js → send-mgWPKqSV.js} +147 -26
- package/dist/state-contract-4TK_cDDb.js +56 -0
- package/dist/state-migrations-SFdKp3GQ.js +277 -0
- package/node_modules/typebox/build/format/date.d.mts +1 -1
- package/node_modules/typebox/build/format/date.mjs +1 -1
- package/node_modules/typebox/build/format/date_time.d.mts +2 -2
- package/node_modules/typebox/build/format/date_time.mjs +3 -3
- package/node_modules/typebox/build/format/email.d.mts +1 -1
- package/node_modules/typebox/build/format/email.mjs +2 -2
- package/node_modules/typebox/build/format/hostname.mjs +2 -10
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_email.mjs +3 -3
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
- package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
- package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
- package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
- package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
- package/node_modules/typebox/build/format/idna/index.mjs +2 -0
- package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
- package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
- package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
- package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
- package/node_modules/typebox/build/format/ipv4.mjs +2 -32
- package/node_modules/typebox/build/format/ipv6.mjs +2 -61
- package/node_modules/typebox/build/format/iri.d.mts +2 -2
- package/node_modules/typebox/build/format/iri.mjs +26 -8
- package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
- package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
- package/node_modules/typebox/build/format/regex.d.mts +1 -2
- package/node_modules/typebox/build/format/regex.mjs +2 -6
- package/node_modules/typebox/build/format/time.d.mts +2 -2
- package/node_modules/typebox/build/format/time.mjs +19 -14
- package/node_modules/typebox/build/format/uri.d.mts +1 -1
- package/node_modules/typebox/build/format/uri.mjs +3 -130
- package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
- package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
- package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
- package/node_modules/typebox/build/format/uri_template.mjs +4 -5
- package/node_modules/typebox/build/format/url.d.mts +3 -3
- package/node_modules/typebox/build/format/url.mjs +4 -5
- package/node_modules/typebox/build/guard/emit.d.mts +3 -1
- package/node_modules/typebox/build/guard/emit.mjs +12 -5
- package/node_modules/typebox/build/guard/guard.d.mts +8 -2
- package/node_modules/typebox/build/guard/guard.mjs +25 -4
- package/node_modules/typebox/build/guard/string.d.mts +2 -2
- package/node_modules/typebox/build/guard/string.mjs +7 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
- package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
- package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
- package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
- package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
- package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
- package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
- package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
- package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
- package/node_modules/typebox/build/schema/types/index.mjs +0 -2
- package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
- package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
- package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
- package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
- package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
- package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
- package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
- package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
- package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
- package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
- package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
- package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
- package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
- package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
- package/node_modules/typebox/build/type/script/parser.mjs +27 -23
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
- package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
- package/node_modules/typebox/package.json +27 -27
- package/node_modules/typebox/readme.md +79 -82
- package/openclaw.plugin.json +0 -6
- package/package.json +5 -5
- package/dist/catchup-D32oYNxR.js +0 -294
- package/dist/monitor-reply-cache-DKlYGd5x.js +0 -348
- package/dist/persisted-echo-cache-BPWGUK-L.js +0 -143
- package/node_modules/typebox/build/format/_idna.d.mts +0 -2
- package/node_modules/typebox/build/format/_idna.mjs +0 -246
- package/node_modules/typebox/build/format/_puny.d.mts +0 -1
- package/node_modules/typebox/build/format/_puny.mjs +0 -77
- package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
- package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
- package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
- package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
1
|
+
import { a as resolveDefaultIMessageAccountId, i as listIMessageAccountIds, o as resolveIMessageAccount, t as collectIMessageDuplicateAccountSourceWarnings } from "./accounts-CCirBEIm.js";
|
|
2
|
+
import { l as parseIMessageTarget, o as looksLikeIMessageExplicitTargetId, r as inferIMessageTargetChatType, s as normalizeIMessageHandle, u as isIMessagePhoneLikeHandle } from "./message-tool-api-CvIgJpOo.js";
|
|
3
|
+
import { n as sanitizeIMessageFinalOutboundText, r as sanitizeOutboundText, v as resolveIMessageDirectChatService } from "./sanitize-outbound-Du-r1lNQ.js";
|
|
4
|
+
import { a as normalizeIMessageAcpConversationId, c as normalizeIMessageMessagingTarget, d as imessageMessageActions, h as createIMessageSetupWizardProxy, i as matchIMessageAcpConversation, l as getIMessageApprovalApprovers, n as resolveIMessageGroupToolPolicy, o as resolveIMessageConversationIdFromTarget, t as resolveIMessageGroupRequireMention, u as imessageApprovalAuth, v as imessageSetupContract } from "./group-policy-Dvc-BcWo.js";
|
|
5
5
|
import { t as createIMessageConversationBindingManager } from "./conversation-bindings-GDQ_Laxj.js";
|
|
6
|
-
import { t as IMessageChannelConfigSchema } from "./config-schema-
|
|
7
|
-
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-
|
|
6
|
+
import { t as IMessageChannelConfigSchema } from "./config-schema-DuGbA8Kp.js";
|
|
7
|
+
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-D-FhGE98.js";
|
|
8
|
+
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
8
9
|
import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
|
|
10
|
+
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, formatTrimmedAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
9
11
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
10
12
|
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
11
13
|
import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
|
|
@@ -13,17 +15,17 @@ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
|
13
15
|
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
14
16
|
import { chunkMarkdownText } from "openclaw/plugin-sdk/reply-runtime";
|
|
15
17
|
import { buildOutboundBaseSessionKey, normalizeAccountId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
16
|
-
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
18
|
+
import { collectStatusIssuesFromLastError, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
17
19
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
18
20
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
21
|
import { createApproverRestrictedNativeApprovalCapabilityFromForwardingRoutes } from "openclaw/plugin-sdk/approval-delivery-runtime";
|
|
20
22
|
import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
21
23
|
import { shouldSuppressLocalNativeExecApprovalPrompt } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
24
|
+
import { addApprovalReactionHintToText } from "openclaw/plugin-sdk/approval-reaction-runtime";
|
|
22
25
|
import { buildTypedExecApprovalPendingReplyPayload, buildTypedPluginApprovalPendingReplyPayload } from "openclaw/plugin-sdk/approval-reply-runtime";
|
|
23
26
|
import { getExecApprovalReplyMetadata, resolveExecApprovalCommandDisplay, resolveExecApprovalRequestAllowedDecisions } from "openclaw/plugin-sdk/approval-runtime";
|
|
24
|
-
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, formatTrimmedAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
25
|
-
import { createChannelPluginBase } from "openclaw/plugin-sdk/core";
|
|
26
27
|
import { createRestrictSendersChannelSecurity } from "openclaw/plugin-sdk/channel-policy";
|
|
28
|
+
import { createChannelPluginBase, getChatChannelMeta } from "openclaw/plugin-sdk/core";
|
|
27
29
|
//#region extensions/imessage/src/approval-text.ts
|
|
28
30
|
function replaceApprovalIdPlaceholder(text, approvalId) {
|
|
29
31
|
const safeApprovalId = approvalId.replace(/\$/g, "$$$$");
|
|
@@ -84,7 +86,7 @@ const imessageApproval = createApproverRestrictedNativeApprovalCapabilityFromFor
|
|
|
84
86
|
approvalKind,
|
|
85
87
|
request
|
|
86
88
|
}),
|
|
87
|
-
load: async () => (await import("./approval-handler.runtime-
|
|
89
|
+
load: async () => (await import("./approval-handler.runtime-UBd1j2Sg.js")).imessageApprovalNativeRuntime
|
|
88
90
|
})
|
|
89
91
|
});
|
|
90
92
|
const imessageApprovalRouting = imessageApproval.routing;
|
|
@@ -139,7 +141,7 @@ function shouldSuppressLocalIMessageExecApprovalPrompt(params) {
|
|
|
139
141
|
});
|
|
140
142
|
}
|
|
141
143
|
function appendIMessageReactionHint(params) {
|
|
142
|
-
return
|
|
144
|
+
return addApprovalReactionHintToText({
|
|
143
145
|
text: params.text ?? "",
|
|
144
146
|
allowedDecisions: params.allowedDecisions
|
|
145
147
|
});
|
|
@@ -159,6 +161,7 @@ function buildIMessageExecPendingPayload(params) {
|
|
|
159
161
|
cwd: params.request.request.cwd ?? void 0,
|
|
160
162
|
host: params.request.request.host === "node" ? "node" : "gateway",
|
|
161
163
|
nodeId: params.request.request.nodeId ?? void 0,
|
|
164
|
+
scope: params.request.request.scope ?? void 0,
|
|
162
165
|
sessionKey: params.request.request.sessionKey ?? null,
|
|
163
166
|
expiresAtMs: params.request.expiresAtMs,
|
|
164
167
|
nowMs: params.nowMs
|
|
@@ -198,7 +201,7 @@ const imessageDoctor = {
|
|
|
198
201
|
//#region extensions/imessage/src/shared.ts
|
|
199
202
|
const IMESSAGE_CHANNEL = "imessage";
|
|
200
203
|
async function loadIMessageChannelRuntime$1() {
|
|
201
|
-
return await import("./channel.runtime-
|
|
204
|
+
return await import("./channel.runtime-HSkrmWfW.js");
|
|
202
205
|
}
|
|
203
206
|
const imessageSetupWizard = createIMessageSetupWizardProxy(async () => (await loadIMessageChannelRuntime$1()).imessageSetupWizard);
|
|
204
207
|
const imessageConfigAdapter = createScopedChannelConfigAdapter({
|
|
@@ -227,6 +230,7 @@ const imessageSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
|
227
230
|
groupPolicyPath: "channels.imessage.groupPolicy",
|
|
228
231
|
groupAllowFromPath: "channels.imessage.groupAllowFrom",
|
|
229
232
|
mentionGated: false,
|
|
233
|
+
findingTitle: "iMessage security warning",
|
|
230
234
|
policyPathSuffix: "dmPolicy"
|
|
231
235
|
});
|
|
232
236
|
function createIMessagePluginBase(params) {
|
|
@@ -296,7 +300,7 @@ async function probeIMessageStatusAccount(params) {
|
|
|
296
300
|
}
|
|
297
301
|
//#endregion
|
|
298
302
|
//#region extensions/imessage/src/channel.ts
|
|
299
|
-
const loadIMessageChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
303
|
+
const loadIMessageChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-HSkrmWfW.js"));
|
|
300
304
|
function toIMessageMessageSendResult(result, kind, replyToId) {
|
|
301
305
|
const receipt = result.receipt ?? createMessageReceiptFromOutboundResults({
|
|
302
306
|
results: result.messageId ? [{
|
|
@@ -312,8 +316,8 @@ function toIMessageMessageSendResult(result, kind, replyToId) {
|
|
|
312
316
|
...result.meta && Object.keys(result.meta).length > 0 ? { meta: result.meta } : {}
|
|
313
317
|
};
|
|
314
318
|
}
|
|
315
|
-
const loadIMessageApprovalReactionsModule = createLazyRuntimeModule(() => import("./
|
|
316
|
-
const loadIMessageQuestionReactionsModule = createLazyRuntimeModule(() => import("./question-reactions-
|
|
319
|
+
const loadIMessageApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-LL5yn1Rc.js").then((n) => n.t));
|
|
320
|
+
const loadIMessageQuestionReactionsModule = createLazyRuntimeModule(() => import("./question-reactions-viP7ZcyG.js").then((n) => n.r));
|
|
317
321
|
async function prepareForwardedIMessageApprovalPayload(params) {
|
|
318
322
|
const prepared = (await loadIMessageApprovalReactionsModule()).addIMessageApprovalReactionHintToStructuredPayload(params);
|
|
319
323
|
if (prepared) Object.assign(params.payload, prepared);
|
|
@@ -386,7 +390,7 @@ function buildIMessageBaseSessionKey(params) {
|
|
|
386
390
|
function isCanonicalIMessageDirectHandle(raw, normalized) {
|
|
387
391
|
const trimmed = raw.trim();
|
|
388
392
|
if (!trimmed || !normalized) return false;
|
|
389
|
-
if (normalized.startsWith("+")) return
|
|
393
|
+
if (normalized.startsWith("+")) return isIMessagePhoneLikeHandle(trimmed);
|
|
390
394
|
return /^[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+$/.test(trimmed);
|
|
391
395
|
}
|
|
392
396
|
function resolveIMessageOutboundSessionRoute(params) {
|
|
@@ -398,7 +402,7 @@ function resolveIMessageOutboundSessionRoute(params) {
|
|
|
398
402
|
cfg: params.cfg,
|
|
399
403
|
accountId: params.accountId
|
|
400
404
|
});
|
|
401
|
-
const directTarget = `${parsed.serviceExplicit
|
|
405
|
+
const directTarget = `${resolveIMessageDirectChatService(parsed.serviceExplicit ? parsed.service : account.config.service) ?? "auto"}:${handle}`;
|
|
402
406
|
const peer = {
|
|
403
407
|
kind: "direct",
|
|
404
408
|
id: handle
|
|
@@ -451,7 +455,7 @@ const imessagePlugin = createChatChannelPlugin({
|
|
|
451
455
|
allowlist: buildDmGroupAccountAllowlistAdapter({
|
|
452
456
|
channelId: "imessage",
|
|
453
457
|
resolveAccount: resolveIMessageAccount,
|
|
454
|
-
normalize: ({ values }) => formatTrimmedAllowFromEntries
|
|
458
|
+
normalize: ({ values }) => formatTrimmedAllowFromEntries(values),
|
|
455
459
|
resolveDmAllowFrom: (account) => account.config.allowFrom,
|
|
456
460
|
resolveGroupAllowFrom: (account) => account.config.groupAllowFrom,
|
|
457
461
|
resolveDmPolicy: (account) => account.config.dmPolicy,
|
|
@@ -464,6 +468,7 @@ const imessagePlugin = createChatChannelPlugin({
|
|
|
464
468
|
doctor: imessageDoctor,
|
|
465
469
|
conversationBindings: {
|
|
466
470
|
supportsCurrentConversationBinding: true,
|
|
471
|
+
bindingStore: "adapter",
|
|
467
472
|
createManager: ({ cfg, accountId }) => createIMessageConversationBindingManager({
|
|
468
473
|
cfg,
|
|
469
474
|
accountId: accountId ?? void 0
|
|
@@ -486,9 +491,9 @@ const imessagePlugin = createChatChannelPlugin({
|
|
|
486
491
|
resolveOutboundSessionRoute: (params) => resolveIMessageOutboundSessionRoute(params),
|
|
487
492
|
targetResolver: {
|
|
488
493
|
looksLikeId: looksLikeIMessageExplicitTargetId,
|
|
489
|
-
hint: "<
|
|
490
|
-
resolveTarget: async ({
|
|
491
|
-
const to =
|
|
494
|
+
hint: "<phone|email|chat_id:ID|auto:contact|imessage:contact|sms:contact>",
|
|
495
|
+
resolveTarget: async ({ input }) => {
|
|
496
|
+
const to = normalizeIMessageMessagingTarget(input);
|
|
492
497
|
if (!to) return null;
|
|
493
498
|
const chatType = inferIMessageTargetChatType(to);
|
|
494
499
|
if (!chatType) return null;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as IMessageChannelConfigSchema } from "./config-schema-
|
|
1
|
+
import { t as IMessageChannelConfigSchema } from "./config-schema-DuGbA8Kp.js";
|
|
2
2
|
export { IMessageChannelConfigSchema };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as imessagePlugin } from "./channel-
|
|
1
|
+
import { t as imessagePlugin } from "./channel-DNI9DKGN.js";
|
|
2
2
|
export { imessagePlugin };
|
|
@@ -1,26 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { l as resolveIMessageRemoteHost, o as resolveIMessageAccount, r as listEnabledIMessageAccounts, s as resolveIMessageDuplicateSourceOwner } from "./accounts-CCirBEIm.js";
|
|
2
|
+
import { _ as imessageDmPolicy, b as isAutoManagedIMessageCliPath, f as probeIMessage, g as imessageCompletionNote, m as createIMessageCliPathTextInput, p as IMESSAGE_INSTALL_COMMAND, x as normalizeIMessageCliPathForSetup, y as imessageSetupStatusBase } from "./group-policy-Dvc-BcWo.js";
|
|
3
3
|
import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-send-deps-B-QEsLSM.js";
|
|
4
|
-
import { t as sendMessageIMessage } from "./send-
|
|
5
|
-
import { t as monitorIMessageProvider } from "./monitor-
|
|
4
|
+
import { t as sendMessageIMessage } from "./send-mgWPKqSV.js";
|
|
5
|
+
import { t as monitorIMessageProvider } from "./monitor-BywJn1QW.js";
|
|
6
6
|
import { createAccountStatusSink, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
|
|
8
9
|
import fs from "node:fs/promises";
|
|
9
10
|
import { createDetectedBinaryStatus, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
10
11
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
11
12
|
import { detectBinary as detectBinary$1, resolveBrewExecutable } from "openclaw/plugin-sdk/setup-tools";
|
|
13
|
+
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
12
14
|
import { runPluginCommandWithTimeout } from "openclaw/plugin-sdk/run-command";
|
|
13
15
|
//#region extensions/imessage/src/install-imsg.ts
|
|
14
|
-
|
|
16
|
+
const IMESSAGE_BREW_FORMULA = "steipete/tap/imsg";
|
|
17
|
+
function isPathInside(parentPath, candidatePath) {
|
|
18
|
+
const relative = path.relative(parentPath, candidatePath);
|
|
19
|
+
return relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
20
|
+
}
|
|
21
|
+
async function resolveBrewManagedIMessageCliPath(brewExe, cliPath) {
|
|
15
22
|
try {
|
|
16
|
-
const
|
|
23
|
+
const formulae = await runPluginCommandWithTimeout({
|
|
17
24
|
argv: [
|
|
18
25
|
brewExe,
|
|
19
|
-
"
|
|
20
|
-
"
|
|
26
|
+
"list",
|
|
27
|
+
"--formula",
|
|
28
|
+
"--full-name"
|
|
21
29
|
],
|
|
22
30
|
timeoutMs: 1e4
|
|
23
31
|
});
|
|
32
|
+
const installed = formulae.stdout.split(/\r?\n/u).some((formula) => formula.trim() === IMESSAGE_BREW_FORMULA);
|
|
33
|
+
if (formulae.code !== 0 || !installed) return null;
|
|
34
|
+
let resolvedCliPath = cliPath;
|
|
35
|
+
if (!path.isAbsolute(resolvedCliPath)) {
|
|
36
|
+
const resolved = await runPluginCommandWithTimeout({
|
|
37
|
+
argv: [
|
|
38
|
+
"/usr/bin/env",
|
|
39
|
+
"which",
|
|
40
|
+
resolvedCliPath
|
|
41
|
+
],
|
|
42
|
+
timeoutMs: 1e4
|
|
43
|
+
});
|
|
44
|
+
resolvedCliPath = resolved.code === 0 ? resolved.stdout.split(/\r?\n/u)[0]?.trim() ?? "" : "";
|
|
45
|
+
}
|
|
46
|
+
if (!resolvedCliPath) return null;
|
|
47
|
+
const cellar = await runPluginCommandWithTimeout({
|
|
48
|
+
argv: [brewExe, "--cellar"],
|
|
49
|
+
timeoutMs: 1e4
|
|
50
|
+
});
|
|
51
|
+
if (cellar.code !== 0 || !cellar.stdout.trim()) return null;
|
|
52
|
+
const [realCliPath, realFormulaPath] = await Promise.all([fs.realpath(resolvedCliPath), fs.realpath(path.join(cellar.stdout.trim(), "imsg"))]);
|
|
53
|
+
return isPathInside(realFormulaPath, realCliPath) ? resolvedCliPath : null;
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function resolveBrewIMessageCliPath(brewExe) {
|
|
59
|
+
try {
|
|
60
|
+
const result = await runPluginCommandWithTimeout({
|
|
61
|
+
argv: [brewExe, "--prefix"],
|
|
62
|
+
timeoutMs: 1e4
|
|
63
|
+
});
|
|
24
64
|
if (result.code !== 0 || !result.stdout.trim()) return null;
|
|
25
65
|
const candidate = path.join(result.stdout.trim(), "bin", "imsg");
|
|
26
66
|
await fs.access(candidate);
|
|
@@ -41,6 +81,10 @@ async function installIMessageCli(runtime, opts) {
|
|
|
41
81
|
};
|
|
42
82
|
runtime.log(`${opts?.upgrade ? "Updating" : "Installing"} imsg via Homebrew (${brewExe})...`);
|
|
43
83
|
if (opts?.upgrade) {
|
|
84
|
+
if (!await resolveBrewManagedIMessageCliPath(brewExe, opts.cliPath ?? "imsg")) {
|
|
85
|
+
runtime.log("Keeping the detected imsg binary because Homebrew does not manage it.");
|
|
86
|
+
return { ok: true };
|
|
87
|
+
}
|
|
44
88
|
const update = await runPluginCommandWithTimeout({
|
|
45
89
|
argv: [brewExe, "update"],
|
|
46
90
|
timeoutMs: 5 * 6e4
|
|
@@ -129,11 +173,15 @@ const imessageSetupWizard = {
|
|
|
129
173
|
})) return;
|
|
130
174
|
try {
|
|
131
175
|
await options?.beforePersistentEffect?.();
|
|
132
|
-
const result = await installIMessageCli(runtime, {
|
|
176
|
+
const result = await installIMessageCli(runtime, {
|
|
177
|
+
upgrade: cliDetected,
|
|
178
|
+
cliPath: normalizedCliPath
|
|
179
|
+
});
|
|
133
180
|
if (result.ok && result.cliPath) {
|
|
134
181
|
await prompter.note(`Installed imsg at ${result.cliPath}`, "iMessage");
|
|
135
182
|
return { credentialValues: { cliPath: result.cliPath } };
|
|
136
183
|
}
|
|
184
|
+
if (result.ok) await prompter.note(`Using existing imsg at ${normalizedCliPath}; Homebrew does not manage this binary.`, "iMessage");
|
|
137
185
|
if (!result.ok) await prompter.note(result.error ?? "imsg install failed.", "iMessage");
|
|
138
186
|
} catch (error) {
|
|
139
187
|
await prompter.note(`imsg install failed: ${String(error)}`, "iMessage");
|
|
@@ -153,8 +201,7 @@ async function sendIMessageOutbound(params) {
|
|
|
153
201
|
const send = resolveOutboundSendDep(params.deps, "imessage", { legacyKeys: IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageIMessage;
|
|
154
202
|
const maxBytes = resolveChannelMediaMaxBytes({
|
|
155
203
|
cfg: params.cfg,
|
|
156
|
-
resolveChannelLimitMb: (
|
|
157
|
-
accountId: params.accountId
|
|
204
|
+
resolveChannelLimitMb: () => resolveIMessageAccount(params).config.mediaMaxMb
|
|
158
205
|
});
|
|
159
206
|
const result = await send(params.to, params.text, {
|
|
160
207
|
config: params.cfg,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
|
|
2
|
-
import { ChannelDeliveryStreamingConfigSchema, ChannelSendReadReceiptsSchema, ExecutableTokenSchema, buildChannelConfigSchema, buildChannelReactionShape,
|
|
2
|
+
import { ChannelDeliveryStreamingConfigSchema, ChannelSendReadReceiptsSchema, ExecutableTokenSchema, buildChannelAccountSchemaParts, buildChannelConfigSchema, buildChannelReactionShape, buildGroupEntrySchema, isSafeScpRemoteHost, isValidInboundPathRootPattern, requireAllowlistAllowFrom, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region extensions/imessage/src/config-ui-hints.ts
|
|
5
5
|
const iMessageChannelConfigUiHints = {
|
|
@@ -43,13 +43,13 @@ const IMessageActionSchema = z.object({
|
|
|
43
43
|
sendAttachment: z.boolean().optional(),
|
|
44
44
|
polls: z.boolean().optional()
|
|
45
45
|
}).strict().optional();
|
|
46
|
+
const { accountShape, rootPolicyShape } = buildChannelAccountSchemaParts({
|
|
47
|
+
omit: ["mentionPatterns", "replyToMode"],
|
|
48
|
+
streaming: ChannelDeliveryStreamingConfigSchema.optional(),
|
|
49
|
+
mediaMaxMb: z.number().int().positive().optional()
|
|
50
|
+
});
|
|
46
51
|
const IMessageAccountSchemaBase = z.object({
|
|
47
|
-
...
|
|
48
|
-
useDefaults: true,
|
|
49
|
-
omit: ["mentionPatterns", "replyToMode"],
|
|
50
|
-
streaming: ChannelDeliveryStreamingConfigSchema.optional(),
|
|
51
|
-
mediaMaxMb: z.number().int().positive().optional()
|
|
52
|
-
}),
|
|
52
|
+
...accountShape,
|
|
53
53
|
cliPath: ExecutableTokenSchema.optional(),
|
|
54
54
|
dbPath: z.string().optional(),
|
|
55
55
|
remoteHost: z.string().refine(isSafeScpRemoteHost, "expected SSH host or user@host (no spaces/options)").optional(),
|
|
@@ -89,6 +89,7 @@ const IMessageAccountSchemaBase = z.object({
|
|
|
89
89
|
] }).optional()).optional()
|
|
90
90
|
}).strict();
|
|
91
91
|
const IMessageConfigSchema = IMessageAccountSchemaBase.extend({
|
|
92
|
+
...rootPolicyShape,
|
|
92
93
|
accounts: z.record(z.string(), IMessageAccountSchemaBase.optional()).optional(),
|
|
93
94
|
defaultAccount: z.string().optional()
|
|
94
95
|
}).superRefine((value, ctx) => {
|
package/dist/contract-api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots, t as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS } from "./media-contract-
|
|
1
|
+
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots, t as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS } from "./media-contract-D-FhGE98.js";
|
|
2
2
|
import "./media-contract-api.js";
|
|
3
3
|
export { DEFAULT_IMESSAGE_ATTACHMENT_ROOTS, resolveIMessageAttachmentRoots, resolveIMessageAttachmentRoots as resolveInboundAttachmentRoots, resolveIMessageRemoteAttachmentRoots, resolveIMessageRemoteAttachmentRoots as resolveRemoteInboundAttachmentRoots };
|
|
@@ -1,284 +1,6 @@
|
|
|
1
|
-
import {
|
|
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-DKlYGd5x.js";
|
|
3
|
-
import { o as resolveIMessageCatchupCursorKey, r as capFailureRetriesMap, t as IMESSAGE_CATCHUP_CURSOR_NAMESPACE } from "./catchup-D32oYNxR.js";
|
|
4
|
-
import { n as IMESSAGE_SENT_ECHOES_TTL_MS, s as resolveIMessageSentEchoEntryKey, t as IMESSAGE_SENT_ECHOES_NAMESPACE } from "./persisted-echo-cache-BPWGUK-L.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
|
-
|
|
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:
|
|
78
|
+
resolvePlans: async (params) => {
|
|
79
|
+
const { detectIMessageLegacyStateMigrations } = await import("./state-migrations-SFdKp3GQ.js");
|
|
80
|
+
return detectIMessageLegacyStateMigrations(params);
|
|
81
|
+
}
|
|
355
82
|
})];
|
|
356
83
|
//#endregion
|
|
357
84
|
export { legacyConfigRules, normalizeCompatibilityConfig, stateMigrations };
|