@mohak34/opencode-notifier 0.1.19 → 0.1.20-beta.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 +198 -195
- package/dist/index.js +63 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
OpenCode plugin that plays sounds and sends system notifications when permission is needed, generation completes, errors occur, or the question tool is invoked. Works on macOS, Linux, and Windows.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
Add
|
|
7
|
+
Add this to your `opencode.json`:
|
|
8
8
|
|
|
9
9
|
```json
|
|
10
10
|
{
|
|
@@ -12,99 +12,39 @@ Add the plugin to your `opencode.json` or `opencode.jsonc`:
|
|
|
12
12
|
}
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Restart OpenCode. Done.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## What it does
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
You'll get notified when:
|
|
20
|
+
- OpenCode needs permission to run something
|
|
21
|
+
- Your session finishes
|
|
22
|
+
- An error happens
|
|
23
|
+
- The question tool pops up
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
There's also `subagent_complete` for when subagents finish, but that's silent by default so you don't get spammed.
|
|
26
26
|
|
|
27
|
-
##
|
|
28
|
-
|
|
29
|
-
OpenCode caches plugins in `~/.cache/opencode`. Plugins are not auto-updated; you need to clear the cache to get new versions.
|
|
27
|
+
## Setup by platform
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
**macOS**: Nothing to do, works out of the box. Shows the Script Editor icon.
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
**Linux/macOS:**
|
|
31
|
+
**Linux**: Should work if you already have a notification system setup. If not install libnotify:
|
|
36
32
|
|
|
37
33
|
```bash
|
|
38
|
-
|
|
34
|
+
sudo apt install libnotify-bin # Ubuntu/Debian
|
|
35
|
+
sudo dnf install libnotify # Fedora
|
|
36
|
+
sudo pacman -S libnotify # Arch
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```powershell
|
|
44
|
-
Remove-Item -Recurse -Force "$env:USERPROFILE\.cache\opencode\node_modules\@mohak34\opencode-notifier"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Then restart OpenCode - it will download the latest version automatically.
|
|
48
|
-
|
|
49
|
-
### If you use a pinned version (e.g., `@0.1.14`)
|
|
50
|
-
|
|
51
|
-
1. Update the version in your `opencode.json`:
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"plugin": ["@mohak34/opencode-notifier@0.1.14"]
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
2. Clear the cache (see commands above)
|
|
60
|
-
|
|
61
|
-
3. Restart OpenCode
|
|
62
|
-
|
|
63
|
-
### Check installed version
|
|
64
|
-
|
|
65
|
-
**Linux/macOS:**
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
cat ~/.cache/opencode/node_modules/@mohak34/opencode-notifier/package.json | grep version
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
**Windows (PowerShell):**
|
|
72
|
-
|
|
73
|
-
```powershell
|
|
74
|
-
Get-Content "$env:USERPROFILE\.cache\opencode\node_modules\@mohak34\opencode-notifier\package.json" | Select-String "version"
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Platform Notes
|
|
78
|
-
|
|
79
|
-
The plugin works out of the box on all platforms. For best results:
|
|
80
|
-
|
|
81
|
-
- **macOS**: No additional setup required. Notifications display the Script Editor icon (custom icons not supported with osascript for reliability)
|
|
82
|
-
- **Windows**: No additional setup required. The OpenCode icon displays in notifications
|
|
83
|
-
- **Linux**: For sounds, one of these should be installed: `paplay`, `aplay`, `mpv`, or `ffplay`. For notifications, `notify-send` is recommended. The OpenCode icon displays in notifications
|
|
84
|
-
|
|
85
|
-
**Note**: To disable icons, set `showIcon: false` in your configuration.
|
|
86
|
-
|
|
87
|
-
### macOS: Choosing Your Notification System
|
|
88
|
-
|
|
89
|
-
On macOS, you can choose between two notification backends:
|
|
39
|
+
For sounds, you need one of: `paplay`, `aplay`, `mpv`, or `ffplay`
|
|
90
40
|
|
|
91
|
-
|
|
41
|
+
**Windows**: Works out of the box. But heads up:
|
|
42
|
+
- Only `.wav` files work (not mp3)
|
|
43
|
+
- Use full paths like `C:/Users/You/sounds/alert.wav` not `~/`
|
|
92
44
|
|
|
93
|
-
|
|
45
|
+
## Config file
|
|
94
46
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"notificationSystem": "node-notifier"
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
If you experience missing notifications with `node-notifier`, switch back to `osascript` (or remove the option to use the default).
|
|
104
|
-
|
|
105
|
-
## Configuration
|
|
106
|
-
|
|
107
|
-
To customize the plugin, create `~/.config/opencode/opencode-notifier.json`:
|
|
47
|
+
Create `~/.config/opencode/opencode-notifier.json` with the defaults:
|
|
108
48
|
|
|
109
49
|
```json
|
|
110
50
|
{
|
|
@@ -135,204 +75,267 @@ To customize the plugin, create `~/.config/opencode/opencode-notifier.json`:
|
|
|
135
75
|
"question": "Session has a question"
|
|
136
76
|
},
|
|
137
77
|
"sounds": {
|
|
138
|
-
"permission":
|
|
139
|
-
"complete":
|
|
140
|
-
"subagent_complete":
|
|
141
|
-
"error":
|
|
142
|
-
"question":
|
|
78
|
+
"permission": null,
|
|
79
|
+
"complete": null,
|
|
80
|
+
"subagent_complete": null,
|
|
81
|
+
"error": null,
|
|
82
|
+
"question": null
|
|
83
|
+
},
|
|
84
|
+
"volumes": {
|
|
85
|
+
"permission": 1,
|
|
86
|
+
"complete": 1,
|
|
87
|
+
"subagent_complete": 1,
|
|
88
|
+
"error": 1,
|
|
89
|
+
"question": 1
|
|
143
90
|
}
|
|
144
91
|
}
|
|
145
92
|
```
|
|
146
93
|
|
|
147
|
-
|
|
94
|
+
## All options
|
|
148
95
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
96
|
+
### Global options
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"sound": true,
|
|
101
|
+
"notification": true,
|
|
102
|
+
"timeout": 5,
|
|
103
|
+
"showProjectName": true,
|
|
104
|
+
"showIcon": true,
|
|
105
|
+
"notificationSystem": "osascript"
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- `sound` - Turn sounds on/off (default: true)
|
|
110
|
+
- `notification` - Turn notifications on/off (default: true)
|
|
111
|
+
- `timeout` - How long notifications show in seconds, Linux only (default: 5)
|
|
112
|
+
- `showProjectName` - Show folder name in notification title (default: true)
|
|
113
|
+
- `showIcon` - Show OpenCode icon, Windows/Linux only (default: true)
|
|
114
|
+
- `notificationSystem` - macOS only: `"osascript"` or `"node-notifier"` (default: "osascript")
|
|
158
115
|
|
|
159
116
|
### Events
|
|
160
117
|
|
|
161
|
-
Control
|
|
118
|
+
Control each event separately:
|
|
162
119
|
|
|
163
120
|
```json
|
|
164
121
|
{
|
|
165
122
|
"events": {
|
|
166
123
|
"permission": { "sound": true, "notification": true },
|
|
167
|
-
"complete": { "sound":
|
|
168
|
-
"subagent_complete": { "sound":
|
|
169
|
-
"error": { "sound": true, "notification":
|
|
124
|
+
"complete": { "sound": true, "notification": true },
|
|
125
|
+
"subagent_complete": { "sound": false, "notification": false },
|
|
126
|
+
"error": { "sound": true, "notification": true },
|
|
170
127
|
"question": { "sound": true, "notification": true }
|
|
171
128
|
}
|
|
172
129
|
}
|
|
173
130
|
```
|
|
174
131
|
|
|
175
|
-
Or use
|
|
132
|
+
Or use true/false for both:
|
|
176
133
|
|
|
177
134
|
```json
|
|
178
135
|
{
|
|
179
136
|
"events": {
|
|
180
|
-
"
|
|
181
|
-
"complete": false,
|
|
182
|
-
"subagent_complete": true,
|
|
183
|
-
"error": true,
|
|
184
|
-
"question": true
|
|
137
|
+
"complete": false
|
|
185
138
|
}
|
|
186
139
|
}
|
|
187
140
|
```
|
|
188
141
|
|
|
189
|
-
Note: `complete` fires for primary (main) session completion, while `subagent_complete` fires for subagent completion. `subagent_complete` defaults to disabled (both sound and notification are false).
|
|
190
|
-
|
|
191
142
|
### Messages
|
|
192
143
|
|
|
193
|
-
Customize notification text:
|
|
144
|
+
Customize the notification text:
|
|
194
145
|
|
|
195
146
|
```json
|
|
196
147
|
{
|
|
197
148
|
"messages": {
|
|
198
|
-
"permission": "
|
|
199
|
-
"complete": "
|
|
200
|
-
"subagent_complete": "Subagent
|
|
201
|
-
"error": "
|
|
202
|
-
"question": "
|
|
149
|
+
"permission": "Session needs permission",
|
|
150
|
+
"complete": "Session has finished",
|
|
151
|
+
"subagent_complete": "Subagent task completed",
|
|
152
|
+
"error": "Session encountered an error",
|
|
153
|
+
"question": "Session has a question"
|
|
203
154
|
}
|
|
204
155
|
}
|
|
205
156
|
```
|
|
206
157
|
|
|
207
|
-
###
|
|
208
|
-
|
|
209
|
-
Run a custom command when events fire. Use `{event}` and `{message}` tokens in `path` or `args` to inject the event name and message.
|
|
158
|
+
### Sounds
|
|
210
159
|
|
|
211
|
-
|
|
212
|
-
- Applies to all events for the custom command.
|
|
213
|
-
- If elapsed time is known and is below `minDuration`, the command is skipped.
|
|
214
|
-
- If elapsed time cannot be determined for an event, the command still runs.
|
|
160
|
+
Use your own sound files:
|
|
215
161
|
|
|
216
162
|
```json
|
|
217
163
|
{
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"
|
|
164
|
+
"sounds": {
|
|
165
|
+
"permission": "/path/to/alert.wav",
|
|
166
|
+
"complete": "/path/to/done.wav",
|
|
167
|
+
"subagent_complete": "/path/to/subagent-done.wav",
|
|
168
|
+
"error": "/path/to/error.wav",
|
|
169
|
+
"question": "/path/to/question.wav"
|
|
223
170
|
}
|
|
224
171
|
}
|
|
225
172
|
```
|
|
226
173
|
|
|
227
|
-
|
|
174
|
+
Platform notes:
|
|
175
|
+
- macOS/Linux: .wav or .mp3 files work
|
|
176
|
+
- Windows: Only .wav files work
|
|
177
|
+
- If file doesn't exist, falls back to bundled sound
|
|
228
178
|
|
|
229
|
-
|
|
179
|
+
### Volumes
|
|
180
|
+
|
|
181
|
+
Set per-event volume from `0` to `1`:
|
|
230
182
|
|
|
231
183
|
```json
|
|
232
184
|
{
|
|
233
|
-
"
|
|
234
|
-
"permission":
|
|
235
|
-
"complete":
|
|
236
|
-
"subagent_complete":
|
|
237
|
-
"error":
|
|
238
|
-
"question":
|
|
185
|
+
"volumes": {
|
|
186
|
+
"permission": 0.6,
|
|
187
|
+
"complete": 0.3,
|
|
188
|
+
"subagent_complete": 0.15,
|
|
189
|
+
"error": 1,
|
|
190
|
+
"question": 0.7
|
|
239
191
|
}
|
|
240
192
|
}
|
|
241
193
|
```
|
|
242
194
|
|
|
243
|
-
|
|
195
|
+
- `0` = mute, `1` = full volume
|
|
196
|
+
- Values outside `0..1` are clamped automatically
|
|
197
|
+
- On Windows, playback still works but custom volume may not be honored by the default player
|
|
244
198
|
|
|
245
|
-
###
|
|
199
|
+
### Custom commands
|
|
246
200
|
|
|
247
|
-
|
|
201
|
+
Run your own script when something happens. Use `{event}` and `{message}` as placeholders:
|
|
248
202
|
|
|
249
|
-
|
|
250
|
-
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"command": {
|
|
206
|
+
"enabled": true,
|
|
207
|
+
"path": "/path/to/your/script",
|
|
208
|
+
"args": ["{event}", "{message}"],
|
|
209
|
+
"minDuration": 10
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
- `enabled` - Turn command on/off
|
|
215
|
+
- `path` - Path to your script/executable
|
|
216
|
+
- `args` - Arguments to pass, can use `{event}` and `{message}` tokens
|
|
217
|
+
- `minDuration` - Skip if response was quick, avoids spam (seconds)
|
|
218
|
+
|
|
219
|
+
#### Example: Log events to a file
|
|
251
220
|
|
|
252
221
|
```json
|
|
253
222
|
{
|
|
254
|
-
"
|
|
255
|
-
"
|
|
256
|
-
"
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
},
|
|
262
|
-
"sounds": {
|
|
263
|
-
"complete": "/home/user/sounds/main-done.wav",
|
|
264
|
-
"subagent_complete": "/home/user/sounds/subagent-chime.wav"
|
|
223
|
+
"command": {
|
|
224
|
+
"enabled": true,
|
|
225
|
+
"path": "/bin/bash",
|
|
226
|
+
"args": [
|
|
227
|
+
"-c",
|
|
228
|
+
"echo '[{event}] {message}' >> /tmp/opencode.log"
|
|
229
|
+
]
|
|
265
230
|
}
|
|
266
231
|
}
|
|
267
232
|
```
|
|
268
233
|
|
|
269
|
-
##
|
|
234
|
+
## macOS: Pick your notification style
|
|
270
235
|
|
|
271
|
-
|
|
236
|
+
**osascript** (default): Reliable but shows Script Editor icon
|
|
272
237
|
|
|
273
|
-
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"notificationSystem": "osascript"
|
|
241
|
+
}
|
|
242
|
+
```
|
|
274
243
|
|
|
275
|
-
|
|
244
|
+
**node-notifier**: Shows OpenCode icon but might miss notifications sometimes
|
|
276
245
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"notificationSystem": "node-notifier"
|
|
249
|
+
}
|
|
250
|
+
```
|
|
281
251
|
|
|
282
|
-
|
|
252
|
+
**NOTE:** If you go with node-notifier and start missing notifications, just switch back or remove the option from the config. Users have reported issues with using node-notifier for receiving only sounds and no notification popups.
|
|
283
253
|
|
|
284
|
-
|
|
254
|
+
## Updating
|
|
285
255
|
|
|
286
|
-
|
|
287
|
-
# Debian/Ubuntu
|
|
288
|
-
sudo apt install libnotify-bin
|
|
256
|
+
If Opencode does not update the plugin or there is an issue with the cache version:
|
|
289
257
|
|
|
290
|
-
|
|
291
|
-
|
|
258
|
+
```bash
|
|
259
|
+
# Linux/macOS
|
|
260
|
+
rm -rf ~/.cache/opencode/node_modules/@mohak34/opencode-notifier
|
|
292
261
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
262
|
+
# Windows
|
|
263
|
+
Remove-Item -Recurse -Force "$env:USERPROFILE\.cache\opencode\node_modules\@mohak34\opencode-notifier"
|
|
264
|
+
```
|
|
296
265
|
|
|
297
|
-
|
|
266
|
+
Then restart OpenCode.
|
|
298
267
|
|
|
299
|
-
|
|
300
|
-
notify-send "Test" "Hello"
|
|
301
|
-
```
|
|
268
|
+
## Troubleshooting
|
|
302
269
|
|
|
303
|
-
|
|
270
|
+
**macOS: Not seeing notifications?**
|
|
271
|
+
Go to System Settings > Notifications > Script Editor, make sure it's set to Banners or Alerts.
|
|
304
272
|
|
|
305
|
-
|
|
273
|
+
**macOS: node-notifier not showing notifications?**
|
|
274
|
+
Switch back to osascript. Some users report node-notifier works for sounds but not visual notifications on certain macOS versions.
|
|
306
275
|
|
|
276
|
+
**Linux: No notifications?**
|
|
277
|
+
Install libnotify-bin:
|
|
307
278
|
```bash
|
|
308
|
-
# Debian/Ubuntu
|
|
309
|
-
sudo
|
|
310
|
-
|
|
311
|
-
# Or install mpv
|
|
312
|
-
sudo apt install mpv
|
|
279
|
+
sudo apt install libnotify-bin # Debian/Ubuntu
|
|
280
|
+
sudo dnf install libnotify # Fedora
|
|
281
|
+
sudo pacman -S libnotify # Arch
|
|
313
282
|
```
|
|
314
283
|
|
|
315
|
-
|
|
284
|
+
Test with: `notify-send "Test" "Hello"`
|
|
285
|
+
|
|
286
|
+
**Linux: No sounds?**
|
|
287
|
+
Install one of: `paplay`, `aplay`, `mpv`, or `ffplay`
|
|
316
288
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
289
|
+
**Windows: Custom sounds not working?**
|
|
290
|
+
- Must be .wav format (not .mp3)
|
|
291
|
+
- Use full Windows paths: `C:/Users/YourName/sounds/alert.wav` (not `~/`)
|
|
292
|
+
- Make sure the file actually plays in Windows Media Player
|
|
293
|
+
- If using WSL, the path should be accessible from Windows
|
|
294
|
+
|
|
295
|
+
**Windows WSL notifications not working?**
|
|
296
|
+
WSL doesn't have a native notification daemon. Use PowerShell commands instead:
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"notification": false,
|
|
301
|
+
"sound": true,
|
|
302
|
+
"command": {
|
|
303
|
+
"enabled": true,
|
|
304
|
+
"path": "powershell.exe",
|
|
305
|
+
"args": [
|
|
306
|
+
"-Command",
|
|
307
|
+
"$wshell = New-Object -ComObject Wscript.Shell; $wshell.Popup('{message}', 5, 'OpenCode - {event}', 0+64)"
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
320
312
|
|
|
321
|
-
|
|
313
|
+
**Windows: OpenCode crashes when notifications appear?**
|
|
314
|
+
This is a known Bun issue on Windows. Disable native notifications and use PowerShell popups:
|
|
322
315
|
|
|
323
|
-
|
|
316
|
+
```json
|
|
317
|
+
{
|
|
318
|
+
"notification": false,
|
|
319
|
+
"sound": true,
|
|
320
|
+
"command": {
|
|
321
|
+
"enabled": true,
|
|
322
|
+
"path": "powershell.exe",
|
|
323
|
+
"args": [
|
|
324
|
+
"-Command",
|
|
325
|
+
"$wshell = New-Object -ComObject Wscript.Shell; $wshell.Popup('{message}', 5, 'OpenCode - {event}', 0+64)"
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
324
330
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
```
|
|
331
|
+
**Plugin not loading?**
|
|
332
|
+
- Check your opencode.json syntax
|
|
333
|
+
- Clear the cache (see Updating section)
|
|
334
|
+
- Restart OpenCode
|
|
330
335
|
|
|
331
|
-
|
|
336
|
+
## Changelog
|
|
332
337
|
|
|
333
|
-
|
|
334
|
-
rm -rf ~/.cache/opencode/node_modules/@mohak34/opencode-notifier
|
|
335
|
-
```
|
|
338
|
+
See [CHANGELOG.md](CHANGELOG.md)
|
|
336
339
|
|
|
337
340
|
## License
|
|
338
341
|
|
package/dist/index.js
CHANGED
|
@@ -3770,6 +3770,13 @@ var DEFAULT_CONFIG = {
|
|
|
3770
3770
|
subagent_complete: null,
|
|
3771
3771
|
error: null,
|
|
3772
3772
|
question: null
|
|
3773
|
+
},
|
|
3774
|
+
volumes: {
|
|
3775
|
+
permission: 1,
|
|
3776
|
+
complete: 1,
|
|
3777
|
+
subagent_complete: 1,
|
|
3778
|
+
error: 1,
|
|
3779
|
+
question: 1
|
|
3773
3780
|
}
|
|
3774
3781
|
};
|
|
3775
3782
|
function getConfigPath() {
|
|
@@ -3790,6 +3797,18 @@ function parseEventConfig(userEvent, defaultConfig) {
|
|
|
3790
3797
|
notification: userEvent.notification ?? defaultConfig.notification
|
|
3791
3798
|
};
|
|
3792
3799
|
}
|
|
3800
|
+
function parseVolume(value, defaultVolume) {
|
|
3801
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3802
|
+
return defaultVolume;
|
|
3803
|
+
}
|
|
3804
|
+
if (value < 0) {
|
|
3805
|
+
return 0;
|
|
3806
|
+
}
|
|
3807
|
+
if (value > 1) {
|
|
3808
|
+
return 1;
|
|
3809
|
+
}
|
|
3810
|
+
return value;
|
|
3811
|
+
}
|
|
3793
3812
|
function loadConfig() {
|
|
3794
3813
|
const configPath = getConfigPath();
|
|
3795
3814
|
if (!existsSync(configPath)) {
|
|
@@ -3840,6 +3859,13 @@ function loadConfig() {
|
|
|
3840
3859
|
subagent_complete: userConfig.sounds?.subagent_complete ?? DEFAULT_CONFIG.sounds.subagent_complete,
|
|
3841
3860
|
error: userConfig.sounds?.error ?? DEFAULT_CONFIG.sounds.error,
|
|
3842
3861
|
question: userConfig.sounds?.question ?? DEFAULT_CONFIG.sounds.question
|
|
3862
|
+
},
|
|
3863
|
+
volumes: {
|
|
3864
|
+
permission: parseVolume(userConfig.volumes?.permission, DEFAULT_CONFIG.volumes.permission),
|
|
3865
|
+
complete: parseVolume(userConfig.volumes?.complete, DEFAULT_CONFIG.volumes.complete),
|
|
3866
|
+
subagent_complete: parseVolume(userConfig.volumes?.subagent_complete, DEFAULT_CONFIG.volumes.subagent_complete),
|
|
3867
|
+
error: parseVolume(userConfig.volumes?.error, DEFAULT_CONFIG.volumes.error),
|
|
3868
|
+
question: parseVolume(userConfig.volumes?.question, DEFAULT_CONFIG.volumes.question)
|
|
3843
3869
|
}
|
|
3844
3870
|
};
|
|
3845
3871
|
} catch {
|
|
@@ -3858,6 +3884,9 @@ function getMessage(config, event) {
|
|
|
3858
3884
|
function getSoundPath(config, event) {
|
|
3859
3885
|
return config.sounds[event];
|
|
3860
3886
|
}
|
|
3887
|
+
function getSoundVolume(config, event) {
|
|
3888
|
+
return config.volumes[event];
|
|
3889
|
+
}
|
|
3861
3890
|
function getIconPath(config) {
|
|
3862
3891
|
if (!config.showIcon) {
|
|
3863
3892
|
return;
|
|
@@ -3939,6 +3968,8 @@ import { existsSync as existsSync2 } from "fs";
|
|
|
3939
3968
|
import { spawn } from "child_process";
|
|
3940
3969
|
var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
3941
3970
|
var DEBOUNCE_MS2 = 1000;
|
|
3971
|
+
var FULL_VOLUME_PERCENT = 100;
|
|
3972
|
+
var FULL_VOLUME_PULSE = 65536;
|
|
3942
3973
|
var lastSoundTime = {};
|
|
3943
3974
|
function getBundledSoundPath(event) {
|
|
3944
3975
|
const soundFilename = `${event}.wav`;
|
|
@@ -3981,12 +4012,32 @@ async function runCommand(command, args) {
|
|
|
3981
4012
|
});
|
|
3982
4013
|
});
|
|
3983
4014
|
}
|
|
3984
|
-
|
|
4015
|
+
function normalizeVolume(volume) {
|
|
4016
|
+
if (!Number.isFinite(volume)) {
|
|
4017
|
+
return 1;
|
|
4018
|
+
}
|
|
4019
|
+
if (volume < 0) {
|
|
4020
|
+
return 0;
|
|
4021
|
+
}
|
|
4022
|
+
if (volume > 1) {
|
|
4023
|
+
return 1;
|
|
4024
|
+
}
|
|
4025
|
+
return volume;
|
|
4026
|
+
}
|
|
4027
|
+
function toPercentVolume(volume) {
|
|
4028
|
+
return Math.round(volume * FULL_VOLUME_PERCENT);
|
|
4029
|
+
}
|
|
4030
|
+
function toPulseVolume(volume) {
|
|
4031
|
+
return Math.round(volume * FULL_VOLUME_PULSE);
|
|
4032
|
+
}
|
|
4033
|
+
async function playOnLinux(soundPath, volume) {
|
|
4034
|
+
const percentVolume = toPercentVolume(volume);
|
|
4035
|
+
const pulseVolume = toPulseVolume(volume);
|
|
3985
4036
|
const players = [
|
|
3986
|
-
{ command: "paplay", args: [soundPath] },
|
|
4037
|
+
{ command: "paplay", args: [`--volume=${pulseVolume}`, soundPath] },
|
|
3987
4038
|
{ command: "aplay", args: [soundPath] },
|
|
3988
|
-
{ command: "mpv", args: ["--no-video", "--no-terminal", soundPath] },
|
|
3989
|
-
{ command: "ffplay", args: ["-nodisp", "-autoexit", "-loglevel", "quiet", soundPath] }
|
|
4039
|
+
{ command: "mpv", args: ["--no-video", "--no-terminal", `--volume=${percentVolume}`, soundPath] },
|
|
4040
|
+
{ command: "ffplay", args: ["-nodisp", "-autoexit", "-loglevel", "quiet", "-volume", `${percentVolume}`, soundPath] }
|
|
3990
4041
|
];
|
|
3991
4042
|
for (const player of players) {
|
|
3992
4043
|
try {
|
|
@@ -3997,20 +4048,21 @@ async function playOnLinux(soundPath) {
|
|
|
3997
4048
|
}
|
|
3998
4049
|
}
|
|
3999
4050
|
}
|
|
4000
|
-
async function playOnMac(soundPath) {
|
|
4001
|
-
await runCommand("afplay", [soundPath]);
|
|
4051
|
+
async function playOnMac(soundPath, volume) {
|
|
4052
|
+
await runCommand("afplay", ["-v", `${volume}`, soundPath]);
|
|
4002
4053
|
}
|
|
4003
4054
|
async function playOnWindows(soundPath) {
|
|
4004
4055
|
const script = `& { (New-Object Media.SoundPlayer $args[0]).PlaySync() }`;
|
|
4005
4056
|
await runCommand("powershell", ["-c", script, soundPath]);
|
|
4006
4057
|
}
|
|
4007
|
-
async function playSound(event, customPath) {
|
|
4058
|
+
async function playSound(event, customPath, volume) {
|
|
4008
4059
|
const now = Date.now();
|
|
4009
4060
|
if (lastSoundTime[event] && now - lastSoundTime[event] < DEBOUNCE_MS2) {
|
|
4010
4061
|
return;
|
|
4011
4062
|
}
|
|
4012
4063
|
lastSoundTime[event] = now;
|
|
4013
4064
|
const soundPath = getSoundFilePath(event, customPath);
|
|
4065
|
+
const normalizedVolume = normalizeVolume(volume);
|
|
4014
4066
|
if (!soundPath) {
|
|
4015
4067
|
return;
|
|
4016
4068
|
}
|
|
@@ -4018,10 +4070,10 @@ async function playSound(event, customPath) {
|
|
|
4018
4070
|
try {
|
|
4019
4071
|
switch (os2) {
|
|
4020
4072
|
case "darwin":
|
|
4021
|
-
await playOnMac(soundPath);
|
|
4073
|
+
await playOnMac(soundPath, normalizedVolume);
|
|
4022
4074
|
break;
|
|
4023
4075
|
case "linux":
|
|
4024
|
-
await playOnLinux(soundPath);
|
|
4076
|
+
await playOnLinux(soundPath, normalizedVolume);
|
|
4025
4077
|
break;
|
|
4026
4078
|
case "win32":
|
|
4027
4079
|
await playOnWindows(soundPath);
|
|
@@ -4068,7 +4120,8 @@ async function handleEvent(config, eventType, projectName, elapsedSeconds) {
|
|
|
4068
4120
|
}
|
|
4069
4121
|
if (isEventSoundEnabled(config, eventType)) {
|
|
4070
4122
|
const customSoundPath = getSoundPath(config, eventType);
|
|
4071
|
-
|
|
4123
|
+
const soundVolume = getSoundVolume(config, eventType);
|
|
4124
|
+
promises.push(playSound(eventType, customSoundPath, soundVolume));
|
|
4072
4125
|
}
|
|
4073
4126
|
const minDuration = config.command?.minDuration;
|
|
4074
4127
|
const shouldSkipCommand = typeof minDuration === "number" && Number.isFinite(minDuration) && minDuration > 0 && typeof elapsedSeconds === "number" && Number.isFinite(elapsedSeconds) && elapsedSeconds < minDuration;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mohak34/opencode-notifier",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20-beta.0",
|
|
4
4
|
"description": "OpenCode plugin that sends system notifications and plays sounds when permission is needed, generation completes, or errors occur",
|
|
5
5
|
"author": "mohak34",
|
|
6
6
|
"license": "MIT",
|