feat(plugins): externalize iMessage channel (#117101)

This commit is contained in:
Vincent Koc
2026-08-01 08:01:18 +08:00
committed by GitHub
parent 08305dbb94
commit 89aadef6ef
23 changed files with 239 additions and 40 deletions
+13 -7
View File
@@ -1,5 +1,5 @@
---
summary: "BlueBubbles support was removed from OpenClaw. Use the bundled iMessage plugin with imsg for new and migrated iMessage setups."
summary: "BlueBubbles support was removed from OpenClaw. Use the official iMessage plugin with imsg for new and migrated iMessage setups."
read_when:
- You used the old BlueBubbles channel and need to move to iMessage
- You are choosing the supported OpenClaw iMessage setup
@@ -9,7 +9,7 @@ title: "BlueBubbles removal and the imsg iMessage path"
# BlueBubbles removal and the imsg iMessage path
OpenClaw no longer ships the BlueBubbles channel. iMessage support runs through the bundled `imessage` plugin: the Gateway spawns [`imsg`](https://github.com/steipete/imsg) as a child process, locally or through an SSH wrapper, and talks JSON-RPC over stdin/stdout. No server, no webhook, no port.
OpenClaw no longer ships the BlueBubbles channel. iMessage support runs through the official `@openclaw/imessage` plugin: the Gateway spawns [`imsg`](https://github.com/steipete/imsg) as a child process, locally or through an SSH wrapper, and talks JSON-RPC over stdin/stdout. No server, no webhook, no port.
If your config still contains `channels.bluebubbles`, migrate it to `channels.imessage`. The legacy `/channels/bluebubbles` docs URL redirects to [Coming from BlueBubbles](/channels/imessage-from-bluebubbles), which has the full config translation table and cutover checklist.
@@ -23,7 +23,13 @@ If your config still contains `channels.bluebubbles`, migrate it to `channels.im
## What to do
1. Install and verify `imsg` on the Messages Mac:
1. Install the official plugin on the Gateway host, then restart the Gateway:
```bash
openclaw plugins install @openclaw/imessage
```
2. Install and verify `imsg` on the Messages Mac:
```bash
brew install steipete/tap/imsg
@@ -32,9 +38,9 @@ If your config still contains `channels.bluebubbles`, migrate it to `channels.im
imsg rpc --help
```
2. Grant Full Disk Access and Automation permissions to the process context that runs `imsg` and OpenClaw.
3. Grant Full Disk Access and Automation permissions to the process context that runs `imsg` and OpenClaw.
3. Translate the old config:
4. Translate the old config:
```json5
{
@@ -55,13 +61,13 @@ If your config still contains `channels.bluebubbles`, migrate it to `channels.im
}
```
4. Restart the gateway and verify:
5. Restart the gateway and verify:
```bash
openclaw channels status --probe
```
5. Test DMs, groups, attachments, and any private API actions you depend on before deleting your old BlueBubbles server.
6. Test DMs, groups, attachments, and any private API actions you depend on before deleting your old BlueBubbles server.
## Migration notes
+1 -1
View File
@@ -121,7 +121,7 @@ Access groups work in the shared message-channel authorization paths:
- channel-specific per-room sender allowlists that use the same sender matching rules (for example Google Chat `groups.<space>.users`)
- command authorization paths that reuse message-channel sender allowlists
Channel support depends on whether that channel is wired through the shared OpenClaw sender-authorization helpers. Current bundled support includes ClickClack, Discord, Feishu, Google Chat, iMessage, IRC, LINE, Mattermost, Microsoft Teams, Nextcloud Talk, Nostr, QQ Bot, Signal, Slack, SMS, Telegram, WhatsApp, Zalo, and Zalo Personal. Static `message.senders` groups are channel-agnostic, so new message channels get them by using the shared plugin SDK ingress helpers instead of custom allowlist expansion.
Channel support depends on whether that channel is wired through the shared OpenClaw sender-authorization helpers. Current supported channel integrations include ClickClack, Discord, Feishu, Google Chat, iMessage, IRC, LINE, Mattermost, Microsoft Teams, Nextcloud Talk, Nostr, QQ Bot, Signal, Slack, SMS, Telegram, WhatsApp, Zalo, and Zalo Personal. Static `message.senders` groups are channel-agnostic, so new message channels get them by using the shared plugin SDK ingress helpers instead of custom allowlist expansion.
## Discord channel audiences
+1 -1
View File
@@ -14,7 +14,7 @@ channel converge on the agent's [main session](/concepts/main-session).
## Key terms
- **Channel**: a bundled channel plugin such as `discord`, `googlechat`, `imessage`, `irc`, `line`, `signal`, `slack`, `telegram`, or `whatsapp`, plus installed plugin channels. `webchat` is the internal WebChat UI channel and is not a configurable outbound channel.
- **Channel**: a channel plugin such as `discord`, `googlechat`, `imessage`, `irc`, `line`, `signal`, `slack`, `telegram`, or `whatsapp`. `webchat` is the internal WebChat UI channel and is not a configurable outbound channel.
- **AccountId**: per-channel account instance (when supported).
- Optional channel default account: `channels.<channel>.defaultAccount` chooses
which account is used when an outbound path does not specify `accountId`.
+15 -14
View File
@@ -1,13 +1,13 @@
---
summary: "Translate old BlueBubbles configs to the bundled iMessage plugin: key mapping, group allowlist gates, and cutover verification."
summary: "Translate old BlueBubbles configs to the official iMessage plugin: key mapping, group allowlist gates, and cutover verification."
read_when:
- Planning a move from BlueBubbles to the bundled iMessage plugin
- Planning a move from BlueBubbles to the official iMessage plugin
- Translating BlueBubbles config keys to iMessage equivalents
- Verifying imsg before enabling the iMessage plugin
title: "Coming from BlueBubbles"
---
BlueBubbles support was removed. OpenClaw supports iMessage only through the bundled `imessage` plugin, which drives [`steipete/imsg`](https://github.com/steipete/imsg) over JSON-RPC and reaches the same private API surface BlueBubbles had (`react`, `edit`, `unsend`, `reply`, `sendWithEffect`, native polls, group management, attachments). One CLI binary replaces the BlueBubbles server + client app + webhook plumbing: no REST endpoint, no webhook auth.
BlueBubbles support was removed. OpenClaw supports iMessage only through the official `@openclaw/imessage` plugin, which drives [`steipete/imsg`](https://github.com/steipete/imsg) over JSON-RPC and reaches the same private API surface BlueBubbles had (`react`, `edit`, `unsend`, `reply`, `sendWithEffect`, native polls, group management, attachments). One CLI binary replaces the BlueBubbles server + client app + webhook plumbing: no REST endpoint, no webhook auth.
This guide migrates old `channels.bluebubbles` configs to `channels.imessage`. There is no other supported migration path. On current OpenClaw a leftover `channels.bluebubbles` block is inert — no runtime reads it.
@@ -19,13 +19,14 @@ For the short announcement and operator summary, see [BlueBubbles removal and th
The shortest safe path when you already know your old BlueBubbles config:
1. Verify `imsg` directly on the Mac that runs Messages.app (`imsg chats`, `imsg history`, `imsg send`, `imsg rpc --help`).
2. Copy behavior keys from `channels.bluebubbles` to `channels.imessage`: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `includeAttachments`, `attachmentRoots`, `mediaMaxMb`, `textChunkLimit`, and `actions`.
3. Drop transport keys that no longer exist: `serverUrl`, `password`, webhook URLs, and BlueBubbles server setup.
4. If the Gateway is not running on the Messages Mac, set `channels.imessage.cliPath` to an SSH wrapper and set `remoteHost` for remote attachment fetches.
5. Enable `channels.imessage`, restart the Gateway, then run `openclaw channels status --probe --channel imessage`.
6. Test one DM, one allowed group, attachments if enabled, and every private API action you expect the agent to use.
7. Delete the BlueBubbles server and the old `channels.bluebubbles` config after the iMessage path is verified.
1. Install the official plugin with `openclaw plugins install @openclaw/imessage`, then restart the Gateway.
2. Verify `imsg` directly on the Mac that runs Messages.app (`imsg chats`, `imsg history`, `imsg send`, `imsg rpc --help`).
3. Copy behavior keys from `channels.bluebubbles` to `channels.imessage`: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `includeAttachments`, `attachmentRoots`, `mediaMaxMb`, `textChunkLimit`, and `actions`.
4. Drop transport keys that no longer exist: `serverUrl`, `password`, webhook URLs, and BlueBubbles server setup.
5. If the Gateway is not running on the Messages Mac, set `channels.imessage.cliPath` to an SSH wrapper and set `remoteHost` for remote attachment fetches.
6. Enable `channels.imessage`, restart the Gateway, then run `openclaw channels status --probe --channel imessage`.
7. Test one DM, one allowed group, attachments if enabled, and every private API action you expect the agent to use.
8. Delete the BlueBubbles server and the old `channels.bluebubbles` config after the iMessage path is verified.
## What imsg does
@@ -89,7 +90,7 @@ The shortest safe path when you already know your old BlueBubbles config:
iMessage and BlueBubbles share most channel-level behavior keys. What changes is transport (REST server vs local CLI) and the group registry key format.
| BlueBubbles | bundled iMessage | Notes |
| BlueBubbles | iMessage plugin | Notes |
| ---------------------------------------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channels.bluebubbles.enabled` | `channels.imessage.enabled` | Same semantics (default `true` once the block exists). |
| `channels.bluebubbles.serverUrl` | _(removed)_ | No REST server — the plugin spawns `imsg rpc` over stdio. |
@@ -102,7 +103,7 @@ iMessage and BlueBubbles share most channel-level behavior keys. What changes is
| `channels.bluebubbles.groupPolicy` | `channels.imessage.groupPolicy` | Same values (`allowlist` / `open` / `disabled`); default `allowlist`. |
| `channels.bluebubbles.groupAllowFrom` | `channels.imessage.groupAllowFrom` | Same. When unset, iMessage falls back to `allowFrom`; an explicitly empty `groupAllowFrom: []` blocks all groups under `groupPolicy: "allowlist"`. |
| `channels.bluebubbles.groups` | `channels.imessage.groups` | Copy the `"*"` wildcard entry verbatim; re-key per-group entries by numeric iMessage `chat_id` — see "Group registry footgun". `requireMention`, `tools`, `toolsBySender`, `systemPrompt` carry over. |
| `channels.bluebubbles.sendReadReceipts` | `channels.imessage.sendReadReceipts` | Default `true`. With the bundled plugin this only fires when the private API probe is up. |
| `channels.bluebubbles.sendReadReceipts` | `channels.imessage.sendReadReceipts` | Default `true`. This only fires when the private API probe is up. |
| `channels.bluebubbles.includeAttachments` | `channels.imessage.includeAttachments` | Same shape, same off-by-default. If attachments flowed on BlueBubbles, set this explicitly — inbound photos/media are silently dropped (no `Inbound message` log line) until you do. |
| `channels.bluebubbles.attachmentRoots` | `channels.imessage.attachmentRoots` | Local roots; same wildcard rules. |
| _(N/A)_ | `channels.imessage.remoteAttachmentRoots` | Only used when `remoteHost` is set for SCP fetches. |
@@ -116,7 +117,7 @@ Multi-account configs (`channels.bluebubbles.accounts.*`) translate one-to-one t
## Group registry footgun
The bundled iMessage plugin runs two group gates back to back. A group message must pass both to reach the agent:
The iMessage plugin runs two group gates back to back. A group message must pass both to reach the agent:
1. **Sender / chat-target allowlist** (`channels.imessage.groupAllowFrom`) — matches the sender handle or the chat target (`chat_id:`, `chat_guid:`, `chat_identifier:` entries). When `groupAllowFrom` is unset, this gate falls back to `allowFrom`; an explicit `groupAllowFrom: []` disables that fallback and drops every group message under `groupPolicy: "allowlist"`.
2. **Group registry** (`channels.imessage.groups`) — keyed by numeric iMessage `chat_id`:
@@ -188,7 +189,7 @@ This admits the configured senders in any group. Add `groups` entries to scope a
## Action parity at a glance
| Action | legacy BlueBubbles | bundled iMessage |
| Action | legacy BlueBubbles | iMessage plugin |
| --------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------- |
| Send text / SMS fallback | ✅ | ✅ |
| Send media (photo, video, file, voice) | ✅ | ✅ |
+9 -1
View File
@@ -20,6 +20,14 @@ Status: native external CLI integration. The Gateway spawns `imsg rpc` and speak
For the common local setup, OpenClaw setup can offer a user-confirmed Homebrew install or update for `imsg` on the signed-in Messages Mac. Manual setup and SSH-wrapper topologies remain operator-managed: install or update `imsg` in the same user context that will run the Gateway or wrapper.
## Install the plugin
Install the official iMessage plugin on the Gateway host, then restart the Gateway:
```bash
openclaw plugins install @openclaw/imessage
```
<CardGroup cols={3}>
<Card title="Private API actions" icon="wand-sparkles" href="#private-api-actions">
Replies, tapbacks, effects, polls, attachments, and group management.
@@ -200,7 +208,7 @@ The helper-injection technique uses `imsg`'s own dylib to reach Messages private
<Warning>
**Disabling SIP is a real security tradeoff.** SIP is one of macOS's core protections against running modified system code; turning it off system-wide opens up additional attack surface and side effects. Notably, **disabling SIP on Apple Silicon Macs also disables the ability to install and run iOS apps on your Mac**.
Treat this as a deliberate operational choice, especially on a primary personal Mac. For production-quality OpenClaw iMessage, prefer a dedicated Mac or bot macOS user where you are comfortable enabling the bridge. If your threat model cannot tolerate SIP being off anywhere, bundled iMessage is limited to basic mode — text and media send/receive only, no reactions / edit / unsend / effects / group ops.
Treat this as a deliberate operational choice, especially on a primary personal Mac. For production-quality OpenClaw iMessage, prefer a dedicated Mac or bot macOS user where you are comfortable enabling the bridge. If your threat model cannot tolerate SIP being off anywhere, the iMessage plugin is limited to basic mode — text and media send/receive only, no reactions / edit / unsend / effects / group ops.
</Warning>
### Setup
+2 -2
View File
@@ -9,7 +9,7 @@ title: "Chat channels"
OpenClaw can talk to you on any chat app you already use. Each channel connects via the Gateway.
Text is supported everywhere; media and reactions vary by channel.
iMessage, Telegram, and the WebChat UI ship with the core install. Channels marked
Telegram and the WebChat UI ship with the core install. Channels marked
"official plugin" install with one command (`openclaw plugins install @openclaw/<id>`)
or on demand during `openclaw onboard` / `openclaw channels add`, then need a Gateway
restart. "External plugin" channels are maintained outside the OpenClaw repo.
@@ -20,7 +20,7 @@ restart. "External plugin" channels are maintained outside the OpenClaw repo.
- [Discord](/channels/discord) - Discord Bot API + Gateway; supports servers, channels, and DMs (official plugin).
- [Feishu](/channels/feishu) - Feishu/Lark bot via WebSocket (official plugin).
- [Google Chat](/channels/googlechat) - Google Chat API app via HTTP webhook (official plugin).
- [iMessage](/channels/imessage) - Included in core. Native macOS integration via the `imsg` bridge on a signed-in Mac (or SSH wrapper when the Gateway runs elsewhere), including private API actions for replies, tapbacks, effects, attachments, and group management.
- [iMessage](/channels/imessage) - Native macOS integration via the `imsg` bridge on a signed-in Mac (or SSH wrapper when the Gateway runs elsewhere), including private API actions for replies, tapbacks, effects, attachments, and group management (official plugin).
- [IRC](/channels/irc) - Classic IRC servers; channels + DMs with pairing/allowlist controls (official plugin).
- [LINE](/channels/line) - LINE Messaging API bot (official plugin).
- [Matrix](/channels/matrix) - Matrix protocol (official plugin).
+2 -2
View File
@@ -32,10 +32,10 @@ title: "Features"
**Channels:**
- iMessage, Telegram, and WebChat ship with the core install; every other channel is an
- Telegram and WebChat ship with the core install; every other channel is an
official plugin installed with `openclaw plugins install @openclaw/<id>` (or on demand
during `openclaw onboard` / `openclaw channels add`)
- Official plugin channels: Discord, Feishu, Google Chat, IRC, LINE, Matrix, Mattermost,
- Official plugin channels: Discord, Feishu, Google Chat, iMessage, IRC, LINE, Matrix, Mattermost,
Microsoft Teams, Nextcloud Talk, Nostr, QQ Bot, Raft, Signal, Slack, SMS, Synology Chat,
Tlon, Twitch, Voice Call, WhatsApp, Zalo, and Zalo Personal
- External plugin channels maintained outside the OpenClaw repo: WeChat, Yuanbao, and Zalo ClawBot
+1
View File
@@ -524,6 +524,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- Route: /channels/imessage
- Headings:
- H2: Install the plugin
- H2: Quick setup
- H2: Requirements and permissions (macOS)
- H2: Enabling the imsg private API
+1 -1
View File
@@ -13,7 +13,7 @@ For agents, tools, gateway runtime, and other top-level keys, see [Configuration
## Channels
Each channel starts automatically when its config section exists (unless `enabled: false`). Telegram and iMessage ship inside the core `openclaw` package. Other official channels (Discord, Slack, WhatsApp, Matrix, Microsoft Teams, IRC, Google Chat, Signal, Mattermost, and more) install as separate plugins with `openclaw plugins install <spec>`; see [Channels](/channels) for the full list and install specs.
Each channel starts automatically when its config section exists (unless `enabled: false`). Telegram ships inside the core `openclaw` package. Other official channels (iMessage, Discord, Slack, WhatsApp, Matrix, Microsoft Teams, IRC, Google Chat, Signal, Mattermost, and more) install as separate plugins with `openclaw plugins install <spec>`; see [Channels](/channels) for the full list and install specs.
### DM and group access
+1 -1
View File
@@ -32,7 +32,7 @@ Dedicated deep references:
## Channels
Per-channel config keys live in [Configuration - channels](/gateway/config-channels): `channels.*` for Slack, Discord, Telegram, WhatsApp, Matrix, iMessage, and other bundled channels (auth, access control, multi-account, mention gating).
Per-channel config keys live in [Configuration - channels](/gateway/config-channels): `channels.*` for Slack, Discord, Telegram, WhatsApp, Matrix, iMessage, and other channel plugins (auth, access control, multi-account, mention gating).
## Agent defaults, multi-agent, sessions, and messages
+1 -1
View File
@@ -39,7 +39,7 @@ health commands above for live connectivity checks.
- `channels.<provider>.healthMonitor.enabled`: disable health-monitor restarts for a specific channel while leaving global monitoring enabled.
- `channels.<provider>.accounts.<accountId>.healthMonitor.enabled`: multi-account override that wins over the channel-level setting.
- These per-channel overrides apply to the built-in channels that expose them today: Discord, Google Chat, iMessage, IRC, Microsoft Teams, Signal, Slack, Telegram, and WhatsApp.
- These per-channel overrides apply to the channels that expose them today: Discord, Google Chat, iMessage, IRC, Microsoft Teams, Signal, Slack, Telegram, and WhatsApp.
- A crashing channel is recovered by its own auto-restart backoff first (`auto-restart attempt N/10` in the logs). The health monitor stays out of the way until that ladder ends with `giving up after 10 restart attempts`, then takes over as the last restart owner.
## Inbound ingress health
+4 -4
View File
@@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
## Core npm package
55 plugins
54 plugins
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
@@ -93,8 +93,6 @@ Each entry lists the package, distribution route, and description.
- **[huggingface](/plugins/reference/huggingface)** (`@openclaw/huggingface-provider`) - included in OpenClaw. Adds Hugging Face model provider support to OpenClaw.
- **[imessage](/plugins/reference/imessage)** (`@openclaw/imessage`) - included in OpenClaw. Adds the iMessage channel surface for sending and receiving OpenClaw messages.
- **[linux-canvas](/plugins/reference/linux-canvas)** (`@openclaw/linux-canvas`) - included in OpenClaw. Canvas rendering bridge for the OpenClaw Linux desktop app.
- **[linux-node](/plugins/reference/linux-node)** (`@openclaw/linux-node`) - included in OpenClaw. Desktop notifications, camera capture, and location for Linux node hosts.
@@ -165,7 +163,7 @@ Each entry lists the package, distribution route, and description.
## Official external packages
90 plugins
91 plugins
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
@@ -239,6 +237,8 @@ Each entry lists the package, distribution route, and description.
- **[groq](/plugins/reference/groq)** (`@openclaw/groq-provider`) - npm; ClawHub: `clawhub:@openclaw/groq-provider`. Adds Groq model provider support to OpenClaw.
- **[imessage](/plugins/reference/imessage)** (`@openclaw/imessage`) - npm; ClawHub: `clawhub:@openclaw/imessage`. Adds the iMessage channel surface for sending and receiving OpenClaw messages.
- **[inworld](/plugins/reference/inworld)** (`@openclaw/inworld-speech`) - npm; ClawHub: `clawhub:@openclaw/inworld-speech`. Inworld streaming text-to-speech (MP3, OGG_OPUS, PCM telephony).
- **[irc](/plugins/reference/irc)** (`@openclaw/irc`) - npm; ClawHub: `clawhub:@openclaw/irc`. Adds the IRC channel surface for sending and receiving OpenClaw messages.
+1 -1
View File
@@ -12,7 +12,7 @@ Adds the iMessage channel surface for sending and receiving OpenClaw messages.
## Distribution
- Package: `@openclaw/imessage`
- Install route: included in OpenClaw
- Install route: npm; ClawHub: `clawhub:@openclaw/imessage`
## Surface
+29
View File
@@ -0,0 +1,29 @@
# @openclaw/imessage
Official iMessage channel plugin for OpenClaw, using `imsg` on a signed-in Mac.
The plugin supports iMessage and SMS DMs and groups, media, replies, tapbacks,
effects, polls, and group management when the `imsg` private API bridge is
available.
## Install
```bash
openclaw plugins install @openclaw/imessage
```
Restart the Gateway after installing or updating the plugin.
## Configure
Follow the iMessage guide for installing `imsg`, granting macOS permissions,
enabling private API actions, and configuring local or remote-Mac operation:
- https://docs.openclaw.ai/channels/imessage
## Package
- Plugin id: `imessage`
- Channel id: `imessage`
- Package: `@openclaw/imessage`
- Minimum OpenClaw host: `2026.7.2`
+27 -3
View File
@@ -1,15 +1,27 @@
{
"name": "@openclaw/imessage",
"version": "2026.7.2",
"private": true,
"description": "OpenClaw iMessage channel plugin using imsg on a signed-in Mac",
"repository": {
"type": "git",
"url": "https://github.com/openclaw/openclaw"
},
"type": "module",
"dependencies": {
"typebox": "1.3.6",
"zod": "4.4.3"
},
"devDependencies": {
"@openclaw/plugin-sdk": "workspace:*"
"@openclaw/plugin-sdk": "workspace:*",
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.7.2"
},
"peerDependenciesMeta": {
"openclaw": {
"optional": true
}
},
"openclaw": {
"extensions": [
@@ -61,11 +73,23 @@
]
}
},
"install": {
"clawhubSpec": "clawhub:@openclaw/imessage",
"npmSpec": "@openclaw/imessage",
"defaultChoice": "npm",
"minHostVersion": ">=2026.7.2",
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.7.2"
},
"build": {
"openclawVersion": "2026.7.2"
"openclawVersion": "2026.7.2",
"bundledDist": false
},
"release": {
"publishToClawHub": true,
"publishToNpm": true
}
},
"pluginInspector": {
+1
View File
@@ -276,6 +276,7 @@
"!dist/extensions/gradium/**",
"!dist/extensions/groq/**",
"!dist/extensions/inworld/**",
"!dist/extensions/imessage/**",
"!dist/extensions/irc/**",
"!dist/extensions/kilocode/**",
"!dist/extensions/kimi-coding/**",
+3
View File
@@ -1037,6 +1037,9 @@ importers:
'@openclaw/plugin-sdk':
specifier: workspace:*
version: link:../../packages/plugin-sdk
openclaw:
specifier: workspace:*
version: link:../..
extensions/inworld:
devDependencies:
@@ -3,7 +3,6 @@
"dist/extensions/canvas/runtime-api.js",
"dist/extensions/copilot-proxy/runtime-api.js",
"dist/extensions/google/runtime-api.js",
"dist/extensions/imessage/runtime-api.js",
"dist/extensions/lmstudio/runtime-api.js",
"dist/extensions/memory-core/runtime-api.js",
"dist/extensions/ollama/runtime-api.js",
@@ -309,6 +309,50 @@
}
}
},
{
"name": "@openclaw/imessage",
"description": "OpenClaw iMessage channel plugin using imsg on a signed-in Mac",
"source": "official",
"kind": "channel",
"openclaw": {
"channel": {
"id": "imessage",
"label": "iMessage",
"selectionLabel": "iMessage (imsg)",
"detailLabel": "iMessage",
"docsPath": "/channels/imessage",
"docsLabel": "imessage",
"blurb": "Local iMessage/SMS through the imsg bridge, including private API message actions when enabled.",
"aliases": ["imsg"],
"systemImage": "message.fill",
"cliAddOptions": [
{
"flags": "--cli-path <path>",
"description": "iMessage CLI path"
},
{
"flags": "--db-path <path>",
"description": "iMessage database path"
},
{
"flags": "--service <service>",
"description": "iMessage service"
},
{
"flags": "--region <region>",
"description": "SMS region"
}
]
},
"install": {
"clawhubSpec": "clawhub:@openclaw/imessage",
"npmSpec": "@openclaw/imessage",
"defaultChoice": "npm",
"minHostVersion": ">=2026.7.2",
"allowInvalidConfigRecovery": true
}
}
},
{
"name": "@openclaw/irc",
"description": "OpenClaw IRC channel plugin",
+33
View File
@@ -245,6 +245,39 @@ describe("listPersistedBundledPluginLocationBridges", () => {
]);
});
it("externalizes the shipped bundled iMessage channel while preserving default enablement", async () => {
readPersistedInstalledPluginIndexMock.mockResolvedValue(
makeIndex({
pluginId: "imessage",
manifestPath: "/app/dist/extensions/imessage/openclaw.plugin.json",
manifestHash: "hash",
source: "/app/dist/extensions/imessage/index.js",
rootDir: "/app/dist/extensions/imessage",
origin: "bundled",
enabled: true,
enabledByDefault: true,
startup: startupInfo,
compat: [],
packageInstall: {
warnings: [],
},
}),
);
loadPluginManifestRegistryForInstalledIndexMock.mockReturnValue(makeRegistry("imessage"));
await expect(listPersistedBundledPluginLocationBridges({})).resolves.toEqual([
{
bundledPluginId: "imessage",
pluginId: "imessage",
preferredSource: "npm",
npmSpec: "@openclaw/imessage",
clawhubSpec: "clawhub:@openclaw/imessage",
enabledByDefault: true,
channelIds: ["imessage"],
},
]);
});
it("does not create a relocation bridge without persisted or official install metadata", async () => {
readPersistedInstalledPluginIndexMock.mockResolvedValue(
makeIndex({
@@ -2226,6 +2226,25 @@ describe("official external plugin catalog", () => {
).toEqual(["novita"]);
});
it("lists iMessage as an official external channel", () => {
const imessage = expectCatalogEntry("imessage");
const channel = getOfficialExternalPluginCatalogManifest(imessage)?.channel;
expect(resolveOfficialExternalPluginId(imessage)).toBe("imessage");
expect(channel).toMatchObject({
id: "imessage",
aliases: ["imsg"],
docsPath: "/channels/imessage",
});
expect(resolveOfficialExternalPluginInstall(imessage)).toEqual({
clawhubSpec: "clawhub:@openclaw/imessage",
npmSpec: "@openclaw/imessage",
defaultChoice: "npm",
minHostVersion: ">=2026.7.2",
allowInvalidConfigRecovery: true,
});
});
it.each([
["teams-meetings", "@openclaw/teams-meetings", "teams_meetings", "teams"],
["zoom-meetings", "@openclaw/zoom-meetings", "zoom_meetings", "zoom"],
+23
View File
@@ -247,6 +247,29 @@ describe("buildOfficialChannelCatalog", () => {
expect(installSource.warnings).toEqual(["npm-spec-floating", "npm-spec-missing-integrity"]);
});
it("keeps iMessage available for cold install after core package externalization", () => {
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-imessage-");
const imessage = buildOfficialChannelCatalog({ repoRoot }).entries.find(
(entry) => entry.openclaw?.channel?.id === "imessage",
);
expect({
name: imessage?.name,
aliases: imessage?.openclaw?.channel?.aliases,
install: imessage?.openclaw?.install,
}).toEqual({
name: "@openclaw/imessage",
aliases: ["imsg"],
install: {
clawhubSpec: "clawhub:@openclaw/imessage",
npmSpec: "@openclaw/imessage",
defaultChoice: "npm",
minHostVersion: ">=2026.7.2",
allowInvalidConfigRecovery: true,
},
});
});
it("preserves ClawHub specs when generating publishable channel catalog entries", () => {
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-clawhub-");
writeJson(path.join(repoRoot, "extensions", "storepack-chat", "package.json"), {
@@ -414,6 +414,14 @@ describe("bundled plugin build entries", () => {
expect(artifacts).not.toContain("dist/extensions/volcengine/package.json");
});
it("excludes the externalized iMessage channel from bundled artifacts", () => {
const entries = listBundledPluginBuildEntries();
const artifacts = listBundledPluginPackArtifacts();
expectNoPrefixMatches(Object.keys(entries), "extensions/imessage/");
expectNoPrefixMatches(artifacts, "dist/extensions/imessage/");
});
it("keeps bundled channel secret contracts on packed top-level sidecars", () => {
const artifacts = listBundledPluginPackArtifacts();
const excludedPackageDirs = collectRootPackageExcludedExtensionDirs();