Prefer BlueBubbles for iMessage; add BlueBubbles iMessage skill

This commit is contained in:
Tyler Yust
2026-01-29 04:20:52 -08:00
parent 4583f88626
commit 79130efcb3
17 changed files with 287 additions and 40 deletions

View File

@@ -17,7 +17,7 @@
</p>
**Moltbot** is a *personal AI assistant* you run on your own devices.
It answers you on the channels you already use (WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, Microsoft Teams, WebChat), plus extension channels like BlueBubbles, Matrix, Zalo, and Zalo Personal. It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant.
It answers you on the channels you already use (WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, Microsoft Teams, WebChat), plus extension channels like Matrix, Zalo, and Zalo Personal. For iMessage, **BlueBubbles is recommended** (the legacy `imsg` integration is still supported but deprecated for new setups). It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant.
If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.
@@ -66,7 +66,7 @@ moltbot gateway --port 18789 --verbose
# Send a message
moltbot message send --to +1234567890 --message "Hello from Moltbot"
# Talk to the assistant (optionally deliver back to any connected channel: WhatsApp/Telegram/Slack/Discord/Google Chat/Signal/iMessage/BlueBubbles/Microsoft Teams/Matrix/Zalo/Zalo Personal/WebChat)
# Talk to the assistant (optionally deliver back to any connected channel: WhatsApp/Telegram/Slack/Discord/Google Chat/Signal/iMessage (BlueBubbles)/Microsoft Teams/Matrix/Zalo/Zalo Personal/WebChat)
moltbot agent --message "Ship checklist" --thinking high
```
@@ -139,7 +139,7 @@ Run `moltbot doctor` to surface risky/misconfigured DM policies.
- [Media pipeline](https://docs.molt.bot/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.molt.bot/nodes/audio).
### Channels
- [Channels](https://docs.molt.bot/channels): [WhatsApp](https://docs.molt.bot/channels/whatsapp) (Baileys), [Telegram](https://docs.molt.bot/channels/telegram) (grammY), [Slack](https://docs.molt.bot/channels/slack) (Bolt), [Discord](https://docs.molt.bot/channels/discord) (discord.js), [Google Chat](https://docs.molt.bot/channels/googlechat) (Chat API), [Signal](https://docs.molt.bot/channels/signal) (signal-cli), [iMessage](https://docs.molt.bot/channels/imessage) (imsg), [BlueBubbles](https://docs.molt.bot/channels/bluebubbles) (extension), [Microsoft Teams](https://docs.molt.bot/channels/msteams) (extension), [Matrix](https://docs.molt.bot/channels/matrix) (extension), [Zalo](https://docs.molt.bot/channels/zalo) (extension), [Zalo Personal](https://docs.molt.bot/channels/zalouser) (extension), [WebChat](https://docs.molt.bot/web/webchat).
- [Channels](https://docs.molt.bot/channels): [WhatsApp](https://docs.molt.bot/channels/whatsapp) (Baileys), [Telegram](https://docs.molt.bot/channels/telegram) (grammY), [Slack](https://docs.molt.bot/channels/slack) (Bolt), [Discord](https://docs.molt.bot/channels/discord) (discord.js), [Google Chat](https://docs.molt.bot/channels/googlechat) (Chat API), [Signal](https://docs.molt.bot/channels/signal) (signal-cli), [iMessage](https://docs.molt.bot/channels/bluebubbles) (BlueBubbles, recommended), [iMessage (legacy)](https://docs.molt.bot/channels/imessage) (imsg), [Microsoft Teams](https://docs.molt.bot/channels/msteams) (extension), [Matrix](https://docs.molt.bot/channels/matrix) (extension), [Zalo](https://docs.molt.bot/channels/zalo) (extension), [Zalo Personal](https://docs.molt.bot/channels/zalouser) (extension), [WebChat](https://docs.molt.bot/web/webchat).
- [Group routing](https://docs.molt.bot/concepts/group-messages): mention gating, reply tags, per-channel chunking and routing. Channel rules: [Channels](https://docs.molt.bot/channels).
### Apps + nodes
@@ -170,7 +170,7 @@ Run `moltbot doctor` to surface risky/misconfigured DM policies.
## How it works (short)
```
WhatsApp / Telegram / Slack / Discord / Google Chat / Signal / iMessage / BlueBubbles / Microsoft Teams / Matrix / Zalo / Zalo Personal / WebChat
WhatsApp / Telegram / Slack / Discord / Google Chat / Signal / iMessage (BlueBubbles) / iMessage (legacy imsg) / Microsoft Teams / Matrix / Zalo / Zalo Personal / WebChat
┌───────────────────────────────┐

