@settinghead/voxlert 0.3.5

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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +353 -0
  3. package/assets/cortana.png +0 -0
  4. package/assets/deckard-cain.png +0 -0
  5. package/assets/demo-thumbnail.png +0 -0
  6. package/assets/glados.png +0 -0
  7. package/assets/hl-hev-suit.png +0 -0
  8. package/assets/logo.png +0 -0
  9. package/assets/red-alert-eva.png +0 -0
  10. package/assets/sc1-adjutant.gif +0 -0
  11. package/assets/sc1-kerrigan.gif +0 -0
  12. package/assets/sc1-protoss-advisor.jpg +0 -0
  13. package/assets/sc2-adjutant.jpg +0 -0
  14. package/assets/sc2-kerrigan.jpg +0 -0
  15. package/assets/ss1-shodan.png +0 -0
  16. package/config.default.json +35 -0
  17. package/openclaw-plugin/index.ts +100 -0
  18. package/openclaw-plugin/openclaw.plugin.json +21 -0
  19. package/package.json +51 -0
  20. package/packs/hl-hev-suit/pack.json +72 -0
  21. package/packs/hl-hev-suit/voice.wav +0 -0
  22. package/packs/red-alert-eva/pack.json +73 -0
  23. package/packs/red-alert-eva/voice.wav +0 -0
  24. package/packs/sc1-adjutant/pack.json +31 -0
  25. package/packs/sc1-adjutant/voice.wav +0 -0
  26. package/packs/sc1-kerrigan/pack.json +69 -0
  27. package/packs/sc1-kerrigan/voice.wav +0 -0
  28. package/packs/sc1-protoss-advisor/pack.json +70 -0
  29. package/packs/sc1-protoss-advisor/voice.wav +0 -0
  30. package/packs/sc2-adjutant/pack.json +14 -0
  31. package/packs/sc2-adjutant/voice.wav +0 -0
  32. package/packs/sc2-kerrigan/pack.json +69 -0
  33. package/packs/sc2-kerrigan/voice.wav +0 -0
  34. package/packs/sc2-protoss-advisor/pack.json +70 -0
  35. package/packs/sc2-protoss-advisor/voice.wav +0 -0
  36. package/packs/ss1-shodan/pack.json +69 -0
  37. package/packs/ss1-shodan/voice.wav +0 -0
  38. package/skills/voxlert-config/SKILL.md +44 -0
  39. package/src/activity-log.js +58 -0
  40. package/src/audio.js +381 -0
  41. package/src/cli.js +86 -0
  42. package/src/codex-config.js +149 -0
  43. package/src/commands/codex-notify.js +70 -0
  44. package/src/commands/config.js +141 -0
  45. package/src/commands/cost.js +20 -0
  46. package/src/commands/cursor-hook.js +52 -0
  47. package/src/commands/help.js +25 -0
  48. package/src/commands/hook-utils.js +73 -0
  49. package/src/commands/hook.js +27 -0
  50. package/src/commands/index.js +45 -0
  51. package/src/commands/log.js +92 -0
  52. package/src/commands/notification.js +50 -0
  53. package/src/commands/pack-helpers.js +157 -0
  54. package/src/commands/pack.js +25 -0
  55. package/src/commands/setup.js +13 -0
  56. package/src/commands/test.js +14 -0
  57. package/src/commands/uninstall.js +60 -0
  58. package/src/commands/version.js +12 -0
  59. package/src/commands/voice.js +14 -0
  60. package/src/commands/volume.js +38 -0
  61. package/src/config.js +230 -0
  62. package/src/cost.js +124 -0
  63. package/src/cursor-hooks.js +93 -0
  64. package/src/formats.js +55 -0
  65. package/src/hooks.js +129 -0
  66. package/src/llm.js +237 -0
  67. package/src/overlay.js +212 -0
  68. package/src/overlay.jxa +186 -0
  69. package/src/pack-registry.js +28 -0
  70. package/src/packs.js +182 -0
  71. package/src/paths.js +39 -0
  72. package/src/postinstall.js +13 -0
  73. package/src/providers.js +129 -0
  74. package/src/setup-ui.js +177 -0
  75. package/src/setup.js +504 -0
  76. package/src/tts-test.js +243 -0
  77. package/src/upgrade-check.js +137 -0
  78. package/src/voxlert.js +200 -0
  79. package/voxlert.sh +4 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Voxlert Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,353 @@
