opencode-plugin-boops 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,18 +4,28 @@ Sound notifications for OpenCode - plays pleasant "boop" sounds when tasks compl
4
4
 
5
5
  ## Features
6
6
 
7
- - 🎵 Pleasant glass chime when AI completes a response
8
- - 📡 Sonar ping when AI needs your permission or input
9
- - 🔄 Automatic fallback to alternative sounds if preferred sounds aren't available
7
+ - 🎵 Soft, friendly notification sounds when AI completes tasks
8
+ - 📡 Gentle alert when AI needs your permission or input
9
+ - 🌐 Works out of the box with online sounds (auto-downloaded and cached)
10
+ - 🔄 Fully configurable - use URLs or local files
10
11
  - 🐧 Works on Linux (with `paplay` or `aplay`)
11
- - 🍎 Works on macOS (requires custom sound configuration)
12
+ - 🍎 Works on macOS (with `afplay`)
12
13
 
13
14
  ## Installation
14
15
 
15
- ### Using OpenCode config
16
+ Add to your OpenCode config file:
16
17
 
17
- Add to your `opencode.json` or `~/.config/opencode/opencode.json`:
18
+ **Global installation** (recommended):
19
+ ```bash
20
+ # Edit ~/.config/opencode/opencode.json
21
+ ```
22
+
23
+ **Per-project installation**:
24
+ ```bash
25
+ # Edit opencode.json in your project root
26
+ ```
18
27
 
28
+ Add the plugin to the config:
19
29
  ```json
20
30
  {
21
31
  "$schema": "https://opencode.ai/config.json",
@@ -23,51 +33,239 @@ Add to your `opencode.json` or `~/.config/opencode/opencode.json`:
23
33
  }
24
34
  ```
25
35
 
26
- ### Manual installation
36
+ Then restart OpenCode. The plugin will be automatically downloaded and installed from npm.
27
37
 
28
- Place the plugin file in your OpenCode plugins directory:
38
+ ### Quick setup
39
+
40
+ If you don't have an OpenCode config yet:
29
41
 
30
42
  ```bash
31
- # Global
32
- mkdir -p ~/.config/opencode/plugins
33
- cp index.ts ~/.config/opencode/plugins/boops.ts
43
+ # Create global config
44
+ mkdir -p ~/.config/opencode
45
+ echo '{"$schema":"https://opencode.ai/config.json","plugin":["opencode-plugin-boops"]}' > ~/.config/opencode/opencode.json
46
+ ```
47
+
48
+ Or for a specific project:
34
49
 
35
- # Per-project
36
- mkdir -p .opencode/plugins
37
- cp index.ts .opencode/plugins/boops.ts
50
+ ```bash
51
+ # In your project directory
52
+ echo '{"$schema":"https://opencode.ai/config.json","plugin":["opencode-plugin-boops"]}' > opencode.json
38
53
  ```
39
54
 
40
55
  ## How it works
41
56
 
