agentvibes 4.0.1 โ 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.
- package/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config.json +12 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/tracks/README.md +52 -52
- package/.claude/commands/agent-vibes/add.md +21 -21
- package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
- package/.claude/commands/agent-vibes/agent.md +79 -79
- package/.claude/commands/agent-vibes/background-music.md +111 -111
- package/.claude/commands/agent-vibes/bmad.md +198 -198
- package/.claude/commands/agent-vibes/clean.md +18 -18
- package/.claude/commands/agent-vibes/cleanup.md +18 -18
- package/.claude/commands/agent-vibes/commands.json +145 -145
- package/.claude/commands/agent-vibes/effects.md +97 -97
- package/.claude/commands/agent-vibes/get.md +9 -9
- package/.claude/commands/agent-vibes/hide.md +91 -91
- package/.claude/commands/agent-vibes/language.md +23 -23
- package/.claude/commands/agent-vibes/learn.md +67 -67
- package/.claude/commands/agent-vibes/list.md +13 -13
- package/.claude/commands/agent-vibes/mute.md +37 -37
- package/.claude/commands/agent-vibes/preview.md +17 -17
- package/.claude/commands/agent-vibes/provider.md +68 -68
- package/.claude/commands/agent-vibes/replay-target.md +14 -14
- package/.claude/commands/agent-vibes/sample.md +12 -12
- package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
- package/.claude/commands/agent-vibes/set-pretext.md +65 -65
- package/.claude/commands/agent-vibes/set-speed.md +41 -41
- package/.claude/commands/agent-vibes/show.md +84 -84
- package/.claude/commands/agent-vibes/switch.md +87 -87
- package/.claude/commands/agent-vibes/target-voice.md +26 -26
- package/.claude/commands/agent-vibes/target.md +30 -30
- package/.claude/commands/agent-vibes/translate.md +68 -68
- package/.claude/commands/agent-vibes/unmute.md +45 -45
- package/.claude/commands/agent-vibes/verbosity.md +89 -89
- package/.claude/commands/agent-vibes/whoami.md +7 -7
- package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
- package/.claude/commands/agent-vibes-rdp.md +24 -24
- package/.claude/config/agentvibes.json +1 -0
- package/.claude/config/audio-effects.cfg +3 -2
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-volume.txt +1 -0
- package/.claude/config/intro-text.txt +1 -0
- package/.claude/config/piper-speech-rate.txt +4 -0
- package/.claude/config/piper-target-speech-rate.txt +1 -0
- package/.claude/config/reverb-level.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +4 -0
- package/.claude/config/tts-target-speech-rate.txt +1 -0
- package/.claude/docs/TERMUX_SETUP.md +408 -408
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/README-TTS-QUEUE.md +135 -135
- package/.claude/hooks/audio-cache-utils.sh +246 -246
- package/.claude/hooks/audio-processor.sh +433 -389
- package/.claude/hooks/background-music-manager.sh +404 -404
- package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
- package/.claude/hooks/bmad-speak.sh +269 -112
- package/.claude/hooks/bmad-tts-injector.sh +568 -568
- package/.claude/hooks/bmad-voice-manager.sh +928 -928
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
- package/.claude/hooks/clawdbot-receiver.sh +107 -107
- package/.claude/hooks/clean-audio-cache.sh +22 -22
- package/.claude/hooks/cleanup-cache.sh +106 -106
- package/.claude/hooks/configure-rdp-mode.sh +137 -137
- package/.claude/hooks/download-extra-voices.sh +244 -244
- package/.claude/hooks/effects-manager.sh +268 -268
- package/.claude/hooks/github-star-reminder.sh +154 -154
- package/.claude/hooks/language-manager.sh +362 -362
- package/.claude/hooks/learn-manager.sh +492 -492
- package/.claude/hooks/macos-voice-manager.sh +205 -205
- package/.claude/hooks/migrate-background-music.sh +125 -125
- package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
- package/.claude/hooks/optimize-background-music.sh +87 -87
- package/.claude/hooks/path-resolver.sh +60 -60
- package/.claude/hooks/personality-manager.sh +448 -448
- package/.claude/hooks/piper-download-voices.sh +225 -225
- package/.claude/hooks/piper-installer.sh +292 -292
- package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
- package/.claude/hooks/piper-voice-manager.sh +24 -3
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
- package/.claude/hooks/play-tts-enhanced.sh +105 -70
- package/.claude/hooks/play-tts-macos.sh +368 -345
- package/.claude/hooks/play-tts-piper.sh +679 -578
- package/.claude/hooks/play-tts-soprano.sh +356 -320
- package/.claude/hooks/play-tts-ssh-remote.sh +167 -88
- package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
- package/.claude/hooks/play-tts.sh +301 -298
- package/.claude/hooks/prepare-release.sh +54 -54
- package/.claude/hooks/provider-commands.sh +617 -617
- package/.claude/hooks/provider-manager.sh +399 -399
- package/.claude/hooks/replay-target-audio.sh +95 -95
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +201 -201
- package/.claude/hooks/session-start-tts.sh +81 -71
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +291 -291
- package/.claude/hooks/stop-tts.sh +84 -0
- package/.claude/hooks/termux-installer.sh +261 -261
- package/.claude/hooks/translate-manager.sh +341 -341
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +145 -114
- package/.claude/hooks/tts-queue.sh +165 -136
- package/.claude/hooks/verbosity-manager.sh +178 -178
- package/.claude/hooks/voice-manager.sh +548 -544
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
- package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
- package/.claude/hooks-windows/effects-manager.ps1 +294 -0
- package/.claude/hooks-windows/language-manager.ps1 +193 -0
- package/.claude/hooks-windows/learn-manager.ps1 +241 -0
- package/.claude/hooks-windows/personality-manager.ps1 +266 -0
- package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
- package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
- package/.claude/hooks-windows/play-tts.ps1 +344 -266
- package/.claude/hooks-windows/provider-manager.ps1 +29 -10
- package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -0
- package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
- package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
- package/.claude/output-styles/agent-vibes.md +202 -202
- package/.claude/personalities/angry.md +14 -14
- package/.claude/personalities/annoying.md +14 -14
- package/.claude/personalities/crass.md +14 -14
- package/.claude/personalities/dramatic.md +14 -14
- package/.claude/personalities/dry-humor.md +50 -50
- package/.claude/personalities/flirty.md +20 -20
- package/.claude/personalities/funny.md +14 -14
- package/.claude/personalities/grandpa.md +32 -32
- package/.claude/personalities/millennial.md +14 -14
- package/.claude/personalities/moody.md +14 -14
- package/.claude/personalities/normal.md +16 -16
- package/.claude/personalities/pirate.md +14 -14
- package/.claude/personalities/poetic.md +14 -14
- package/.claude/personalities/professional.md +14 -14
- package/.claude/personalities/rapper.md +55 -55
- package/.claude/personalities/robot.md +14 -14
- package/.claude/personalities/sarcastic.md +38 -38
- package/.claude/personalities/sassy.md +14 -14
- package/.claude/personalities/surfer-dude.md +14 -14
- package/.claude/personalities/zen.md +14 -14
- package/.claude/settings.json +15 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +241 -241
- package/.mcp.json +12 -0
- package/CLAUDE.md +170 -181
- package/README.md +2029 -1909
- package/RELEASE_NOTES.md +1310 -66
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/agentvibes-voice-browser.js +1840 -1826
- package/bin/agentvibes.js +48 -2
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +206 -206
- package/bin/test-bmad-pr +78 -78
- package/mcp-server/QUICK_START.md +203 -203
- package/mcp-server/README.md +345 -345
- package/mcp-server/WINDOWS_SETUP.md +260 -260
- package/mcp-server/docs/troubleshooting-audio.md +313 -313
- package/mcp-server/examples/claude_desktop_config.json +11 -11
- package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
- package/mcp-server/examples/custom_instructions.md +169 -169
- package/mcp-server/install-deps.js +130 -130
- package/mcp-server/pyproject.toml +52 -52
- package/mcp-server/requirements.txt +2 -2
- package/mcp-server/server.py +1465 -1417
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +336 -0
- package/package.json +110 -112
- package/setup-windows.ps1 +815 -815
- package/src/bmad-detector.js +71 -71
- package/src/cli/list-personalities.js +110 -110
- package/src/cli/list-voices.js +114 -114
- package/src/commands/bmad-voices.js +394 -394
- package/src/commands/install-mcp.js +476 -476
- package/src/console/app.js +824 -806
- package/src/console/audio-env.js +20 -1
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -0
- package/src/console/footer-config.js +50 -46
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +62 -61
- package/src/console/tabs/agents-tab.js +1684 -369
- package/src/console/tabs/help-tab.js +261 -261
- package/src/console/tabs/install-tab.js +1007 -991
- package/src/console/tabs/music-tab.js +22 -8
- package/src/console/tabs/placeholder-tab.js +53 -46
- package/src/console/tabs/readme-tab.js +267 -267
- package/src/console/tabs/receiver-tab.js +1472 -0
- package/src/console/tabs/settings-tab.js +185 -402
- package/src/console/tabs/voices-tab.js +100 -21
- package/src/console/widgets/destroy-list.js +25 -0
- package/src/console/widgets/format-utils.js +89 -0
- package/src/console/widgets/notice.js +55 -0
- package/src/console/widgets/personality-picker.js +185 -0
- package/src/console/widgets/reverb-picker.js +94 -0
- package/src/console/widgets/track-picker.js +285 -0
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +5882 -5777
- package/src/services/agent-voice-store.js +423 -163
- package/src/services/config-service.js +264 -264
- package/src/services/navigation-service.js +123 -123
- package/src/services/provider-service.js +132 -132
- package/src/services/verbosity-service.js +157 -157
- package/src/utils/audio-duration-validator.js +298 -298
- package/src/utils/audio-format-validator.js +277 -277
- package/src/utils/dependency-checker.js +469 -466
- package/src/utils/file-ownership-verifier.js +358 -358
- package/src/utils/list-formatter.js +194 -194
- package/src/utils/music-file-validator.js +285 -275
- package/src/utils/preview-list-prompt.js +136 -136
- package/src/utils/provider-validator.js +96 -12
- package/src/utils/secure-music-storage.js +412 -412
- package/templates/agentvibes-receiver.sh +482 -162
- package/templates/audio/welcome-music.mp3 +0 -0
- package/voice-assignments.json +8244 -8244
- package/.claude/config/background-music-position.txt +0 -1
|
@@ -1,345 +1,368 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# File: .claude/hooks/play-tts-macos.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. Use at your own risk. See the Apache License for details.
|
|
26
|
-
#
|
|
27
|
-
# ---
|
|
28
|
-
#
|
|
29
|
-
# @fileoverview macOS Say Provider Implementation - Native macOS TTS using the 'say' command
|
|
30
|
-
# @context Provides zero-dependency, offline TTS for macOS users using built-in Apple voices
|
|
31
|
-
# @architecture Implements provider interface contract for macOS 'say' command integration
|
|
32
|
-
# @dependencies macOS only (Darwin), say command (built-in), afplay (built-in)
|
|
33
|
-
# @entrypoints Called by play-tts.sh router when provider=macos
|
|
34
|
-
# @patterns Provider contract: text/voice โ audio file path, voice validation, platform guard
|
|
35
|
-
# @related play-tts.sh, macos-voice-manager.sh, provider-manager.sh
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
# Platform guard - fail fast on non-macOS systems
|
|
39
|
-
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
40
|
-
echo "โ Error: macOS provider only works on macOS"
|
|
41
|
-
echo " Current platform: $(uname -s)"
|
|
42
|
-
echo ""
|
|
43
|
-
echo " Switch to a different provider:"
|
|
44
|
-
echo " /agent-vibes:provider switch piper"
|
|
45
|
-
exit 1
|
|
46
|
-
fi
|
|
47
|
-
|
|
48
|
-
TEXT="$1"
|
|
49
|
-
VOICE_OVERRIDE="$2" # Optional: voice name (e.g., "Samantha", "Daniel")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
fi
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
# @
|
|
127
|
-
# @
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
say -v ?
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
#
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
# @
|
|
215
|
-
# @
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
#
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
#
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
#
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
#
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
fi
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
#
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# File: .claude/hooks/play-tts-macos.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. Use at your own risk. See the Apache License for details.
|
|
26
|
+
#
|
|
27
|
+
# ---
|
|
28
|
+
#
|
|
29
|
+
# @fileoverview macOS Say Provider Implementation - Native macOS TTS using the 'say' command
|
|
30
|
+
# @context Provides zero-dependency, offline TTS for macOS users using built-in Apple voices
|
|
31
|
+
# @architecture Implements provider interface contract for macOS 'say' command integration
|
|
32
|
+
# @dependencies macOS only (Darwin), say command (built-in), afplay (built-in)
|
|
33
|
+
# @entrypoints Called by play-tts.sh router when provider=macos
|
|
34
|
+
# @patterns Provider contract: text/voice โ audio file path, voice validation, platform guard
|
|
35
|
+
# @related play-tts.sh, macos-voice-manager.sh, provider-manager.sh
|
|
36
|
+
#
|
|
37
|
+
|
|
38
|
+
# Platform guard - fail fast on non-macOS systems
|
|
39
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
40
|
+
echo "โ Error: macOS provider only works on macOS"
|
|
41
|
+
echo " Current platform: $(uname -s)"
|
|
42
|
+
echo ""
|
|
43
|
+
echo " Switch to a different provider:"
|
|
44
|
+
echo " /agent-vibes:provider switch piper"
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
TEXT="$1"
|
|
49
|
+
VOICE_OVERRIDE="$2" # Optional: voice name (e.g., "Samantha", "Daniel")
|
|
50
|
+
|
|
51
|
+
# Strip emojis, asterisks, and markdown formatting
|
|
52
|
+
TEXT=$(printf '%s' "$TEXT" | perl -CSD -pe '
|
|
53
|
+
s/[\x{1F300}-\x{1F9FF}]//g;
|
|
54
|
+
s/[\x{2600}-\x{27BF}]//g;
|
|
55
|
+
s/[\x{FE00}-\x{FE0F}]//g;
|
|
56
|
+
s/[\x{200D}]//g;
|
|
57
|
+
s/[\x{2500}-\x{257F}]//g;
|
|
58
|
+
s/[\x{2580}-\x{259F}]//g;
|
|
59
|
+
s/\*+//g; s/#+\s*//g; s/`//g; s/~+//g; s/^\s*[-]\s*//g;
|
|
60
|
+
')
|
|
61
|
+
|
|
62
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
63
|
+
|
|
64
|
+
# Source audio cache utilities
|
|
65
|
+
source "$SCRIPT_DIR/audio-cache-utils.sh"
|
|
66
|
+
|
|
67
|
+
# Default voice for macOS
|
|
68
|
+
DEFAULT_VOICE="Samantha"
|
|
69
|
+
|
|
70
|
+
# Common macOS voices with descriptions
|
|
71
|
+
# These are typically available on all macOS systems
|
|
72
|
+
# Using simple list format for bash 3.x compatibility (macOS default)
|
|
73
|
+
show_common_voices() {
|
|
74
|
+
echo " Alex - American English male (enhanced)"
|
|
75
|
+
echo " Daniel - British English male (enhanced)"
|
|
76
|
+
echo " Fiona - Scottish English female (enhanced)"
|
|
77
|
+
echo " Karen - Australian English female (enhanced)"
|
|
78
|
+
echo " Moira - Irish English female (enhanced)"
|
|
79
|
+
echo " Samantha - American English female (enhanced)"
|
|
80
|
+
echo " Tessa - South African English female (enhanced)"
|
|
81
|
+
echo " Veena - Indian English female (enhanced)"
|
|
82
|
+
echo " Victoria - American English female"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# @function get_voice_file_path
|
|
86
|
+
# @intent Determine path to voice configuration file
|
|
87
|
+
# @returns Echoes path to tts-voice.txt
|
|
88
|
+
get_voice_file_path() {
|
|
89
|
+
local voice_file=""
|
|
90
|
+
|
|
91
|
+
if [[ -n "$CLAUDE_PROJECT_DIR" ]] && [[ -f "$CLAUDE_PROJECT_DIR/.claude/tts-voice.txt" ]]; then
|
|
92
|
+
voice_file="$CLAUDE_PROJECT_DIR/.claude/tts-voice.txt"
|
|
93
|
+
elif [[ -f "$SCRIPT_DIR/../tts-voice.txt" ]]; then
|
|
94
|
+
voice_file="$SCRIPT_DIR/../tts-voice.txt"
|
|
95
|
+
elif [[ -f "$HOME/.claude/tts-voice.txt" ]]; then
|
|
96
|
+
voice_file="$HOME/.claude/tts-voice.txt"
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
echo "$voice_file"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# @function determine_voice
|
|
103
|
+
# @intent Resolve which voice to use
|
|
104
|
+
# @returns Sets $VOICE_NAME global variable
|
|
105
|
+
VOICE_NAME=""
|
|
106
|
+
|
|
107
|
+
if [[ -n "$VOICE_OVERRIDE" ]]; then
|
|
108
|
+
VOICE_NAME="$VOICE_OVERRIDE"
|
|
109
|
+
echo "๐ค Using voice: $VOICE_OVERRIDE (session-specific)"
|
|
110
|
+
else
|
|
111
|
+
VOICE_FILE=$(get_voice_file_path)
|
|
112
|
+
|
|
113
|
+
if [[ -n "$VOICE_FILE" ]] && [[ -f "$VOICE_FILE" ]]; then
|
|
114
|
+
FILE_VOICE=$(cat "$VOICE_FILE" 2>/dev/null | tr -d '\n\r')
|
|
115
|
+
if [[ -n "$FILE_VOICE" ]]; then
|
|
116
|
+
VOICE_NAME="$FILE_VOICE"
|
|
117
|
+
fi
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Fallback to default if no voice set
|
|
121
|
+
if [[ -z "$VOICE_NAME" ]]; then
|
|
122
|
+
VOICE_NAME="$DEFAULT_VOICE"
|
|
123
|
+
fi
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# @function validate_inputs
|
|
127
|
+
# @intent Check required parameters
|
|
128
|
+
if [[ -z "$TEXT" ]]; then
|
|
129
|
+
echo "Usage: $0 \"text to speak\" [voice_name]"
|
|
130
|
+
echo ""
|
|
131
|
+
echo "Common voices (run 'say -v ?' for full list):"
|
|
132
|
+
show_common_voices
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# @function validate_voice
|
|
137
|
+
# @intent Check if the specified voice exists on this system
|
|
138
|
+
# @param $1 Voice name to validate
|
|
139
|
+
# @returns 0 if valid, 1 if not found
|
|
140
|
+
validate_voice() {
|
|
141
|
+
local voice="$1"
|
|
142
|
+
say -v ? 2>/dev/null | grep -qi "^${voice} "
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Validate voice exists (case-insensitive search)
|
|
146
|
+
if ! validate_voice "$VOICE_NAME"; then
|
|
147
|
+
echo "โ ๏ธ Voice '$VOICE_NAME' not found on this system"
|
|
148
|
+
echo " Falling back to default: $DEFAULT_VOICE"
|
|
149
|
+
VOICE_NAME="$DEFAULT_VOICE"
|
|
150
|
+
|
|
151
|
+
# If default also doesn't exist, try to find any English voice
|
|
152
|
+
if ! validate_voice "$VOICE_NAME"; then
|
|
153
|
+
VOICE_NAME=$(say -v ? 2>/dev/null | grep -i "en_" | head -1 | awk '{print $1}')
|
|
154
|
+
if [[ -z "$VOICE_NAME" ]]; then
|
|
155
|
+
echo "โ No English voices found on this system"
|
|
156
|
+
exit 2
|
|
157
|
+
fi
|
|
158
|
+
echo " Using first available English voice: $VOICE_NAME"
|
|
159
|
+
fi
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# @function determine_audio_directory
|
|
163
|
+
# @intent Find appropriate directory for audio file storage
|
|
164
|
+
if [[ -n "$CLAUDE_PROJECT_DIR" ]]; then
|
|
165
|
+
AUDIO_DIR="$CLAUDE_PROJECT_DIR/.claude/audio"
|
|
166
|
+
else
|
|
167
|
+
CURRENT_DIR="$PWD"
|
|
168
|
+
while [[ "$CURRENT_DIR" != "/" ]]; do
|
|
169
|
+
if [[ -d "$CURRENT_DIR/.claude" ]]; then
|
|
170
|
+
AUDIO_DIR="$CURRENT_DIR/.claude/audio"
|
|
171
|
+
break
|
|
172
|
+
fi
|
|
173
|
+
CURRENT_DIR=$(dirname "$CURRENT_DIR")
|
|
174
|
+
done
|
|
175
|
+
if [[ -z "$AUDIO_DIR" ]]; then
|
|
176
|
+
AUDIO_DIR="$HOME/.claude/audio"
|
|
177
|
+
fi
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
mkdir -p "$AUDIO_DIR"
|
|
181
|
+
|
|
182
|
+
# SECURITY: Use mktemp for unpredictable filenames (#130)
|
|
183
|
+
TEMP_FILE=$(mktemp "$AUDIO_DIR/tts-XXXXXX.aiff")
|
|
184
|
+
FINAL_FILE=$(mktemp "$AUDIO_DIR/tts-padded-XXXXXX.wav")
|
|
185
|
+
|
|
186
|
+
# @function get_speech_rate
|
|
187
|
+
# @intent Determine speech rate for synthesis
|
|
188
|
+
# @returns Speech rate value (words per minute, default ~175-200)
|
|
189
|
+
get_speech_rate() {
|
|
190
|
+
local rate_config=""
|
|
191
|
+
|
|
192
|
+
# Check for rate config file
|
|
193
|
+
if [[ -f "$SCRIPT_DIR/../config/tts-speech-rate.txt" ]]; then
|
|
194
|
+
rate_config="$SCRIPT_DIR/../config/tts-speech-rate.txt"
|
|
195
|
+
elif [[ -f "$HOME/.claude/config/tts-speech-rate.txt" ]]; then
|
|
196
|
+
rate_config="$HOME/.claude/config/tts-speech-rate.txt"
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
if [[ -n "$rate_config" ]]; then
|
|
200
|
+
local user_speed=$(cat "$rate_config" 2>/dev/null | grep -v '^#' | grep -v '^$' | tail -1)
|
|
201
|
+
# Convert multiplier to words per minute (base ~200 WPM)
|
|
202
|
+
# User: 0.5=slower, 1.0=normal, 2.0=faster
|
|
203
|
+
echo "scale=0; 200 * $user_speed / 1" | bc -l 2>/dev/null || echo "200"
|
|
204
|
+
return
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
# Default: 200 WPM (normal rate)
|
|
208
|
+
echo "200"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
SPEECH_RATE=$(get_speech_rate)
|
|
212
|
+
|
|
213
|
+
# @function synthesize_with_say
|
|
214
|
+
# @intent Generate speech using macOS 'say' command
|
|
215
|
+
# @returns Creates audio file at $TEMP_FILE
|
|
216
|
+
echo "$TEXT" | say -v "$VOICE_NAME" -r "$SPEECH_RATE" -o "$TEMP_FILE" 2>/dev/null
|
|
217
|
+
|
|
218
|
+
if [[ ! -f "$TEMP_FILE" ]] || [[ ! -s "$TEMP_FILE" ]]; then
|
|
219
|
+
echo "โ Failed to synthesize speech with macOS say command"
|
|
220
|
+
echo "Voice: $VOICE_NAME"
|
|
221
|
+
exit 3
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
# @function convert_and_pad_audio
|
|
225
|
+
# @intent Convert AIFF to WAV and add silence padding for consistency
|
|
226
|
+
# @why Maintains consistent audio format across providers
|
|
227
|
+
if command -v ffmpeg &> /dev/null; then
|
|
228
|
+
# Add 200ms of silence at the beginning and convert to WAV
|
|
229
|
+
ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo:d=0.2 -i "$TEMP_FILE" \
|
|
230
|
+
-filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" \
|
|
231
|
+
-map "[out]" -y "$FINAL_FILE" 2>/dev/null
|
|
232
|
+
|
|
233
|
+
if [[ -f "$FINAL_FILE" ]]; then
|
|
234
|
+
rm -f "$TEMP_FILE"
|
|
235
|
+
TEMP_FILE="$FINAL_FILE"
|
|
236
|
+
fi
|
|
237
|
+
else
|
|
238
|
+
# No ffmpeg - use AIFF directly (rename for consistency)
|
|
239
|
+
FINAL_FILE=$(mktemp "$AUDIO_DIR/tts-padded-XXXXXX.aiff")
|
|
240
|
+
mv "$TEMP_FILE" "$FINAL_FILE"
|
|
241
|
+
TEMP_FILE="$FINAL_FILE"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# @function play_audio
|
|
245
|
+
# @intent Play generated audio - via PulseAudio tunnel for SSH, afplay for local
|
|
246
|
+
# SECURITY: Use user-isolated lock directory (#129)
|
|
247
|
+
_LOCK_DIR="${XDG_RUNTIME_DIR:-/tmp/agentvibes-$(id -u)}"
|
|
248
|
+
mkdir -p "$_LOCK_DIR"
|
|
249
|
+
chmod 700 "$_LOCK_DIR"
|
|
250
|
+
LOCK_FILE="$_LOCK_DIR/agentvibes-audio.lock"
|
|
251
|
+
|
|
252
|
+
# Auto-remove stale lock files (older than 30 seconds)
|
|
253
|
+
if [ -f "$LOCK_FILE" ]; then
|
|
254
|
+
_lock_mtime=$(stat -f %m "$LOCK_FILE" 2>/dev/null || echo 0)
|
|
255
|
+
_lock_age=$(( $(date +%s) - _lock_mtime ))
|
|
256
|
+
if [[ $_lock_age -gt 30 ]]; then
|
|
257
|
+
rm -f "$LOCK_FILE"
|
|
258
|
+
fi
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
# Wait for previous audio to finish (max 30 seconds)
|
|
262
|
+
for i in {1..60}; do
|
|
263
|
+
if [ ! -f "$LOCK_FILE" ]; then
|
|
264
|
+
break
|
|
265
|
+
fi
|
|
266
|
+
sleep 0.5
|
|
267
|
+
done
|
|
268
|
+
|
|
269
|
+
# Create lock and play audio
|
|
270
|
+
touch "$LOCK_FILE"
|
|
271
|
+
|
|
272
|
+
# Get audio duration for proper lock timing
|
|
273
|
+
if command -v ffprobe &> /dev/null; then
|
|
274
|
+
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$TEMP_FILE" 2>/dev/null)
|
|
275
|
+
DURATION=${DURATION%.*} # Round to integer
|
|
276
|
+
else
|
|
277
|
+
# Estimate duration based on text length (~150 WPM)
|
|
278
|
+
WORD_COUNT=$(echo "$TEXT" | wc -w)
|
|
279
|
+
DURATION=$(( (WORD_COUNT * 60 / 150) + 1 ))
|
|
280
|
+
fi
|
|
281
|
+
DURATION=${DURATION:-2} # Default to 2 seconds if detection fails
|
|
282
|
+
|
|
283
|
+
# Play audio in background (skip if in test mode or no-playback mode)
|
|
284
|
+
# AGENTVIBES_NO_PLAYBACK: Set to "true" to generate audio without playing (for post-processing)
|
|
285
|
+
if [[ "${AGENTVIBES_TEST_MODE:-false}" != "true" ]] && [[ "${AGENTVIBES_NO_PLAYBACK:-false}" != "true" ]]; then
|
|
286
|
+
# Check if we're in an SSH session with PulseAudio tunnel available
|
|
287
|
+
if [[ -n "$SSH_CONNECTION" ]] && [[ -n "$PULSE_SERVER" ]]; then
|
|
288
|
+
# Use paplay to send audio through PulseAudio tunnel to remote machine
|
|
289
|
+
if command -v /opt/homebrew/bin/paplay &> /dev/null; then
|
|
290
|
+
/opt/homebrew/bin/paplay "$TEMP_FILE" >/dev/null 2>&1 &
|
|
291
|
+
PLAYER_PID=$!
|
|
292
|
+
echo "๐ Playing via PulseAudio tunnel"
|
|
293
|
+
else
|
|
294
|
+
echo "โ ๏ธ paplay not found - install pulseaudio for SSH audio"
|
|
295
|
+
afplay "$TEMP_FILE" >/dev/null 2>&1 &
|
|
296
|
+
PLAYER_PID=$!
|
|
297
|
+
fi
|
|
298
|
+
else
|
|
299
|
+
# Local session - use native macOS player
|
|
300
|
+
afplay "$TEMP_FILE" >/dev/null 2>&1 &
|
|
301
|
+
PLAYER_PID=$!
|
|
302
|
+
fi
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
# Wait for audio to finish, then release lock
|
|
306
|
+
(sleep $DURATION; rm -f "$LOCK_FILE") &
|
|
307
|
+
disown
|
|
308
|
+
|
|
309
|
+
# Get audio cache stats
|
|
310
|
+
AUDIO_DIR_PATH=$(get_audio_dir)
|
|
311
|
+
FILE_COUNT=$(count_tts_files "$AUDIO_DIR_PATH")
|
|
312
|
+
SIZE_BYTES=$(calculate_tts_size_bytes "$AUDIO_DIR_PATH")
|
|
313
|
+
SIZE_HUMAN=$(bytes_to_human "$SIZE_BYTES")
|
|
314
|
+
|
|
315
|
+
# Color codes
|
|
316
|
+
BLUE='\033[0;34m'
|
|
317
|
+
YELLOW='\033[1;33m'
|
|
318
|
+
PURPLE='\033[0;35m'
|
|
319
|
+
LIGHT_PURPLE='\033[1;35m'
|
|
320
|
+
RED='\033[0;31m'
|
|
321
|
+
GREEN='\033[0;32m'
|
|
322
|
+
ORANGE='\033[0;33m'
|
|
323
|
+
WHITE='\033[1;37m'
|
|
324
|
+
MAGENTA='\033[0;35m'
|
|
325
|
+
CYAN='\033[0;36m'
|
|
326
|
+
GOLD='\033[38;5;226m'
|
|
327
|
+
NC='\033[0m'
|
|
328
|
+
|
|
329
|
+
# Dynamic color coding based on cache size
|
|
330
|
+
# Green: < 500MB (small)
|
|
331
|
+
# Yellow: 500MB - 3GB (lots)
|
|
332
|
+
# Red: > 3GB (extreme)
|
|
333
|
+
CACHE_COLOR=$GREEN
|
|
334
|
+
if [[ $SIZE_BYTES -gt 3221225472 ]]; then # > 3GB
|
|
335
|
+
CACHE_COLOR=$RED
|
|
336
|
+
elif [[ $SIZE_BYTES -gt 524288000 ]]; then # > 500MB
|
|
337
|
+
CACHE_COLOR=$YELLOW
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
# Display with file count and auto-clean indicator
|
|
341
|
+
# Get auto-clean threshold for display
|
|
342
|
+
AUTO_CLEAN_THRESHOLD=$(get_auto_clean_threshold)
|
|
343
|
+
echo -e "${WHITE}๐พ Saved to:${NC} ${CYAN}$TEMP_FILE${NC} ${WHITE}๐ฆ${NC} ${YELLOW}$FILE_COUNT${NC} ${CACHE_COLOR}$SIZE_HUMAN${NC} ${WHITE}๐งน${NC}${GOLD}[${AUTO_CLEAN_THRESHOLD}mb]${NC}"
|
|
344
|
+
|
|
345
|
+
# Auto-cleanup check - delete oldest files if over size threshold
|
|
346
|
+
THRESHOLD_MB=$(get_auto_clean_threshold)
|
|
347
|
+
if [[ $SIZE_BYTES -gt $((THRESHOLD_MB * 1048576)) ]]; then
|
|
348
|
+
DELETED=$(auto_clean_old_files "$AUDIO_DIR_PATH" "$THRESHOLD_MB")
|
|
349
|
+
if [[ $DELETED -gt 0 ]]; then
|
|
350
|
+
echo -e "${ORANGE}๐งน Auto-cleaned $DELETED files${NC}"
|
|
351
|
+
fi
|
|
352
|
+
fi
|
|
353
|
+
|
|
354
|
+
echo -e "${CYAN}๐ค Voice used:${NC} ${WHITE}$VOICE_NAME (macOS Say)${NC}"
|
|
355
|
+
|
|
356
|
+
# Show personality if configured
|
|
357
|
+
PERSONALITY=$(cat "$PROJECT_ROOT/.claude/tts-personality.txt" 2>/dev/null || cat "$HOME/.claude/tts-personality.txt" 2>/dev/null || echo "")
|
|
358
|
+
if [[ -n "$PERSONALITY" ]] && [[ "$PERSONALITY" != "none" ]] && [[ "$PERSONALITY" != "normal" ]]; then
|
|
359
|
+
echo -e "${GOLD}๐ซ Personality:${NC} ${WHITE}$PERSONALITY${NC}"
|
|
360
|
+
fi
|
|
361
|
+
|
|
362
|
+
# Check audio folder size and warn if getting large
|
|
363
|
+
if [[ -d "$AUDIO_DIR_PATH" ]]; then
|
|
364
|
+
AUDIO_SIZE=$(du -sm "$AUDIO_DIR_PATH" 2>/dev/null | cut -f1)
|
|
365
|
+
if [[ -n "$AUDIO_SIZE" ]] && [[ "$AUDIO_SIZE" -gt 100 ]]; then
|
|
366
|
+
echo -e "\033[0;31mโ ๏ธ Audio cache is ${AUDIO_SIZE}MB - Run: /agent-vibes:cleanup\033[0m"
|
|
367
|
+
fi
|
|
368
|
+
fi
|