View File

@@ -5,9 +5,9 @@ read_when:
- Troubleshooting webhook pairing
- Configuring iMessage on macOS
---
# BlueBubbles (macOS REST)
# iMessage (BlueBubbles)
Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **Recommended for iMessage integration** due to its richer API and easier setup compared to the legacy imsg channel.
Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **Recommended iMessage integration** due to its richer API and easier setup compared to the legacy imsg channel.
## Overview
- Runs on macOS via the BlueBubbles helper app ([bluebubbles.app](https://bluebubbles.app)).
@@ -38,6 +38,74 @@ Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **R
4. Point BlueBubbles webhooks to your gateway (example: `https://your-gateway-host:3000/bluebubbles-webhook?password=<password>`).
5. Start the gateway; it will register the webhook handler and start pairing.
## Keep BlueBubbles running (recommended)
If the BlueBubbles Server app quits or the Mac sleeps, iMessage delivery, webhooks, and advanced actions will stop.
### Prevent sleep
On macOS (especially VMs), ensure the machine stays awake:
- One-time: `caffeinate -dims`
- Permanent: configure your VM/host power settings (or a LaunchAgent that runs `caffeinate`).
### launchd keepalive (re-open BlueBubbles every 5 minutes)
This LaunchAgent periodically re-opens BlueBubbles + Messages in the background.
1) Create a script at `~/.clawdbot/scripts/keepalive-bluebubbles.sh`:
```bash
#!/usr/bin/env bash
set -euo pipefail
# App names vary across builds; try both.
open -gj -a "BlueBubbles" || open -gj -a "BlueBubbles Server" || true
open -gj -a "Messages" || true
```
2) Make it executable:
```bash
chmod +x ~/.clawdbot/scripts/keepalive-bluebubbles.sh
```
3) Create a LaunchAgent at `~/Library/LaunchAgents/com.moltbot.bluebubbles.keepalive.plist`:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.moltbot.bluebubbles.keepalive</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-lc</string>
<string>~/.clawdbot/scripts/keepalive-bluebubbles.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<!-- IMPORTANT: 300 seconds (5 minutes), not 600 -->
<key>StartInterval</key>
<integer>300</integer>
<key>StandardOutPath</key>
<string>/tmp/com.moltbot.bluebubbles.keepalive.out</string>
<key>StandardErrorPath</key>
<string>/tmp/com.moltbot.bluebubbles.keepalive.err</string>
</dict>
</plist>
```
4) Load it:
```bash
launchctl load -w ~/Library/LaunchAgents/com.moltbot.bluebubbles.keepalive.plist
launchctl list | rg bluebubbles
```
## Onboarding
BlueBubbles is available in the interactive setup wizard:
```

View File

@@ -1,11 +1,12 @@
---
summary: "iMessage support via imsg (JSON-RPC over stdio), setup, and chat_id routing"
summary: "Legacy iMessage support via imsg (JSON-RPC over stdio). Deprecated for new setups; prefer BlueBubbles."
read_when:
- Setting up iMessage support
- Debugging iMessage send/receive
---
# iMessage (imsg)
# iMessage (legacy: imsg)
> **Deprecated for new setups.** Prefer **[iMessage (BlueBubbles)](/channels/bluebubbles)**.
Status: external CLI integration. Gateway spawns `imsg rpc` (JSON-RPC over stdio).

View File