1
+ <p align="center">
2
+ <a href="https://youtu.be/-aiSZnGNyE4">
3
+ <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/demo-thumbnail.png" alt="Voxlert Demo" width="100%" />
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://github.com/settinghead/voxlert/actions/workflows/cli-integration.yml">
9
+ <img src="https://github.com/settinghead/voxlert/actions/workflows/cli-integration.yml/badge.svg" alt="CLI Integration" />
10
+ </a>
11
+ </p>
12
+
13
+ # Voxlert
14
+
15
+ LLM-generated voice notifications for [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor](https://cursor.com/docs/agent/hooks), [OpenAI Codex](https://developers.openai.com/codex/), and [OpenClaw](https://openclaw.dev), spoken by game characters like the StarCraft Adjutant, Kerrigan, C&C EVA, SHODAN, and more.
16
+
17
+ ## Why Voxlert?
18
+
19
+ Existing notification chimes (like [peon-ping](https://github.com/PeonPing/peon-ping)) do a great job of telling you *when* something happened, but not *what* happened or *which* agent needs your attention. If you have several agent sessions running at once, you end up alt-tabbing through windows just to find the one waiting on you.
20
+
21
+ Voxlert makes each session speak in a distinct character voice with its own tone and vocabulary. You hear *"Query efficiency restored to nominal"* from the HEV Suit in one window and *"Pathetic test suite for code validation processed"* from SHODAN in another, and you know immediately what changed. Because phrases are generated by an LLM instead of picked from a tiny fixed set, they stay varied instead of becoming wallpaper.
22
+
23
+ ## Quick Start
24
+
25
+ ### 1. Install prerequisites
26
+
27
+ | Aspect | macOS | Windows | Linux |
28
+ |--------|-------|---------|-------|
29
+ | **Node.js 18+** | [nodejs.org](https://nodejs.org) or `brew install node` | [nodejs.org](https://nodejs.org) or `winget install OpenJS.NodeJS` | [nodejs.org](https://nodejs.org) or distro package (for example `sudo apt install nodejs`) |
30
+ | **Audio playback** | Built-in (`afplay`) | [FFmpeg](docs/installing-ffmpeg.md) so `ffplay` is on PATH | [FFmpeg](docs/installing-ffmpeg.md) so `ffplay` is on PATH |
31
+ | **Audio effects** | [SoX](docs/installing-sox.md) (optional) | [SoX](docs/installing-sox.md) (optional) | [SoX](docs/installing-sox.md) (optional) |
32
+
33
+ See [Installing FFmpeg](docs/installing-ffmpeg.md) and [Installing SoX](docs/installing-sox.md) for platform-specific commands.
34
+
35
+ You will also want:
36
+
37
+ - An **LLM API key** from [OpenRouter](https://openrouter.ai) (recommended), [OpenAI](https://platform.openai.com/api-keys), [Google Gemini](https://aistudio.google.com/apikey), or [Anthropic](https://console.anthropic.com/settings/keys). You can skip this and use fallback phrases only.
38
+ - At least one **TTS backend** if you want spoken output instead of notifications only.
39
+
40
+ | Backend | Best for | Requirements |
41
+ |---|---|---|
42
+ | [**Qwen3-TTS**](qwen3-tts-server/README.md) (recommended) | Apple Silicon or NVIDIA GPU | Python 3.13+, 16 GB RAM, ~8 GB disk |
43
+ | [**Chatterbox**](docs/chatterbox-tts.md) | Any platform with GPU | Python 3.10+, CUDA or MPS |
44
+
45
+ The setup wizard auto-detects running TTS backends. If none are running yet, setup still completes, but you will only get text notifications and fallback phrases until you start one and rerun setup.
46
+
47
+ ### 2. Install and run setup
48
+
49
+ ```bash
50
+ npm install -g @settinghead/voxlert
51
+ voxlert setup
52
+ ```
53
+
54
+ The setup wizard configures:
55
+
56
+ - LLM provider and API key
57
+ - Voice pack downloads
58
+ - Active voice pack
59
+ - TTS backend
60
+ - Platform hooks for Claude Code, Cursor, and Codex
61
+
62
+ For OpenClaw, install the separate [OpenClaw plugin](docs/openclaw.md).
63
+
64
+ ### 3. Start a TTS backend for spoken voice
65
+
66
+ Start [Qwen3-TTS](qwen3-tts-server/README.md) or [Chatterbox](docs/chatterbox-tts.md), then run:
67
+
68
+ ```bash
69
+ voxlert setup
70
+ ```
71
+
72
+ This lets the wizard detect the backend and store it in config.
73
+
74
+ ### 4. Verify
75
+
76
+ ```bash
77
+ voxlert test "Hello"
78
+ ```
79
+
80
+ You should hear a phrase and see a notification. If you do not hear speech, check that:
81
+
82
+ - A TTS server is running
83
+ - `voxlert config` shows the expected `tts_backend`
84
+
85
+ > **Visual notifications**: Voxlert shows a popup with each phrase without extra install. On macOS you can use the custom overlay or system Notification Center. On Windows and Linux you get system toasts. Change it anytime with:
86
+ > ```bash
87
+ > voxlert notification
88
+ > ```
89
+
90
+ ### From a git clone
91
+
92
+ Run `npm install` inside `cli/`, then use `node src/cli.js` or link it globally if you prefer. Config and cache live in `~/.voxlert` (Windows: `%USERPROFILE%\.voxlert`).
93
+
94
+ ## Development
95
+
96
+ Run tests locally with:
97
+
98
+ ```bash
99
+ npm test
100
+ ```
101
+
102
+ For release-impacting changes, add a changeset before opening a PR:
103
+
104
+ ```bash
105
+ npm run changeset
106
+ ```
107
+
108
+ ## Supported Voices
109
+
110
+ | | Pack ID | Voice | Source | Status |
111
+ |---|---------|-------|--------|--------|
112
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/sc1-adjutant.gif" width="48" height="48" /> | `sc1-adjutant` | **SC1 Adjutant** | StarCraft | ✅ Available |
113
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/sc2-adjutant.jpg" width="48" height="48" /> | `sc2-adjutant` | **SC2 Adjutant** | StarCraft II | ✅ Available |
114
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/red-alert-eva.png" width="48" height="48" /> | `red-alert-eva` | **EVA** | Command & Conquer: Red Alert | ✅ Available |
115
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/sc1-kerrigan.gif" width="48" height="48" /> | `sc1-kerrigan` | **SC1 Kerrigan** | StarCraft | ✅ Available |
116
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/sc2-kerrigan.jpg" width="48" height="48" /> | `sc2-kerrigan` | **SC2 Kerrigan** | StarCraft II | ✅ Available |
117
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/sc1-protoss-advisor.jpg" width="48" height="48" /> | `sc1-protoss-advisor` | **Protoss Advisor** | StarCraft | ✅ Available |
118
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/ss1-shodan.png" width="48" height="48" /> | `ss1-shodan` | **SHODAN** | System Shock | ✅ Available |
119
+ | <img src="https://raw.githubusercontent.com/settinghead/voxlert/main/assets/hl-hev-suit.png" width="48" height="48" /> | `hl-hev-suit` | **HEV Suit** | Half-Life | ✅ Available |
120
+
121
+ More coming soon: [Request a voice](https://github.com/settinghead/voxlert/issues/new?title=Voice+request%3A+%5BCharacter+Name%5D&body=**Character%3A**+%0A**Game%2FSource%3A**+%0A**Why%3A**+)
122
+
123
+ ```bash
124
+ voxlert voice
125
+ ```
126
+
127
+ ## Integrations
128
+
129
+ ### Claude Code
130
+
131
+ Installed through `voxlert setup`. Claude Code hook events are processed by:
132
+
133
+ ```bash
134
+ voxlert hook
135
+ ```
136
+
137
+ ### Cursor
138
+
139
+ Installed through `voxlert setup`, or add hooks manually in `~/.cursor/hooks.json`:
140
+
141
+ ```json
142
+ {
143
+ "version": 1,
144
+ "hooks": {
145
+ "sessionStart": [{ "command": "voxlert cursor-hook", "timeout": 10 }],
146
+ "sessionEnd": [{ "command": "voxlert cursor-hook", "timeout": 10 }],
147
+ "stop": [{ "command": "voxlert cursor-hook", "timeout": 10 }],
148
+ "postToolUseFailure": [{ "command": "voxlert cursor-hook", "timeout": 10 }],
149
+ "preCompact": [{ "command": "voxlert cursor-hook", "timeout": 10 }]
150
+ }
151
+ }
152
+ ```
153
+
154
+ | Cursor Hook Event | Voxlert Event | Category |
155
+ |---|---|---|
156
+ | `sessionStart` | SessionStart | `session.start` |
157
+ | `sessionEnd` | SessionEnd | `session.end` |
158
+ | `stop` | Stop | `task.complete` |
159
+ | `postToolUseFailure` | PostToolUseFailure | `task.error` |
160
+ | `preCompact` | PreCompact | `resource.limit` |
161
+
162
+ Restart Cursor after installing or changing hooks. See [Cursor integration](docs/cursor.md) for details.
163
+
164
+ ### Codex
165
+
166
+ Voxlert uses Codex's `notify` config so that completed agent turns call:
167
+
168
+ ```bash
169
+ voxlert codex-notify
170
+ ```
171
+
172
+ `voxlert setup` can install or update the `notify` entry in `~/.codex/config.toml`. See [Codex integration](docs/codex.md).
173
+
174
+ ### OpenClaw
175
+
176
+ OpenClaw uses a separate plugin. See [OpenClaw integration](docs/openclaw.md) for installation, config, and troubleshooting.
177
+
178
+ ## Common Commands
179
+
180
+ ```bash
181
+ voxlert setup # Interactive setup wizard
182
+ voxlert voice # Interactive voice pack picker
183
+ voxlert pack list # List available voice packs
184
+ voxlert pack show # Show active pack details
185
+ voxlert pack use <pack-id> # Switch active voice pack
186
+ voxlert config # Show current configuration
187
+ voxlert config set <key> <val> # Set a config value
188
+ voxlert volume # Show or change playback volume
189
+ voxlert notification # Choose popup / system / off
190
+ voxlert test "<text>" # Run the full pipeline
191
+ voxlert log # Stream activity log
192
+ voxlert uninstall # Remove installed integrations
193
+ voxlert help # Show full help
194
+ ```
195
+
196
+ ## How It Works
197
+
198
+ ```mermaid
199
+ flowchart TD
200
+ A1[Claude Code Hook] --> B[voxlert.sh]
201
+ A2[OpenClaw Plugin] --> B
202
+ A3[Cursor Hook] --> B
203
+ A4[Codex notify] --> B
204
+ B --> C[src/voxlert.js]
205
+ C --> D{Event type?}
206
+ D -- "Contextual (e.g. Stop)" --> E[LLM<br><i>generate in-character phrase</i>]
207
+ D -- "Other events" --> F[Fallback phrases<br><i>from voice pack</i>]
208
+ E --> G{TTS backend?}
209
+ F --> G
210
+ G -- Chatterbox --> G1[Chatterbox TTS<br><i>local speech synthesis</i>]
211
+ G -- Qwen3 --> G2[Qwen3-TTS<br><i>local speech synthesis</i>]
212
+ G1 --> H[Audio processing<br><i>echo · normalize · post-process</i>]
213
+ G2 --> H
214
+ H --> I[(Cache<br><i>LRU, keyed by phrase + params</i>)]
215
+ I --> J[Playback queue<br><i>serial via file lock</i>]
216
+ J --> K[afplay / ffplay]
217
+ ```
218
+
219
+ 1. A hook or notify event fires from Claude Code, Cursor, Codex, or OpenClaw.
220
+ 2. Voxlert maps it to an event category and loads the active voice pack.
221
+ 3. Contextual events such as task completion or tool failure can use the configured LLM to generate a short in-character phrase.
222
+ 4. Other events use predefined fallback phrases from the pack.
223
+ 5. The chosen phrase is synthesized by the configured TTS backend.
224
+ 6. Audio is optionally post-processed, cached, then played through a serialized queue.
225
+
226
+ ## Configuration
227
+
228
+ Run `voxlert config path` to find `config.json`. You can edit it directly or use `voxlert setup` and `voxlert config set`.
229
+
230
+ | Field | Type | Default | Description |
231
+ |---|---|---|---|
232
+ | `enabled` | boolean | `true` | Master on/off switch |
233
+ | `llm_backend` | string | `"openrouter"` | LLM provider: `openrouter`, `openai`, `gemini`, `anthropic`, or `local` |
234
+ | `llm_api_key` | string \| null | `null` | API key for the chosen LLM provider |
235
+ | `llm_model` | string \| null | `null` | Model ID (`null` = provider default) |
236
+ | `openrouter_api_key` | string \| null | `null` | Legacy alias used when `llm_backend` is `openrouter` and `llm_api_key` is empty |
237
+ | `openrouter_model` | string \| null | `null` | Legacy alias used when `llm_model` is empty and backend is `openrouter` |
238
+ | `chatterbox_url` | string | `"http://localhost:8004"` | Chatterbox TTS server URL |
239
+ | `tts_backend` | string | `"chatterbox"` | TTS backend: `chatterbox` or `qwen` |
240
+ | `active_pack` | string | `"sc2-adjutant"` | Active voice pack ID |
241
+ | `volume` | number | `1.0` | Playback volume (0.0-1.0) |
242
+ | `categories` | object | — | Per-category enable/disable settings |
243
+ | `logging` | boolean | `true` | Activity log in `~/.voxlert/voxlert.log` |
244
+ | `error_log` | boolean | `false` | Fallback/error log in `~/.voxlert/fallback.log` |
245
+
246
+ ### Event categories
247
+
248
+ Event categories apply across Claude Code, Cursor, Codex, and OpenClaw where the corresponding event exists.
249
+
250
+ | Category | Hook Event | Description | Default |
251
+ |---|---|---|---|
252
+ | `session.start` | SessionStart | New session begins | on |
253
+ | `session.end` | SessionEnd | Session ends | on |
254
+ | `task.complete` | Stop | Agent finishes a task | on |
255
+ | `task.acknowledge` | UserPromptSubmit | User sends a prompt | off |
256
+ | `task.error` | PostToolUseFailure | A tool call fails | on |
257
+ | `input.required` | PermissionRequest | Agent needs user approval | on |
258
+ | `resource.limit` | PreCompact | Context window nearing limit | on |
259
+ | `notification` | Notification | General notification | on |
260
+
261
+ Omitted categories default to enabled. Set any category to `false` to disable it:
262
+
263
+ ```bash
264
+ voxlert config set categories.task.complete true
265
+ voxlert config set categories.task.acknowledge false
266
+ voxlert config set categories.session.start true
267
+ ```
268
+
269
+ ### Logging
270
+
271
+ - Activity logging is on by default and writes one line per event to `~/.voxlert/voxlert.log`.
272
+ - Error logging is off by default and records fallback situations in `~/.voxlert/fallback.log`.
273
+ - Debug logging for hook sources is written to `~/.voxlert/hook-debug.log`.
274
+
275
+ Useful commands:
276
+
277
+ ```bash
278
+ voxlert log
279
+ voxlert log on
280
+ voxlert log off
281
+ voxlert log path
282
+ voxlert log error on
283
+ voxlert log error off
284
+ voxlert log error-path
285
+ ```
286
+
287
+ You can also manage configuration interactively with the `/voxlert-config` slash command in Claude Code.
288
+
289
+ ### Integration behavior
290
+
291
+ - `voxlert setup` installs hooks for Claude Code, Cursor, and Codex.
292
+ - Re-run setup anytime to add a platform you skipped earlier.
293
+ - `voxlert uninstall` removes Claude Code, Cursor, and Codex integration.
294
+ - OpenClaw is managed separately through its plugin.
295
+ - The global `enabled` flag disables processing everywhere; there is no separate per-integration toggle in `config.json`.
296
+
297
+ ## Full CLI Reference
298
+
299
+ ```bash
300
+ voxlert setup # Interactive setup wizard (LLM, voice, TTS, hooks)
301
+ voxlert hook # Process hook event from stdin (Claude Code)
302
+ voxlert cursor-hook # Process hook event from stdin (Cursor)
303
+ voxlert codex-notify # Process notify payload from argv (Codex)
304
+ voxlert config # Show current configuration
305
+ voxlert config show # Show current configuration
306
+ voxlert config set <k> <v> # Set a config value (supports categories.X dot notation)
307
+ voxlert config path # Print config file path
308
+ voxlert log # Stream activity log (tail -f style)
309
+ voxlert log path # Print activity log file path
310
+ voxlert log error-path # Print error/fallback log file path
311
+ voxlert log on | off # Enable or disable activity logging
312
+ voxlert log error on | off # Enable or disable error logging
313
+ voxlert voice # Interactive voice pack picker
314
+ voxlert pack list # List available voice packs
315
+ voxlert pack show # Show active pack details
316
+ voxlert pack use <pack-id> # Switch active voice pack
317
+ voxlert volume # Show current volume and prompt for new value
318
+ voxlert volume <0-100> # Set playback volume (0 = mute, 100 = max)
319
+ voxlert notification # Choose notification style (popup / system / off)
320
+ voxlert test "<text>" # Run full pipeline: LLM -> TTS -> audio playback
321
+ voxlert cost # Show accumulated token usage and estimated cost
322
+ voxlert cost reset # Clear the usage log
323
+ voxlert uninstall # Remove hooks from Claude Code, Cursor, and Codex, optionally config/cache
324
+ voxlert help # Show help
325
+ voxlert --version # Show version
326
+ ```
327
+
328
+ ## Platform Notes
329
+
330
+ - **Windows**: Install [Node.js](https://nodejs.org) and [FFmpeg](docs/installing-ffmpeg.md). Ensure the npm global bin directory is on PATH so hooks can find `voxlert` or `voxlert.cmd`.
331
+ - **Linux**: Install Node and [FFmpeg](docs/installing-ffmpeg.md) so `ffplay` is on PATH.
332
+ - **macOS**: Playback uses the built-in `afplay`; install [SoX](docs/installing-sox.md) if you want optional effects and processing.
333
+
334
+ ## Uninstall
335
+
336
+ ```bash
337
+ voxlert uninstall
338
+ npm uninstall -g @settinghead/voxlert
339
+ ```
340
+
341
+ This removes Voxlert hooks from Claude Code, Cursor, and Codex, the `voxlert-config` skill, and optionally your local config and cache in `~/.voxlert`.
342
+
343
+ ## Advanced
344
+
345
+ See [Creating Voice Packs](docs/creating-voice-packs.md) for building your own character voice packs.
346
+
347
+ ## Credits
348
+
349
+ - **Protoss Advisor** voice pack inspired by [openclaw/protoss-voice](https://playbooks.com/skills/openclaw/skills/protoss-voice)
350
+
351
+ ## License
352
+
353
+ MIT - see [LICENSE](LICENSE).
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,35 @@
1
+ {
2
+ "enabled": true,
3
+ "collect_llm_data": true,
4
+ "llm_backend": "openrouter",
5
+ "llm_api_key": null,
6
+ "llm_model": null,
7
+ "openrouter_api_key": null,
8
+ "openrouter_model": null,
9
+ "local_api": {
10
+ "base_url": "http://localhost:8000",
11
+ "model": "default",
12
+ "max_tokens": 50,
13
+ "timeout": 15000
14
+ },
15
+ "chatterbox_url": "http://localhost:8004",
16
+ "tts_backend": "chatterbox",
17
+ "qwen_tts_url": "http://localhost:8100",
18
+ "active_pack": "sc2-adjutant",
19
+ "volume": 1.0,
20
+ "logging": true,
21
+ "error_log": false,
22
+ "overlay": true,
23
+ "overlay_dismiss": 4,
24
+ "overlay_style": "custom",
25
+ "categories": {
26
+ "session.start": true,
27
+ "session.end": true,
28
+ "task.complete": true,
29
+ "task.acknowledge": false,
30
+ "task.error": true,
31
+ "input.required": true,
32
+ "resource.limit": true,
33
+ "notification": true
34
+ }
35
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Voxlert OpenClaw plugin.
3
+ *
4
+ * Registers agent_end lifecycle hook and spawns `voxlert hook` with
5
+ * Stop + source: "openclaw" when an agent run completes, so users get
6
+ * voice notifications (especially for long-running tasks).
7
+ *
8
+ * Requires: Voxlert installed and `voxlert` on PATH when the gateway runs.
9
+ */
10
+
11
+ import { spawn } from "child_process";
12
+ import { appendFileSync, mkdirSync } from "fs";
13
+ import { join } from "path";
14
+ import { homedir } from "os";
15
+
16
+ const HOOK_DEBUG_LOG = join(homedir(), ".voxlert", "hook-debug.log");
17
+
18
+ function debugLog(msg, data) {
19
+ try {
20
+ mkdirSync(join(homedir(), ".voxlert"), { recursive: true });
21
+ const line =
22
+ data !== undefined
23
+ ? `[${new Date().toISOString()}] [voxlert-plugin] ${msg} ${JSON.stringify(data)}\n`
24
+ : `[${new Date().toISOString()}] [voxlert-plugin] ${msg}\n`;
25
+ appendFileSync(HOOK_DEBUG_LOG, line);
26
+ } catch {
27
+ // best-effort
28
+ }
29
+ }
30
+
31
+ export default function register(api) {
32
+ api.on(
33
+ "agent_end",
34
+ async (event, ctx) => {
35
+ const config = api.config?.plugins?.entries?.voxlert?.config ?? {};
36
+ if (config.enabled === false) return;
37
+
38
+ const minDurationSeconds = Number(config.minDurationSeconds) || 0;
39
+ const startedAt = event?.startedAt ?? event?.context?.startedAt;
40
+ const endedAt = event?.endedAt ?? event?.context?.endedAt;
41
+ if (
42
+ minDurationSeconds > 0 &&
43
+ typeof startedAt === "number" &&
44
+ typeof endedAt === "number"
45
+ ) {
46
+ const durationMs = endedAt - startedAt;
47
+ if (durationMs < minDurationSeconds * 1000) return;
48
+ }
49
+
50
+ let lastAssistantMessage = "";
51
+ const messages = event?.messages ?? event?.context?.messages ?? [];
52
+ if (Array.isArray(messages) && messages.length > 0) {
53
+ const last = messages[messages.length - 1];
54
+ if (last?.content ?? last?.text) {
55
+ lastAssistantMessage = String(last.content ?? last.text).slice(0, 2000);
56
+ }
57
+ }
58
+ if (!lastAssistantMessage && event?.context?.sessionEntry) {
59
+ lastAssistantMessage = String(event.context.sessionEntry).slice(0, 2000);
60
+ }
61
+
62
+ const cwd =
63
+ event?.context?.workspaceDir ??
64
+ event?.context?.workspace ??
65
+ ctx?.workspaceDir ??
66
+ ctx?.workspace ??
67
+ "";
68
+
69
+ const payload = {
70
+ hook_event_name: "Stop",
71
+ source: "openclaw",
72
+ cwd: typeof cwd === "string" ? cwd : "",
73
+ last_assistant_message: lastAssistantMessage || undefined,
74
+ };
75
+
76
+ try {
77
+ debugLog("agent_end: spawning voxlert hook", payload);
78
+ } catch {
79
+ // ignore
80
+ }
81
+
82
+ const child = spawn("voxlert", ["hook"], {
83
+ stdio: ["pipe", "ignore", "ignore"],
84
+ detached: true,
85
+ });
86
+
87
+ child.on("error", (err) => {
88
+ debugLog("voxlert spawn error", {
89
+ message: err.message,
90
+ code: err.code,
91
+ });
92
+ });
93
+
94
+ child.stdin.write(JSON.stringify(payload));
95
+ child.stdin.end();
96
+ child.unref();
97
+ },
98
+ { priority: 0 }
99
+ );
100
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "id": "voxlert",
3
+ "name": "Voxlert Notify",
4
+ "description": "Speak when OpenClaw agent runs complete (e.g. long-running tasks) using Voxlert character voices.",
5
+ "configSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "minDurationSeconds": {
10
+ "type": "number",
11
+ "default": 0,
12
+ "description": "Only notify for runs lasting at least this many seconds (0 = always notify)"
13
+ },
14
+ "enabled": {
15
+ "type": "boolean",
16
+ "default": true,
17
+ "description": "Master switch for Voxlert notifications"
18
+ }
19
+ }
20
+ }
21
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@settinghead/voxlert",
3
+ "version": "0.3.5",
4
+ "description": "LLM-generated voice notifications for Claude Code, Cursor, OpenAI Codex, and OpenClaw, spoken by game characters like the StarCraft Adjutant, Kerrigan, C&C EVA, SHODAN, and more.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/settinghead/voxlert.git"
8
+ },
9
+ "homepage": "https://github.com/settinghead/voxlert",
10
+ "type": "module",
11
+ "bin": {
12
+ "voxlert": "src/cli.js"
13
+ },
14
+ "files": [
15
+ "src/",
16
+ "packs/*/pack.json",
17
+ "packs/*/voice.wav",
18
+ "skills/",
19
+ "assets/*.png",
20
+ "assets/*.jpg",
21
+ "assets/*.gif",
22
+ "config.default.json",
23
+ "voxlert.sh",
24
+ "openclaw-plugin/",
25
+ "LICENSE"
26
+ ],
27
+ "scripts": {
28
+ "start": "node src/voxlert.js",
29
+ "postinstall": "node src/postinstall.js",
30
+ "changeset": "changeset",
31
+ "version": "changeset version",
32
+ "release": "changeset publish",
33
+ "test": "node --test ./test/*.test.js"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public",
37
+ "provenance": true
38
+ },
39
+ "license": "MIT",
40
+ "dependencies": {
41
+ "@inquirer/checkbox": "^5.0.0",
42
+ "@inquirer/confirm": "^6.0.8",
43
+ "@inquirer/input": "^4.1.0",
44
+ "@inquirer/select": "^5.1.0",
45
+ "node-notifier": "^10.0.1"
46
+ },
47
+ "devDependencies": {
48
+ "@changesets/changelog-github": "^0.6.0",
49
+ "@changesets/cli": "^2.30.0"
50
+ }
51
+ }