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
package/setup-windows.ps1 CHANGED
@@ -1,815 +1,815 @@
1
- #
2
- # File: setup-windows.ps1
3
- #
4
- # AgentVibes Windows Native Setup Script
5
- # Installs and configures AgentVibes for Windows
6
- #
7
- # Usage:
8
- # .\setup-windows.ps1 # Interactive setup
9
- # .\setup-windows.ps1 -Provider soprano # Skip provider prompt
10
- #
11
-
12
- param(
13
- [Parameter(Mandatory = $false)]
14
- [ValidateSet('soprano', 'piper', 'sapi')]
15
- [string]$Provider
16
- )
17
-
18
- $ErrorActionPreference = "Stop"
19
-
20
- # ── UI Helper Functions ─────────────────────────────────────
21
-
22
- $BoxWidth = 58
23
-
24
- function Write-BoxTop {
25
- Write-Host " $([char]0x256D)$([string]::new([char]0x2500, $BoxWidth))$([char]0x256E)" -ForegroundColor Cyan
26
- }
27
-
28
- function Write-BoxBottom {
29
- Write-Host " $([char]0x2570)$([string]::new([char]0x2500, $BoxWidth))$([char]0x256F)" -ForegroundColor Cyan
30
- }
31
-
32
- function Write-BoxLine([string]$text, [string]$color = "White") {
33
- $padding = $BoxWidth - $text.Length
34
- if ($padding -lt 0) { $padding = 0; $text = $text.Substring(0, $BoxWidth) }
35
- Write-Host " $([char]0x2502)" -ForegroundColor Cyan -NoNewline
36
- Write-Host "$text$([string]::new(' ', $padding))" -ForegroundColor $color -NoNewline
37
- Write-Host "$([char]0x2502)" -ForegroundColor Cyan
38
- }
39
-
40
- function Write-BoxEmpty {
41
- Write-BoxLine ([string]::new(' ', $BoxWidth)) "White"
42
- }
43
-
44
- function Write-Section([string]$label) {
45
- Write-Host ""
46
- Write-Host " $([string]::new([char]0x2501, 56))" -ForegroundColor Yellow
47
- Write-Host " $label" -ForegroundColor Yellow
48
- Write-Host " $([string]::new([char]0x2501, 56))" -ForegroundColor Yellow
49
- Write-Host ""
50
- }
51
-
52
- function Write-Ok([string]$text) {
53
- Write-Host " [OK] $text" -ForegroundColor Green
54
- }
55
-
56
- function Write-Warn([string]$text) {
57
- Write-Host " [!!] $text" -ForegroundColor Yellow
58
- }
59
-
60
- function Write-Err([string]$text) {
61
- Write-Host " [XX] $text" -ForegroundColor Red
62
- }
63
-
64
- function Write-Info([string]$text) {
65
- Write-Host " $text" -ForegroundColor Gray
66
- }
67
-
68
- function Write-Item([string]$icon, [string]$name, [string]$desc) {
69
- $nameWidth = 30
70
- $paddedName = $name.PadRight($nameWidth)
71
- Write-Host " $icon " -ForegroundColor Green -NoNewline
72
- Write-Host $paddedName -ForegroundColor White -NoNewline
73
- Write-Host $desc -ForegroundColor DarkGray
74
- }
75
-
76
- # ── Read Version ────────────────────────────────────────────
77
-
78
- $Version = "unknown"
79
- $ScriptDir = $PSScriptRoot
80
- $PackageJson = Join-Path $ScriptDir "package.json"
81
- if (Test-Path $PackageJson) {
82
- try {
83
- $pkg = Get-Content $PackageJson -Raw | ConvertFrom-Json
84
- $Version = $pkg.version
85
- } catch {}
86
- }
87
-
88
- # ── Banner ──────────────────────────────────────────────────
89
-
90
- # ANSI Shadow figlet art matching the Node.js installer
91
- $AgentArt = @(
92
- " █████╗ ██████╗ ███████╗███╗ ██╗████████╗",
93
- "██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝",
94
- "███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ",
95
- "██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ",
96
- "██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ",
97
- "╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ "
98
- )
99
- $VibesArt = @(
100
- "██╗ ██╗██╗██████╗ ███████╗███████╗",
101
- "██║ ██║██║██╔══██╗██╔════╝██╔════╝",
102
- "██║ ██║██║██████╔╝█████╗ ███████╗",
103
- "╚██╗ ██╔╝██║██╔══██╗██╔══╝ ╚════██║",
104
- " ╚████╔╝ ██║██████╔╝███████╗███████║",
105
- " ╚═══╝ ╚═╝╚═════╝ ╚══════╝╚══════╝"
106
- )
107
-
108
- Write-Host ""
109
- for ($i = 0; $i -lt $AgentArt.Count; $i++) {
110
- Write-Host $AgentArt[$i] -ForegroundColor Cyan -NoNewline
111
- Write-Host " " -NoNewline
112
- Write-Host $VibesArt[$i] -ForegroundColor Magenta
113
- }
114
- Write-Host ""
115
- Write-BoxTop
116
- Write-BoxEmpty
117
- Write-BoxLine " Windows Native Setup v$Version" "Cyan"
118
- Write-BoxEmpty
119
- Write-BoxLine " Now your AI Agents can finally talk back!" "White"
120
- Write-BoxLine " Professional TTS for Claude Code on Windows" "DarkGray"
121
- Write-BoxEmpty
122
- Write-BoxLine " https://agentvibes.org" "DarkCyan"
123
- Write-BoxBottom
124
- Write-Host ""
125
-
126
- # ── What's New ──────────────────────────────────────────────
127
-
128
- Write-Host " WHAT'S NEW in v$Version" -ForegroundColor Green
129
- Write-Host ""
130
- Write-Host " Native Windows support with three TTS providers (Soprano neural," -ForegroundColor Cyan
131
- Write-Host " Piper offline, Windows SAPI), background music from 16 genre tracks," -ForegroundColor Cyan
132
- Write-Host " reverb effects via ffmpeg, and verbosity control." -ForegroundColor Cyan
133
- Write-Host ""
134
- Write-Host " Thanks to @nathanchase (Soprano), @alexeyv (Windows SAPI)," -ForegroundColor Yellow
135
- Write-Host " @bmadcode (BMAD Method)!" -ForegroundColor Yellow
136
- Write-Host ""
137
- Write-Host " KEY HIGHLIGHTS:" -ForegroundColor Green
138
- Write-Host " [*] Native Windows TTS - Soprano, Piper, SAPI. No WSL needed!" -ForegroundColor Gray
139
- Write-Host " [*] Background Music - 16 genre tracks (Bachata, Flamenco, etc.)" -ForegroundColor Gray
140
- Write-Host " [*] Reverb & Effects - 5 reverb levels via ffmpeg aecho filter" -ForegroundColor Gray
141
- Write-Host " [*] Verbosity Control - High, Medium, or Low transparency" -ForegroundColor Gray
142
- Write-Host " [*] Beautiful Installer - Figlet banner, provider detection" -ForegroundColor Gray
143
- Write-Host " [*] 93/93 Tests Passing - 46 Windows + 47 cross-platform" -ForegroundColor Gray
144
- Write-Host ""
145
-
146
- # ── Node.js Detection ──────────────────────────────────────
147
-
148
- try {
149
- $nodeVersion = & node --version 2>$null
150
- if ($nodeVersion) {
151
- Write-Host " Node.js detected " -ForegroundColor Gray -NoNewline
152
- Write-Host "($nodeVersion)" -ForegroundColor Green
153
- Write-Host ""
154
- Write-Host " Tip: For a richer install experience, you can also run:" -ForegroundColor DarkGray
155
- Write-Host " npx agentvibes install" -ForegroundColor Cyan
156
- Write-Host ""
157
- $choice = Read-Host " Launch the Node.js installer instead? (y/N)"
158
- if ($choice -eq 'y' -or $choice -eq 'Y') {
159
- Write-Host ""
160
- Write-Host " Launching Node.js installer..." -ForegroundColor Cyan
161
- Write-Host ""
162
- $installerPath = Join-Path $ScriptDir "src\installer.js"
163
- if (Test-Path $installerPath) {
164
- & node $installerPath install
165
- } else {
166
- & npx agentvibes install
167
- }
168
- exit 0
169
- }
170
- Write-Host ""
171
- Write-Host " Continuing with PowerShell installer..." -ForegroundColor Gray
172
- }
173
- } catch {}
174
-
175
- # ── PowerShell Version Check ───────────────────────────────
176
-
177
- Write-Section "System Check"
178
-
179
- $PSVersionRequired = [Version]"5.1"
180
- if ($PSVersionTable.PSVersion -lt $PSVersionRequired) {
181
- Write-Err "PowerShell 5.1+ required (found $($PSVersionTable.PSVersion))"
182
- exit 1
183
- }
184
- Write-Ok "PowerShell $($PSVersionTable.PSVersion)"
185
-
186
- # ── Detect Project Root ─────────────────────────────────────
187
-
188
- if ($ScriptDir -match '[\\/]node_modules[\\/]agentvibes$') {
189
- $ProjectRoot = (Resolve-Path (Join-Path $ScriptDir "..\..")).Path
190
- Write-Ok "Detected npm package in: $ProjectRoot"
191
- } else {
192
- $ProjectRoot = $ScriptDir
193
- Write-Ok "Project root: $ProjectRoot"
194
- }
195
-
196
- # ── Setup Directories ───────────────────────────────────────
197
-
198
- Write-Section "Setting Up Directories"
199
-
200
- Write-Host " These directories store AgentVibes config and data:" -ForegroundColor Gray
201
- Write-Host ""
202
-
203
- $ProjectClaudeDir = "$ProjectRoot\.claude"
204
- $HooksDir = "$ProjectClaudeDir\hooks-windows"
205
- $UserClaudeDir = "$env:USERPROFILE\.claude"
206
- $AudioDir = "$UserClaudeDir\audio"
207
- $VoicesDir = "$UserClaudeDir\piper-voices"
208
- $PiperDir = "$env:LOCALAPPDATA\Programs\Piper"
209
- $PiperExe = "$PiperDir\piper.exe"
210
-
211
- # Directory info: path, description, category
212
- $DirInfo = @(
213
- @{ Path = $ProjectClaudeDir; Desc = "Project settings and hooks config"; Cat = "Project" },
214
- @{ Path = $HooksDir; Desc = "PowerShell TTS hook scripts"; Cat = "Project" },
215
- @{ Path = $UserClaudeDir; Desc = "Global AgentVibes configuration"; Cat = "User Profile" },
216
- @{ Path = $AudioDir; Desc = "TTS audio file cache"; Cat = "User Profile" },
217
- @{ Path = $VoicesDir; Desc = "Piper voice model files"; Cat = "User Profile" },
218
- @{ Path = $PiperDir; Desc = "Piper TTS engine binary"; Cat = "Applications" }
219
- )
220
-
221
- $CurrentCat = ""
222
- foreach ($entry in $DirInfo) {
223
- if ($entry.Cat -ne $CurrentCat) {
224
- if ($CurrentCat -ne "") { Write-Host "" }
225
- Write-Host " $($entry.Cat)" -ForegroundColor Cyan
226
- $CurrentCat = $entry.Cat
227
- }
228
-
229
- $dir = $entry.Path
230
- $existed = Test-Path $dir
231
- if (-not $existed) {
232
- New-Item -ItemType Directory -Path $dir -Force | Out-Null
233
- }
234
-
235
- # Show relative path where possible
236
- $displayPath = $dir
237
- if ($dir.StartsWith($ProjectRoot)) {
238
- $displayPath = $dir.Substring($ProjectRoot.Length + 1)
239
- } elseif ($dir.StartsWith($env:USERPROFILE)) {
240
- $displayPath = "~" + $dir.Substring($env:USERPROFILE.Length)
241
- } elseif ($dir.StartsWith($env:LOCALAPPDATA)) {
242
- $displayPath = "%LOCALAPPDATA%" + $dir.Substring($env:LOCALAPPDATA.Length)
243
- }
244
-
245
- $status = if ($existed) { "[OK]" } else { "[OK]" }
246
- $action = if ($existed) { "exists" } else { "created" }
247
-
248
- Write-Host " $status " -ForegroundColor Green -NoNewline
249
- Write-Host $displayPath.PadRight(32) -ForegroundColor White -NoNewline
250
- Write-Host $entry.Desc -ForegroundColor DarkGray
251
- }
252
-
253
- # ── Install Hook Scripts ────────────────────────────────────
254
-
255
- Write-Section "Installing TTS Scripts"
256
-
257
- Write-Host " These scripts enable Claude Code to speak on Windows:" -ForegroundColor Gray
258
- Write-Host ""
259
-
260
- $SourceHooksDir = Join-Path $ScriptDir ".claude\hooks-windows"
261
-
262
- # Validate source path is within the script directory (path traversal prevention)
263
- $ResolvedSource = (Resolve-Path -Path $SourceHooksDir -ErrorAction SilentlyContinue).Path
264
- $ResolvedScript = (Resolve-Path -Path $ScriptDir).Path
265
-
266
- if (-not $ResolvedSource -or -not $ResolvedSource.StartsWith($ResolvedScript)) {
267
- Write-Err "Hook scripts source path is outside the project directory"
268
- exit 1
269
- }
270
-
271
- if (-not (Test-Path $SourceHooksDir)) {
272
- Write-Err "Hook scripts not found at: $SourceHooksDir"
273
- Write-Info "Make sure you're running this from the AgentVibes project directory"
274
- exit 1
275
- }
276
-
277
- # Ensure destination hooks directory exists
278
- if (-not (Test-Path $HooksDir)) {
279
- New-Item -ItemType Directory -Path $HooksDir -Force | Out-Null
280
- }
281
-
282
- # Script info: filename, description
283
- $HookScriptInfo = @(
284
- @{ Name = "play-tts.ps1"; Desc = "Main TTS router - dispatches to active provider" },
285
- @{ Name = "play-tts-soprano.ps1"; Desc = "Soprano neural voice provider (fastest)" },
286
- @{ Name = "play-tts-windows-piper.ps1"; Desc = "Piper offline neural voice provider" },
287
- @{ Name = "play-tts-windows-sapi.ps1"; Desc = "Windows built-in SAPI voice provider" },
288
- @{ Name = "provider-manager.ps1"; Desc = "Switch between TTS providers" },
289
- @{ Name = "voice-manager-windows.ps1"; Desc = "Browse and select voice models" },
290
- @{ Name = "audio-cache-utils.ps1"; Desc = "Manage TTS audio file cache" },
291
- @{ Name = "session-start-tts.ps1"; Desc = "Auto-activates TTS when Claude starts" }
292
- )
293
-
294
- $CopiedCount = 0
295
- foreach ($info in $HookScriptInfo) {
296
- $script = $info.Name
297
- $SourceFile = Join-Path $SourceHooksDir $script
298
- $DestFile = Join-Path $HooksDir $script
299
-
300
- if (Test-Path $SourceFile) {
301
- # Skip if source and destination are the same file (running from project root)
302
- $resolvedSrc = (Resolve-Path $SourceFile).Path
303
- $resolvedDst = if (Test-Path $DestFile) { (Resolve-Path $DestFile).Path } else { "" }
304
- if ($resolvedSrc -eq $resolvedDst) {
305
- Write-Item "[OK]" $script $info.Desc
306
- } else {
307
- Copy-Item -Path $SourceFile -Destination $DestFile -Force
308
- Write-Item "[OK]" $script $info.Desc
309
- }
310
- $CopiedCount++
311
- }
312
- else {
313
- Write-Host " [!!] " -ForegroundColor Yellow -NoNewline
314
- Write-Host "$($script.PadRight(30))" -ForegroundColor White -NoNewline
315
- Write-Host "not found" -ForegroundColor Yellow
316
- }
317
- }
318
-
319
- if ($CopiedCount -eq 0) {
320
- Write-Err "No hook scripts were installed"
321
- exit 1
322
- }
323
-
324
- Write-Host ""
325
- Write-Host " Location: " -ForegroundColor Gray -NoNewline
326
- Write-Host ".claude\hooks-windows\" -ForegroundColor Cyan
327
- Write-Ok "Installed $CopiedCount TTS scripts"
328
-
329
- # ── Provider Selection ──────────────────────────────────────
330
-
331
- Write-Section "Choose Your TTS Provider"
332
-
333
- # Check if pip is available
334
- $PipAvailable = $false
335
- try {
336
- $pipTest = & pip --version 2>$null
337
- if ($pipTest) { $PipAvailable = $true }
338
- } catch {}
339
-
340
- # Check Soprano availability
341
- $SopranoAvailable = $false
342
- try {
343
- $response = Invoke-WebRequest -Uri "http://127.0.0.1:7860/api/predict" `
344
- -Method POST -UseBasicParsing -TimeoutSec 2 `
345
- -ContentType "application/json" `
346
- -Body '{"data":["test",1.0],"fn_index":0}' `
347
- -ErrorAction SilentlyContinue
348
- if ($response.StatusCode -eq 200) { $SopranoAvailable = $true }
349
- } catch {}
350
-
351
- # Check if pip has soprano-tts (only if pip is available)
352
- $SopranoInstalled = $false
353
- if ($PipAvailable) {
354
- try {
355
- $pipResult = & pip show soprano-tts 2>$null
356
- if ($pipResult) { $SopranoInstalled = $true }
357
- } catch {}
358
- }
359
-
360
- if (-not $Provider) {
361
- Write-Host " [1] Soprano (Best Quality)" -ForegroundColor White
362
- Write-Host " Ultra-fast neural TTS, 80M parameter model" -ForegroundColor DarkGray
363
- if ($SopranoAvailable) {
364
- Write-Host " Status: " -ForegroundColor DarkGray -NoNewline
365
- Write-Host "Running on port 7860" -ForegroundColor Green
366
- } elseif ($SopranoInstalled) {
367
- Write-Host " Status: " -ForegroundColor DarkGray -NoNewline
368
- Write-Host "Installed (not running)" -ForegroundColor Yellow
369
- } else {
370
- Write-Host " Requires: pip install soprano-tts" -ForegroundColor DarkGray
371
- }
372
- Write-Host ""
373
-
374
- Write-Host " [2] Piper (Recommended Offline)" -ForegroundColor White
375
- Write-Host " High quality neural voices, works fully offline" -ForegroundColor DarkGray
376
- if (Test-Path $PiperExe) {
377
- Write-Host " Status: " -ForegroundColor DarkGray -NoNewline
378
- Write-Host "Installed" -ForegroundColor Green
379
- } else {
380
- Write-Host " Downloads: ~100MB (piper.exe + voice model)" -ForegroundColor DarkGray
381
- }
382
- Write-Host ""
383
-
384
- Write-Host " [3] Windows SAPI (Zero Setup)" -ForegroundColor White
385
- Write-Host " Built-in Windows voices (David, Zira, Mark)" -ForegroundColor DarkGray
386
- Write-Host " No download required" -ForegroundColor DarkGray
387
- Write-Host ""
388
-
389
- $choice = Read-Host " Enter choice (1-3, default: 1)"
390
-
391
- switch ($choice) {
392
- "2" { $Provider = "piper" }
393
- "3" { $Provider = "sapi" }
394
- default { $Provider = "soprano" }
395
- }
396
- }
397
-
398
- $ProviderDisplayName = switch ($Provider) {
399
- "soprano" { "Soprano TTS" }
400
- "piper" { "Piper TTS" }
401
- "sapi" { "Windows SAPI" }
402
- }
403
-
404
- Write-Host ""
405
- Write-Ok "Selected: $ProviderDisplayName"
406
-
407
- # ── Install Soprano if selected ─────────────────────────────
408
-
409
- if ($Provider -eq "soprano") {
410
- Write-Section "Soprano Setup"
411
-
412
- if ($SopranoAvailable) {
413
- Write-Ok "Soprano server running on port 7860"
414
- } elseif ($SopranoInstalled) {
415
- Write-Warn "Soprano is installed but not running"
416
- Write-Info "Start it with: soprano-tts --share"
417
- Write-Info "Or run it in WSL and forward port 7860"
418
- } else {
419
- Write-Warn "Soprano TTS not detected"
420
- Write-Host ""
421
-
422
- if (-not $PipAvailable) {
423
- Write-Error "pip is not available on this system"
424
- Write-Info "Please install Python 3 with pip, then run:"
425
- Write-Host " pip install soprano-tts" -ForegroundColor Cyan
426
- Write-Host ""
427
- } else {
428
- # Offer to install Soprano
429
- $installChoice = Read-Host "Would you like to install Soprano now? (y/n, default: y)"
430
-
431
- if ($installChoice -eq "" -or $installChoice -eq "y" -or $installChoice -eq "Y") {
432
- Write-Info "Installing Soprano TTS..."
433
- Write-Host ""
434
-
435
- try {
436
- & pip install soprano-tts 2>&1 | Tee-Object -Variable pipOutput | Write-Host
437
-
438
- # Re-check if installation succeeded
439
- $SopranoInstalled = $false
440
- try {
441
- $pipResult = & pip show soprano-tts 2>$null
442
- if ($pipResult) { $SopranoInstalled = $true }
443
- } catch {}
444
-
445
- if ($SopranoInstalled) {
446
- Write-Ok "Soprano TTS installed successfully!"
447
- Write-Info "Start it with: soprano-tts --share"
448
- } else {
449
- Write-Error "Installation may have failed. Please check the output above."
450
- Write-Info "You can try installing manually: pip install soprano-tts"
451
- }
452
- } catch {
453
- Write-Error "Installation failed: $_"
454
- Write-Info "Please install manually: pip install soprano-tts"
455
- }
456
- } else {
457
- Write-Host ""
458
- Write-Host " To install Soprano manually:" -ForegroundColor White
459
- Write-Host " pip install soprano-tts" -ForegroundColor Cyan
460
- Write-Host ""
461
- Write-Host " Or use Soprano in WSL with port forwarding:" -ForegroundColor White
462
- Write-Host " ssh -L 7860:localhost:7860 your-wsl-host" -ForegroundColor Cyan
463
- Write-Host ""
464
- Write-Info "AgentVibes will work once Soprano is accessible on port 7860"
465
- }
466
- }
467
- }
468
- }
469
-
470
- # ── Install Piper if selected ───────────────────────────────
471
-
472
- if ($Provider -eq "piper") {
473
- Write-Section "Piper Installation"
474
-
475
- if (Test-Path $PiperExe) {
476
- Write-Ok "Piper already installed at: $PiperDir"
477
- }
478
- else {
479
- Write-Host " Downloading Piper TTS engine from GitHub..." -ForegroundColor White
480
-
481
- $DownloadUrl = "https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_windows_amd64.zip"
482
- $DownloadFile = "$env:TEMP\piper-windows.zip"
483
-
484
- try {
485
- Write-Info $DownloadUrl
486
-
487
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
488
- Invoke-WebRequest -Uri $DownloadUrl -OutFile $DownloadFile -UseBasicParsing -ErrorAction Stop
489
-
490
- Write-Ok "Downloaded ($('{0:N2}' -f ((Get-Item $DownloadFile).Length / 1MB)) MB)"
491
-
492
- Write-Host " Extracting..." -ForegroundColor Gray
493
- $TempExtractDir = "$env:TEMP\piper-extract"
494
- Remove-Item -Path $TempExtractDir -Recurse -Force -ErrorAction SilentlyContinue
495
- Expand-Archive -Path $DownloadFile -DestinationPath $TempExtractDir -Force
496
-
497
- # Find piper.exe recursively
498
- $PiperFound = Get-ChildItem -Path $TempExtractDir -Name "piper.exe" -Recurse
499
-
500
- if ($PiperFound) {
501
- $PiperExePath = (Get-ChildItem -Path $TempExtractDir -Filter "piper.exe" -Recurse).FullName | Select-Object -First 1
502
- $PiperSourceDir = Split-Path -Parent $PiperExePath
503
-
504
- Copy-Item -Path "$PiperSourceDir\*" -Destination $PiperDir -Recurse -Force
505
-
506
- if (Test-Path $PiperExe) {
507
- Write-Ok "Piper installed to: $PiperDir"
508
- }
509
- else {
510
- throw "Failed to copy Piper executable"
511
- }
512
- }
513
- else {
514
- throw "piper.exe not found in extracted files"
515
- }
516
-
517
- # Cleanup
518
- Remove-Item -Path $TempExtractDir -Recurse -Force -ErrorAction SilentlyContinue
519
- Remove-Item $DownloadFile -Force -ErrorAction SilentlyContinue
520
- }
521
- catch {
522
- Write-Err "Failed to install Piper: $_"
523
- Write-Info "Please check your internet connection and try again"
524
- exit 1
525
- }
526
- }
527
-
528
- # Download default voice
529
- Write-Host ""
530
- Write-Host " Setting up default voice model..." -ForegroundColor White
531
-
532
- $DefaultVoice = "en_US-ryan-high"
533
- $VoiceDir = $VoicesDir
534
-
535
- if ((Test-Path "$VoiceDir\$DefaultVoice.onnx") -and (Test-Path "$VoiceDir\$DefaultVoice.onnx.json")) {
536
- Write-Ok "Default voice ($DefaultVoice) already downloaded"
537
- }
538
- else {
539
- Write-Host " Downloading $DefaultVoice..." -ForegroundColor Gray
540
-
541
- try {
542
- $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/ryan/high"
543
-
544
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
545
-
546
- Write-Host " Downloading model file..." -ForegroundColor Gray
547
- Invoke-WebRequest -Uri "$HFBase/$DefaultVoice.onnx" `
548
- -OutFile "$VoiceDir\$DefaultVoice.onnx" `
549
- -UseBasicParsing -ErrorAction Stop
550
-
551
- Write-Host " Downloading config file..." -ForegroundColor Gray
552
- Invoke-WebRequest -Uri "$HFBase/$DefaultVoice.onnx.json" `
553
- -OutFile "$VoiceDir\$DefaultVoice.onnx.json" `
554
- -UseBasicParsing -ErrorAction Stop
555
-
556
- Write-Ok "Voice model downloaded: $DefaultVoice"
557
- }
558
- catch {
559
- Write-Warn "Could not download voice: $_"
560
- Write-Info "You can download voices manually later"
561
- }
562
- }
563
- }
564
-
565
- # ── Set Active Provider ─────────────────────────────────────
566
-
567
- Write-Section "Configuring Provider"
568
-
569
- $ProviderFile = "$ProjectClaudeDir\tts-provider.txt"
570
- $ProviderName = switch ($Provider) {
571
- "soprano" { "soprano" }
572
- "piper" { "windows-piper" }
573
- "sapi" { "windows-sapi" }
574
- }
575
-
576
- Set-Content -Path $ProviderFile -Value $ProviderName -NoNewline
577
- Write-Ok "Active provider set to: $ProviderName"
578
- Write-Info "Config file: .claude\tts-provider.txt"
579
-
580
- # ── Background Music Selection ─────────────────────────
581
-
582
- Write-Section "Background Music"
583
-
584
- Write-Host " Play background music under TTS voice output?" -ForegroundColor Gray
585
- Write-Host " Requires ffmpeg (mixing voice + music)." -ForegroundColor DarkGray
586
- Write-Host ""
587
-
588
- # Check ffmpeg availability
589
- $HasFfmpeg = $false
590
- try {
591
- $null = Get-Command ffmpeg -ErrorAction Stop
592
- $HasFfmpeg = $true
593
- } catch {}
594
-
595
- $BgMusicEnabled = $false
596
- $BgMusicTrack = "agent_vibes_bachata_v1_loop.mp3"
597
- $BgMusicDisplayName = "Off"
598
-
599
- if (-not $HasFfmpeg) {
600
- Write-Warn "ffmpeg not found - background music requires ffmpeg"
601
- Write-Info "Install ffmpeg and re-run setup to enable background music"
602
- } else {
603
- Write-Host " [1] Yes - Enable background music (Recommended)" -ForegroundColor White
604
- Write-Host " [2] No - Voice only" -ForegroundColor White
605
- Write-Host ""
606
-
607
- $bgChoice = Read-Host " Enter choice (1-2, default: 1)"
608
-
609
- if ($bgChoice -eq "2") {
610
- $BgMusicEnabled = $false
611
- $BgMusicDisplayName = "Off"
612
- Write-Host ""
613
- Write-Ok "Background music: Disabled"
614
- } else {
615
- $BgMusicEnabled = $true
616
-
617
- # Track list with filenames and display info
618
- $Tracks = @(
619
- @{ File = "agentvibes_soft_flamenco_loop.mp3"; Name = "Soft Flamenco"; Desc = "Spanish guitar" },
620
- @{ File = "agent_vibes_bachata_v1_loop.mp3"; Name = "Bachata"; Desc = "Latin rhythm" },
621
- @{ File = "agent_vibes_bossa_nova_v2_loop.mp3"; Name = "Bossa Nova"; Desc = "Brazilian jazz" },
622
- @{ File = "agent_vibes_salsa_v2_loop.mp3"; Name = "Salsa"; Desc = "Latin dance" },
623
- @{ File = "agent_vibes_cumbia_v1_loop.mp3"; Name = "Cumbia"; Desc = "Colombian folk" },
624
- @{ File = "agent_vibes_japanese_city_pop_v1_loop.mp3"; Name = "Japanese City Pop"; Desc = "80s synth" },
625
- @{ File = "agent_vibes_chillwave_v2_loop.mp3"; Name = "Chillwave"; Desc = "Electronic ambient" },
626
- @{ File = "dreamy_house_loop.mp3"; Name = "Dreamy House"; Desc = "Electronic dance" },
627
- @{ File = "agent_vibes_dark_chill_step_loop.mp3"; Name = "Dark Chill Step"; Desc = "Electronic bass" },
628
- @{ File = "agent_vibes_goa_trance_v2_loop.mp3"; Name = "Goa Trance"; Desc = "Psychedelic electronic" },
629
- @{ File = "agent_vibes_harpsichord_v2_loop.mp3"; Name = "Harpsichord"; Desc = "Baroque classical" },
630
- @{ File = "agent_vibes_celtic_harp_v1_loop.mp3"; Name = "Celtic Harp"; Desc = "Irish traditional" },
631
- @{ File = "agent_vibes_hawaiian_slack_key_guitar_v2_loop.mp3"; Name = "Hawaiian Slack Key"; Desc = "Island guitar" },
632
- @{ File = "agent_vibes_arabic_v2_loop.mp3"; Name = "Arabic Oud"; Desc = "Middle Eastern" },
633
- @{ File = "agent_vibes_ganawa_ambient_v2_loop.mp3"; Name = "Gnawa Ambient"; Desc = "North African" },
634
- @{ File = "agent_vibes_tabla_dream_pop_v1_loop.mp3"; Name = "Tabla Dream Pop"; Desc = "Indian percussion" }
635
- )
636
-
637
- Write-Host ""
638
- Write-Host " Choose a background music genre:" -ForegroundColor White
639
- Write-Host ""
640
-
641
- for ($i = 0; $i -lt $Tracks.Count; $i++) {
642
- $num = ($i + 1).ToString().PadLeft(2)
643
- $trackName = $Tracks[$i].Name.PadRight(22)
644
- Write-Host " [$num] " -ForegroundColor White -NoNewline
645
- Write-Host $trackName -ForegroundColor Cyan -NoNewline
646
- Write-Host $Tracks[$i].Desc -ForegroundColor DarkGray
647
- }
648
-
649
- Write-Host ""
650
- $trackChoice = Read-Host " Enter choice (1-16, default: 2)"
651
-
652
- $trackIndex = 1 # default to Bachata (index 1)
653
- if ($trackChoice -match '^\d+$') {
654
- $parsed = [int]$trackChoice
655
- if ($parsed -ge 1 -and $parsed -le $Tracks.Count) {
656
- $trackIndex = $parsed - 1
657
- }
658
- }
659
-
660
- $BgMusicTrack = $Tracks[$trackIndex].File
661
- $BgMusicDisplayName = $Tracks[$trackIndex].Name
662
-
663
- Write-Host ""
664
- Write-Ok "Background music: $BgMusicDisplayName"
665
- }
666
- }
667
-
668
- # Write background music config
669
- $ConfigDir = "$ProjectClaudeDir\config"
670
- if (-not (Test-Path $ConfigDir)) {
671
- New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null
672
- }
673
-
674
- $bgEnabledValue = if ($BgMusicEnabled) { "true" } else { "false" }
675
- Set-Content -Path "$ConfigDir\background-music-enabled.txt" -Value $bgEnabledValue -NoNewline
676
- Set-Content -Path "$ConfigDir\background-music-default.txt" -Value $BgMusicTrack -NoNewline
677
- Set-Content -Path "$ConfigDir\background-music-volume.txt" -Value "0.10" -NoNewline
678
-
679
- # ── Audio Effects (Reverb) ─────────────────────────────
680
-
681
- Write-Section "Audio Effects"
682
-
683
- Write-Host " Add reverb effect to voice output?" -ForegroundColor Gray
684
- Write-Host ""
685
-
686
- $ReverbLevel = "off"
687
- $ReverbDisplayName = "Off"
688
-
689
- if (-not $HasFfmpeg) {
690
- Write-Warn "ffmpeg not found - reverb requires ffmpeg"
691
- Write-Info "Install ffmpeg and re-run setup to enable reverb"
692
- } else {
693
- Write-Host " [1] Off Dry, no reverb" -ForegroundColor White
694
- Write-Host " [2] Light Small room (Recommended)" -ForegroundColor White
695
- Write-Host " [3] Medium Conference room" -ForegroundColor White
696
- Write-Host " [4] Heavy Large hall" -ForegroundColor White
697
- Write-Host " [5] Cathedral Epic space" -ForegroundColor White
698
- Write-Host ""
699
-
700
- $reverbChoice = Read-Host " Enter choice (1-5, default: 2)"
701
-
702
- switch ($reverbChoice) {
703
- "1" { $ReverbLevel = "off"; $ReverbDisplayName = "Off" }
704
- "3" { $ReverbLevel = "medium"; $ReverbDisplayName = "Medium" }
705
- "4" { $ReverbLevel = "heavy"; $ReverbDisplayName = "Heavy" }
706
- "5" { $ReverbLevel = "cathedral"; $ReverbDisplayName = "Cathedral" }
707
- default { $ReverbLevel = "light"; $ReverbDisplayName = "Light" }
708
- }
709
-
710
- Write-Host ""
711
- Write-Ok "Reverb: $ReverbDisplayName"
712
- }
713
-
714
- # Write reverb config
715
- Set-Content -Path "$ConfigDir\reverb-level.txt" -Value $ReverbLevel -NoNewline
716
-
717
- # ── Verbosity / Transparency ──────────────────────────
718
-
719
- Write-Section "TTS Verbosity"
720
-
721
- Write-Host " How much should Claude speak during interactions?" -ForegroundColor Gray
722
- Write-Host ""
723
-
724
- Write-Host " [1] High Full reasoning, decisions, trade-offs" -ForegroundColor White
725
- Write-Host " [2] Medium Key updates and acknowledgments" -ForegroundColor White
726
- Write-Host " [3] Low Only essential messages" -ForegroundColor White
727
- Write-Host ""
728
-
729
- $verbChoice = Read-Host " Enter choice (1-3, default: 1)"
730
-
731
- $VerbosityLevel = "high"
732
- $VerbosityDisplayName = "High"
733
-
734
- switch ($verbChoice) {
735
- "2" { $VerbosityLevel = "medium"; $VerbosityDisplayName = "Medium" }
736
- "3" { $VerbosityLevel = "low"; $VerbosityDisplayName = "Low" }
737
- default { $VerbosityLevel = "high"; $VerbosityDisplayName = "High" }
738
- }
739
-
740
- Write-Host ""
741
- Write-Ok "Verbosity: $VerbosityDisplayName"
742
-
743
- # Write verbosity config
744
- Set-Content -Path "$ProjectClaudeDir\tts-verbosity.txt" -Value $VerbosityLevel -NoNewline
745
-
746
- # ── Test TTS ────────────────────────────────────────────────
747
-
748
- Write-Section "Testing TTS"
749
-
750
- Write-Host " Running a quick TTS test..." -ForegroundColor Gray
751
- Write-Host ""
752
-
753
- $TestMessage = "Agent Vibes here. Setup complete, ready to speak on Windows."
754
-
755
- try {
756
- switch ($Provider) {
757
- "soprano" {
758
- if ($SopranoAvailable) {
759
- & "$HooksDir\play-tts-soprano.ps1" $TestMessage | Out-Null
760
- Write-Ok "Soprano TTS is working"
761
- } else {
762
- Write-Warn "Soprano not running - skipping audio test"
763
- Write-Info "Start Soprano, then test with:"
764
- Write-Info ".\.claude\hooks-windows\play-tts.ps1 'Hello'"
765
- }
766
- }
767
- "piper" {
768
- & "$HooksDir\play-tts-windows-piper.ps1" $TestMessage | Out-Null
769
- Write-Ok "Piper TTS is working"
770
- }
771
- "sapi" {
772
- & "$HooksDir\play-tts-windows-sapi.ps1" $TestMessage | Out-Null
773
- Write-Ok "Windows SAPI is working"
774
- }
775
- }
776
- }
777
- catch {
778
- Write-Warn "TTS test failed: $_"
779
- Write-Info "AgentVibes should still work - check troubleshooting in WINDOWS-SETUP.md"
780
- }
781
-
782
- # ── Completion ──────────────────────────────────────────────
783
-
784
- Write-Host ""
785
- Write-BoxTop
786
- Write-BoxEmpty
787
- Write-BoxLine " Setup Complete!" "Green"
788
- Write-BoxEmpty
789
- Write-BoxLine " Provider: $ProviderDisplayName" "White"
790
- Write-BoxLine " Background: $BgMusicDisplayName" "White"
791
- Write-BoxLine " Reverb: $ReverbDisplayName" "White"
792
- Write-BoxLine " Verbosity: $VerbosityDisplayName" "White"
793
- Write-BoxLine " Version: $Version" "DarkGray"
794
- Write-BoxEmpty
795
- Write-BoxBottom
796
-
797
- Write-Host ""
798
- Write-Host " Quick Start Commands:" -ForegroundColor Cyan
799
- Write-Host ""
800
- Write-Host " Test TTS" -ForegroundColor White
801
- Write-Host " .\.claude\hooks-windows\play-tts.ps1 ""Hello from AgentVibes""" -ForegroundColor Gray
802
- Write-Host ""
803
- Write-Host " List voices" -ForegroundColor White
804
- Write-Host " .\.claude\hooks-windows\voice-manager-windows.ps1 list" -ForegroundColor Gray
805
- Write-Host ""
806
- Write-Host " Switch provider" -ForegroundColor White
807
- Write-Host " .\.claude\hooks-windows\provider-manager.ps1 set soprano" -ForegroundColor Gray
808
- Write-Host ""
809
- Write-Host " List providers" -ForegroundColor White
810
- Write-Host " .\.claude\hooks-windows\provider-manager.ps1 list" -ForegroundColor Gray
811
- Write-Host ""
812
-
813
- Write-Host " Documentation:" -ForegroundColor Cyan
814
- Write-Host " Setup Guide: WINDOWS-SETUP.md" -ForegroundColor Gray
815
- Write-Host ""
1
+ #
2
+ # File: setup-windows.ps1
3
+ #
4
+ # AgentVibes Windows Native Setup Script
5
+ # Installs and configures AgentVibes for Windows
6
+ #
7
+ # Usage:
8
+ # .\setup-windows.ps1 # Interactive setup
9
+ # .\setup-windows.ps1 -Provider soprano # Skip provider prompt
10
+ #
11
+
12
+ param(
13
+ [Parameter(Mandatory = $false)]
14
+ [ValidateSet('soprano', 'piper', 'sapi')]
15
+ [string]$Provider
16
+ )
17
+
18
+ $ErrorActionPreference = "Stop"
19
+
20
+ # ── UI Helper Functions ─────────────────────────────────────
21
+
22
+ $BoxWidth = 58
23
+
24
+ function Write-BoxTop {
25
+ Write-Host " $([char]0x256D)$([string]::new([char]0x2500, $BoxWidth))$([char]0x256E)" -ForegroundColor Cyan
26
+ }
27
+
28
+ function Write-BoxBottom {
29
+ Write-Host " $([char]0x2570)$([string]::new([char]0x2500, $BoxWidth))$([char]0x256F)" -ForegroundColor Cyan
30
+ }
31
+
32
+ function Write-BoxLine([string]$text, [string]$color = "White") {
33
+ $padding = $BoxWidth - $text.Length
34
+ if ($padding -lt 0) { $padding = 0; $text = $text.Substring(0, $BoxWidth) }
35
+ Write-Host " $([char]0x2502)" -ForegroundColor Cyan -NoNewline
36
+ Write-Host "$text$([string]::new(' ', $padding))" -ForegroundColor $color -NoNewline
37
+ Write-Host "$([char]0x2502)" -ForegroundColor Cyan
38
+ }
39
+
40
+ function Write-BoxEmpty {
41
+ Write-BoxLine ([string]::new(' ', $BoxWidth)) "White"
42
+ }
43
+
44
+ function Write-Section([string]$label) {
45
+ Write-Host ""
46
+ Write-Host " $([string]::new([char]0x2501, 56))" -ForegroundColor Yellow
47
+ Write-Host " $label" -ForegroundColor Yellow
48
+ Write-Host " $([string]::new([char]0x2501, 56))" -ForegroundColor Yellow
49
+ Write-Host ""
50
+ }
51
+
52
+ function Write-Ok([string]$text) {
53
+ Write-Host " [OK] $text" -ForegroundColor Green
54
+ }
55
+
56
+ function Write-Warn([string]$text) {
57
+ Write-Host " [!!] $text" -ForegroundColor Yellow
58
+ }
59
+
60
+ function Write-Err([string]$text) {
61
+ Write-Host " [XX] $text" -ForegroundColor Red
62
+ }
63
+
64
+ function Write-Info([string]$text) {
65
+ Write-Host " $text" -ForegroundColor Gray
66
+ }
67
+
68
+ function Write-Item([string]$icon, [string]$name, [string]$desc) {
69
+ $nameWidth = 30
70
+ $paddedName = $name.PadRight($nameWidth)
71
+ Write-Host " $icon " -ForegroundColor Green -NoNewline
72
+ Write-Host $paddedName -ForegroundColor White -NoNewline
73
+ Write-Host $desc -ForegroundColor DarkGray
74
+ }
75
+
76
+ # ── Read Version ────────────────────────────────────────────
77
+
78
+ $Version = "unknown"
79
+ $ScriptDir = $PSScriptRoot
80
+ $PackageJson = Join-Path $ScriptDir "package.json"
81
+ if (Test-Path $PackageJson) {
82
+ try {
83
+ $pkg = Get-Content $PackageJson -Raw | ConvertFrom-Json
84
+ $Version = $pkg.version
85
+ } catch {}
86
+ }
87
+
88
+ # ── Banner ──────────────────────────────────────────────────
89
+
90
+ # ANSI Shadow figlet art matching the Node.js installer
91
+ $AgentArt = @(
92
+ " █████╗ ██████╗ ███████╗███╗ ██╗████████╗",
93
+ "██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝",
94
+ "███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ",
95
+ "██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ",
96
+ "██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ",
97
+ "╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ "
98
+ )
99
+ $VibesArt = @(
100
+ "██╗ ██╗██╗██████╗ ███████╗███████╗",
101
+ "██║ ██║██║██╔══██╗██╔════╝██╔════╝",
102
+ "██║ ██║██║██████╔╝█████╗ ███████╗",
103
+ "╚██╗ ██╔╝██║██╔══██╗██╔══╝ ╚════██║",
104
+ " ╚████╔╝ ██║██████╔╝███████╗███████║",
105
+ " ╚═══╝ ╚═╝╚═════╝ ╚══════╝╚══════╝"
106
+ )
107
+
108
+ Write-Host ""
109
+ for ($i = 0; $i -lt $AgentArt.Count; $i++) {
110
+ Write-Host $AgentArt[$i] -ForegroundColor Cyan -NoNewline
111
+ Write-Host " " -NoNewline
112
+ Write-Host $VibesArt[$i] -ForegroundColor Magenta
113
+ }
114
+ Write-Host ""
115
+ Write-BoxTop
116
+ Write-BoxEmpty
117
+ Write-BoxLine " Windows Native Setup v$Version" "Cyan"
118
+ Write-BoxEmpty
119
+ Write-BoxLine " Now your AI Agents can finally talk back!" "White"
120
+ Write-BoxLine " Professional TTS for Claude Code on Windows" "DarkGray"
121
+ Write-BoxEmpty
122
+ Write-BoxLine " https://agentvibes.org" "DarkCyan"
123
+ Write-BoxBottom
124
+ Write-Host ""
125
+
126
+ # ── What's New ──────────────────────────────────────────────
127
+
128
+ Write-Host " WHAT'S NEW in v$Version" -ForegroundColor Green
129
+ Write-Host ""
130
+ Write-Host " Native Windows support with three TTS providers (Soprano neural," -ForegroundColor Cyan
131
+ Write-Host " Piper offline, Windows SAPI), background music from 16 genre tracks," -ForegroundColor Cyan
132
+ Write-Host " reverb effects via ffmpeg, and verbosity control." -ForegroundColor Cyan
133
+ Write-Host ""
134
+ Write-Host " Thanks to @nathanchase (Soprano), @alexeyv (Windows SAPI)," -ForegroundColor Yellow
135
+ Write-Host " @bmadcode (BMAD Method)!" -ForegroundColor Yellow
136
+ Write-Host ""
137
+ Write-Host " KEY HIGHLIGHTS:" -ForegroundColor Green
138
+ Write-Host " [*] Native Windows TTS - Soprano, Piper, SAPI. No WSL needed!" -ForegroundColor Gray
139
+ Write-Host " [*] Background Music - 16 genre tracks (Bachata, Flamenco, etc.)" -ForegroundColor Gray
140
+ Write-Host " [*] Reverb & Effects - 5 reverb levels via ffmpeg aecho filter" -ForegroundColor Gray
141
+ Write-Host " [*] Verbosity Control - High, Medium, or Low transparency" -ForegroundColor Gray
142
+ Write-Host " [*] Beautiful Installer - Figlet banner, provider detection" -ForegroundColor Gray
143
+ Write-Host " [*] 93/93 Tests Passing - 46 Windows + 47 cross-platform" -ForegroundColor Gray
144
+ Write-Host ""
145
+
146
+ # ── Node.js Detection ──────────────────────────────────────
147
+
148
+ try {
149
+ $nodeVersion = & node --version 2>$null
150
+ if ($nodeVersion) {
151
+ Write-Host " Node.js detected " -ForegroundColor Gray -NoNewline
152
+ Write-Host "($nodeVersion)" -ForegroundColor Green
153
+ Write-Host ""
154
+ Write-Host " Tip: For a richer install experience, you can also run:" -ForegroundColor DarkGray
155
+ Write-Host " npx agentvibes install" -ForegroundColor Cyan
156
+ Write-Host ""
157
+ $choice = Read-Host " Launch the Node.js installer instead? (y/N)"
158
+ if ($choice -eq 'y' -or $choice -eq 'Y') {
159
+ Write-Host ""
160
+ Write-Host " Launching Node.js installer..." -ForegroundColor Cyan
161
+ Write-Host ""
162
+ $installerPath = Join-Path $ScriptDir "src\installer.js"
163
+ if (Test-Path $installerPath) {
164
+ & node $installerPath install
165
+ } else {
166
+ & npx agentvibes install
167
+ }
168
+ exit 0
169
+ }
170
+ Write-Host ""
171
+ Write-Host " Continuing with PowerShell installer..." -ForegroundColor Gray
172
+ }
173
+ } catch {}
174
+
175
+ # ── PowerShell Version Check ───────────────────────────────
176
+
177
+ Write-Section "System Check"
178
+
179
+ $PSVersionRequired = [Version]"5.1"
180
+ if ($PSVersionTable.PSVersion -lt $PSVersionRequired) {
181
+ Write-Err "PowerShell 5.1+ required (found $($PSVersionTable.PSVersion))"
182
+ exit 1
183
+ }
184
+ Write-Ok "PowerShell $($PSVersionTable.PSVersion)"
185
+
186
+ # ── Detect Project Root ─────────────────────────────────────
187
+
188
+ if ($ScriptDir -match '[\\/]node_modules[\\/]agentvibes$') {
189
+ $ProjectRoot = (Resolve-Path (Join-Path $ScriptDir "..\..")).Path
190
+ Write-Ok "Detected npm package in: $ProjectRoot"
191
+ } else {
192
+ $ProjectRoot = $ScriptDir
193
+ Write-Ok "Project root: $ProjectRoot"
194
+ }
195
+
196
+ # ── Setup Directories ───────────────────────────────────────
197
+
198
+ Write-Section "Setting Up Directories"
199
+
200
+ Write-Host " These directories store AgentVibes config and data:" -ForegroundColor Gray
201
+ Write-Host ""
202
+
203
+ $ProjectClaudeDir = "$ProjectRoot\.claude"
204
+ $HooksDir = "$ProjectClaudeDir\hooks-windows"
205
+ $UserClaudeDir = "$env:USERPROFILE\.claude"
206
+ $AudioDir = "$UserClaudeDir\audio"
207
+ $VoicesDir = "$UserClaudeDir\piper-voices"
208
+ $PiperDir = "$env:LOCALAPPDATA\Programs\Piper"
209
+ $PiperExe = "$PiperDir\piper.exe"
210
+
211
+ # Directory info: path, description, category
212
+ $DirInfo = @(
213
+ @{ Path = $ProjectClaudeDir; Desc = "Project settings and hooks config"; Cat = "Project" },
214
+ @{ Path = $HooksDir; Desc = "PowerShell TTS hook scripts"; Cat = "Project" },
215
+ @{ Path = $UserClaudeDir; Desc = "Global AgentVibes configuration"; Cat = "User Profile" },
216
+ @{ Path = $AudioDir; Desc = "TTS audio file cache"; Cat = "User Profile" },
217
+ @{ Path = $VoicesDir; Desc = "Piper voice model files"; Cat = "User Profile" },
218
+ @{ Path = $PiperDir; Desc = "Piper TTS engine binary"; Cat = "Applications" }
219
+ )
220
+
221
+ $CurrentCat = ""
222
+ foreach ($entry in $DirInfo) {
223
+ if ($entry.Cat -ne $CurrentCat) {
224
+ if ($CurrentCat -ne "") { Write-Host "" }
225
+ Write-Host " $($entry.Cat)" -ForegroundColor Cyan
226
+ $CurrentCat = $entry.Cat
227
+ }
228
+
229
+ $dir = $entry.Path
230
+ $existed = Test-Path $dir
231
+ if (-not $existed) {
232
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
233
+ }
234
+
235
+ # Show relative path where possible
236
+ $displayPath = $dir
237
+ if ($dir.StartsWith($ProjectRoot)) {
238
+ $displayPath = $dir.Substring($ProjectRoot.Length + 1)
239
+ } elseif ($dir.StartsWith($env:USERPROFILE)) {
240
+ $displayPath = "~" + $dir.Substring($env:USERPROFILE.Length)
241
+ } elseif ($dir.StartsWith($env:LOCALAPPDATA)) {
242
+ $displayPath = "%LOCALAPPDATA%" + $dir.Substring($env:LOCALAPPDATA.Length)
243
+ }
244
+
245
+ $status = if ($existed) { "[OK]" } else { "[OK]" }
246
+ $action = if ($existed) { "exists" } else { "created" }
247
+
248
+ Write-Host " $status " -ForegroundColor Green -NoNewline
249
+ Write-Host $displayPath.PadRight(32) -ForegroundColor White -NoNewline
250
+ Write-Host $entry.Desc -ForegroundColor DarkGray
251
+ }
252
+
253
+ # ── Install Hook Scripts ────────────────────────────────────
254
+
255
+ Write-Section "Installing TTS Scripts"
256
+
257
+ Write-Host " These scripts enable Claude Code to speak on Windows:" -ForegroundColor Gray
258
+ Write-Host ""
259
+
260
+ $SourceHooksDir = Join-Path $ScriptDir ".claude\hooks-windows"
261
+
262
+ # Validate source path is within the script directory (path traversal prevention)
263
+ $ResolvedSource = (Resolve-Path -Path $SourceHooksDir -ErrorAction SilentlyContinue).Path
264
+ $ResolvedScript = (Resolve-Path -Path $ScriptDir).Path
265
+
266
+ if (-not $ResolvedSource -or -not $ResolvedSource.StartsWith($ResolvedScript)) {
267
+ Write-Err "Hook scripts source path is outside the project directory"
268
+ exit 1
269
+ }
270
+
271
+ if (-not (Test-Path $SourceHooksDir)) {
272
+ Write-Err "Hook scripts not found at: $SourceHooksDir"
273
+ Write-Info "Make sure you're running this from the AgentVibes project directory"
274
+ exit 1
275
+ }
276
+
277
+ # Ensure destination hooks directory exists
278
+ if (-not (Test-Path $HooksDir)) {
279
+ New-Item -ItemType Directory -Path $HooksDir -Force | Out-Null
280
+ }
281
+
282
+ # Script info: filename, description
283
+ $HookScriptInfo = @(
284
+ @{ Name = "play-tts.ps1"; Desc = "Main TTS router - dispatches to active provider" },
285
+ @{ Name = "play-tts-soprano.ps1"; Desc = "Soprano neural voice provider (fastest)" },
286
+ @{ Name = "play-tts-windows-piper.ps1"; Desc = "Piper offline neural voice provider" },
287
+ @{ Name = "play-tts-windows-sapi.ps1"; Desc = "Windows built-in SAPI voice provider" },
288
+ @{ Name = "provider-manager.ps1"; Desc = "Switch between TTS providers" },
289
+ @{ Name = "voice-manager-windows.ps1"; Desc = "Browse and select voice models" },
290
+ @{ Name = "audio-cache-utils.ps1"; Desc = "Manage TTS audio file cache" },
291
+ @{ Name = "session-start-tts.ps1"; Desc = "Auto-activates TTS when Claude starts" }
292
+ )
293
+
294
+ $CopiedCount = 0
295
+ foreach ($info in $HookScriptInfo) {
296
+ $script = $info.Name
297
+ $SourceFile = Join-Path $SourceHooksDir $script
298
+ $DestFile = Join-Path $HooksDir $script
299
+
300
+ if (Test-Path $SourceFile) {
301
+ # Skip if source and destination are the same file (running from project root)
302
+ $resolvedSrc = (Resolve-Path $SourceFile).Path
303
+ $resolvedDst = if (Test-Path $DestFile) { (Resolve-Path $DestFile).Path } else { "" }
304
+ if ($resolvedSrc -eq $resolvedDst) {
305
+ Write-Item "[OK]" $script $info.Desc
306
+ } else {
307
+ Copy-Item -Path $SourceFile -Destination $DestFile -Force
308
+ Write-Item "[OK]" $script $info.Desc
309
+ }
310
+ $CopiedCount++
311
+ }
312
+ else {
313
+ Write-Host " [!!] " -ForegroundColor Yellow -NoNewline
314
+ Write-Host "$($script.PadRight(30))" -ForegroundColor White -NoNewline
315
+ Write-Host "not found" -ForegroundColor Yellow
316
+ }
317
+ }
318
+
319
+ if ($CopiedCount -eq 0) {
320
+ Write-Err "No hook scripts were installed"
321
+ exit 1
322
+ }
323
+
324
+ Write-Host ""
325
+ Write-Host " Location: " -ForegroundColor Gray -NoNewline
326
+ Write-Host ".claude\hooks-windows\" -ForegroundColor Cyan
327
+ Write-Ok "Installed $CopiedCount TTS scripts"
328
+
329
+ # ── Provider Selection ──────────────────────────────────────
330
+
331
+ Write-Section "Choose Your TTS Provider"
332
+
333
+ # Check if pip is available
334
+ $PipAvailable = $false
335
+ try {
336
+ $pipTest = & pip --version 2>$null
337
+ if ($pipTest) { $PipAvailable = $true }
338
+ } catch {}
339
+
340
+ # Check Soprano availability
341
+ $SopranoAvailable = $false
342
+ try {
343
+ $response = Invoke-WebRequest -Uri "http://127.0.0.1:7860/api/predict" `
344
+ -Method POST -UseBasicParsing -TimeoutSec 2 `
345
+ -ContentType "application/json" `
346
+ -Body '{"data":["test",1.0],"fn_index":0}' `
347
+ -ErrorAction SilentlyContinue
348
+ if ($response.StatusCode -eq 200) { $SopranoAvailable = $true }
349
+ } catch {}
350
+
351
+ # Check if pip has soprano-tts (only if pip is available)
352
+ $SopranoInstalled = $false
353
+ if ($PipAvailable) {
354
+ try {
355
+ $pipResult = & pip show soprano-tts 2>$null
356
+ if ($pipResult) { $SopranoInstalled = $true }
357
+ } catch {}
358
+ }
359
+
360
+ if (-not $Provider) {
361
+ Write-Host " [1] Soprano (Best Quality)" -ForegroundColor White
362
+ Write-Host " Ultra-fast neural TTS, 80M parameter model" -ForegroundColor DarkGray
363
+ if ($SopranoAvailable) {
364
+ Write-Host " Status: " -ForegroundColor DarkGray -NoNewline
365
+ Write-Host "Running on port 7860" -ForegroundColor Green
366
+ } elseif ($SopranoInstalled) {
367
+ Write-Host " Status: " -ForegroundColor DarkGray -NoNewline
368
+ Write-Host "Installed (not running)" -ForegroundColor Yellow
369
+ } else {
370
+ Write-Host " Requires: pip install soprano-tts" -ForegroundColor DarkGray
371
+ }
372
+ Write-Host ""
373
+
374
+ Write-Host " [2] Piper (Recommended Offline)" -ForegroundColor White
375
+ Write-Host " High quality neural voices, works fully offline" -ForegroundColor DarkGray
376
+ if (Test-Path $PiperExe) {
377
+ Write-Host " Status: " -ForegroundColor DarkGray -NoNewline
378
+ Write-Host "Installed" -ForegroundColor Green
379
+ } else {
380
+ Write-Host " Downloads: ~100MB (piper.exe + voice model)" -ForegroundColor DarkGray
381
+ }
382
+ Write-Host ""
383
+
384
+ Write-Host " [3] Windows SAPI (Zero Setup)" -ForegroundColor White
385
+ Write-Host " Built-in Windows voices (David, Zira, Mark)" -ForegroundColor DarkGray
386
+ Write-Host " No download required" -ForegroundColor DarkGray
387
+ Write-Host ""
388
+
389
+ $choice = Read-Host " Enter choice (1-3, default: 1)"
390
+
391
+ switch ($choice) {
392
+ "2" { $Provider = "piper" }
393
+ "3" { $Provider = "sapi" }
394
+ default { $Provider = "soprano" }
395
+ }
396
+ }
397
+
398
+ $ProviderDisplayName = switch ($Provider) {
399
+ "soprano" { "Soprano TTS" }
400
+ "piper" { "Piper TTS" }
401
+ "sapi" { "Windows SAPI" }
402
+ }
403
+
404
+ Write-Host ""
405
+ Write-Ok "Selected: $ProviderDisplayName"
406
+
407
+ # ── Install Soprano if selected ─────────────────────────────
408
+
409
+ if ($Provider -eq "soprano") {
410
+ Write-Section "Soprano Setup"
411
+
412
+ if ($SopranoAvailable) {
413
+ Write-Ok "Soprano server running on port 7860"
414
+ } elseif ($SopranoInstalled) {
415
+ Write-Warn "Soprano is installed but not running"
416
+ Write-Info "Start it with: soprano-tts --share"
417
+ Write-Info "Or run it in WSL and forward port 7860"
418
+ } else {
419
+ Write-Warn "Soprano TTS not detected"
420
+ Write-Host ""
421
+
422
+ if (-not $PipAvailable) {
423
+ Write-Error "pip is not available on this system"
424
+ Write-Info "Please install Python 3 with pip, then run:"
425
+ Write-Host " pip install soprano-tts" -ForegroundColor Cyan
426
+ Write-Host ""
427
+ } else {
428
+ # Offer to install Soprano
429
+ $installChoice = Read-Host "Would you like to install Soprano now? (y/n, default: y)"
430
+
431
+ if ($installChoice -eq "" -or $installChoice -eq "y" -or $installChoice -eq "Y") {
432
+ Write-Info "Installing Soprano TTS..."
433
+ Write-Host ""
434
+
435
+ try {
436
+ & pip install soprano-tts 2>&1 | Tee-Object -Variable pipOutput | Write-Host
437
+
438
+ # Re-check if installation succeeded
439
+ $SopranoInstalled = $false
440
+ try {
441
+ $pipResult = & pip show soprano-tts 2>$null
442
+ if ($pipResult) { $SopranoInstalled = $true }
443
+ } catch {}
444
+
445
+ if ($SopranoInstalled) {
446
+ Write-Ok "Soprano TTS installed successfully!"
447
+ Write-Info "Start it with: soprano-tts --share"
448
+ } else {
449
+ Write-Error "Installation may have failed. Please check the output above."
450
+ Write-Info "You can try installing manually: pip install soprano-tts"
451
+ }
452
+ } catch {
453
+ Write-Error "Installation failed: $_"
454
+ Write-Info "Please install manually: pip install soprano-tts"
455
+ }
456
+ } else {
457
+ Write-Host ""
458
+ Write-Host " To install Soprano manually:" -ForegroundColor White
459
+ Write-Host " pip install soprano-tts" -ForegroundColor Cyan
460
+ Write-Host ""
461
+ Write-Host " Or use Soprano in WSL with port forwarding:" -ForegroundColor White
462
+ Write-Host " ssh -L 7860:localhost:7860 your-wsl-host" -ForegroundColor Cyan
463
+ Write-Host ""
464
+ Write-Info "AgentVibes will work once Soprano is accessible on port 7860"
465
+ }
466
+ }
467
+ }
468
+ }
469
+
470
+ # ── Install Piper if selected ───────────────────────────────
471
+
472
+ if ($Provider -eq "piper") {
473
+ Write-Section "Piper Installation"
474
+
475
+ if (Test-Path $PiperExe) {
476
+ Write-Ok "Piper already installed at: $PiperDir"
477
+ }
478
+ else {
479
+ Write-Host " Downloading Piper TTS engine from GitHub..." -ForegroundColor White
480
+
481
+ $DownloadUrl = "https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_windows_amd64.zip"
482
+ $DownloadFile = "$env:TEMP\piper-windows.zip"
483
+
484
+ try {
485
+ Write-Info $DownloadUrl
486
+
487
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
488
+ Invoke-WebRequest -Uri $DownloadUrl -OutFile $DownloadFile -UseBasicParsing -ErrorAction Stop
489
+
490
+ Write-Ok "Downloaded ($('{0:N2}' -f ((Get-Item $DownloadFile).Length / 1MB)) MB)"
491
+
492
+ Write-Host " Extracting..." -ForegroundColor Gray
493
+ $TempExtractDir = "$env:TEMP\piper-extract"
494
+ Remove-Item -Path $TempExtractDir -Recurse -Force -ErrorAction SilentlyContinue
495
+ Expand-Archive -Path $DownloadFile -DestinationPath $TempExtractDir -Force
496
+
497
+ # Find piper.exe recursively
498
+ $PiperFound = Get-ChildItem -Path $TempExtractDir -Name "piper.exe" -Recurse
499
+
500
+ if ($PiperFound) {
501
+ $PiperExePath = (Get-ChildItem -Path $TempExtractDir -Filter "piper.exe" -Recurse).FullName | Select-Object -First 1
502
+ $PiperSourceDir = Split-Path -Parent $PiperExePath
503
+
504
+ Copy-Item -Path "$PiperSourceDir\*" -Destination $PiperDir -Recurse -Force
505
+
506
+ if (Test-Path $PiperExe) {
507
+ Write-Ok "Piper installed to: $PiperDir"
508
+ }
509
+ else {
510
+ throw "Failed to copy Piper executable"
511
+ }
512
+ }
513
+ else {
514
+ throw "piper.exe not found in extracted files"
515
+ }
516
+
517
+ # Cleanup
518
+ Remove-Item -Path $TempExtractDir -Recurse -Force -ErrorAction SilentlyContinue
519
+ Remove-Item $DownloadFile -Force -ErrorAction SilentlyContinue
520
+ }
521
+ catch {
522
+ Write-Err "Failed to install Piper: $_"
523
+ Write-Info "Please check your internet connection and try again"
524
+ exit 1
525
+ }
526
+ }
527
+
528
+ # Download default voice
529
+ Write-Host ""
530
+ Write-Host " Setting up default voice model..." -ForegroundColor White
531
+
532
+ $DefaultVoice = "en_US-ryan-high"
533
+ $VoiceDir = $VoicesDir
534
+
535
+ if ((Test-Path "$VoiceDir\$DefaultVoice.onnx") -and (Test-Path "$VoiceDir\$DefaultVoice.onnx.json")) {
536
+ Write-Ok "Default voice ($DefaultVoice) already downloaded"
537
+ }
538
+ else {
539
+ Write-Host " Downloading $DefaultVoice..." -ForegroundColor Gray
540
+
541
+ try {
542
+ $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/ryan/high"
543
+
544
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
545
+
546
+ Write-Host " Downloading model file..." -ForegroundColor Gray
547
+ Invoke-WebRequest -Uri "$HFBase/$DefaultVoice.onnx" `
548
+ -OutFile "$VoiceDir\$DefaultVoice.onnx" `
549
+ -UseBasicParsing -ErrorAction Stop
550
+
551
+ Write-Host " Downloading config file..." -ForegroundColor Gray
552
+ Invoke-WebRequest -Uri "$HFBase/$DefaultVoice.onnx.json" `
553
+ -OutFile "$VoiceDir\$DefaultVoice.onnx.json" `
554
+ -UseBasicParsing -ErrorAction Stop
555
+
556
+ Write-Ok "Voice model downloaded: $DefaultVoice"
557
+ }
558
+ catch {
559
+ Write-Warn "Could not download voice: $_"
560
+ Write-Info "You can download voices manually later"
561
+ }
562
+ }
563
+ }
564
+
565
+ # ── Set Active Provider ─────────────────────────────────────
566
+
567
+ Write-Section "Configuring Provider"
568
+
569
+ $ProviderFile = "$ProjectClaudeDir\tts-provider.txt"
570
+ $ProviderName = switch ($Provider) {
571
+ "soprano" { "soprano" }
572
+ "piper" { "windows-piper" }
573
+ "sapi" { "windows-sapi" }
574
+ }
575
+
576
+ Set-Content -Path $ProviderFile -Value $ProviderName -NoNewline
577
+ Write-Ok "Active provider set to: $ProviderName"
578
+ Write-Info "Config file: .claude\tts-provider.txt"
579
+
580
+ # ── Background Music Selection ─────────────────────────
581
+
582
+ Write-Section "Background Music"
583
+
584
+ Write-Host " Play background music under TTS voice output?" -ForegroundColor Gray
585
+ Write-Host " Requires ffmpeg (mixing voice + music)." -ForegroundColor DarkGray
586
+ Write-Host ""
587
+
588
+ # Check ffmpeg availability
589
+ $HasFfmpeg = $false
590
+ try {
591
+ $null = Get-Command ffmpeg -ErrorAction Stop
592
+ $HasFfmpeg = $true
593
+ } catch {}
594
+
595
+ $BgMusicEnabled = $false
596
+ $BgMusicTrack = "agent_vibes_bachata_v1_loop.mp3"
597
+ $BgMusicDisplayName = "Off"
598
+
599
+ if (-not $HasFfmpeg) {
600
+ Write-Warn "ffmpeg not found - background music requires ffmpeg"
601
+ Write-Info "Install ffmpeg and re-run setup to enable background music"
602
+ } else {
603
+ Write-Host " [1] Yes - Enable background music (Recommended)" -ForegroundColor White
604
+ Write-Host " [2] No - Voice only" -ForegroundColor White
605
+ Write-Host ""
606
+
607
+ $bgChoice = Read-Host " Enter choice (1-2, default: 1)"
608
+
609
+ if ($bgChoice -eq "2") {
610
+ $BgMusicEnabled = $false
611
+ $BgMusicDisplayName = "Off"
612
+ Write-Host ""
613
+ Write-Ok "Background music: Disabled"
614
+ } else {
615
+ $BgMusicEnabled = $true
616
+
617
+ # Track list with filenames and display info
618
+ $Tracks = @(
619
+ @{ File = "agentvibes_soft_flamenco_loop.mp3"; Name = "Soft Flamenco"; Desc = "Spanish guitar" },
620
+ @{ File = "agent_vibes_bachata_v1_loop.mp3"; Name = "Bachata"; Desc = "Latin rhythm" },
621
+ @{ File = "agent_vibes_bossa_nova_v2_loop.mp3"; Name = "Bossa Nova"; Desc = "Brazilian jazz" },
622
+ @{ File = "agent_vibes_salsa_v2_loop.mp3"; Name = "Salsa"; Desc = "Latin dance" },
623
+ @{ File = "agent_vibes_cumbia_v1_loop.mp3"; Name = "Cumbia"; Desc = "Colombian folk" },
624
+ @{ File = "agent_vibes_japanese_city_pop_v1_loop.mp3"; Name = "Japanese City Pop"; Desc = "80s synth" },
625
+ @{ File = "agent_vibes_chillwave_v2_loop.mp3"; Name = "Chillwave"; Desc = "Electronic ambient" },
626
+ @{ File = "dreamy_house_loop.mp3"; Name = "Dreamy House"; Desc = "Electronic dance" },
627
+ @{ File = "agent_vibes_dark_chill_step_loop.mp3"; Name = "Dark Chill Step"; Desc = "Electronic bass" },
628
+ @{ File = "agent_vibes_goa_trance_v2_loop.mp3"; Name = "Goa Trance"; Desc = "Psychedelic electronic" },
629
+ @{ File = "agent_vibes_harpsichord_v2_loop.mp3"; Name = "Harpsichord"; Desc = "Baroque classical" },
630
+ @{ File = "agent_vibes_celtic_harp_v1_loop.mp3"; Name = "Celtic Harp"; Desc = "Irish traditional" },
631
+ @{ File = "agent_vibes_hawaiian_slack_key_guitar_v2_loop.mp3"; Name = "Hawaiian Slack Key"; Desc = "Island guitar" },
632
+ @{ File = "agent_vibes_arabic_v2_loop.mp3"; Name = "Arabic Oud"; Desc = "Middle Eastern" },
633
+ @{ File = "agent_vibes_ganawa_ambient_v2_loop.mp3"; Name = "Gnawa Ambient"; Desc = "North African" },
634
+ @{ File = "agent_vibes_tabla_dream_pop_v1_loop.mp3"; Name = "Tabla Dream Pop"; Desc = "Indian percussion" }
635
+ )
636
+
637
+ Write-Host ""
638
+ Write-Host " Choose a background music genre:" -ForegroundColor White
639
+ Write-Host ""
640
+
641
+ for ($i = 0; $i -lt $Tracks.Count; $i++) {
642
+ $num = ($i + 1).ToString().PadLeft(2)
643
+ $trackName = $Tracks[$i].Name.PadRight(22)
644
+ Write-Host " [$num] " -ForegroundColor White -NoNewline
645
+ Write-Host $trackName -ForegroundColor Cyan -NoNewline
646
+ Write-Host $Tracks[$i].Desc -ForegroundColor DarkGray
647
+ }
648
+
649
+ Write-Host ""
650
+ $trackChoice = Read-Host " Enter choice (1-16, default: 2)"
651
+
652
+ $trackIndex = 1 # default to Bachata (index 1)
653
+ if ($trackChoice -match '^\d+$') {
654
+ $parsed = [int]$trackChoice
655
+ if ($parsed -ge 1 -and $parsed -le $Tracks.Count) {
656
+ $trackIndex = $parsed - 1
657
+ }
658
+ }
659
+
660
+ $BgMusicTrack = $Tracks[$trackIndex].File
661
+ $BgMusicDisplayName = $Tracks[$trackIndex].Name
662
+
663
+ Write-Host ""
664
+ Write-Ok "Background music: $BgMusicDisplayName"
665
+ }
666
+ }
667
+
668
+ # Write background music config
669
+ $ConfigDir = "$ProjectClaudeDir\config"
670
+ if (-not (Test-Path $ConfigDir)) {
671
+ New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null
672
+ }
673
+
674
+ $bgEnabledValue = if ($BgMusicEnabled) { "true" } else { "false" }
675
+ Set-Content -Path "$ConfigDir\background-music-enabled.txt" -Value $bgEnabledValue -NoNewline
676
+ Set-Content -Path "$ConfigDir\background-music-default.txt" -Value $BgMusicTrack -NoNewline
677
+ Set-Content -Path "$ConfigDir\background-music-volume.txt" -Value "0.10" -NoNewline
678
+
679
+ # ── Audio Effects (Reverb) ─────────────────────────────
680
+
681
+ Write-Section "Audio Effects"
682
+
683
+ Write-Host " Add reverb effect to voice output?" -ForegroundColor Gray
684
+ Write-Host ""
685
+
686
+ $ReverbLevel = "off"
687
+ $ReverbDisplayName = "Off"
688
+
689
+ if (-not $HasFfmpeg) {
690
+ Write-Warn "ffmpeg not found - reverb requires ffmpeg"
691
+ Write-Info "Install ffmpeg and re-run setup to enable reverb"
692
+ } else {
693
+ Write-Host " [1] Off Dry, no reverb" -ForegroundColor White
694
+ Write-Host " [2] Light Small room (Recommended)" -ForegroundColor White
695
+ Write-Host " [3] Medium Conference room" -ForegroundColor White
696
+ Write-Host " [4] Heavy Large hall" -ForegroundColor White
697
+ Write-Host " [5] Cathedral Epic space" -ForegroundColor White
698
+ Write-Host ""
699
+
700
+ $reverbChoice = Read-Host " Enter choice (1-5, default: 2)"
701
+
702
+ switch ($reverbChoice) {
703
+ "1" { $ReverbLevel = "off"; $ReverbDisplayName = "Off" }
704
+ "3" { $ReverbLevel = "medium"; $ReverbDisplayName = "Medium" }
705
+ "4" { $ReverbLevel = "heavy"; $ReverbDisplayName = "Heavy" }
706
+ "5" { $ReverbLevel = "cathedral"; $ReverbDisplayName = "Cathedral" }
707
+ default { $ReverbLevel = "light"; $ReverbDisplayName = "Light" }
708
+ }
709
+
710
+ Write-Host ""
711
+ Write-Ok "Reverb: $ReverbDisplayName"
712
+ }
713
+
714
+ # Write reverb config
715
+ Set-Content -Path "$ConfigDir\reverb-level.txt" -Value $ReverbLevel -NoNewline
716
+
717
+ # ── Verbosity / Transparency ──────────────────────────
718
+
719
+ Write-Section "TTS Verbosity"
720
+
721
+ Write-Host " How much should Claude speak during interactions?" -ForegroundColor Gray
722
+ Write-Host ""
723
+
724
+ Write-Host " [1] High Full reasoning, decisions, trade-offs" -ForegroundColor White
725
+ Write-Host " [2] Medium Key updates and acknowledgments" -ForegroundColor White
726
+ Write-Host " [3] Low Only essential messages" -ForegroundColor White
727
+ Write-Host ""
728
+
729
+ $verbChoice = Read-Host " Enter choice (1-3, default: 1)"
730
+
731
+ $VerbosityLevel = "high"
732
+ $VerbosityDisplayName = "High"
733
+
734
+ switch ($verbChoice) {
735
+ "2" { $VerbosityLevel = "medium"; $VerbosityDisplayName = "Medium" }
736
+ "3" { $VerbosityLevel = "low"; $VerbosityDisplayName = "Low" }
737
+ default { $VerbosityLevel = "high"; $VerbosityDisplayName = "High" }
738
+ }
739
+
740
+ Write-Host ""
741
+ Write-Ok "Verbosity: $VerbosityDisplayName"
742
+
743
+ # Write verbosity config
744
+ Set-Content -Path "$ProjectClaudeDir\tts-verbosity.txt" -Value $VerbosityLevel -NoNewline
745
+
746
+ # ── Test TTS ────────────────────────────────────────────────
747
+
748
+ Write-Section "Testing TTS"
749
+
750
+ Write-Host " Running a quick TTS test..." -ForegroundColor Gray
751
+ Write-Host ""
752
+
753
+ $TestMessage = "Agent Vibes here. Setup complete, ready to speak on Windows."
754
+
755
+ try {
756
+ switch ($Provider) {
757
+ "soprano" {
758
+ if ($SopranoAvailable) {
759
+ & "$HooksDir\play-tts-soprano.ps1" $TestMessage | Out-Null
760
+ Write-Ok "Soprano TTS is working"
761
+ } else {
762
+ Write-Warn "Soprano not running - skipping audio test"
763
+ Write-Info "Start Soprano, then test with:"
764
+ Write-Info ".\.claude\hooks-windows\play-tts.ps1 'Hello'"
765
+ }
766
+ }
767
+ "piper" {
768
+ & "$HooksDir\play-tts-windows-piper.ps1" $TestMessage | Out-Null
769
+ Write-Ok "Piper TTS is working"
770
+ }
771
+ "sapi" {
772
+ & "$HooksDir\play-tts-windows-sapi.ps1" $TestMessage | Out-Null
773
+ Write-Ok "Windows SAPI is working"
774
+ }
775
+ }
776
+ }
777
+ catch {
778
+ Write-Warn "TTS test failed: $_"
779
+ Write-Info "AgentVibes should still work - check troubleshooting in WINDOWS-SETUP.md"
780
+ }
781
+
782
+ # ── Completion ──────────────────────────────────────────────
783
+
784
+ Write-Host ""
785
+ Write-BoxTop
786
+ Write-BoxEmpty
787
+ Write-BoxLine " Setup Complete!" "Green"
788
+ Write-BoxEmpty
789
+ Write-BoxLine " Provider: $ProviderDisplayName" "White"
790
+ Write-BoxLine " Background: $BgMusicDisplayName" "White"
791
+ Write-BoxLine " Reverb: $ReverbDisplayName" "White"
792
+ Write-BoxLine " Verbosity: $VerbosityDisplayName" "White"
793
+ Write-BoxLine " Version: $Version" "DarkGray"
794
+ Write-BoxEmpty
795
+ Write-BoxBottom
796
+
797
+ Write-Host ""
798
+ Write-Host " Quick Start Commands:" -ForegroundColor Cyan
799
+ Write-Host ""
800
+ Write-Host " Test TTS" -ForegroundColor White
801
+ Write-Host " .\.claude\hooks-windows\play-tts.ps1 ""Hello from AgentVibes""" -ForegroundColor Gray
802
+ Write-Host ""
803
+ Write-Host " List voices" -ForegroundColor White
804
+ Write-Host " .\.claude\hooks-windows\voice-manager-windows.ps1 list" -ForegroundColor Gray
805
+ Write-Host ""
806
+ Write-Host " Switch provider" -ForegroundColor White
807
+ Write-Host " .\.claude\hooks-windows\provider-manager.ps1 set soprano" -ForegroundColor Gray
808
+ Write-Host ""
809
+ Write-Host " List providers" -ForegroundColor White
810
+ Write-Host " .\.claude\hooks-windows\provider-manager.ps1 list" -ForegroundColor Gray
811
+ Write-Host ""
812
+
813
+ Write-Host " Documentation:" -ForegroundColor Cyan
814
+ Write-Host " Setup Guide: WINDOWS-SETUP.md" -ForegroundColor Gray
815
+ Write-Host ""