@@ -18,8 +18,8 @@ Text is supported everywhere; media and reactions vary by channel.
- [Google Chat](/channels/googlechat) — Google Chat API app via HTTP webhook.
- [Mattermost](/channels/mattermost) — Bot API + WebSocket; channels, groups, DMs (plugin, installed separately).
- [Signal](/channels/signal) — signal-cli; privacy-focused.
- [BlueBubbles](/channels/bluebubbles) — **Recommended for iMessage**; uses the BlueBubbles macOS server REST API with full feature support (edit, unsend, effects, reactions, group management — edit currently broken on macOS 26 Tahoe).
- [iMessage](/channels/imessage) — macOS only; native integration via imsg (legacy, consider BlueBubbles for new setups).
- [iMessage (BlueBubbles)](/channels/bluebubbles) — **Recommended**; uses the BlueBubbles macOS server REST API with full feature support (edit, unsend, effects, reactions, group management — edit currently broken on macOS 26 Tahoe).
- [iMessage (legacy: imsg)](/channels/imessage) — macOS only; native integration via imsg (deprecated for new setups).
- [Microsoft Teams](/channels/msteams) — Bot Framework; enterprise support (plugin, installed separately).
- [LINE](/channels/line) — LINE Messaging API bot (plugin, installed separately).
- [Nextcloud Talk](/channels/nextcloud-talk) — Self-hosted chat via Nextcloud Talk (plugin, installed separately).

View File

@@ -1313,7 +1313,9 @@ Reaction notification modes:
- `all`: all reactions on all messages.
- `allowlist`: reactions from `channels.signal.reactionAllowlist` on all messages (empty list disables).
### `channels.imessage` (imsg CLI)
### `channels.imessage` (legacy: imsg CLI)
**Deprecated for new setups.** Prefer **iMessage (BlueBubbles)**: [/channels/bluebubbles](/channels/bluebubbles).
Moltbot spawns `imsg rpc` (JSON-RPC over stdio). No daemon or port required.

View File

