All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.4.0 - 2026-05-09
- Matrix transport via
matrix-bot-sdk— works with Element X, Element Web, FluffyChat, any Matrix client. Auto-joins rooms, group chat support with mention detection, optional E2EE (Rust SDK crypto store). Set"encryption": falsein thematrixconfig to disable E2EE (thanks @jchidley) hideToolCallsconfig option,/msg-bridge toggletoolspi command, and matching/toggletoolsDM admin command — trusted users can hide/show tool call summaries in their replies from either side- Empty-message guard in all transports (Discord, Telegram, Slack, WhatsApp, Matrix) to prevent provider errors on whitespace-only payloads
- Tool call summaries now wrap the tool name in inline-code backticks (
🔧 \hud_canvas` (...)`), rendering as code across all 5 transports and avoiding Telegram's underscore-escape backslashes leaking into messages - Migrated peer dependencies from deprecated
@mariozechner/pi-{ai,coding-agent,tui}to@earendil-works/pi-{ai,coding-agent,tui}(>=0.74). The@mariozechnerpackages were deprecated upstream with the message "please use @earendil-works/pi-coding-agent instead going forward" - Tightened peer constraints from
*to>=0.74and removed the duplicated entries from devDependencies (npm auto-installs peers in dev) - Bumped devDependency floors:
@biomejs/biome^2.4.14,@types/node^25.6.2,typescript^6.0.3,vitest^4.1.5
sendUserMessagecrash when a remote message arrives mid-turn — messages are now queued via{ deliverAs: "followUp" }so each remote message gets its own turn after the current one finishes, instead of being interleaved into it (fixes #10)pendingRemoteChatno longer cleared on tool-call-only turns, so the next response reaches the right chat- Whitespace-only assistant responses no longer trigger Discord's "Cannot send an empty message" error
- Telegram MarkdownV1 parse errors on stray special chars (e.g. snake_case tool names like
hud_canvastriggering400 Bad Request: can't parse entities).formatForTelegramnow lifts valid markdown patterns into sentinel placeholders, escapes literal `_*[``, then restores
- Interactive menu (
/msg-bridgewith no args) — configure, connect, widget, help viaui.select() - Single-instance connection guard to prevent duplicate polling / 409 conflicts (fixes #2)
- Layer 1: global flag for same-process re-entrant calls (sub-agents)
- Layer 2: PID lock file (
~/.pi/msg-bridge.lock) for cross-process duplicates
- Session shutdown handler — releases lock and disconnects transports on exit
- Lock check on
/msg-bridge configureconnect calls to prevent bypassing the guard - Test suite (vitest): config, lock, and formatting modules
- CI workflow (GitHub Actions: lint + typecheck + test)
- Biome linter configuration
- Discord DM messages not received — added required
Partials.ChannelandPartials.Messageto client options (fixes #5, thanks @chr15m) - Transport errors now show clean messages instead of full stack traces
- Extracted
config.ts,lock.ts,formatting.ts,ui/main-menu.tsfrom index.ts - Moved
@mariozechner/pi-*packages to peerDependencies - Updated devDependencies: typescript ^6.0.2, @types/node ^25.3.0, @biomejs/biome ^2.4.8, vitest ^4.1.1
prepublishOnlynow runs lint and typecheck before build- Applied
npm audit fixfor transitive dependency vulnerabilities
- Package renamed from
pi-msg-bridgetopi-messenger-bridgefor better clarity - Updated all repository URLs and documentation to reflect new package name
- Command remains
/msg-bridgefor brevity and ease of use
- WhatsApp integration via Baileys library with QR code authentication
- Slack integration with Socket Mode support
- Discord integration with Message Content intent support
- Debug mode for troubleshooting (config.debug or MSG_BRIDGE_DEBUG env var)
- Non-blocking async transport initialization for faster startup
- Widget toggle command (
/msg-bridge widget) - Help command with full command reference
- Automatic invalid session cleanup (WhatsApp 401 handling)
- Session detection to prevent QR spam on startup
- Renamed from "remote-pilot" to "msg-bridge" throughout codebase
- Command changed from
/remoteto/msg-bridge - Config file moved from
~/.pi/msg-bridge/config.jsonto~/.pi/msg-bridge.json - WhatsApp auth directory:
~/.pi/msg-bridge-whatsapp-auth/ - All debug output now behind debug flag (no spam by default)
- Status widget only shows connected transports
- Environment variables now override config file settings
- Config file permissions enforced: chmod 600 for files, 700 for directories
- Config directory permissions validated on startup with warnings
- WhatsApp auth directory created with secure permissions (700)
- Invalid WhatsApp sessions automatically cleared on 401 errors
- QR code display for WhatsApp (using qrcode-terminal instead of Baileys built-in)
- Tool call formatting now shows actual parameters instead of speculation
- Username extraction from WhatsApp messages
- Connection state tracking for accurate widget display
- Startup performance (transports load in background)
- Added: @whiskeysockets/baileys, qrcode-terminal, @slack/bolt, discord.js
- Known vulnerabilities in transitive dependencies (node-telegram-bot-api, discord.js) - low impact for this use case
0.1.0 - 2026-02-10
- Initial MVP release
- Event-driven architecture using
pi.sendUserMessage()andturn_endevents - Telegram bot integration with polling support
- Challenge-based authentication (6-digit codes)
- Trusted user management
- Admin commands for user and channel management
- Status widget showing connection status
- Commands:
/remote,/remote connect,/remote disconnect,/remote configure - Environment variable and file-based configuration
- Support for group chats with mention detection
- Channel authorization modes: all, mentions, trusted-only
- 6-digit challenge codes with 2-minute expiry
- 3-attempt limit with 5-minute blocking
- First authenticated user becomes admin
- Trusted user validation on all messages