openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
690 lines (689 loc) • 27 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { c as parseAgentSessionKey } from "./session-key-utils-Bx3apsJ3.js";
import { n as normalizeAccountId, t as DEFAULT_ACCOUNT_ID } from "./account-id-Df9e41E6.js";
import { r as createLazyRuntimeModule } from "./lazy-runtime-D-7_JraP.js";
import { j as resolveExecApprovalRequestAllowedDecisions } from "./exec-approvals-C6M6SGY3.js";
import { t as sanitizeForPlainText } from "./sanitize-text-BOGhD8MR.js";
import { t as createMessageReceiptFromOutboundResults } from "./receipt-B3SXxhHV.js";
import { p as formatTrimmedAllowFromEntries, s as createScopedChannelConfigAdapter, t as adaptScopedAccountAccessor } from "./channel-config-helpers-lj5quus3.js";
import { t as buildOutboundBaseSessionKey } from "./base-session-key-BpTC-eng.js";
import "./string-coerce-runtime-CEGJWkQ_.js";
import { t as chunkTextForOutbound } from "./text-chunking-D45TeeEs.js";
import { n as describeAccountSnapshot } from "./account-helpers-pcH3lGFY.js";
import { c as getChatChannelMeta, i as createChatChannelPlugin, r as createChannelPluginBase } from "./core-DSxVv-v1.js";
import "./channel-core-IukkNCd-.js";
import "./routing-CQ63ICPX.js";
import { r as createRestrictSendersChannelSecurity } from "./channel-policy-CIW58SA5.js";
import { c as buildExecApprovalPendingReplyPayload, p as getExecApprovalReplyMetadata } from "./exec-approval-reply-BXMsffTv.js";
import { i as splitChannelApprovalCapability, r as createChannelApprovalCapability } from "./approval-delivery-helpers-IkWw0ui8.js";
import "./approval-delivery-runtime-CYw5jxIp.js";
import { n as createLazyChannelApprovalNativeRuntimeAdapter } from "./approval-handler-adapter-runtime-DLWtIqHq.js";
import { t as resolveExecApprovalCommandDisplay } from "./exec-approval-command-display-BYD_3EWn.js";
import { r as buildPluginApprovalPendingReplyPayload } from "./approval-renderers-Cf0JuAfU.js";
import { a as createNativeApprovalForwardingFallbackSuppressor, c as shouldSuppressLocalNativeExecApprovalPrompt, i as createNativeApprovalChannelRouteGates, n as createChannelApproverDmTargetResolver, r as createChannelNativeOriginTargetResolver } from "./approval-native-helpers-WitYuyrm.js";
import "./approval-native-runtime-BeD_vgZw.js";
import "./approval-runtime-B6CZRTwB.js";
import { T as defineChannelMessageAdapter } from "./channel-outbound-B3_Zy-kG.js";
import { n as buildDmGroupAccountAllowlistAdapter } from "./allowlist-config-edit-dX8vJeki.js";
import { c as collectStatusIssuesFromLastError, d as createDefaultChannelRuntimeState, u as createComputedAccountStatusAdapter } from "./status-helpers-BevxX6Pu.js";
import { n as buildPassiveProbedChannelStatusSummary } from "./extension-shared-B8fkO3TV.js";
import { a as resolveIMessageAccount, i as resolveDefaultIMessageAccountId, r as listIMessageAccountIds, t as collectIMessageDuplicateAccountSourceWarnings } from "./accounts-DzoymhDS.js";
import { a as looksLikeIMessageExplicitTargetId, c as parseIMessageTarget, n as inferIMessageTargetChatType, o as normalizeIMessageHandle } from "./targets-BhNdlUSi.js";
import { a as resolveIMessageConversationIdFromTarget, i as normalizeIMessageAcpConversationId, r as matchIMessageAcpConversation, t as sanitizeOutboundText } from "./sanitize-outbound-B_Wx0jBt.js";
import { n as resolveIMessageGroupToolPolicy, r as imessageMessageActions, t as resolveIMessageGroupRequireMention } from "./group-policy-B3Dv_Ucw.js";
import { m as imessageApprovalAuth, n as normalizeIMessageMessagingTarget, p as getIMessageApprovalApprovers, r as addIMessageApprovalReactionHintToText } from "./normalize-BfDcnrra.js";
import { t as createIMessageConversationBindingManager } from "./conversation-bindings-7y_2axvB.js";
import { a as imessageSetupAdapter, n as createIMessageSetupWizardProxy } from "./setup-core-e4UFbnJk.js";
import { t as IMessageChannelConfigSchema } from "./config-schema-DdYrT07e.js";
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-BEafhpgp.js";
//#region extensions/imessage/src/approval-text.ts
function replaceApprovalIdPlaceholder(text, approvalId) {
const safeApprovalId = approvalId.replace(/\$/g, "$$$$");
return (text ?? "").replace(/\/approve\s+<id>/g, `/approve ${safeApprovalId}`);
}
//#endregion
//#region extensions/imessage/src/approval-native.ts
const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
const DEFAULT_PLUGIN_APPROVAL_DECISIONS = [
"allow-once",
"allow-always",
"deny"
];
function isIMessageApprovalTransportEnabled(params) {
return resolveIMessageAccount({
cfg: params.cfg,
accountId: params.accountId
}).enabled;
}
function normalizeIMessageForwardTarget(target) {
if (normalizeLowercaseStringOrEmpty(target.channel) !== "imessage") return null;
const to = normalizeIMessageMessagingTarget(target.to);
if (!to) return null;
return {
to,
accountId: normalizeOptionalString(target.accountId),
threadId: target.threadId ?? null
};
}
function resolveTurnSourceIMessageOriginTarget(request) {
if (normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel) !== "imessage") return null;
const to = normalizeIMessageMessagingTarget(request.request.turnSourceTo ?? "");
if (!to) return null;
return {
to,
accountId: normalizeOptionalString(request.request.turnSourceAccountId)
};
}
function resolveSessionIMessageOriginTarget(sessionTarget) {
const to = normalizeIMessageMessagingTarget(sessionTarget.to);
return to ? {
to,
accountId: normalizeOptionalString(sessionTarget.accountId)
} : null;
}
const { canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToIMessage, canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToIMessage, isSessionApprovalEligible: isIMessageSessionApprovalEligible, isExplicitTargetEligible: isIMessageExplicitTargetEligible, shouldHandleApprovalRequest: shouldHandleIMessageApprovalRequest } = createNativeApprovalChannelRouteGates({
channel: "imessage",
defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE,
isTransportEnabled: isIMessageApprovalTransportEnabled,
listAccountIds: listIMessageAccountIds,
resolveDefaultAccountId: resolveDefaultIMessageAccountId,
normalizeForwardTarget: normalizeIMessageForwardTarget,
resolveTurnSourceTarget: resolveTurnSourceIMessageOriginTarget
});
function resolveIMessageSessionTargetFromSessionKey(sessionKey) {
const rest = parseAgentSessionKey(sessionKey)?.rest ?? normalizeOptionalString(sessionKey);
if (!rest || !normalizeLowercaseStringOrEmpty(rest).startsWith("imessage:")) return null;
const route = rest.slice(9).trim();
const routeLower = normalizeLowercaseStringOrEmpty(route);
if (!route || routeLower.startsWith("group:") || routeLower.startsWith("channel:") || routeLower.startsWith("chat:")) return null;
if (routeLower.startsWith("direct:")) {
const to = normalizeIMessageMessagingTarget(route.slice(7));
return to ? { to } : null;
}
const accountScopedDirect = /^([^:]+):direct:(.+)$/i.exec(route);
if (accountScopedDirect) {
const to = normalizeIMessageMessagingTarget(accountScopedDirect[2] ?? "");
return to ? {
to,
accountId: normalizeAccountId(accountScopedDirect[1] ?? "")
} : null;
}
const to = normalizeIMessageMessagingTarget(route);
if (!to || inferIMessageTargetChatType(to) !== "direct") return null;
return { to };
}
function shouldSuppressLocalIMessageExecApprovalPrompt(params) {
if (shouldSuppressLocalNativeExecApprovalPrompt({
...params,
isTransportEnabled: isIMessageApprovalTransportEnabled,
isSessionRouteEligible: ({ cfg, accountId, metadata }) => {
if (getIMessageApprovalApprovers({
cfg,
accountId
}).length > 0) return true;
const sessionTarget = resolveIMessageSessionTargetFromSessionKey(metadata.sessionKey);
if (!sessionTarget || inferIMessageTargetChatType(sessionTarget.to) !== "direct") return false;
const targetAccountId = normalizeOptionalString(sessionTarget.accountId);
return !targetAccountId || !accountId || normalizeAccountId(targetAccountId) === normalizeAccountId(accountId);
}
})) return true;
const metadata = getExecApprovalReplyMetadata(params.payload);
if (params.hint?.kind !== "approval-pending" || params.hint.approvalKind !== "exec" || params.hint.nativeRouteActive !== true || metadata?.approvalKind !== "exec") return false;
if (metadata.agentId || metadata.sessionKey) return false;
if (getIMessageApprovalApprovers({
cfg: params.cfg,
accountId: params.accountId
}).length === 0) return false;
return canApprovalPotentiallyRouteToIMessage({
...params,
approvalKind: "exec",
nativeSessionOnly: true
});
}
const resolveIMessageOriginTargetBase = createChannelNativeOriginTargetResolver({
channel: "imessage",
shouldHandleRequest: shouldHandleIMessageApprovalRequest,
resolveTurnSourceTarget: resolveTurnSourceIMessageOriginTarget,
resolveSessionTarget: resolveSessionIMessageOriginTarget,
normalizeTarget: (target) => {
const to = normalizeIMessageMessagingTarget(target.to);
return to ? {
...target,
to
} : null;
}
});
function resolveIMessageOriginTarget(params) {
const target = resolveIMessageOriginTargetBase(params);
if (!target) return null;
if (inferIMessageTargetChatType(target.to) === "group" && getIMessageApprovalApprovers({
cfg: params.cfg,
accountId: params.accountId
}).length === 0) return null;
return target;
}
const resolveIMessageApproverDmTargets = createChannelApproverDmTargetResolver({
shouldHandleRequest: shouldHandleIMessageApprovalRequest,
resolveApprovers: getIMessageApprovalApprovers,
mapApprover: (approver, params) => {
const to = normalizeIMessageMessagingTarget(approver);
if (!to) return null;
return {
to,
accountId: normalizeOptionalString(params.accountId)
};
}
});
const shouldSuppressIMessageForwardingFallback = createNativeApprovalForwardingFallbackSuppressor({
channel: "imessage",
normalizeForwardTarget: normalizeIMessageForwardTarget,
resolveAccountId: ({ forwardingTarget, request }) => forwardingTarget.accountId ?? normalizeOptionalString(request.request.turnSourceAccountId),
resolveForwardingTargetForMatch: ({ forwardingTarget, accountId }) => ({
...forwardingTarget,
accountId
}),
isSessionRouteEligible: isIMessageSessionApprovalEligible,
isExplicitTargetEligible: isIMessageExplicitTargetEligible,
resolveOriginTarget: resolveIMessageOriginTarget,
resolveApproverDmTargets: resolveIMessageApproverDmTargets
});
function appendIMessageReactionHint(params) {
return addIMessageApprovalReactionHintToText({
text: params.text ?? "",
allowedDecisions: params.allowedDecisions
});
}
function buildIMessageExecPendingPayload(params) {
const allowedDecisions = resolveExecApprovalRequestAllowedDecisions(params.request.request);
const command = resolveExecApprovalCommandDisplay(params.request.request).commandText;
const payload = buildExecApprovalPendingReplyPayload({
approvalId: params.request.id,
approvalSlug: params.request.id.slice(0, 8),
approvalCommandId: params.request.id,
warningText: params.request.request.warningText ?? void 0,
ask: params.request.request.ask ?? null,
agentId: params.request.request.agentId ?? null,
allowedDecisions,
command,
cwd: params.request.request.cwd ?? void 0,
host: params.request.request.host === "node" ? "node" : "gateway",
nodeId: params.request.request.nodeId ?? void 0,
sessionKey: params.request.request.sessionKey ?? null,
expiresAtMs: params.request.expiresAtMs,
nowMs: params.nowMs
});
return {
...payload,
text: appendIMessageReactionHint({
text: replaceApprovalIdPlaceholder(payload.text, params.request.id),
allowedDecisions
})
};
}
function buildIMessagePluginPendingPayload(params) {
const configuredDecisions = params.request.request.allowedDecisions;
const allowedDecisions = configuredDecisions && configuredDecisions.length > 0 ? configuredDecisions : DEFAULT_PLUGIN_APPROVAL_DECISIONS;
const payload = buildPluginApprovalPendingReplyPayload({
request: params.request,
nowMs: params.nowMs,
allowedDecisions
});
return {
...payload,
text: appendIMessageReactionHint({
text: replaceApprovalIdPlaceholder(payload.text, params.request.id),
allowedDecisions
})
};
}
const imessageApprovalCapability = createChannelApprovalCapability({
...imessageApprovalAuth,
getActionAvailabilityState: ({ cfg, accountId, approvalKind }) => (approvalKind ? canApprovalPotentiallyRouteToIMessage({
cfg,
accountId,
approvalKind
}) : canAnyApprovalPotentiallyRouteToIMessage({
cfg,
accountId
})) ? { kind: "enabled" } : { kind: "disabled" },
getExecInitiatingSurfaceState: ({ cfg, accountId }) => canApprovalPotentiallyRouteToIMessage({
cfg,
accountId,
approvalKind: "exec"
}) ? { kind: "enabled" } : { kind: "disabled" },
describeExecApprovalSetup: ({ accountId }) => {
return `iMessage supports native exec approvals for this account when \`approvals.exec.enabled\` is true and the route allows iMessage. Keep the macOS imsg bridge running and configure \`${accountId && accountId !== "default" ? `channels.imessage.accounts.${accountId}` : "channels.imessage"}.allowFrom\` to restrict approvers.`;
},
delivery: {
hasConfiguredDmRoute: ({ cfg }) => listIMessageAccountIds(cfg).some((accountId) => {
if (!canAnyApprovalPotentiallyRouteToIMessage({
cfg,
accountId,
nativeSessionOnly: true
})) return false;
return getIMessageApprovalApprovers({
cfg,
accountId
}).length > 0;
}),
shouldSuppressForwardingFallback: shouldSuppressIMessageForwardingFallback
},
render: {
exec: { buildPendingPayload: ({ request, nowMs }) => buildIMessageExecPendingPayload({
request,
nowMs
}) },
plugin: { buildPendingPayload: ({ request, nowMs }) => buildIMessagePluginPendingPayload({
request,
nowMs
}) }
},
native: {
describeDeliveryCapabilities: ({ cfg, accountId, approvalKind, request }) => {
const originTarget = resolveIMessageOriginTarget({
cfg,
accountId,
approvalKind,
request
});
const approverTargets = resolveIMessageApproverDmTargets({
cfg,
accountId,
approvalKind,
request
});
return {
enabled: Boolean(originTarget) || approverTargets.length > 0,
preferredSurface: originTarget ? "origin" : "approver-dm",
supportsOriginSurface: Boolean(originTarget),
supportsApproverDmSurface: approverTargets.length > 0,
notifyOriginWhenDmOnly: true
};
},
resolveOriginTarget: resolveIMessageOriginTarget,
resolveApproverDmTargets: resolveIMessageApproverDmTargets
},
nativeRuntime: createLazyChannelApprovalNativeRuntimeAdapter({
eventKinds: ["exec", "plugin"],
isConfigured: ({ cfg, accountId, context }) => Boolean(context) && canAnyApprovalPotentiallyRouteToIMessage({
cfg,
accountId,
nativeSessionOnly: true
}),
shouldHandle: ({ cfg, accountId, context, request }) => Boolean(context) && shouldHandleIMessageApprovalRequest({
cfg,
accountId,
request
}),
load: async () => (await import("./approval-handler.runtime-ClLi7hi2.js")).imessageApprovalNativeRuntime
})
});
splitChannelApprovalCapability(imessageApprovalCapability);
//#endregion
//#region extensions/imessage/src/doctor.ts
const imessageDoctor = {
groupAllowFromFallbackToAllowFrom: false,
collectPreviewWarnings: ({ cfg }) => collectIMessageDuplicateAccountSourceWarnings({ cfg })
};
//#endregion
//#region extensions/imessage/src/shared.ts
const IMESSAGE_CHANNEL = "imessage";
async function loadIMessageChannelRuntime$1() {
return await import("./channel.runtime-VRuGVo52.js");
}
const imessageSetupWizard = createIMessageSetupWizardProxy(async () => (await loadIMessageChannelRuntime$1()).imessageSetupWizard);
const imessageConfigAdapter = createScopedChannelConfigAdapter({
sectionKey: IMESSAGE_CHANNEL,
listAccountIds: listIMessageAccountIds,
resolveAccount: adaptScopedAccountAccessor(resolveIMessageAccount),
defaultAccountId: resolveDefaultIMessageAccountId,
clearBaseFields: [
"cliPath",
"dbPath",
"service",
"region",
"name"
],
resolveAllowFrom: (account) => account.config.allowFrom,
formatAllowFrom: (allowFrom) => formatTrimmedAllowFromEntries(allowFrom),
resolveDefaultTo: (account) => account.config.defaultTo
});
const imessageSecurityAdapter = createRestrictSendersChannelSecurity({
channelKey: IMESSAGE_CHANNEL,
resolveDmPolicy: (account) => account.config.dmPolicy,
resolveDmAllowFrom: (account) => account.config.allowFrom,
resolveGroupPolicy: (account) => account.config.groupPolicy,
surface: "iMessage groups",
openScope: "any member",
groupPolicyPath: "channels.imessage.groupPolicy",
groupAllowFromPath: "channels.imessage.groupAllowFrom",
mentionGated: false,
policyPathSuffix: "dmPolicy"
});
function createIMessagePluginBase(params) {
return {
...createChannelPluginBase({
id: IMESSAGE_CHANNEL,
meta: {
...getChatChannelMeta(IMESSAGE_CHANNEL),
aliases: ["imsg"],
showConfigured: false
},
setupWizard: params.setupWizard,
capabilities: {
chatTypes: ["direct", "group"],
media: true,
tts: { voice: {
synthesisTarget: "audio-file",
audioFileFormats: [
"mp3",
"caf",
"audio/mpeg",
"audio/x-caf"
],
preferAudioFileFormat: "caf"
} },
reactions: true,
edit: true,
unsend: true,
reply: true,
effects: true,
groupManagement: true
},
reload: { configPrefixes: ["channels.imessage"] },
configSchema: IMessageChannelConfigSchema,
config: {
...imessageConfigAdapter,
isConfigured: (account) => account.configured,
describeAccount: (account) => describeAccountSnapshot({
account,
configured: account.configured
})
},
security: imessageSecurityAdapter,
setup: params.setup
}),
messaging: {
resolveInboundAttachmentRoots: (paramsValue) => resolveIMessageAttachmentRoots({
accountId: paramsValue.accountId,
cfg: paramsValue.cfg
}),
resolveRemoteInboundAttachmentRoots: (paramsLocal) => resolveIMessageRemoteAttachmentRoots({
accountId: paramsLocal.accountId,
cfg: paramsLocal.cfg
})
}
};
}
//#endregion
//#region extensions/imessage/src/status-core.ts
async function probeIMessageStatusAccount(params) {
return await params.probeIMessageAccount({
timeoutMs: params.timeoutMs,
cliPath: params.account.config.cliPath,
dbPath: params.account.config.dbPath
});
}
//#endregion
//#region extensions/imessage/src/channel.ts
const loadIMessageChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-VRuGVo52.js"));
function toIMessageMessageSendResult(result, kind, replyToId) {
const receipt = result.receipt ?? createMessageReceiptFromOutboundResults({
results: result.messageId ? [{
channel: "imessage",
messageId: result.messageId
}] : [],
kind,
...replyToId ? { replyToId } : {}
});
return {
messageId: result.messageId || receipt.primaryPlatformMessageId,
receipt
};
}
const imessageMessageAdapter = defineChannelMessageAdapter({
id: "imessage",
durableFinal: { capabilities: {
text: true,
media: true,
replyTo: true,
messageSendingHooks: true
} },
send: {
text: async (ctx) => {
return toIMessageMessageSendResult(await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
cfg: ctx.cfg,
to: ctx.to,
text: ctx.text,
accountId: ctx.accountId ?? void 0,
deps: ctx.deps,
replyToId: ctx.replyToId ?? void 0
}), "text", ctx.replyToId);
},
media: async (ctx) => {
return toIMessageMessageSendResult(await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
cfg: ctx.cfg,
to: ctx.to,
text: ctx.text,
mediaUrl: ctx.mediaUrl,
mediaLocalRoots: ctx.mediaLocalRoots,
audioAsVoice: ctx.audioAsVoice,
accountId: ctx.accountId ?? void 0,
deps: ctx.deps,
replyToId: ctx.replyToId ?? void 0
}), ctx.audioAsVoice ? "voice" : "media", ctx.replyToId);
}
}
});
function buildIMessageBaseSessionKey(params) {
return buildOutboundBaseSessionKey({
...params,
channel: "imessage"
});
}
function resolveIMessageOutboundSessionRoute(params) {
const parsed = parseIMessageTarget(params.target);
if (parsed.kind === "handle") {
const handle = normalizeIMessageHandle(parsed.to);
if (!handle) return null;
const account = resolveIMessageAccount({
cfg: params.cfg,
accountId: params.accountId
});
const directTarget = `${parsed.serviceExplicit || parsed.service !== "auto" ? parsed.service : account.config.service === "sms" ? "sms" : "imessage"}:${handle}`;
const peer = {
kind: "direct",
id: handle
};
const baseSessionKey = buildIMessageBaseSessionKey({
cfg: params.cfg,
agentId: params.agentId,
accountId: params.accountId,
peer
});
return {
sessionKey: baseSessionKey,
baseSessionKey,
peer,
chatType: "direct",
from: directTarget,
to: directTarget
};
}
const peerId = parsed.kind === "chat_id" ? String(parsed.chatId) : parsed.kind === "chat_guid" ? parsed.chatGuid : parsed.chatIdentifier;
if (!peerId) return null;
const peer = {
kind: "group",
id: peerId
};
const baseSessionKey = buildIMessageBaseSessionKey({
cfg: params.cfg,
agentId: params.agentId,
accountId: params.accountId,
peer
});
const toPrefix = parsed.kind === "chat_id" ? "chat_id" : parsed.kind === "chat_guid" ? "chat_guid" : "chat_identifier";
return {
sessionKey: baseSessionKey,
baseSessionKey,
peer,
chatType: "group",
from: `imessage:group:${peerId}`,
to: `${toPrefix}:${peerId}`
};
}
const imessagePlugin = createChatChannelPlugin({
base: {
...createIMessagePluginBase({
setupWizard: imessageSetupWizard,
setup: imessageSetupAdapter
}),
allowlist: buildDmGroupAccountAllowlistAdapter({
channelId: "imessage",
resolveAccount: resolveIMessageAccount,
normalize: ({ values }) => formatTrimmedAllowFromEntries(values),
resolveDmAllowFrom: (account) => account.config.allowFrom,
resolveGroupAllowFrom: (account) => account.config.groupAllowFrom,
resolveDmPolicy: (account) => account.config.dmPolicy,
resolveGroupPolicy: (account) => account.config.groupPolicy
}),
groups: {
resolveRequireMention: resolveIMessageGroupRequireMention,
resolveToolPolicy: resolveIMessageGroupToolPolicy
},
doctor: imessageDoctor,
conversationBindings: {
supportsCurrentConversationBinding: true,
createManager: ({ cfg, accountId }) => createIMessageConversationBindingManager({
cfg,
accountId: accountId ?? void 0
})
},
bindings: {
compileConfiguredBinding: ({ conversationId }) => normalizeIMessageAcpConversationId(conversationId),
matchInboundConversation: ({ compiledBinding, conversationId }) => matchIMessageAcpConversation({
bindingConversationId: compiledBinding.conversationId,
conversationId
}),
resolveCommandConversation: ({ originatingTo, commandTo, fallbackTo }) => {
const conversationId = resolveIMessageConversationIdFromTarget(originatingTo ?? "") ?? resolveIMessageConversationIdFromTarget(commandTo ?? "") ?? resolveIMessageConversationIdFromTarget(fallbackTo ?? "");
return conversationId ? { conversationId } : null;
}
},
messaging: {
normalizeTarget: normalizeIMessageMessagingTarget,
inferTargetChatType: ({ to }) => inferIMessageTargetChatType(to),
resolveOutboundSessionRoute: (params) => resolveIMessageOutboundSessionRoute(params),
targetResolver: {
looksLikeId: looksLikeIMessageExplicitTargetId,
hint: "<handle|chat_id:ID>",
resolveTarget: async ({ normalized }) => {
const to = normalized?.trim();
if (!to) return null;
const chatType = inferIMessageTargetChatType(to);
if (!chatType) return null;
return {
to,
kind: chatType === "direct" ? "user" : "group",
source: "normalized"
};
}
}
},
status: createComputedAccountStatusAdapter({
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID, {
cliPath: null,
dbPath: null
}),
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("imessage", accounts),
buildChannelSummary: ({ snapshot }) => buildPassiveProbedChannelStatusSummary(snapshot, {
cliPath: snapshot.cliPath ?? null,
dbPath: snapshot.dbPath ?? null
}),
probeAccount: async ({ account, timeoutMs }) => await probeIMessageStatusAccount({
account,
timeoutMs,
probeIMessageAccount: async (params) => await (await loadIMessageChannelRuntime()).probeIMessageAccount(params)
}),
resolveAccountSnapshot: ({ account, runtime }) => ({
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: account.configured,
extra: {
cliPath: runtime?.cliPath ?? account.config.cliPath ?? null,
dbPath: runtime?.dbPath ?? account.config.dbPath ?? null
}
}),
resolveAccountState: ({ enabled }) => enabled ? "enabled" : "disabled"
}),
gateway: { startAccount: async (ctx) => {
const conversationBindings = createIMessageConversationBindingManager({
cfg: ctx.cfg,
accountId: ctx.accountId
});
try {
return await (await loadIMessageChannelRuntime()).startIMessageGatewayAccount(ctx);
} finally {
conversationBindings.stop();
}
} },
message: imessageMessageAdapter,
actions: imessageMessageActions,
approvalCapability: imessageApprovalCapability
},
pairing: { text: {
idLabel: "imessageSenderId",
message: "OpenClaw: your access has been approved.",
notify: async ({ id, cfg }) => await (await loadIMessageChannelRuntime()).notifyIMessageApproval({
id,
cfg
})
} },
security: imessageSecurityAdapter,
outbound: {
base: {
deliveryMode: "direct",
chunker: chunkTextForOutbound,
chunkerMode: "text",
textChunkLimit: 4e3,
sanitizeText: ({ text }) => sanitizeForPlainText(sanitizeOutboundText(text)),
shouldSuppressLocalPayloadPrompt: ({ cfg, accountId, payload, hint }) => shouldSuppressLocalIMessageExecApprovalPrompt({
cfg,
accountId,
payload,
hint
}),
deliveryCapabilities: { durableFinal: {
text: true,
media: true,
replyTo: true,
messageSendingHooks: true
} }
},
attachedResults: {
channel: "imessage",
sendText: async ({ cfg, to, text, accountId, deps, replyToId }) => await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
cfg,
to,
text,
accountId: accountId ?? void 0,
deps,
replyToId: replyToId ?? void 0
}),
sendMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, audioAsVoice, accountId, deps, replyToId }) => await (await loadIMessageChannelRuntime()).sendIMessageOutbound({
cfg,
to,
text,
mediaUrl,
mediaLocalRoots,
audioAsVoice,
accountId: accountId ?? void 0,
deps,
replyToId: replyToId ?? void 0
})
}
}
});
//#endregion
export { createIMessagePluginBase as n, imessageSetupWizard as r, imessagePlugin as t };