cmux-imessage: send to a chat through Messages.app (opt-in mirror, library step)
Leo's ask: "i mean like obviously we already are in an imessage type zone im saying like actual imessage chats with contacts/group chats" ... "hm. could we mirror it?"
This is the sending half of the opt-in Messages mirror, at the library level. It adds cmux_imessage::send to the crate from #32891. Nothing calls it yet: the daemon op and the composer come in a follow-up, behind the same off-by-default imessage.enabled setting, and every send needs a user gesture.
What it does
send(&SendRequest { chat_guid, text }, &SystemRunner)runsosascriptwith a fixed script:tell application "Messages" to send messageText to chat id chatGuid.- The chat guid and the text reach the script only as
argvitems and are never spliced into its source, so a message can't change what the script does. A test sends a hostile string and checks that it arrives verbatim. - Validation: refuses empty text, text over 20,000 bytes and NUL bytes. A chat guid must be
service;-;idorservice;+;id, with no control characters and no leading-, so osascript never reads it as an option. - Errors map to stable codes:
- AppleScript
-1743(Automation of Messages not allowed) becomesnot_permitted. -1728(no such chat) becomesinvalid_chat.- No osascript becomes
unsupported. - A send that runs past 2 minutes becomes
timed_out. - Anything else becomes
failed.
- AppleScript
- Stop condition and cleanup: the child is waited on, and on timeout it is killed and reaped. Nothing is left running.
Nothing leaves the Mac except the message Leo sends through his own Messages.app.
Tests
Two commits: the failing tests against stubs (5 of 5 red), then the implementation (5 of 5 green, the reader's 10 still green, clippy -D warnings clean on Linux CI). They use a fake runner, so no Messages.app or osascript is needed.
Agent session: agent session
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds cmux_imessage::send, the sending half of the opt-in Messages mirror at the library level. Nothing calls it yet; the daemon op and composer follow in a later PR, behind the same off-by-default imessage.enabled setting, and every send needs a user gesture.
Security and validation
- The chat guid and text reach a fixed AppleScript only as
argvitems, never spliced into its source, so a hostile message can't change what the script does. - Refuses empty text, text over 20,000 bytes, and NUL bytes; chat guids must match
service;-;idorservice;+;idwith no control characters and no leading-. - AppleScript
-1743(Automation not allowed) maps tonot_permitted,-1728(no such chat) toinvalid_chat, missing osascript tounsupported, a two-minute overrun totimed_out, and anything else tofailed.
Tests
- Tests use a fake runner, so no Messages.app or osascript is needed, and cover the hostile-string case, validation, one osascript call per send, and error-code mapping.