feat: cross-platform update notifications for OpenCode#53
Conversation
Add cross-platform notification support to the OpenCode plugin: - Parse reminder text for update availability - Show native OS notifications via osascript (macOS), notify-send (Linux), or PowerShell (Windows) when updates are available - Respect CYMBAL_NO_UPDATE_NOTIFIER environment variable - Track notified versions per session to prevent spam - Add comprehensive test suite with 14 tests
Add structured update notification payload command for agent plugins: - New 'cymbal hook notify' with --format=json|text and --update=cache|if-stale - Returns structured payload when update available and throttle allows - Calls updatecheck.MarkNotified after emitting payload - Add test seams for status, shouldNotify, and markNotified - Include comprehensive tests for JSON output, throttling, and opt-out
Update documentation for the new notification features: - AGENT_HOOKS.md: Document native OS notifications in OpenCode section - commands.md: Add cymbal hook notify command reference - README.md: Mention OS notifications in OpenCode install section - CHANGELOG.md: Add unreleased entry for notifications and hook notify
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 352354e645
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Two fixes from automated code review: 1. Use structured cymbal hook notify command instead of parsing reminder text, so OpenCode plugin respects the persistent 24h per-version throttle via updatecheck.ShouldNotify/MarkNotified. 2. Capture fmt.Fprintln errors in text mode before calling MarkNotified, preventing false 'already notified' state when stdout is closed or piped to a failing consumer. All tests pass. No breaking changes.
Phototonic
left a comment
There was a problem hiding this comment.
Addressed both Codex review comments in commit ecd5ddc:
-
Throttled notifications: The OpenCode plugin now uses cymbal hook notify --format=json --update=cache instead of parsing reminder text. This consults updatecheck.ShouldNotify and calls MarkNotified, honoring the persistent 24h per-version throttle across sessions.
-
Text output errors: fmt.Fprintln errors in text mode are now captured in writeErr before MarkNotified is called. If stdout is closed or piped to a failing consumer, the error is returned early and the version is not marked as notified.
All tests pass.
Summary
This PR adds cross-platform update notifications for the OpenCode plugin, ensuring users actually see when a new cymbal version is available regardless of whether they are using TUI or Desktop mode.
Problem
Currently, cymbal update notices are injected into the OpenCode system prompt via
output.system.push(text). This means:This was reported in #23 where agents ignore the "use cymbal first" prompt as context grows, but the same invisible-delivery problem applies to update notices.
Solution
Phase 1: Enhanced OpenCode Plugin
The plugin (
cmd/hook_assets/opencode/cymbal-opencode.js) now parses the reminder text for the "cymbal update:" block and spawns a native OS notification when an update is available:osascriptdisplaying a Notification Center notificationnotify-send(only when DISPLAY or WAYLAND_DISPLAY is present)Key features:
CYMBAL_NO_UPDATE_NOTIFIERenvironment variablestdio: "ignore"for fire-and-forget deliveryPhase 2: New
cymbal hook notifyCommandA new Go command provides structured update notification payloads for agent plugins:
Returns:
{ "notify": true, "latestVersion": "v0.14.0", "title": "cymbal v0.14.0 is available", "body": "Update: brew upgrade 1broseidon/tap/cymbal", "command": "brew upgrade 1broseidon/tap/cymbal", "releaseURL": "https://github.com/1broseidon/cymbal/releases/latest" }Or
{"notify": false}when no update is available or the user was already notified within the 24h throttle window.This gives plugins a structured alternative to parsing human-readable reminder text.
Files Changed
cmd/hook_assets/opencode/cymbal-opencode.jscmd/hook_assets/opencode/cymbal-opencode.test.mjscmd/hook.gohookNotifyCmdandemitHookNotify()cmd/hook_test.godocs/AGENT_HOOKS.mddocs/reference/commands.mdhook notifycommand referenceREADME.mdCHANGELOG.mdTesting
go test ./...passes (all packages)node --test cmd/hook_assets/opencode/cymbal-opencode.test.mjspasses (14/14)go build .succeedscymbal hook notify --helpshows correct usagecymbal hook notify --format=jsonreturns correct payloadCYMBAL_NO_UPDATE_NOTIFIER=1suppresses notificationsType of Change
Pre-flight Checklist