agentvibes 4.2.0 → 4.4.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.
Files changed (219) hide show
  1. package/.agentvibes/bmad/bmad-voices.md +69 -69
  2. package/.agentvibes/config.json +12 -0
  3. package/.claude/activation-instructions +54 -54
  4. package/.claude/audio/tracks/README.md +52 -52
  5. package/.claude/commands/agent-vibes/add.md +21 -21
  6. package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
  7. package/.claude/commands/agent-vibes/agent.md +79 -79
  8. package/.claude/commands/agent-vibes/background-music.md +111 -111
  9. package/.claude/commands/agent-vibes/bmad.md +198 -198
  10. package/.claude/commands/agent-vibes/clean.md +18 -18
  11. package/.claude/commands/agent-vibes/cleanup.md +18 -18
  12. package/.claude/commands/agent-vibes/commands.json +145 -145
  13. package/.claude/commands/agent-vibes/effects.md +97 -97
  14. package/.claude/commands/agent-vibes/get.md +9 -9
  15. package/.claude/commands/agent-vibes/hide.md +91 -91
  16. package/.claude/commands/agent-vibes/language.md +23 -23
  17. package/.claude/commands/agent-vibes/learn.md +67 -67
  18. package/.claude/commands/agent-vibes/list.md +13 -13
  19. package/.claude/commands/agent-vibes/mute.md +37 -37
  20. package/.claude/commands/agent-vibes/preview.md +17 -17
  21. package/.claude/commands/agent-vibes/provider.md +68 -68
  22. package/.claude/commands/agent-vibes/replay-target.md +14 -14
  23. package/.claude/commands/agent-vibes/sample.md +12 -12
  24. package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
  25. package/.claude/commands/agent-vibes/set-pretext.md +65 -65
  26. package/.claude/commands/agent-vibes/set-speed.md +41 -41
  27. package/.claude/commands/agent-vibes/show.md +84 -84
  28. package/.claude/commands/agent-vibes/switch.md +87 -87
  29. package/.claude/commands/agent-vibes/target-voice.md +26 -26
  30. package/.claude/commands/agent-vibes/target.md +30 -30
  31. package/.claude/commands/agent-vibes/translate.md +68 -68
  32. package/.claude/commands/agent-vibes/unmute.md +45 -45
  33. package/.claude/commands/agent-vibes/verbosity.md +89 -89
  34. package/.claude/commands/agent-vibes/whoami.md +7 -7
  35. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  36. package/.claude/commands/agent-vibes-rdp.md +24 -24
  37. package/.claude/config/agentvibes.json +1 -0
  38. package/.claude/config/audio-effects.cfg +2 -2
  39. package/.claude/config/audio-effects.cfg.sample +52 -52
  40. package/.claude/config/background-music-volume.txt +1 -0
  41. package/.claude/config/intro-text.txt +1 -0
  42. package/.claude/config/piper-speech-rate.txt +4 -0
  43. package/.claude/config/piper-target-speech-rate.txt +1 -0
  44. package/.claude/config/reverb-level.txt +1 -0
  45. package/.claude/config/tts-speech-rate.txt +4 -0
  46. package/.claude/config/tts-target-speech-rate.txt +1 -0
  47. package/.claude/docs/TERMUX_SETUP.md +408 -408
  48. package/.claude/github-star-reminder.txt +1 -1
  49. package/.claude/hooks/README-TTS-QUEUE.md +135 -135
  50. package/.claude/hooks/audio-cache-utils.sh +246 -246
  51. package/.claude/hooks/audio-processor.sh +433 -433
  52. package/.claude/hooks/background-music-manager.sh +404 -404
  53. package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
  54. package/.claude/hooks/bmad-speak.sh +269 -269
  55. package/.claude/hooks/bmad-tts-injector.sh +568 -568
  56. package/.claude/hooks/bmad-voice-manager.sh +928 -928
  57. package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
  58. package/.claude/hooks/clawdbot-receiver.sh +107 -107
  59. package/.claude/hooks/clean-audio-cache.sh +22 -22
  60. package/.claude/hooks/cleanup-cache.sh +106 -106
  61. package/.claude/hooks/configure-rdp-mode.sh +137 -137
  62. package/.claude/hooks/download-extra-voices.sh +244 -244
  63. package/.claude/hooks/effects-manager.sh +268 -268
  64. package/.claude/hooks/github-star-reminder.sh +154 -154
  65. package/.claude/hooks/language-manager.sh +362 -362
  66. package/.claude/hooks/learn-manager.sh +492 -492
  67. package/.claude/hooks/macos-voice-manager.sh +205 -205
  68. package/.claude/hooks/migrate-background-music.sh +125 -125
  69. package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
  70. package/.claude/hooks/optimize-background-music.sh +87 -87
  71. package/.claude/hooks/path-resolver.sh +60 -60
  72. package/.claude/hooks/personality-manager.sh +448 -448
  73. package/.claude/hooks/piper-download-voices.sh +225 -225
  74. package/.claude/hooks/piper-installer.sh +292 -292
  75. package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
  76. package/.claude/hooks/piper-voice-manager.sh +24 -3
  77. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
  78. package/.claude/hooks/play-tts-enhanced.sh +105 -105
  79. package/.claude/hooks/play-tts-macos.sh +368 -368
  80. package/.claude/hooks/play-tts-piper.sh +679 -679
  81. package/.claude/hooks/play-tts-soprano.sh +356 -356
  82. package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
  83. package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
  84. package/.claude/hooks/play-tts.sh +301 -301
  85. package/.claude/hooks/prepare-release.sh +54 -54
  86. package/.claude/hooks/provider-commands.sh +617 -617
  87. package/.claude/hooks/provider-manager.sh +399 -399
  88. package/.claude/hooks/replay-target-audio.sh +95 -95
  89. package/.claude/hooks/requirements.txt +6 -6
  90. package/.claude/hooks/sentiment-manager.sh +201 -201
  91. package/.claude/hooks/session-start-tts.sh +81 -81
  92. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  93. package/.claude/hooks/speed-manager.sh +291 -291
  94. package/.claude/hooks/stop-tts.sh +84 -84
  95. package/.claude/hooks/termux-installer.sh +261 -261
  96. package/.claude/hooks/translate-manager.sh +341 -341
  97. package/.claude/hooks/translator.py +237 -237
  98. package/.claude/hooks/tts-queue-worker.sh +145 -145
  99. package/.claude/hooks/tts-queue.sh +165 -165
  100. package/.claude/hooks/verbosity-manager.sh +178 -178
  101. package/.claude/hooks/voice-manager.sh +548 -548
  102. package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
  103. package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
  104. package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
  105. package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
  106. package/.claude/hooks-windows/effects-manager.ps1 +294 -0
  107. package/.claude/hooks-windows/language-manager.ps1 +193 -0
  108. package/.claude/hooks-windows/learn-manager.ps1 +241 -0
  109. package/.claude/hooks-windows/personality-manager.ps1 +266 -0
  110. package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
  111. package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
  112. package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
  113. package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
  114. package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
  115. package/.claude/hooks-windows/play-tts.ps1 +344 -266
  116. package/.claude/hooks-windows/provider-manager.ps1 +29 -10
  117. package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
  118. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  119. package/.claude/hooks-windows/speed-manager.ps1 +166 -0
  120. package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
  121. package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
  122. package/.claude/output-styles/agent-vibes.md +202 -202
  123. package/.claude/personalities/angry.md +14 -14
  124. package/.claude/personalities/annoying.md +14 -14
  125. package/.claude/personalities/crass.md +14 -14
  126. package/.claude/personalities/dramatic.md +14 -14
  127. package/.claude/personalities/dry-humor.md +50 -50
  128. package/.claude/personalities/flirty.md +20 -20
  129. package/.claude/personalities/funny.md +14 -14
  130. package/.claude/personalities/grandpa.md +32 -32
  131. package/.claude/personalities/millennial.md +14 -14
  132. package/.claude/personalities/moody.md +14 -14
  133. package/.claude/personalities/normal.md +16 -16
  134. package/.claude/personalities/pirate.md +14 -14
  135. package/.claude/personalities/poetic.md +14 -14
  136. package/.claude/personalities/professional.md +14 -14
  137. package/.claude/personalities/rapper.md +55 -55
  138. package/.claude/personalities/robot.md +14 -14
  139. package/.claude/personalities/sarcastic.md +38 -38
  140. package/.claude/personalities/sassy.md +14 -14
  141. package/.claude/personalities/surfer-dude.md +14 -14
  142. package/.claude/personalities/zen.md +14 -14
  143. package/.claude/settings.json +15 -15
  144. package/.claude/verbosity.txt +1 -1
  145. package/.clawdbot/README.md +105 -105
  146. package/.clawdbot/skill/SKILL.md +241 -241
  147. package/.mcp.json +12 -0
  148. package/CLAUDE.md +170 -170
  149. package/README.md +2029 -2007
  150. package/RELEASE_NOTES.md +1310 -1203
  151. package/WINDOWS-SETUP.md +208 -208
  152. package/bin/agent-vibes +39 -39
  153. package/bin/agentvibes-voice-browser.js +1840 -1840
  154. package/bin/agentvibes.js +48 -2
  155. package/bin/mcp-server.js +121 -121
  156. package/bin/mcp-server.sh +206 -206
  157. package/bin/test-bmad-pr +78 -78
  158. package/mcp-server/QUICK_START.md +203 -203
  159. package/mcp-server/README.md +345 -345
  160. package/mcp-server/WINDOWS_SETUP.md +260 -260
  161. package/mcp-server/docs/troubleshooting-audio.md +313 -313
  162. package/mcp-server/examples/claude_desktop_config.json +11 -11
  163. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  164. package/mcp-server/examples/custom_instructions.md +169 -169
  165. package/mcp-server/install-deps.js +130 -130
  166. package/mcp-server/pyproject.toml +52 -52
  167. package/mcp-server/requirements.txt +2 -2
  168. package/mcp-server/server.py +1465 -1453
  169. package/mcp-server/test_server.py +395 -395
  170. package/mcp-server/test_windows_script_parity.py +336 -0
  171. package/package.json +110 -110
  172. package/setup-windows.ps1 +815 -815
  173. package/src/bmad-detector.js +71 -71
  174. package/src/cli/list-personalities.js +110 -110
  175. package/src/cli/list-voices.js +114 -114
  176. package/src/commands/bmad-voices.js +394 -394
  177. package/src/commands/install-mcp.js +476 -476
  178. package/src/console/app.js +824 -824
  179. package/src/console/audio-env.js +20 -1
  180. package/src/console/brand-colors.js +13 -13
  181. package/src/console/constants/personalities.js +44 -44
  182. package/src/console/footer-config.js +50 -50
  183. package/src/console/modals/modal-overlay.js +247 -247
  184. package/src/console/navigation.js +62 -62
  185. package/src/console/tabs/agents-tab.js +1684 -1516
  186. package/src/console/tabs/help-tab.js +261 -261
  187. package/src/console/tabs/install-tab.js +1007 -991
  188. package/src/console/tabs/music-tab.js +22 -8
  189. package/src/console/tabs/placeholder-tab.js +53 -53
  190. package/src/console/tabs/readme-tab.js +267 -267
  191. package/src/console/tabs/receiver-tab.js +1472 -1212
  192. package/src/console/tabs/settings-tab.js +152 -79
  193. package/src/console/tabs/voices-tab.js +100 -21
  194. package/src/console/widgets/destroy-list.js +25 -25
  195. package/src/console/widgets/format-utils.js +89 -89
  196. package/src/console/widgets/notice.js +55 -55
  197. package/src/console/widgets/personality-picker.js +185 -185
  198. package/src/console/widgets/reverb-picker.js +94 -94
  199. package/src/console/widgets/track-picker.js +285 -285
  200. package/src/installer/music-file-input.js +304 -304
  201. package/src/installer.js +5882 -5829
  202. package/src/services/agent-voice-store.js +423 -423
  203. package/src/services/config-service.js +264 -264
  204. package/src/services/navigation-service.js +123 -123
  205. package/src/services/provider-service.js +132 -132
  206. package/src/services/verbosity-service.js +157 -157
  207. package/src/utils/audio-duration-validator.js +298 -298
  208. package/src/utils/audio-format-validator.js +277 -277
  209. package/src/utils/dependency-checker.js +469 -466
  210. package/src/utils/file-ownership-verifier.js +358 -358
  211. package/src/utils/list-formatter.js +194 -194
  212. package/src/utils/music-file-validator.js +285 -285
  213. package/src/utils/preview-list-prompt.js +136 -136
  214. package/src/utils/provider-validator.js +96 -12
  215. package/src/utils/secure-music-storage.js +412 -412
  216. package/templates/agentvibes-receiver.sh +482 -482
  217. package/templates/audio/welcome-music.mp3 +0 -0
  218. package/voice-assignments.json +8244 -8244
  219. package/.claude/config/background-music-position.txt +0 -1