42
- The plugin listens to OpenCode events:
57
+ The plugin listens to OpenCode events and plays sounds based on your configuration. By default, it uses online sounds that are automatically downloaded and cached:
58
+
59
+ - **`session.idle`** - AI finishes responding → soft "pristine" notification
60
+ - **`permission.asked`** - AI needs permission → gentle "relax" chime
61
+ - **`session.error`** - An error occurs → friendly "magic" alert
62
+
63
+ Sounds are downloaded once on first use and cached in `~/.cache/opencode/boops/` for instant playback.
64
+
65
+ ## Configuration
66
+
67
+ The plugin uses a TOML configuration file located at `~/.config/opencode/boops.toml`.
68
+
69
+ ### Create your config
70
+
71
+ Copy the default configuration:
72
+
73
+ ```bash
74
+ # Get the default config template
75
+ curl -o ~/.config/opencode/boops.toml https://raw.githubusercontent.com/towc/opencode-plugin-boops/main/boops.default.toml
76
+ ```
77
+
78
+ Or create it manually:
79
+
80
+ ```toml
81
+ # ~/.config/opencode/boops.toml
82
+
83
+ [sounds]
84
+ # Simple: Use notificationsounds.com IDs (recommended)
85
+ "session.idle" = "1150-pristine"
86
+ "permission.asked" = "1217-relax"
87
+ "session.error" = "1219-magic"
88
+
89
+ # Or search by name (finds first match):
90
+ # "session.idle" = "pristine"
91
+
92
+ # Or use full URLs:
93
+ # "session.idle" = "https://example.com/sound.ogg"
94
+
95
+ # Or use local file paths:
96
+ # "session.idle" = "/usr/share/sounds/gnome/default/alerts/drip.ogg"
97
+ ```
98
+
99
+ ### Sound sources
100
+
101
+ The plugin supports multiple ways to specify sounds:
102
+
103
+ **1. notificationsounds.com IDs (easiest):**
104
+ ```toml
105
+ "session.idle" = "1150-pristine" # Direct ID (fast)
106
+ "session.idle" = "pristine" # Search by name (slower, first match)
107
+ ```
108
+
109
+ Browse sounds at [notificationsounds.com](https://notificationsounds.com/notification-sounds) to find IDs.
110
+
111
+ **2. Full URLs:**
112
+ ```toml
113
+ "session.idle" = "https://example.com/sound.ogg"
114
+ ```
115
+
116
+ **3. Local file paths:**
117
+ ```toml
118
+ "session.idle" = "/usr/share/sounds/gnome/default/alerts/drip.ogg"
119
+ ```
120
+
121
+ **Caching:** Remote sounds (IDs and URLs) are cached in `~/.cache/opencode/boops/` by event name (e.g. `session-idle`, `permission-asked`). Once downloaded, they're reused instantly. If you change a sound, the cache is automatically updated on next play.
122
+
123
+ ### Available events
124
+
125
+ You can configure sounds for any of the 28 OpenCode events:
126
+
127
+ **Session events (8):**
128
+ - `session.idle` - AI completes response
129
+ - `session.error` - Error occurs
130
+ - `session.created` - New session starts
131
+ - `session.deleted` - Session deleted
132
+ - `session.compacted` - Session compacted
133
+ - `session.diff` - Session diff generated
134
+ - `session.status` - Session status changed
135
+ - `session.updated` - Session updated
136
+
137
+ **Permission events (2):**
138
+ - `permission.asked` - AI needs permission
139
+ - `permission.replied` - Permission response given
140
+
141
+ **File events (2):**
142
+ - `file.edited` - File is edited
143
+ - `file.watcher.updated` - File watcher detects change
43
144
 
44
- - **`session.idle`** - Fires when the AI finishes responding → plays completion sound (glass.ogg)
45
- - **`permission.asked`** - Fires when the AI needs permission → plays attention sound (sonar.ogg)
145
+ **Tool events (2):**
146
+ - `tool.execute.before` - Before tool execution
147
+ - `tool.execute.after` - After tool execution
46
148
 
47
- ## Customization
149
+ **Message events (4):**
150
+ - `message.part.removed` - Message part removed
151
+ - `message.part.updated` - Message part updated
152
+ - `message.removed` - Message removed
153
+ - `message.updated` - Message updated
48
154
 
49
- ### Custom sounds
155
+ **LSP events (2):**
156
+ - `lsp.client.diagnostics` - LSP diagnostics received
157
+ - `lsp.updated` - LSP server updated
50
158
 
51
- To use your own sounds, modify the sound file paths in `index.ts`:
159
+ **TUI events (3):**
160
+ - `tui.prompt.append` - Text appended to prompt
161
+ - `tui.command.execute` - TUI command executed
162
+ - `tui.toast.show` - Toast notification shown
52
163
 
53
- ```typescript
54
- const inputSound = '/path/to/your/input-sound.ogg'
55
- const completeSound = '/path/to/your/complete-sound.ogg'
164
+ **Other events (5):**
165
+ - `command.executed` - Command executed
166
+ - `todo.updated` - Todo list updated
167
+ - `installation.updated` - Installation/package updated
168
+ - `server.connected` - Connected to server
169
+
170
+ See the [default config](boops.default.toml) for the complete list with descriptions.
171
+
172
+ ### Event filters
173
+
174
+ For advanced use cases, you can add filters to play sounds only when certain conditions match. This is useful for events that fire frequently or in different contexts.
175
+
176
+ **Example: Only play sound for main session, not subagents:**
177
+
178
+ ```toml
179
+ [sounds.session.idle]
180
+ sound = "https://notificationsounds.com/storage/sounds/file-sounds-1150-pristine.ogg"
181
+ not_if = { agent = "explore" } # Skip subagent completions
182
+ ```
183
+
184
+ **How to find available properties:**
185
+
186
+ 1. Check OpenCode logs when the event fires:
187
+ ```bash
188
+ tail -f ~/.local/share/opencode/log/*.log | grep "session.idle event"
189
+ ```
190
+
191
+ 2. The logs will show all event properties you can filter on
192
+
193
+ **Filter syntax:**
194
+
195
+ ```toml
196
+ [sounds.event-name]
197
+ sound = "/path/to/sound"
198
+ only_if = { property = "value" } # Only play if property equals value
199
+ not_if = { property = "value" } # Don't play if property equals value
200
+ ```
201
+
202
+ ### Testing sounds
203
+
204
+ You can test sounds without restarting OpenCode using the custom tool:
205
+
206
+ ```bash
207
+ # Test a configured event (reloads config automatically)
208
+ test-sound session.idle
209
+
210
+ # Test a sound ID directly
211
+ test-sound pristine
212
+ test-sound 1150-pristine
213
+
214
+ # Test a URL directly
215
+ test-sound https://example.com/sound.ogg
216
+
217
+ # Test a local file directly
218
+ test-sound /usr/share/sounds/alert.ogg
219
+ ```
220
+
221
+ This is helpful when:
222
+ - Configuring new sounds
223
+ - Trying different sound files before committing to config
224
+ - Testing event filters
225
+ - Verifying URLs/IDs work
226
+
227
+ The test command automatically reloads your config file, so you can edit `boops.toml` and test immediately!
228
+
229
+ ### Browse sounds interactively
230
+
231
+ The plugin includes a beautiful TUI for browsing and assigning sounds:
232
+
233
+ ```bash
234
+ # If plugin is installed
235
+ ~/.config/opencode/plugins/boops/browse
236
+
237
+ # Or try it with npx (browse-only, saving disabled)
238
+ npx opencode-plugin-boops browse
56
239
  ```
57
240
 
58
- ### macOS
241
+ Features:
242
+ - 🎨 Browse 448 sounds with tags and descriptions
243
+ - 🏷️ Filter by tags (music, bell, quiet, etc.)
244
+ - 🔍 Search by name
245
+ - 🎵 Preview sounds before assigning
246
+ - ⚡ Assign sounds to OpenCode events (if plugin installed)
247
+ - 🖱️ Full mouse support with hover effects
248
+ - ⌨️ Keyboard navigation
249
+
250
+ **Note**: When running via `npx`, you can browse and preview sounds, but saving assignments requires the plugin to be installed.
59
251
 
60
- On macOS, you can use system sounds:
252
+ ### Custom sound player
61
253
 
62
- ```typescript
63
- const inputSound = '/System/Library/Sounds/Ping.aiff'
64
- const completeSound = '/System/Library/Sounds/Glass.aiff'
254
+ By default, the plugin auto-detects `paplay` (PulseAudio), `aplay` (ALSA), or `afplay` (macOS). You can override this:
255
+
256
+ ```toml
257
+ player = "afplay" # Force specific player
65
258
  ```
66
259
 
67
- And update the `playSound` function to use `afplay`:
260
+ ### macOS example
261
+
262
+ ```toml
263
+ player = "afplay"
68
264
 
69
- ```typescript
70
- await Bun.$`afplay ${primaryFile}`.quiet()
265
+ [sounds]
266
+ "session.idle" = "/System/Library/Sounds/Glass.aiff"
267
+ "permission.asked" = "/System/Library/Sounds/Ping.aiff"
268
+ "session.error" = "/System/Library/Sounds/Basso.aiff"
71
269
  ```
72
270
 
73
271
  ## Requirements
@@ -75,28 +273,40 @@ await Bun.$`afplay ${primaryFile}`.quiet()
75
273
  - OpenCode 1.0+
76
274
  - Linux: `paplay` (PulseAudio) or `aplay` (ALSA)
77
275
  - macOS: `afplay` (built-in)
78
- - Sound files at specified paths (or system sounds)
276
+ - Internet connection (only for initial sound download)
79
277
 
80
278
  ## Troubleshooting
81
279
 
82
280
  ### No sound playing
83
281
 
84
- 1. Check if sound files exist:
282
+ 1. **Use the test command first:**
85
283
  ```bash
86
- ls /usr/share/sounds/gnome/default/alerts/glass.ogg
87
- ls /usr/share/sounds/gnome/default/alerts/sonar.ogg
284
+ test-sound event="session.idle"
88
285
  ```
89
286
 
90
- 2. Test sound manually:
287
+ 2. **Check if sound player is installed:**
91
288
  ```bash
92
- paplay /usr/share/sounds/gnome/default/alerts/glass.ogg
289
+ which paplay # Linux (PulseAudio)
290
+ which aplay # Linux (ALSA)
291
+ which afplay # macOS
93
292
  ```
94
293
 
95
- 3. Check OpenCode logs:
294
+ 3. **Check OpenCode logs:**
96
295
  ```bash
97
296
  tail -f ~/.local/share/opencode/log/*.log | grep boops
98
297
  ```
99
298
 
299
+ 4. **Check cached sounds:**
300
+ ```bash
301
+ ls -la ~/.cache/opencode/boops/
302
+ ```
303
+
304
+ 5. **Clear cache and re-download:**
305
+ ```bash
306
+ rm -rf ~/.cache/opencode/boops/
307
+ # Then use test-sound to re-download
308
+ ```
309
+
100
310
  ### Sounds too loud/quiet
101
311
 
102
312
  Adjust your system volume or use different sound files.
@@ -109,6 +319,10 @@ Contributions welcome! Feel free to:
109
319
  - Improve cross-platform compatibility
110
320
  - Add more event triggers
111
321
 
322
+ ## Credits
323
+
324
+ Sounds from [Notification Sounds](https://notificationsounds.com) - a wonderful collection of free notification sounds provided under Creative Commons Attribution license.
325
+
112
326
  ## License
113
327
 
114
328
  MIT
@@ -0,0 +1,71 @@
1
+ # OpenCode Boops Plugin Configuration
2
+ # Sounds can be local file paths OR URLs (automatically downloaded and cached)
3
+
4
+ # player = "paplay" # Auto-detected if not set (paplay/aplay/afplay)
5
+
6
+ [sounds]
7
+ "session.idle" = "1150-pristine" # AI completes response
8
+ "permission.asked" = "1217-relax" # AI needs permission
9
+ "session.error" = "1219-magic" # Error occurs
10
+
11
+ # You can use:
12
+ # - Sound IDs: "pristine" (searches notificationsounds.com)
13
+ # - Numeric IDs: "1150-pristine" (direct match, faster)
14
+ # - Full URLs: "https://example.com/sound.ogg"
15
+ # - Local paths: "/usr/share/sounds/..."
16
+
17
+ # Advanced: Event filters (play sound only when conditions match)
18
+ # Uncomment and adjust after checking logs to see available properties
19
+ # [sounds.session.idle]
20
+ # sound = "1150-pristine"
21
+ # not_if = { agent = "explore" } # Don't play for subagent completions
22
+
23
+ # Optional events (uncomment to enable):
24
+ # Command events
25
+ # "command.executed" = "/path/to/sound" # Command executed
26
+
27
+ # File events
28
+ # "file.edited" = "/path/to/sound" # File edited
29
+ # "file.watcher.updated" = "/path/to/sound" # File watcher detected change
30
+
31
+ # Installation events
32
+ # "installation.updated" = "/path/to/sound" # Installation/package updated
33
+
34
+ # LSP events
35
+ # "lsp.client.diagnostics" = "/path/to/sound" # LSP diagnostics received
36
+ # "lsp.updated" = "/path/to/sound" # LSP server updated
37
+
38
+ # Message events
39
+ # "message.part.removed" = "/path/to/sound" # Message part removed
40
+ # "message.part.updated" = "/path/to/sound" # Message part updated
41
+ # "message.removed" = "/path/to/sound" # Message removed
42
+ # "message.updated" = "/path/to/sound" # Message updated
43
+
44
+ # Permission events
45
+ # "permission.replied" = "/path/to/sound" # Permission response given
46
+
47
+ # Server events
48
+ # "server.connected" = "/path/to/sound" # Connected to server
49
+
50
+ # Session events
51
+ # "session.created" = "/path/to/sound" # New session created
52
+ # "session.compacted" = "/path/to/sound" # Session compacted
53
+ # "session.deleted" = "/path/to/sound" # Session deleted
54
+ # "session.diff" = "/path/to/sound" # Session diff generated
55
+ # "session.status" = "/path/to/sound" # Session status changed
56
+ # "session.updated" = "/path/to/sound" # Session updated
57
+
58
+ # Todo events
59
+ # "todo.updated" = "/path/to/sound" # Todo list updated
60
+
61
+ # Tool events
62
+ # "tool.execute.before" = "/path/to/sound" # Before tool execution
63
+ # "tool.execute.after" = "/path/to/sound" # After tool execution
64
+
65
+ # TUI events
66
+ # "tui.prompt.append" = "/path/to/sound" # Text appended to prompt
67
+ # "tui.command.execute" = "/path/to/sound" # TUI command executed
68
+ # "tui.toast.show" = "/path/to/sound" # Toast notification shown
69
+
70
+ [fallbacks]
71
+ # default = "/usr/share/sounds/alsa/Front_Center.wav" # Optional: local fallback if download fails