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
|
@@ -25,12 +25,26 @@ if (Test-Path $ProjectClaudeDir) {
|
|
|
25
25
|
|
|
26
26
|
# Audio cache and voice config use project-local .claude
|
|
27
27
|
$AudioDir = "$ClaudeDir\audio"
|
|
28
|
+
# Try provider-specific file first, then generic tts-voice.txt (set by TUI)
|
|
28
29
|
$VoiceFile = "$ClaudeDir\tts-voice-piper.txt"
|
|
30
|
+
if (-not (Test-Path $VoiceFile)) {
|
|
31
|
+
$VoiceFile = "$ClaudeDir\tts-voice.txt"
|
|
32
|
+
}
|
|
29
33
|
|
|
30
34
|
# Voices and Piper binary are global (shared across projects, ~100MB+)
|
|
31
35
|
$UserClaudeDir = "$env:USERPROFILE\.claude"
|
|
32
36
|
$VoicesDir = "$UserClaudeDir\piper-voices"
|
|
37
|
+
# Try standard install location first, then fall back to PATH
|
|
33
38
|
$PiperExe = "$env:LOCALAPPDATA\Programs\Piper\piper.exe"
|
|
39
|
+
if (-not (Test-Path $PiperExe)) {
|
|
40
|
+
$found = Get-Command piper.exe -ErrorAction SilentlyContinue
|
|
41
|
+
if (-not $found) {
|
|
42
|
+
# PATH may be stale (SSH sessions inherit minimal PATH); refresh from registry
|
|
43
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
44
|
+
$found = Get-Command piper.exe -ErrorAction SilentlyContinue
|
|
45
|
+
}
|
|
46
|
+
if ($found) { $PiperExe = $found.Source }
|
|
47
|
+
}
|
|
34
48
|
|
|
35
49
|
# Ensure directories exist
|
|
36
50
|
foreach ($dir in @($AudioDir, $VoicesDir)) {
|
|
@@ -56,9 +70,38 @@ elseif (Test-Path $VoiceFile) {
|
|
|
56
70
|
$VoiceName = (Get-Content $VoiceFile -Raw).Trim()
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
# Strip display name suffix (e.g. "en_US-libritts-high::Bella-9" -> "en_US-libritts-high")
|
|
74
|
+
# and extract speaker ID if present (works for both override and file)
|
|
75
|
+
if ($VoiceName -match '::') {
|
|
76
|
+
$parts = $VoiceName -split '::'
|
|
77
|
+
$VoiceName = $parts[0]
|
|
78
|
+
if ($parts.Length -ge 2 -and $parts[1] -match '-(\d+)$') {
|
|
79
|
+
$env:PIPER_SPEAKER = $Matches[1]
|
|
80
|
+
} else {
|
|
81
|
+
Remove-Item env:PIPER_SPEAKER -ErrorAction SilentlyContinue
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
# No multi-speaker syntax — clear any stale speaker env var
|
|
85
|
+
Remove-Item env:PIPER_SPEAKER -ErrorAction SilentlyContinue
|
|
86
|
+
}
|
|
87
|
+
|
|
59
88
|
# Default voice if not specified
|
|
89
|
+
# Prefer en_US-lessac-medium (bundled/commonly installed) over en_US-ryan-high
|
|
60
90
|
if (-not $VoiceName) {
|
|
61
|
-
$
|
|
91
|
+
$UserClaudePiperDir = "$env:USERPROFILE\.claude\piper-voices"
|
|
92
|
+
if (Test-Path "$UserClaudePiperDir\en_US-lessac-medium.onnx") {
|
|
93
|
+
$VoiceName = "en_US-lessac-medium"
|
|
94
|
+
} elseif (Test-Path "$UserClaudePiperDir\en_US-ryan-high.onnx") {
|
|
95
|
+
$VoiceName = "en_US-ryan-high"
|
|
96
|
+
} else {
|
|
97
|
+
# Fallback: use first available .onnx file, or default name for auto-download
|
|
98
|
+
$firstVoice = Get-ChildItem -Path $UserClaudePiperDir -Filter "*.onnx" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
99
|
+
if ($firstVoice) {
|
|
100
|
+
$VoiceName = $firstVoice.BaseName
|
|
101
|
+
} else {
|
|
102
|
+
$VoiceName = "en_US-lessac-medium"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
62
105
|
}
|
|
63
106
|
|
|
64
107
|
# Security: Validate voice name to prevent path traversal
|
|
@@ -128,10 +171,12 @@ try {
|
|
|
128
171
|
Write-Host "[SYNTH] Synthesizing with Piper..." -ForegroundColor Cyan
|
|
129
172
|
|
|
130
173
|
# Run Piper with text input
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
174
|
+
# Add --speaker for multi-speaker models (e.g. libritts-high with speaker 9)
|
|
175
|
+
$piperArgs = @("--model", $VoiceModelFile, "--output-file", $AudioFile)
|
|
176
|
+
if ($env:PIPER_SPEAKER) {
|
|
177
|
+
$piperArgs += @("--speaker", $env:PIPER_SPEAKER)
|
|
178
|
+
}
|
|
179
|
+
$Text | & $PiperExe @piperArgs 2>$null
|
|
135
180
|
|
|
136
181
|
if (-not (Test-Path $AudioFile)) {
|
|
137
182
|
Write-Host "[ERROR] Piper synthesis failed" -ForegroundColor Red
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
#
|
|
2
|
-
# File: .claude/hooks-windows/play-tts-windows-sapi.ps1
|
|
3
|
-
#
|
|
4
|
-
# AgentVibes - Windows SAPI TTS Provider (Zero Dependencies)
|
|
5
|
-
# Uses built-in Windows System.Speech API
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
param(
|
|
9
|
-
[Parameter(Mandatory = $true)]
|
|
10
|
-
[string]$Text,
|
|
11
|
-
|
|
12
|
-
[Parameter(Mandatory = $false)]
|
|
13
|
-
[string]$VoiceOverride
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
# Configuration paths
|
|
17
|
-
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
18
|
-
$ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
|
|
19
|
-
|
|
20
|
-
if (Test-Path $ProjectClaudeDir) {
|
|
21
|
-
$ClaudeDir = $ProjectClaudeDir
|
|
22
|
-
} else {
|
|
23
|
-
$ClaudeDir = "$env:USERPROFILE\.claude"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
$AudioDir = "$ClaudeDir\audio"
|
|
27
|
-
$VoiceFile = "$ClaudeDir\tts-voice-sapi.txt"
|
|
28
|
-
|
|
29
|
-
# Ensure directories exist
|
|
30
|
-
if (-not (Test-Path $AudioDir)) {
|
|
31
|
-
New-Item -ItemType Directory -Path $AudioDir -Force | Out-Null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
# Load System.Speech assembly
|
|
35
|
-
try {
|
|
36
|
-
Add-Type -AssemblyName System.Speech
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
Write-Host "[ERROR] System.Speech assembly not available" -ForegroundColor Red
|
|
40
|
-
exit 1
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
# Determine voice to use
|
|
44
|
-
$VoiceName = ""
|
|
45
|
-
|
|
46
|
-
if ($VoiceOverride) {
|
|
47
|
-
$VoiceName = $VoiceOverride
|
|
48
|
-
}
|
|
49
|
-
elseif (Test-Path $VoiceFile) {
|
|
50
|
-
$VoiceName = (Get-Content $VoiceFile -Raw).Trim()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
# Initialize speech synthesizer
|
|
54
|
-
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
|
|
55
|
-
|
|
56
|
-
# Set voice if specified
|
|
57
|
-
if ($VoiceName) {
|
|
58
|
-
try {
|
|
59
|
-
$synth.SelectVoice($VoiceName)
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
Write-Host "[WARNING] Voice '$VoiceName' not found, using default" -ForegroundColor Yellow
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
# Sanitize text for speech - strip shell metacharacters
|
|
67
|
-
$Text = $Text -replace '\\', ' '
|
|
68
|
-
$Text = $Text -replace '[{}
|
|
69
|
-
$Text = $Text -replace '&[a-zA-Z]+;', ''
|
|
70
|
-
$Text = $Text -replace '\s+', ' '
|
|
71
|
-
$Text = $Text.Trim()
|
|
72
|
-
|
|
73
|
-
# Get actual voice name (after selection or default)
|
|
74
|
-
$ActualVoice = $synth.Voice.Name
|
|
75
|
-
|
|
76
|
-
# Create audio file path
|
|
77
|
-
$Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
|
|
78
|
-
$AudioFile = "$AudioDir\tts-$Timestamp.wav"
|
|
79
|
-
|
|
80
|
-
# Save to WAV file with proper resource cleanup
|
|
81
|
-
$player = $null
|
|
82
|
-
try {
|
|
83
|
-
$synth.SetOutputToWaveFile($AudioFile)
|
|
84
|
-
$synth.Speak($Text)
|
|
85
|
-
|
|
86
|
-
# Display results
|
|
87
|
-
Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
|
|
88
|
-
Write-Host "[VOICE] Voice used: $ActualVoice (Windows SAPI)" -ForegroundColor Green
|
|
89
|
-
|
|
90
|
-
# Play the audio using built-in Windows audio player (skip if AGENTVIBES_NO_PLAY is set)
|
|
91
|
-
if (-not $env:AGENTVIBES_NO_PLAY) {
|
|
92
|
-
try {
|
|
93
|
-
$player = New-Object System.Media.SoundPlayer $AudioFile
|
|
94
|
-
$player.PlaySync()
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
Write-Host "[ERROR] Error synthesizing speech: $_" -ForegroundColor Red
|
|
103
|
-
exit 1
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
if ($synth) { $synth.Dispose() }
|
|
107
|
-
if ($player) { $player.Dispose() }
|
|
108
|
-
}
|
|
1
|
+
#
|
|
2
|
+
# File: .claude/hooks-windows/play-tts-windows-sapi.ps1
|
|
3
|
+
#
|
|
4
|
+
# AgentVibes - Windows SAPI TTS Provider (Zero Dependencies)
|
|
5
|
+
# Uses built-in Windows System.Speech API
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
param(
|
|
9
|
+
[Parameter(Mandatory = $true)]
|
|
10
|
+
[string]$Text,
|
|
11
|
+
|
|
12
|
+
[Parameter(Mandatory = $false)]
|
|
13
|
+
[string]$VoiceOverride
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Configuration paths
|
|
17
|
+
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
18
|
+
$ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
|
|
19
|
+
|
|
20
|
+
if (Test-Path $ProjectClaudeDir) {
|
|
21
|
+
$ClaudeDir = $ProjectClaudeDir
|
|
22
|
+
} else {
|
|
23
|
+
$ClaudeDir = "$env:USERPROFILE\.claude"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
$AudioDir = "$ClaudeDir\audio"
|
|
27
|
+
$VoiceFile = "$ClaudeDir\tts-voice-sapi.txt"
|
|
28
|
+
|
|
29
|
+
# Ensure directories exist
|
|
30
|
+
if (-not (Test-Path $AudioDir)) {
|
|
31
|
+
New-Item -ItemType Directory -Path $AudioDir -Force | Out-Null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Load System.Speech assembly
|
|
35
|
+
try {
|
|
36
|
+
Add-Type -AssemblyName System.Speech
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
Write-Host "[ERROR] System.Speech assembly not available" -ForegroundColor Red
|
|
40
|
+
exit 1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Determine voice to use
|
|
44
|
+
$VoiceName = ""
|
|
45
|
+
|
|
46
|
+
if ($VoiceOverride) {
|
|
47
|
+
$VoiceName = $VoiceOverride
|
|
48
|
+
}
|
|
49
|
+
elseif (Test-Path $VoiceFile) {
|
|
50
|
+
$VoiceName = (Get-Content $VoiceFile -Raw).Trim()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Initialize speech synthesizer
|
|
54
|
+
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
|
|
55
|
+
|
|
56
|
+
# Set voice if specified
|
|
57
|
+
if ($VoiceName) {
|
|
58
|
+
try {
|
|
59
|
+
$synth.SelectVoice($VoiceName)
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
Write-Host "[WARNING] Voice '$VoiceName' not found, using default" -ForegroundColor Yellow
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Sanitize text for speech - strip only dangerous shell metacharacters and SSML tags
|
|
67
|
+
$Text = $Text -replace '\\', ' '
|
|
68
|
+
$Text = $Text -replace '[{}<>|`~^;]', ''
|
|
69
|
+
$Text = $Text -replace '&[a-zA-Z]+;', ''
|
|
70
|
+
$Text = $Text -replace '\s+', ' '
|
|
71
|
+
$Text = $Text.Trim()
|
|
72
|
+
|
|
73
|
+
# Get actual voice name (after selection or default)
|
|
74
|
+
$ActualVoice = $synth.Voice.Name
|
|
75
|
+
|
|
76
|
+
# Create audio file path
|
|
77
|
+
$Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
|
|
78
|
+
$AudioFile = "$AudioDir\tts-$Timestamp.wav"
|
|
79
|
+
|
|
80
|
+
# Save to WAV file with proper resource cleanup
|
|
81
|
+
$player = $null
|
|
82
|
+
try {
|
|
83
|
+
$synth.SetOutputToWaveFile($AudioFile)
|
|
84
|
+
$synth.Speak($Text)
|
|
85
|
+
|
|
86
|
+
# Display results
|
|
87
|
+
Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
|
|
88
|
+
Write-Host "[VOICE] Voice used: $ActualVoice (Windows SAPI)" -ForegroundColor Green
|
|
89
|
+
|
|
90
|
+
# Play the audio using built-in Windows audio player (skip if AGENTVIBES_NO_PLAY is set)
|
|
91
|
+
if (-not $env:AGENTVIBES_NO_PLAY) {
|
|
92
|
+
try {
|
|
93
|
+
$player = New-Object System.Media.SoundPlayer $AudioFile
|
|
94
|
+
$player.PlaySync()
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
Write-Host "[ERROR] Error synthesizing speech: $_" -ForegroundColor Red
|
|
103
|
+
exit 1
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
if ($synth) { $synth.Dispose() }
|
|
107
|
+
if ($player) { $player.Dispose() }
|
|
108
|
+
}
|