@@ -1,171 +1,171 @@
1
- #!/usr/bin/env bash
2
- #
3
- # File: .claude/hooks/piper-multispeaker-registry.sh
4
- #
5
- # AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
6
- # Website: https://agentvibes.org
7
- # Repository: https://github.com/paulpreibisch/AgentVibes
8
- #
9
- # Co-created by Paul Preibisch with Claude AI
10
- # Copyright (c) 2025 Paul Preibisch
11
- #
12
- # Licensed under the Apache License, Version 2.0 (the "License");
13
- # you may not use this file except in compliance with the License.
14
- # You may obtain a copy of the License at
15
- #
16
- # http://www.apache.org/licenses/LICENSE-2.0
17
- #
18
- # Unless required by applicable law or agreed to in writing, software
19
- # distributed under the License is distributed on an "AS IS" BASIS,
20
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- # See the License for the specific language governing permissions and
22
- # limitations under the License.
23
- #
24
- # DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
- # express or implied, including but not limited to the warranties of
26
- # merchantability, fitness for a particular purpose and noninfringement.
27
- # In no event shall the authors or copyright holders be liable for any claim,
28
- # damages or other liability, whether in an action of contract, tort or
29
- # otherwise, arising from, out of or in connection with the software or the
30
- # use or other dealings in the software.
31
- #
32
- # ---
33
- #
34
- # @fileoverview Multi-Speaker Voice Registry - Maps speaker names to ONNX models and speaker IDs
35
- # @context Enables individual speaker selection from multi-speaker Piper models (e.g., 16Speakers)
36
- # @architecture Static registry mapping speaker names to model files and numeric speaker IDs
37
- # @dependencies piper-voice-manager.sh (voice storage), play-tts-piper.sh (TTS with speaker ID)
38
- # @entrypoints Sourced by voice-manager.sh for multi-speaker voice switching
39
- # @patterns Registry pattern, speaker ID mapping, model-to-speaker association
40
- # @related voice-manager.sh, play-tts-piper.sh, 16Speakers.onnx.json (speaker_id_map)
41
- #
42
-
43
- # Bash 3.2 compatible lowercase function (macOS ships with bash 3.2)
44
- # ${var,,} syntax requires bash 4.0+
45
- _to_lower() {
46
- echo "$1" | tr '[:upper:]' '[:lower:]'
47
- }
48
-
49
- # Registry of multi-speaker models and their speaker names
50
- # Format: "SpeakerName:model_file:speaker_id:description"
51
- #
52
- # 16Speakers Model (12 US + 4 UK voices):
53
- # Source: LibriVox Public Domain recordings
54
- # Model: 16Speakers.onnx (77MB)
55
- #
56
- MULTISPEAKER_VOICES=(
57
- # US English Speakers (0-11)
58
- "Cori_Samuel:16Speakers:0:US English Female"
59
- "Kara_Shallenberg:16Speakers:1:US English Female"
60
- "Kristin_Hughes:16Speakers:2:US English Female"
61
- "Maria_Kasper:16Speakers:3:US English Female"
62
- "Mike_Pelton:16Speakers:4:US English Male"
63
- "Mark_Nelson:16Speakers:5:US English Male"
64
- "Michael_Scherer:16Speakers:6:US English Male"
65
- "James_K_White:16Speakers:7:US English Male"
66
- "Rose_Ibex:16Speakers:8:US English Female"
67
- "progressingamerica:16Speakers:9:US English Male"
68
- "Steve_C:16Speakers:10:US English Male"
69
- "Owlivia:16Speakers:11:US English Female"
70
-
71
- # UK English Speakers (12-15)
72
- "Paul_Hampton:16Speakers:12:UK English Male"
73
- "Jennifer_Dorr:16Speakers:13:UK English Female"
74
- "Emily_Cripps:16Speakers:14:UK English Female"
75
- "Martin_Clifton:16Speakers:15:UK English Male"
76
- )
77
-
78
- # @function get_multispeaker_info
79
- # @intent Get model and speaker ID for a speaker name
80
- # @why Enables users to select individual speakers from multi-speaker models by name
81
- # @param $1 {string} speaker_name - Speaker name (e.g., "Cori_Samuel", "Rose_Ibex")
82
- # @returns Echoes "model:speaker_id" (e.g., "16Speakers:0") to stdout
83
- # @exitcode 0=speaker found, 1=speaker not found
84
- # @sideeffects None (read-only lookup)
85
- # @edgecases Case-insensitive matching
86
- # @calledby voice-manager.sh switch command
87
- # @calls None (pure bash array iteration)
88
- get_multispeaker_info() {
89
- local speaker_name="$1"
90
- for entry in "${MULTISPEAKER_VOICES[@]}"; do
91
- name="${entry%%:*}"
92
- rest="${entry#*:}"
93
- model="${rest%%:*}"
94
- rest="${rest#*:}"
95
- speaker_id="${rest%%:*}"
96
-
97
- if [[ "$(_to_lower "$name")" == "$(_to_lower "$speaker_name")" ]]; then
98
- echo "$model:$speaker_id"
99
- return 0
100
- fi
101
- done
102
- return 1
103
- }
104
-
105
- # @function list_multispeaker_voices
106
- # @intent Display all available multi-speaker voices with descriptions
107
- # @why Help users discover individual speakers within multi-speaker models
108
- # @param None
109
- # @returns None
110
- # @exitcode Always 0
111
- # @sideeffects Writes formatted list to stdout
112
- # @edgecases None
113
- # @calledby voice-manager.sh list command, /agent-vibes:list
114
- # @calls None (pure bash array iteration)
115
- list_multispeaker_voices() {
116
- echo "🎭 Multi-Speaker Voices (16Speakers Model):"
117
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
118
-
119
- local current_model=""
120
- for entry in "${MULTISPEAKER_VOICES[@]}"; do
121
- name="${entry%%:*}"
122
- rest="${entry#*:}"
123
- model="${rest%%:*}"
124
- rest="${rest#*:}"
125
- speaker_id="${rest%%:*}"
126
- description="${rest#*:}"
127
-
128
- # Print section header when model changes
129
- if [[ "$model" != "$current_model" ]]; then
130
- if [[ -n "$current_model" ]]; then
131
- echo ""
132
- fi
133
- echo " Model: $model.onnx"
134
- current_model="$model"
135
- fi
136
-
137
- echo " • $name (ID: $speaker_id) - $description"
138
- done
139
-
140
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
141
- echo ""
142
- echo "Usage: /agent-vibes:switch Cori_Samuel"
143
- echo " /agent-vibes:switch Rose_Ibex"
144
- }
145
-
146
- # @function get_multispeaker_description
147
- # @intent Get description for a speaker name
148
- # @why Provide user-friendly info about speaker characteristics
149
- # @param $1 {string} speaker_name - Speaker name
150
- # @returns Echoes description (e.g., "US English Female") to stdout
151
- # @exitcode 0=speaker found, 1=speaker not found
152
- # @sideeffects None (read-only lookup)
153
- # @edgecases Case-insensitive matching
154
- # @calledby voice-manager.sh switch command (for confirmation message)
155
- # @calls None (pure bash array iteration)
156
- get_multispeaker_description() {
157
- local speaker_name="$1"
158
- for entry in "${MULTISPEAKER_VOICES[@]}"; do
159
- name="${entry%%:*}"
160
- rest="${entry#*:}"
161
- rest="${rest#*:}"
162
- rest="${rest#*:}"
163
- description="${rest}"
164
-
165
- if [[ "$(_to_lower "$name")" == "$(_to_lower "$speaker_name")" ]]; then
166
- echo "$description"
167
- return 0
168
- fi
169
- done
170
- return 1
171
- }
1
+ #!/usr/bin/env bash
2
+ #
3
+ # File: .claude/hooks/piper-multispeaker-registry.sh
4
+ #
5
+ # AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
6
+ # Website: https://agentvibes.org
7
+ # Repository: https://github.com/paulpreibisch/AgentVibes
8
+ #
9
+ # Co-created by Paul Preibisch with Claude AI
10
+ # Copyright (c) 2025 Paul Preibisch
11
+ #
12
+ # Licensed under the Apache License, Version 2.0 (the "License");
13
+ # you may not use this file except in compliance with the License.
14
+ # You may obtain a copy of the License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the License is distributed on an "AS IS" BASIS,
20
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ # See the License for the specific language governing permissions and
22
+ # limitations under the License.
23
+ #
24
+ # DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
+ # express or implied, including but not limited to the warranties of
26
+ # merchantability, fitness for a particular purpose and noninfringement.
27
+ # In no event shall the authors or copyright holders be liable for any claim,
28
+ # damages or other liability, whether in an action of contract, tort or
29
+ # otherwise, arising from, out of or in connection with the software or the
30
+ # use or other dealings in the software.
31
+ #
32
+ # ---
33
+ #
34
+ # @fileoverview Multi-Speaker Voice Registry - Maps speaker names to ONNX models and speaker IDs
35
+ # @context Enables individual speaker selection from multi-speaker Piper models (e.g., 16Speakers)
36
+ # @architecture Static registry mapping speaker names to model files and numeric speaker IDs
37
+ # @dependencies piper-voice-manager.sh (voice storage), play-tts-piper.sh (TTS with speaker ID)
38
+ # @entrypoints Sourced by voice-manager.sh for multi-speaker voice switching
39
+ # @patterns Registry pattern, speaker ID mapping, model-to-speaker association
40
+ # @related voice-manager.sh, play-tts-piper.sh, 16Speakers.onnx.json (speaker_id_map)
41
+ #
42
+
43
+ # Bash 3.2 compatible lowercase function (macOS ships with bash 3.2)
44
+ # ${var,,} syntax requires bash 4.0+
45
+ _to_lower() {
46
+ echo "$1" | tr '[:upper:]' '[:lower:]'
47
+ }
48
+
49
+ # Registry of multi-speaker models and their speaker names
50
+ # Format: "SpeakerName:model_file:speaker_id:description"
51
+ #
52
+ # 16Speakers Model (12 US + 4 UK voices):
53
+ # Source: LibriVox Public Domain recordings
54
+ # Model: 16Speakers.onnx (77MB)
55
+ #
56
+ MULTISPEAKER_VOICES=(
57
+ # US English Speakers (0-11)
58
+ "Cori_Samuel:16Speakers:0:US English Female"
59
+ "Kara_Shallenberg:16Speakers:1:US English Female"
60
+ "Kristin_Hughes:16Speakers:2:US English Female"
61
+ "Maria_Kasper:16Speakers:3:US English Female"
62
+ "Mike_Pelton:16Speakers:4:US English Male"
63
+ "Mark_Nelson:16Speakers:5:US English Male"
64
+ "Michael_Scherer:16Speakers:6:US English Male"
65
+ "James_K_White:16Speakers:7:US English Male"
66
+ "Rose_Ibex:16Speakers:8:US English Female"
67
+ "progressingamerica:16Speakers:9:US English Male"
68
+ "Steve_C:16Speakers:10:US English Male"
69
+ "Owlivia:16Speakers:11:US English Female"
70
+
71
+ # UK English Speakers (12-15)
72
+ "Paul_Hampton:16Speakers:12:UK English Male"
73
+ "Jennifer_Dorr:16Speakers:13:UK English Female"
74
+ "Emily_Cripps:16Speakers:14:UK English Female"
75
+ "Martin_Clifton:16Speakers:15:UK English Male"
76
+ )
77
+
78
+ # @function get_multispeaker_info
79
+ # @intent Get model and speaker ID for a speaker name
80
+ # @why Enables users to select individual speakers from multi-speaker models by name
81
+ # @param $1 {string} speaker_name - Speaker name (e.g., "Cori_Samuel", "Rose_Ibex")
82
+ # @returns Echoes "model:speaker_id" (e.g., "16Speakers:0") to stdout
83
+ # @exitcode 0=speaker found, 1=speaker not found
84
+ # @sideeffects None (read-only lookup)
85
+ # @edgecases Case-insensitive matching
86
+ # @calledby voice-manager.sh switch command
87
+ # @calls None (pure bash array iteration)
88
+ get_multispeaker_info() {
89
+ local speaker_name="$1"
90
+ for entry in "${MULTISPEAKER_VOICES[@]}"; do
91
+ name="${entry%%:*}"
92
+ rest="${entry#*:}"
93
+ model="${rest%%:*}"
94
+ rest="${rest#*:}"
95
+ speaker_id="${rest%%:*}"
96
+
97
+ if [[ "$(_to_lower "$name")" == "$(_to_lower "$speaker_name")" ]]; then
98
+ echo "$model:$speaker_id"
99
+ return 0
100
+ fi
101
+ done
102
+ return 1
103
+ }
104
+
105
+ # @function list_multispeaker_voices
106
+ # @intent Display all available multi-speaker voices with descriptions
107
+ # @why Help users discover individual speakers within multi-speaker models
108
+ # @param None
109
+ # @returns None
110
+ # @exitcode Always 0
111
+ # @sideeffects Writes formatted list to stdout
112
+ # @edgecases None
113
+ # @calledby voice-manager.sh list command, /agent-vibes:list
114
+ # @calls None (pure bash array iteration)
115
+ list_multispeaker_voices() {
116
+ echo "🎭 Multi-Speaker Voices (16Speakers Model):"
117
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
118
+
119
+ local current_model=""
120
+ for entry in "${MULTISPEAKER_VOICES[@]}"; do
121
+ name="${entry%%:*}"
122
+ rest="${entry#*:}"
123
+ model="${rest%%:*}"
124
+ rest="${rest#*:}"
125
+ speaker_id="${rest%%:*}"
126
+ description="${rest#*:}"
127
+
128
+ # Print section header when model changes
129
+ if [[ "$model" != "$current_model" ]]; then
130
+ if [[ -n "$current_model" ]]; then
131
+ echo ""
132
+ fi
133
+ echo " Model: $model.onnx"
134
+ current_model="$model"
135
+ fi
136
+
137
+ echo " • $name (ID: $speaker_id) - $description"
138
+ done
139
+
140
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
141
+ echo ""
142
+ echo "Usage: /agent-vibes:switch Cori_Samuel"
143
+ echo " /agent-vibes:switch Rose_Ibex"
144
+ }
145
+
146
+ # @function get_multispeaker_description
147
+ # @intent Get description for a speaker name
148
+ # @why Provide user-friendly info about speaker characteristics
149
+ # @param $1 {string} speaker_name - Speaker name
150
+ # @returns Echoes description (e.g., "US English Female") to stdout
151
+ # @exitcode 0=speaker found, 1=speaker not found
152
+ # @sideeffects None (read-only lookup)
153
+ # @edgecases Case-insensitive matching
154
+ # @calledby voice-manager.sh switch command (for confirmation message)
155
+ # @calls None (pure bash array iteration)
156
+ get_multispeaker_description() {
157
+ local speaker_name="$1"
158
+ for entry in "${MULTISPEAKER_VOICES[@]}"; do
159
+ name="${entry%%:*}"
160
+ rest="${entry#*:}"
161
+ rest="${rest#*:}"
162
+ rest="${rest#*:}"
163
+ description="${rest}"
164
+
165
+ if [[ "$(_to_lower "$name")" == "$(_to_lower "$speaker_name")" ]]; then
166
+ echo "$description"
167
+ return 0
168
+ fi
169
+ done
170
+ return 1
171
+ }
@@ -84,8 +84,10 @@ get_voice_storage_dir() {
84
84
  done
85
85
 
86
86
  # Check global config
87
- if [[ -z "$config_file" ]] && [[ -f "$HOME/.claude/piper-voices-dir.txt" ]]; then
88
- config_file="$HOME/.claude/piper-voices-dir.txt"
87
+ # Prefer $USERPROFILE on Windows where $HOME may be a MINGW-internal path
88
+ local _home="${USERPROFILE:-$HOME}"
89
+ if [[ -z "$config_file" ]] && [[ -f "$_home/.claude/piper-voices-dir.txt" ]]; then
90
+ config_file="$_home/.claude/piper-voices-dir.txt"
89
91
  fi
90
92
  fi
91
93
 
@@ -94,9 +96,22 @@ get_voice_storage_dir() {
94
96
  fi
95
97
  fi
96
98
 
99
+ # Validate the path is reachable — on Windows/MINGW, stale config files may
100
+ # contain bogus paths like /home/user that map to C:/Program Files/Git/home/
101
+ if [[ -n "$voice_dir" ]]; then
102
+ local parent_dir
103
+ parent_dir=$(dirname "$voice_dir")
104
+ if ! mkdir -p "$parent_dir" 2>/dev/null; then
105
+ voice_dir=""
106
+ fi
107
+ fi
108
+
97
109
  # Fallback to default global storage
110
+ # On Windows (MINGW/Git Bash), $HOME may resolve to a bogus Git-internal path;
111
+ # prefer $USERPROFILE which always points to the real Windows home directory.
98
112
  if [[ -z "$voice_dir" ]]; then
99
- voice_dir="$HOME/.claude/piper-voices"
113
+ local home_dir="${USERPROFILE:-$HOME}"
114
+ voice_dir="$home_dir/.claude/piper-voices"
100
115
  fi
101
116
 
102
117
  mkdir -p "$voice_dir"
@@ -198,6 +213,12 @@ download_voice() {
198
213
  local voice_name="$1"
199
214
  local lang_code="${2:-}"
200
215
 
216
+ # Security: validate voice name to prevent path traversal
217
+ if [[ ! "$voice_name" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
218
+ echo "❌ Invalid voice name: $voice_name" >&2
219
+ return 1
220
+ fi
221
+
201
222
  local voice_dir
202
223
  voice_dir=$(get_voice_storage_dir)
203
224
 
@@ -1,90 +1,90 @@
1
- #!/usr/bin/env bash
2
- #
3
- # File: .claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh
4
- #
5
- # AgentVibes - AgentVibes Receiver Provider (for voiceless connections)
6
- # Sends text to a remote device via SSH for local AgentVibes playback.
7
- # Use this when the AI agent runs on a server/headless machine that has no
8
- # audio output — the remote device (laptop, phone, etc.) plays the audio.
9
- #
10
- # Copyright (c) 2025 Paul Preibisch
11
- # Licensed under the Apache License, Version 2.0
12
- #
13
-
14
- set -euo pipefail
15
-
16
- TEXT="${1:-}"
17
- VOICE="${2:-en_US-lessac-medium}"
18
- AGENT_NAME="${3:-default}"
19
-
20
- # Validate required input
21
- if [[ -z "$TEXT" ]]; then
22
- echo "❌ No text provided" >&2
23
- echo "Usage: $0 <text> [voice] [agent_name]" >&2
24
- exit 1
25
- fi
26
-
27
- # Get script directory
28
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
30
-
31
- # Get SSH host from config
32
- SSH_HOST=$(cat "$PROJECT_ROOT/.claude/agentvibes-receiver-host.txt" 2>/dev/null || \
33
- cat "$HOME/.claude/agentvibes-receiver-host.txt" 2>/dev/null || echo "")
34
-
35
- if [[ -z "$SSH_HOST" ]]; then
36
- echo "❌ AgentVibes Receiver host not configured" >&2
37
- echo "💡 Set host: echo 'your-device' > ~/.claude/agentvibes-receiver-host.txt" >&2
38
- exit 1
39
- fi
40
-
41
- # SECURITY: Validate SSH_HOST to prevent option injection
42
- # Must be a valid hostname, IP address, or SSH config alias (alphanumeric, dots, hyphens, underscores)
43
- if [[ ! "$SSH_HOST" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
44
- echo "❌ Invalid SSH host format: $SSH_HOST" >&2
45
- echo "💡 Host must be alphanumeric (may contain dots, hyphens, underscores)" >&2
46
- exit 1
47
- fi
48
-
49
- # SECURITY: Reject hosts starting with hyphen (SSH option injection)
50
- if [[ "$SSH_HOST" == -* ]]; then
51
- echo "❌ Invalid SSH host: cannot start with hyphen" >&2
52
- exit 1
53
- fi
54
-
55
- # SECURITY: Validate VOICE to prevent injection (alphanumeric, hyphens, underscores only)
56
- if [[ ! "$VOICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
57
- echo "❌ Invalid voice format: $VOICE" >&2
58
- exit 1
59
- fi
60
-
61
- # SECURITY: Validate AGENT_NAME to prevent injection (alphanumeric, hyphens, underscores, spaces only)
62
- if [[ ! "$AGENT_NAME" =~ ^[a-zA-Z0-9_\ -]+$ ]]; then
63
- echo "❌ Invalid agent name format: $AGENT_NAME" >&2
64
- exit 1
65
- fi
66
-
67
- # SECURITY: Encode text and agent name as base64 to prevent command injection
68
- # The receiver will decode these safely
69
- ENCODED_TEXT=$(printf '%s' "$TEXT" | base64 -w 0)
70
- ENCODED_AGENT=$(printf '%s' "$AGENT_NAME" | base64 -w 0)
71
-
72
- # Send text to remote for local AgentVibes playback
73
- echo "📱 Sending to $SSH_HOST for local playback..." >&2
74
-
75
- # Try receiver scripts in order — single SSH call, no separate probe
76
- # SECURITY: Base64-encoded values are safe to pass as arguments (no shell metacharacters)
77
- ssh "$SSH_HOST" "
78
- if [ -f ~/.agentvibes/play-remote.sh ]; then
79
- bash ~/.agentvibes/play-remote.sh '$ENCODED_TEXT' '$VOICE' '$ENCODED_AGENT'
80
- elif [ -f ~/.termux/agentvibes-play.sh ]; then
81
- bash ~/.termux/agentvibes-play.sh '$ENCODED_TEXT' '$VOICE' '$ENCODED_AGENT'
82
- else
83
- echo 'Error: Receiver script not found' >&2
84
- exit 1
85
- fi
86
- " &
87
- SSH_PID=$!
88
-
89
- echo "Sent to $SSH_HOST (PID: $SSH_PID)" >&2
90
- exit 0
1
+ #!/usr/bin/env bash
2
+ #
3
+ # File: .claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh
4
+ #
5
+ # AgentVibes - AgentVibes Receiver Provider (for voiceless connections)
6
+ # Sends text to a remote device via SSH for local AgentVibes playback.
7
+ # Use this when the AI agent runs on a server/headless machine that has no
8
+ # audio output — the remote device (laptop, phone, etc.) plays the audio.
9
+ #
10
+ # Copyright (c) 2025 Paul Preibisch
11
+ # Licensed under the Apache License, Version 2.0
12
+ #
13
+
14
+ set -euo pipefail
15
+
16
+ TEXT="${1:-}"
17
+ VOICE="${2:-en_US-lessac-medium}"
18
+ AGENT_NAME="${3:-default}"
19
+
20
+ # Validate required input
21
+ if [[ -z "$TEXT" ]]; then
22
+ echo "❌ No text provided" >&2
23
+ echo "Usage: $0 <text> [voice] [agent_name]" >&2
24
+ exit 1
25
+ fi
26
+
27
+ # Get script directory
28
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
30
+
31
+ # Get SSH host from config
32
+ SSH_HOST=$(cat "$PROJECT_ROOT/.claude/agentvibes-receiver-host.txt" 2>/dev/null || \
33
+ cat "$HOME/.claude/agentvibes-receiver-host.txt" 2>/dev/null || echo "")
34
+
35
+ if [[ -z "$SSH_HOST" ]]; then
36
+ echo "❌ AgentVibes Receiver host not configured" >&2
37
+ echo "💡 Set host: echo 'your-device' > ~/.claude/agentvibes-receiver-host.txt" >&2
38
+ exit 1
39
+ fi
40
+
41
+ # SECURITY: Validate SSH_HOST to prevent option injection
42
+ # Must be a valid hostname, IP address, or SSH config alias (alphanumeric, dots, hyphens, underscores)
43
+ if [[ ! "$SSH_HOST" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
44
+ echo "❌ Invalid SSH host format: $SSH_HOST" >&2
45
+ echo "💡 Host must be alphanumeric (may contain dots, hyphens, underscores)" >&2
46
+ exit 1
47
+ fi
48
+
49
+ # SECURITY: Reject hosts starting with hyphen (SSH option injection)
50
+ if [[ "$SSH_HOST" == -* ]]; then
51
+ echo "❌ Invalid SSH host: cannot start with hyphen" >&2
52
+ exit 1
53
+ fi
54
+
55
+ # SECURITY: Validate VOICE to prevent injection (alphanumeric, hyphens, underscores only)
56
+ if [[ ! "$VOICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
57
+ echo "❌ Invalid voice format: $VOICE" >&2
58
+ exit 1
59
+ fi
60
+
61
+ # SECURITY: Validate AGENT_NAME to prevent injection (alphanumeric, hyphens, underscores, spaces only)
62
+ if [[ ! "$AGENT_NAME" =~ ^[a-zA-Z0-9_\ -]+$ ]]; then
63
+ echo "❌ Invalid agent name format: $AGENT_NAME" >&2
64
+ exit 1
65
+ fi
66
+
67
+ # SECURITY: Encode text and agent name as base64 to prevent command injection
68
+ # The receiver will decode these safely
69
+ ENCODED_TEXT=$(printf '%s' "$TEXT" | base64 -w 0)
70
+ ENCODED_AGENT=$(printf '%s' "$AGENT_NAME" | base64 -w 0)
71
+
72
+ # Send text to remote for local AgentVibes playback
73
+ echo "📱 Sending to $SSH_HOST for local playback..." >&2
74
+
75
+ # Try receiver scripts in order — single SSH call, no separate probe
76
+ # SECURITY: Base64-encoded values are safe to pass as arguments (no shell metacharacters)
77
+ ssh "$SSH_HOST" "
78
+ if [ -f ~/.agentvibes/play-remote.sh ]; then
79
+ bash ~/.agentvibes/play-remote.sh '$ENCODED_TEXT' '$VOICE' '$ENCODED_AGENT'
80
+ elif [ -f ~/.termux/agentvibes-play.sh ]; then
81
+ bash ~/.termux/agentvibes-play.sh '$ENCODED_TEXT' '$VOICE' '$ENCODED_AGENT'
82
+ else
83
+ echo 'Error: Receiver script not found' >&2
84
+ exit 1
85
+ fi
86
+ " &
87
+ SSH_PID=$!
88
+
89
+ echo "Sent to $SSH_HOST (PID: $SSH_PID)" >&2
90
+ exit 0