@@ -24,7 +24,7 @@ read_when:
<a href="/start/clawd">Moltbot assistant setup</a>
</p>
Moltbot bridges WhatsApp (via WhatsApp Web / Baileys), Telegram (Bot API / grammY), Discord (Bot API / channels.discord.js), and iMessage (imsg CLI) to coding agents like [Pi](https://github.com/badlogic/pi-mono). Plugins add Mattermost (Bot API + WebSocket) and more.
Moltbot bridges WhatsApp (via WhatsApp Web / Baileys), Telegram (Bot API / grammY), Discord (Bot API / channels.discord.js), and iMessage (BlueBubbles recommended; imsg legacy) to coding agents like [Pi](https://github.com/badlogic/pi-mono). Plugins add Mattermost (Bot API + WebSocket) and more.
Moltbot also powers [Clawd](https://clawd.me), the spacelobster assistant.
## Start here
@@ -81,7 +81,8 @@ Most operations flow through the **Gateway** (`moltbot gateway`), a single long-
- ✈️ **Telegram Bot** — DMs + groups via grammY
- 🎮 **Discord Bot** — DMs + guild channels via channels.discord.js
- 🧩 **Mattermost Bot (plugin)** — Bot token + WebSocket events
- 💬 **iMessage**Local imsg CLI integration (macOS)
- 💬 **iMessage**BlueBubbles macOS server integration (recommended)
- 💬 **iMessage (legacy)** — Local imsg CLI integration (macOS)
- 🤖 **Agent bridge** — Pi (RPC mode) with tool streaming
- ⏱️ **Streaming + chunking** — Block streaming + Telegram draft streaming details ([/concepts/streaming](/concepts/streaming))
- 🧠 **Multi-agent routing** — Route provider accounts/peers to isolated agents (workspace + per-agent sessions)

View File

@@ -89,7 +89,8 @@ git commit -m "Add Clawd workspace"
- **camsnap** — Capture frames, clips, or motion alerts from RTSP/ONVIF security cams.
- **oracle** — OpenAI-ready agent CLI with session replay and browser control.
- **eightctl** — Control your sleep, from the terminal.
- **imsg** — Send, read, stream iMessage & SMS.
- **imessage-bluebubbles** — iMessage via BlueBubbles (recommended): history/search/send/attachments.
- **imsg** — (legacy) Send, read, stream iMessage & SMS via imsg CLI.
- **wacli** — WhatsApp CLI: sync, search, send.
- **discord** — Discord actions: react, stickers, polls. Use `user:<id>` or `channel:<id>` targets (bare numeric ids are ambiguous).
- **gog** — Google Suite CLI: Gmail, Calendar, Drive, Contacts.

View File

@@ -11,9 +11,13 @@ It does not define which tools exist; Moltbot provides built-in tools internally
## Examples
### imsg
- Send an iMessage/SMS: describe who/what, confirm before sending.
- Prefer short messages; avoid sending secrets.
### iMessage (BlueBubbles)
- Preferred iMessage integration. Confirm before sending.
- If you need history/search: use the BlueBubbles REST API (chat/query, message/query).
### imsg (legacy)
- Legacy iMessage/SMS integration on macOS. Deprecated for new setups.
- Confirm before sending; avoid sending secrets.
### sag
- Text-to-speech: specify voice, target speaker/room, and whether to stream.

View File

@@ -123,7 +123,7 @@ Tip: `--json` does **not** imply non-interactive mode. Use `--non-interactive` (
- Google Chat: service account JSON + webhook audience.
- Mattermost (plugin): bot token + base URL.
- Signal: optional `signal-cli` install + account config.
- iMessage: local `imsg` CLI path + DB access.
- iMessage: BlueBubbles server URL + password (recommended) or legacy local `imsg` CLI path + DB access.
- DM security: default is pairing. First DM sends a code; approve via `moltbot pairing approve <channel> <code>` or use allowlists.
6) **Daemon install**

View File

@@ -9,12 +9,12 @@
],
"channel": {
"id": "bluebubbles",
"label": "BlueBubbles",
"selectionLabel": "BlueBubbles (macOS app)",
"detailLabel": "BlueBubbles",
"label": "iMessage (BlueBubbles)",
"selectionLabel": "iMessage (BlueBubbles \u2014 recommended)",
"detailLabel": "iMessage (BlueBubbles)",
"docsPath": "/channels/bluebubbles",
"docsLabel": "bluebubbles",
"blurb": "iMessage via the BlueBubbles mac app + REST API.",
"blurb": "recommended iMessage integration via the BlueBubbles macOS server + REST API.",
"aliases": [
"bb"
],
@@ -22,7 +22,10 @@
"imessage"
],
"systemImage": "bubble.left.and.text.bubble.right",
"order": 75
"order": 75,
"selectionExtras": [
"https://bluebubbles.app"
]
},
"install": {
"npmSpec": "@moltbot/bluebubbles",

View File

@@ -38,14 +38,15 @@ import { sendBlueBubblesMedia } from "./media-send.js";
const meta = {
id: "bluebubbles",
label: "BlueBubbles",
selectionLabel: "BlueBubbles (macOS app)",
detailLabel: "BlueBubbles",
label: "iMessage (BlueBubbles)",
selectionLabel: "iMessage (BlueBubbles — recommended)",
detailLabel: "iMessage (BlueBubbles)",
docsPath: "/channels/bluebubbles",
docsLabel: "bluebubbles",
blurb: "iMessage via the BlueBubbles mac app + REST API.",
blurb: "recommended iMessage integration via the BlueBubbles macOS server + REST API.",
systemImage: "bubble.left.and.text.bubble.right",
aliases: ["bb"],
selectionExtras: ["https://bluebubbles.app"],
order: 75,
preferOver: ["imessage"],
};

View File

@@ -0,0 +1,124 @@
---
name: imessage-bluebubbles
description: iMessage via BlueBubbles REST API (list chats, query history/search, send text + attachments).
homepage: https://bluebubbles.app
metadata: {"moltbot":{"emoji":"💬","requires":{"bins":["curl","jq"]}}}
---
# iMessage (BlueBubbles)
Use the **BlueBubbles Server** REST API to query iMessage chats/messages and send messages/attachments.
This is the recommended iMessage integration for Moltbot.
Requirements
- A macOS host running **BlueBubbles Server**
- BlueBubbles REST API enabled + password set
- Network access from this host to the BlueBubbles Server
Environment variables (recommended)
```bash
export BLUEBUBBLES_SERVER_URL="http://mac-mini.lan:1234"
export BLUEBUBBLES_PASSWORD="..."
```
Quick checks
- Ping:
```bash
curl -s "$BLUEBUBBLES_SERVER_URL/api/v1/ping?password=$BLUEBUBBLES_PASSWORD" | jq
```
Common commands
## List chats (with last message)
```bash
curl -sS \
-X POST "$BLUEBUBBLES_SERVER_URL/api/v1/chat/query?password=$BLUEBUBBLES_PASSWORD" \
-H 'Content-Type: application/json' \
--data '{
"limit": 50,
"offset": 0,
"with": ["lastMessage", "chat.participants"],
"sort": "lastmessage"
}' | jq
```
## Query message history (by chatGuid)
```bash
CHAT_GUID='iMessage;-;+15555550123'
curl -sS \
-X POST "$BLUEBUBBLES_SERVER_URL/api/v1/message/query?password=$BLUEBUBBLES_PASSWORD" \
-H 'Content-Type: application/json' \
--data "$(jq -n --arg chatGuid "$CHAT_GUID" '{
limit: 25,
offset: 0,
chatGuid: $chatGuid,
with: ["chat", "chat.participants", "attachment", "handle", "sms"],
sort: "DESC"
}')" | jq
```
## Search messages (SQL where clause)
BlueBubbles supports server-side filtering via `where` clauses.
Example: search for an exact text match:
```bash
curl -sS \
-X POST "$BLUEBUBBLES_SERVER_URL/api/v1/message/query?password=$BLUEBUBBLES_PASSWORD" \
-H 'Content-Type: application/json' \
--data '{
"limit": 25,
"offset": 0,
"with": ["chat", "handle"],
"where": [{
"statement": "message.text = :text",
"args": {"text": "Kara and Mimi"}
}],
"sort": "DESC"
}' | jq
```
## Send a text message
Note: prefer using Moltbot's `message` tool when available (it automatically resolves targets and threads).
```bash
CHAT_GUID='iMessage;-;+15555550123'
curl -sS \
-X POST "$BLUEBUBBLES_SERVER_URL/api/v1/message/text?password=$BLUEBUBBLES_PASSWORD" \
-H 'Content-Type: application/json' \
--data "$(jq -n --arg chatGuid "$CHAT_GUID" --arg message "hi" '{
chatGuid: $chatGuid,
tempGuid: "temp-" + (now|tostring),
message: $message
}')" | jq
```
## Send an attachment
```bash
CHAT_GUID='iMessage;-;+15555550123'
FILE_PATH='/path/to/pic.jpg'
curl -sS \
-X POST "$BLUEBUBBLES_SERVER_URL/api/v1/message/attachment?password=$BLUEBUBBLES_PASSWORD" \
-F "attachment=@${FILE_PATH}" \
-F "chatGuid=${CHAT_GUID}" \
-F "name=$(basename "$FILE_PATH")" \
-F "tempGuid=temp-$(date +%s)" \
-F "method=private-api" | jq
```
## Download an attachment
```bash
ATTACHMENT_GUID='att-123'
curl -L \
"$BLUEBUBBLES_SERVER_URL/api/v1/attachment/$ATTACHMENT_GUID/download?password=$BLUEBUBBLES_PASSWORD" \
-o ./download.bin
```
Watch / streaming
- BlueBubbles supports **webhooks** for realtime events.
- In Moltbot, realtime inbound iMessage is handled by the **BlueBubbles channel plugin** (configure `channels.bluebubbles.webhookPath` and point BlueBubbles webhooks at the gateway).
Notes
- Confirm recipient + message before sending.
- Many advanced actions (reactions/edit/unsend/effects/group management) require BlueBubbles **Private API**.

View File

@@ -1,11 +1,13 @@
---
name: imsg
description: iMessage/SMS CLI for listing chats, history, watch, and sending.
description: (Deprecated) iMessage/SMS via imsg CLI (legacy). Use BlueBubbles for new setups.
homepage: https://imsg.to
metadata: {"moltbot":{"emoji":"📨","os":["darwin"],"requires":{"bins":["imsg"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/imsg","bins":["imsg"],"label":"Install imsg (brew)"}]}}
---
# imsg
# imsg (legacy)
**Deprecated for new setups.** Prefer **iMessage (BlueBubbles)** for the Moltbot iMessage integration.
Use `imsg` to read and send Messages.app iMessage/SMS on macOS.

View File

@@ -86,6 +86,7 @@ async function promptIMessageAllowFrom(params: {
const existing = resolved.config.allowFrom ?? [];
await params.prompter.note(
[
"Legacy iMessage integration via imsg (deprecated). New setups: use BlueBubbles.",
"Allowlist iMessage DMs by handle or chat target.",
"Examples:",
"- +15555550123",
@@ -93,7 +94,7 @@ async function promptIMessageAllowFrom(params: {
"- chat_id:123",
"- chat_guid:... or chat_identifier:...",
"Multiple entries: comma-separated.",
`Docs: ${formatDocsLink("/imessage", "imessage")}`,
`Docs: ${formatDocsLink("/channels/imessage", "imessage")}`,
].join("\n"),
"iMessage allowlist",
);
@@ -239,11 +240,13 @@ export const imessageOnboardingAdapter: ChannelOnboardingAdapter = {
await prompter.note(
[
"This is still a work in progress.",
"Legacy iMessage integration via imsg (deprecated).",
"New setups: use BlueBubbles instead.",
"Ensure Moltbot has Full Disk Access to Messages DB.",
"Grant Automation permission for Messages when prompted.",
"List chats with: imsg chats --limit 20",
`Docs: ${formatDocsLink("/imessage", "imessage")}`,
`Docs (legacy): ${formatDocsLink("/channels/imessage", "imessage")}`,
`Docs (recommended): ${formatDocsLink("/channels/bluebubbles", "bluebubbles")}`,
].join("\n"),
"iMessage next steps",
);

View File

@@ -91,11 +91,11 @@ const CHAT_CHANNEL_META: Record<ChatChannelId, ChannelMeta> = {
imessage: {
id: "imessage",
label: "iMessage",
selectionLabel: "iMessage (imsg)",
detailLabel: "iMessage",
selectionLabel: "iMessage (legacy: imsg)",
detailLabel: "iMessage (legacy)",
docsPath: "/channels/imessage",
docsLabel: "imessage",
blurb: "this is still a work in progress.",
blurb: "legacy iMessage integration via imsg CLI (deprecated; prefer BlueBubbles).",
systemImage: "message.fill",
},
};

View File

@@ -385,6 +385,41 @@ export async function setupChannels(
};
});
const reorderEntriesByPreferOver = <T extends { id: ChannelChoice; meta: ChannelMeta }>(
entries: T[],
): T[] => {
const resolved = [...entries];
// Prefer-over ordering is a lightweight partial ordering used to make recommended
// providers show up before legacy ones (for example BlueBubbles over imessage).
for (let pass = 0; pass < 25; pass += 1) {
const indexById = new Map<string, number>();
for (let i = 0; i < resolved.length; i += 1) {
indexById.set(String(resolved[i]?.meta?.id ?? resolved[i]?.id), i);
}
let changed = false;
for (const entry of resolved) {
const preferOver = entry.meta.preferOver ?? [];
if (!Array.isArray(preferOver) || preferOver.length === 0) continue;
const entryKey = String(entry.meta.id ?? entry.id);
const entryIndex = indexById.get(entryKey);
if (entryIndex === undefined) continue;
for (const otherId of preferOver) {
const otherKey = String(otherId);
const otherIndex = indexById.get(otherKey);
if (otherIndex === undefined) continue;
if (entryIndex > otherIndex) {
resolved.splice(entryIndex, 1);
resolved.splice(otherIndex, 0, entry);
changed = true;
break;
}
}
if (changed) break;
}
if (!changed) break;
}
return resolved;
};
const getChannelEntries = () => {
const core = listChatChannels();
const installed = listChannelPlugins();
@@ -405,10 +440,12 @@ export async function setupChannels(
metaById.set(entry.id, entry.meta);
}
}
const entries = Array.from(metaById, ([id, meta]) => ({
id: id as ChannelChoice,
meta,
}));
const entries = reorderEntriesByPreferOver(
Array.from(metaById, ([id, meta]) => ({
id: id as ChannelChoice,
meta,
})),
);
return {
entries,
catalog,

View File

@@ -31,7 +31,7 @@ export const createIMessageTestPlugin = (params?: {
meta: {
id: "imessage",
label: "iMessage",
selectionLabel: "iMessage (imsg)",
selectionLabel: "iMessage (legacy: imsg)",
docsPath: "/channels/imessage",
blurb: "iMessage test stub.",
aliases: ["imsg"],