agentvibes 4.2.0 → 4.4.1
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 +2 -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 -433
- 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 -269
- 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 -105
- package/.claude/hooks/play-tts-macos.sh +368 -368
- package/.claude/hooks/play-tts-piper.sh +679 -679
- package/.claude/hooks/play-tts-soprano.sh +356 -356
- package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
- package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
- package/.claude/hooks/play-tts.sh +301 -301
- 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 -81
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +291 -291
- package/.claude/hooks/stop-tts.sh +84 -84
- 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 -145
- package/.claude/hooks/tts-queue.sh +165 -165
- package/.claude/hooks/verbosity-manager.sh +178 -178
- package/.claude/hooks/voice-manager.sh +548 -548
- 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 -170
- package/README.md +2029 -2007
- package/RELEASE_NOTES.md +1310 -1203
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/agentvibes-voice-browser.js +1840 -1840
- 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 -1453
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +336 -0
- package/package.json +110 -110
- 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 -824
- package/src/console/audio-env.js +20 -1
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/footer-config.js +50 -50
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +62 -62
- package/src/console/tabs/agents-tab.js +1684 -1516
- 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 -53
- package/src/console/tabs/readme-tab.js +267 -267
- package/src/console/tabs/receiver-tab.js +1472 -1212
- package/src/console/tabs/settings-tab.js +208 -84
- package/src/console/tabs/voices-tab.js +100 -21
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/format-utils.js +89 -89
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/personality-picker.js +185 -185
- package/src/console/widgets/reverb-picker.js +94 -94
- package/src/console/widgets/track-picker.js +285 -285
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +5895 -5829
- package/src/services/agent-voice-store.js +423 -423
- package/src/services/config-service.js +264 -264
- package/src/services/navigation-service.js +123 -123
- package/src/services/provider-service.js +143 -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 -285
- 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 -482
- package/templates/audio/welcome-music.mp3 +0 -0
- package/voice-assignments.json +8244 -8244
- 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 ""
|