agentvibes 5.3.0 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/.agentvibes/LITE-MODE.md +236 -0
  2. package/.agentvibes/README.md +136 -0
  3. package/.agentvibes/backup/session-start-tts.sh.20251210_212814 +141 -0
  4. package/.agentvibes/backups/agents/analyst_20260204_144958.md +78 -0
  5. package/.agentvibes/backups/agents/architect_20260204_144958.md +72 -0
  6. package/.agentvibes/backups/agents/dev_20260204_144958.md +74 -0
  7. package/.agentvibes/backups/agents/pm_20260204_144958.md +72 -0
  8. package/.agentvibes/backups/agents/quick-flow-solo-dev_20260204_144958.md +64 -0
  9. package/.agentvibes/backups/agents/sm_20260204_144958.md +87 -0
  10. package/.agentvibes/backups/agents/tea_20260204_144958.md +79 -0
  11. package/.agentvibes/backups/agents/tech-writer_20260204_144958.md +82 -0
  12. package/.agentvibes/backups/agents/ux-designer_20260204_144958.md +80 -0
  13. package/.agentvibes/bmad/bmad-voices.md +69 -69
  14. package/.agentvibes/config/README-personality-defaults.md +162 -0
  15. package/.agentvibes/config/mode.txt +1 -0
  16. package/.agentvibes/config/personality-voice-defaults.default.json +21 -0
  17. package/.agentvibes/config/save-audio.txt +1 -0
  18. package/.agentvibes/config/voice-metadata.json +160 -0
  19. package/.agentvibes/config.json +24 -15
  20. package/.agentvibes/hooks/help.sh +191 -0
  21. package/.agentvibes/hooks/post-tool-use-lite.sh +111 -0
  22. package/.agentvibes/hooks/save-audio-manager.sh +162 -0
  23. package/.agentvibes/hooks/session-start-full-optimized.sh +102 -0
  24. package/.agentvibes/hooks/session-start-full.sh +142 -0
  25. package/.agentvibes/hooks/session-start-lite-v2.sh +34 -0
  26. package/.agentvibes/hooks/session-start-lite.sh +29 -0
  27. package/.agentvibes/hooks/stop-lite.sh +115 -0
  28. package/.agentvibes/hooks/switch-mode.sh +215 -0
  29. package/.agentvibes/output-styles/audio-summary.md +30 -0
  30. package/.claude/activation-instructions +54 -54
  31. package/.claude/audio/voice-samples/piper/alan.wav +0 -0
  32. package/.claude/audio/voice-samples/piper/amy.wav +0 -0
  33. package/.claude/audio/voice-samples/piper/charlotte.wav +0 -0
  34. package/.claude/audio/voice-samples/piper/joe.wav +0 -0
  35. package/.claude/audio/voice-samples/piper/john.wav +0 -0
  36. package/.claude/audio/voice-samples/piper/katherine.wav +0 -0
  37. package/.claude/audio/voice-samples/piper/kristin.wav +0 -0
  38. package/.claude/audio/voice-samples/piper/linda.wav +0 -0
  39. package/.claude/audio/voice-samples/piper/marcus.wav +0 -0
  40. package/.claude/audio/voice-samples/piper/ryan.wav +0 -0
  41. package/.claude/commands/agent-vibes/add.md +21 -21
  42. package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
  43. package/.claude/commands/agent-vibes/agent.md +79 -79
  44. package/.claude/commands/agent-vibes/background-music.md +111 -111
  45. package/.claude/commands/agent-vibes/bmad.md +198 -198
  46. package/.claude/commands/agent-vibes/clean.md +18 -18
  47. package/.claude/commands/agent-vibes/cleanup.md +18 -18
  48. package/.claude/commands/agent-vibes/commands.json +145 -145
  49. package/.claude/commands/agent-vibes/effects.md +97 -97
  50. package/.claude/commands/agent-vibes/get.md +9 -9
  51. package/.claude/commands/agent-vibes/hide.md +91 -91
  52. package/.claude/commands/agent-vibes/language.md +23 -23
  53. package/.claude/commands/agent-vibes/learn.md +67 -67
  54. package/.claude/commands/agent-vibes/list.md +13 -13
  55. package/.claude/commands/agent-vibes/mute.md +37 -37
  56. package/.claude/commands/agent-vibes/preview.md +17 -17
  57. package/.claude/commands/agent-vibes/provider.md +68 -68
  58. package/.claude/commands/agent-vibes/replay-target.md +14 -14
  59. package/.claude/commands/agent-vibes/sample.md +12 -12
  60. package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
  61. package/.claude/commands/agent-vibes/set-pretext.md +65 -65
  62. package/.claude/commands/agent-vibes/set-speed.md +41 -41
  63. package/.claude/commands/agent-vibes/show.md +84 -84
  64. package/.claude/commands/agent-vibes/switch.md +87 -87
  65. package/.claude/commands/agent-vibes/target-voice.md +26 -26
  66. package/.claude/commands/agent-vibes/target.md +30 -30
  67. package/.claude/commands/agent-vibes/translate.md +68 -68
  68. package/.claude/commands/agent-vibes/unmute.md +45 -45
  69. package/.claude/commands/agent-vibes/whoami.md +7 -7
  70. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  71. package/.claude/commands/agent-vibes-rdp.md +24 -24
  72. package/.claude/config/audio-effects.cfg +16 -11
  73. package/.claude/config/audio-effects.cfg.sample +52 -52
  74. package/.claude/config/background-music-position.txt +27 -0
  75. package/.claude/config/background-music-volume.txt +1 -1
  76. package/.claude/config/background-music.cfg +1 -0
  77. package/.claude/config/background-music.txt +1 -0
  78. package/.claude/config/tts-speech-rate.txt +1 -4
  79. package/.claude/config/tts-verbosity.txt +1 -0
  80. package/.claude/docs/TERMUX_SETUP.md +408 -408
  81. package/.claude/github-star-reminder.txt +1 -1
  82. package/.claude/hooks/README-TTS-QUEUE.md +135 -135
  83. package/.claude/hooks/audio-cache-utils.sh +0 -0
  84. package/.claude/hooks/audio-processor.sh +60 -14
  85. package/.claude/hooks/background-music-manager.sh +0 -0
  86. package/.claude/hooks/bmad-party-manager.sh +225 -0
  87. package/.claude/hooks/bmad-party-speak.sh +0 -0
  88. package/.claude/hooks/bmad-speak-enhanced.sh +0 -0
  89. package/.claude/hooks/bmad-speak.sh +12 -15
  90. package/.claude/hooks/bmad-tts-injector.sh +0 -0
  91. package/.claude/hooks/bmad-voice-manager.sh +0 -0
  92. package/.claude/hooks/clawdbot-receiver-SECURE.sh +25 -23
  93. package/.claude/hooks/clawdbot-receiver.sh +4 -28
  94. package/.claude/hooks/clean-audio-cache.sh +0 -0
  95. package/.claude/hooks/cleanup-cache.sh +0 -0
  96. package/.claude/hooks/configure-rdp-mode.sh +0 -0
  97. package/.claude/hooks/download-extra-voices.sh +0 -0
  98. package/.claude/hooks/effects-manager.sh +0 -0
  99. package/.claude/hooks/github-star-reminder.sh +0 -0
  100. package/.claude/hooks/language-manager.sh +0 -0
  101. package/.claude/hooks/learn-manager.sh +0 -0
  102. package/.claude/hooks/macos-voice-manager.sh +0 -0
  103. package/.claude/hooks/migrate-background-music.sh +0 -0
  104. package/.claude/hooks/migrate-to-agentvibes.sh +0 -0
  105. package/.claude/hooks/optimize-background-music.sh +0 -0
  106. package/.claude/hooks/personality-manager.sh +0 -0
  107. package/.claude/hooks/piper-download-voices.sh +0 -0
  108. package/.claude/hooks/piper-installer.sh +1 -1
  109. package/.claude/hooks/piper-multispeaker-registry.sh +0 -0
  110. package/.claude/hooks/piper-voice-manager.sh +0 -0
  111. package/.claude/hooks/play-tts-enhanced.sh +0 -0
  112. package/.claude/hooks/play-tts-macos.sh +6 -12
  113. package/.claude/hooks/play-tts-piper.sh +52 -81
  114. package/.claude/hooks/play-tts-soprano.sh +9 -43
  115. package/.claude/hooks/play-tts-ssh-remote.sh +43 -215
  116. package/.claude/hooks/play-tts-termux-ssh.sh +0 -0
  117. package/.claude/hooks/play-tts.sh +41 -20
  118. package/.claude/hooks/post-response.sh +41 -0
  119. package/.claude/hooks/prepare-release.sh +0 -0
  120. package/.claude/hooks/provider-commands.sh +0 -0
  121. package/.claude/hooks/provider-manager.sh +0 -0
  122. package/.claude/hooks/replay-target-audio.sh +0 -0
  123. package/.claude/hooks/requirements.txt +6 -6
  124. package/.claude/hooks/sentiment-manager.sh +0 -0
  125. package/.claude/hooks/session-start-tts.sh +56 -39
  126. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  127. package/.claude/hooks/speed-manager.sh +0 -0
  128. package/.claude/hooks/stop.sh +63 -0
  129. package/.claude/hooks/termux-installer.sh +0 -0
  130. package/.claude/hooks/translate-manager.sh +0 -0
  131. package/.claude/hooks/translator.py +237 -237
  132. package/.claude/hooks/tts-queue-worker.sh +0 -0
  133. package/.claude/hooks/tts-queue.sh +0 -0
  134. package/.claude/hooks/verbosity-manager.sh +0 -0
  135. package/.claude/hooks/voice-manager.sh +26 -4
  136. package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
  137. package/.claude/hooks-windows/bmad-party-speak.ps1 +278 -278
  138. package/.claude/hooks-windows/bmad-speak.ps1 +264 -264
  139. package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -53
  140. package/.claude/hooks-windows/effects-manager.ps1 +294 -294
  141. package/.claude/hooks-windows/language-manager.ps1 +193 -193
  142. package/.claude/hooks-windows/learn-manager.ps1 +241 -241
  143. package/.claude/hooks-windows/personality-manager.ps1 +266 -266
  144. package/.claude/hooks-windows/play-tts-soprano.ps1 +5 -5
  145. package/.claude/hooks-windows/play-tts-termux-ssh.ps1 +138 -138
  146. package/.claude/hooks-windows/play-tts-windows-piper.ps1 +178 -0
  147. package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -0
  148. package/.claude/hooks-windows/play-tts.ps1 +265 -507
  149. package/.claude/hooks-windows/provider-manager.ps1 +158 -192
  150. package/.claude/hooks-windows/session-start-tts.ps1 +55 -46
  151. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  152. package/.claude/hooks-windows/speed-manager.ps1 +166 -166
  153. package/.claude/hooks-windows/voice-manager-windows.ps1 +176 -260
  154. package/.claude/output-styles/agent-vibes.md +202 -202
  155. package/.claude/personalities/angry.md +14 -14
  156. package/.claude/personalities/annoying.md +14 -14
  157. package/.claude/personalities/crass.md +14 -14
  158. package/.claude/personalities/dramatic.md +14 -14
  159. package/.claude/personalities/dry-humor.md +50 -50
  160. package/.claude/personalities/flirty.md +20 -20
  161. package/.claude/personalities/funny.md +14 -14
  162. package/.claude/personalities/grandpa.md +32 -32
  163. package/.claude/personalities/millennial.md +14 -14
  164. package/.claude/personalities/moody.md +14 -14
  165. package/.claude/personalities/normal.md +16 -16
  166. package/.claude/personalities/pirate.md +14 -14
  167. package/.claude/personalities/poetic.md +14 -14
  168. package/.claude/personalities/professional.md +14 -14
  169. package/.claude/personalities/rapper.md +55 -55
  170. package/.claude/personalities/robot.md +14 -14
  171. package/.claude/personalities/sarcastic.md +38 -38
  172. package/.claude/personalities/sassy.md +14 -14
  173. package/.claude/personalities/surfer-dude.md +14 -14
  174. package/.claude/personalities/zen.md +14 -14
  175. package/.claude/piper-voices-dir.txt +1 -0
  176. package/.claude/settings.json +25 -15
  177. package/.claude/verbosity.txt +1 -1
  178. package/.clawdbot/README.md +105 -105
  179. package/.clawdbot/skill/SKILL.md +149 -145
  180. package/.mcp.json +30 -11
  181. package/CLAUDE.md +170 -215
  182. package/README.md +207 -521
  183. package/RELEASE_NOTES.md +1172 -1976
  184. package/WINDOWS-SETUP.md +208 -208
  185. package/bin/agent-vibes +0 -0
  186. package/bin/agentvibes-voice-browser.js +64 -1289
  187. package/bin/agentvibes.js +28 -0
  188. package/bin/ensure-soprano-running.sh +43 -0
  189. package/bin/mcp-server.js +121 -121
  190. package/bin/mcp-server.sh +0 -0
  191. package/bin/test-bmad-pr +78 -78
  192. package/mcp-server/QUICK_START.md +203 -203
  193. package/mcp-server/README.md +345 -345
  194. package/mcp-server/WINDOWS_SETUP.md +260 -260
  195. package/mcp-server/docs/troubleshooting-audio.md +313 -313
  196. package/mcp-server/examples/claude_desktop_config.json +11 -11
  197. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  198. package/mcp-server/examples/custom_instructions.md +169 -169
  199. package/mcp-server/install-deps.js +130 -130
  200. package/mcp-server/pyproject.toml +52 -52
  201. package/mcp-server/requirements.txt +2 -2
  202. package/mcp-server/server.py +1467 -1578
  203. package/mcp-server/test_server.py +395 -395
  204. package/package.json +1 -3
  205. package/setup-windows.ps1 +815 -815
  206. package/src/console/tabs/music-tab.js +5 -2
  207. package/src/console/tabs/voices-tab.js +71 -37
  208. package/src/installer.js +52 -5
  209. package/src/services/llm-provider-service.js +1 -1
  210. package/templates/agentvibes-receiver.sh +158 -483
  211. package/templates/audio/welcome-music.mp3 +0 -0
  212. package/.agentvibes/bmad-voice-map.json +0 -104
  213. package/.agentvibes/copilot-sessions.log +0 -4
  214. package/.claude/config/audio-effects-bmad.cfg +0 -50
  215. package/.claude/config/intro-text.txt +0 -1
  216. package/.claude/config/personality.txt +0 -1
  217. package/.claude/config/piper-speech-rate.txt +0 -4
  218. package/.claude/config/piper-target-speech-rate.txt +0 -1
  219. package/.claude/config/reverb-level.txt +0 -1
  220. package/.claude/config/tts-target-speech-rate.txt +0 -1
  221. package/voice-assignments.json +0 -8245
  222. /package/{.claude → .agentvibes}/config/agentvibes.json +0 -0
@@ -1,264 +1,264 @@
1
- #
2
- # File: .claude/hooks-windows/bmad-speak.ps1
3
- #
4
- # AgentVibes BMAD Voice Integration - Windows
5
- # Maps BMAD agent display names or agent IDs to voices and triggers TTS.
6
- # Windows port of .claude/hooks/bmad-speak.sh
7
- #
8
- # Usage: bmad-speak.ps1 "Agent Name" "dialogue text"
9
- # bmad-speak.ps1 "agent-id" "dialogue text"
10
- #
11
-
12
- param(
13
- [Parameter(Mandatory = $true, Position = 0)]
14
- [string]$AgentNameOrId,
15
-
16
- [Parameter(Mandatory = $true, Position = 1)]
17
- [string]$Dialogue
18
- )
19
-
20
- $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
21
- $ClaudeDir = Split-Path -Parent $ScriptDir
22
- $ProjectRoot = Split-Path -Parent $ClaudeDir
23
-
24
- # When running as global script, prefer CLAUDE_PROJECT_DIR for project root
25
- if ($env:CLAUDE_PROJECT_DIR -and (Test-Path "$env:CLAUDE_PROJECT_DIR\_bmad")) {
26
- $ProjectRoot = $env:CLAUDE_PROJECT_DIR
27
- }
28
-
29
- # Strip markdown formatting — prevent SAPI/Piper from speaking asterisks literally
30
- $Dialogue = $Dialogue -replace '\*{1,3}', '' # bold, italic, bold-italic
31
- $Dialogue = $Dialogue -replace '`{1,3}[^`]*`{1,3}', '' # inline code / code blocks
32
- $Dialogue = $Dialogue -replace '#{1,6}\s*', '' # headings
33
- $Dialogue = $Dialogue -replace '_{1,2}', '' # underline/italic alt
34
- $Dialogue = $Dialogue -replace '\[([^\]]+)\]\([^)]+\)', '$1' # links → label only
35
- $Dialogue = $Dialogue -replace '!\[[^\]]*\]\([^)]+\)', '' # images
36
- $Dialogue = $Dialogue -replace '(?m)^\s*[-*+]\s+', '' # bullet list markers (multiline)
37
- $Dialogue = $Dialogue -replace '(?m)^\s*\d+\.\s+', '' # numbered list markers
38
- $Dialogue = $Dialogue -replace '\\([!$*_`\\])', '$1' # escaped markdown chars
39
-
40
- # Check if party mode is disabled
41
- $PartyModeDisabledFlag = Join-Path $ProjectRoot ".agentvibes\bmad\bmad-party-mode-disabled.flag"
42
- if (Test-Path $PartyModeDisabledFlag) {
43
- exit 0
44
- }
45
-
46
- # Check if BMAD is installed
47
- $ManifestFile = Join-Path $ProjectRoot "_bmad\_config\agent-manifest.csv"
48
- if (-not (Test-Path $ManifestFile)) {
49
- exit 0
50
- }
51
-
52
- # ---------------------------------------------------------------------------
53
- # Read bmad-voice-map.json for per-agent profile
54
- # Prefer project-local voice map, fall back to global
55
- $VoiceMapLocal = Join-Path $ProjectRoot ".agentvibes\bmad-voice-map.json"
56
- $VoiceMapGlobal = Join-Path $env:USERPROFILE ".agentvibes\bmad-voice-map.json"
57
- $VoiceMapFile = if (Test-Path $VoiceMapLocal) { $VoiceMapLocal } else { $VoiceMapGlobal }
58
-
59
- $AgentVoice = ""
60
- $AgentPretext = ""
61
- $AgentPersonality = ""
62
- $AgentBgEnabled = $false
63
- $AgentBgTrack = ""
64
- $AgentId = $null
65
-
66
- # Read global background music volume (stored as 0.0-1.0 float)
67
- $_BgVolFile = Join-Path $ProjectRoot ".claude\config\background-music-volume.txt"
68
- if (-not (Test-Path $_BgVolFile)) {
69
- $_BgVolFile = Join-Path $env:USERPROFILE ".claude\config\background-music-volume.txt"
70
- }
71
- if (Test-Path $_BgVolFile) {
72
- $_BgVolRaw = (Get-Content $_BgVolFile -Raw -ErrorAction SilentlyContinue).Trim()
73
- $_BgVolParsed = 0.0
74
- if ([double]::TryParse($_BgVolRaw, [System.Globalization.NumberStyles]::Float, [System.Globalization.CultureInfo]::InvariantCulture, [ref]$_BgVolParsed)) {
75
- $AgentBgVolume = "{0:F2}" -f $_BgVolParsed
76
- } else {
77
- $AgentBgVolume = "0.20"
78
- }
79
- } else {
80
- $AgentBgVolume = "0.20"
81
- }
82
-
83
- # Resolve agent ID and display name/title from manifest (needed for default pretext)
84
- $AgentDisplayName = ""
85
- $AgentTitle = ""
86
-
87
- if (Test-Path $ManifestFile) {
88
- try {
89
- $ManifestRows = Import-Csv $ManifestFile -Encoding UTF8
90
- foreach ($row in $ManifestRows) {
91
- $id = ($row.PSObject.Properties | Select-Object -First 1).Value -replace '^"|"$', ''
92
- $display = ($row.PSObject.Properties | Select-Object -Skip 1 -First 1).Value -replace '^"|"$', ''
93
- $title = ($row.PSObject.Properties | Select-Object -Skip 2 -First 1).Value -replace '^"|"$', ''
94
- if ($id -ieq $AgentNameOrId -or $display -like "$AgentNameOrId*") {
95
- $AgentId = $id
96
- $AgentDisplayName = $display
97
- $AgentTitle = $title
98
- break
99
- }
100
- }
101
- } catch { }
102
- }
103
-
104
- if (Test-Path $VoiceMapFile) {
105
- try {
106
- $VoiceMap = Get-Content $VoiceMapFile -Raw | ConvertFrom-Json
107
-
108
- if ($AgentId -and $VoiceMap.agents.$AgentId) {
109
- $Profile = $VoiceMap.agents.$AgentId
110
- if ($Profile.voice) { $AgentVoice = $Profile.voice }
111
- if ($Profile.pretext) { $AgentPretext = $Profile.pretext }
112
- if ($Profile.personality) { $AgentPersonality = $Profile.personality }
113
- if ($Profile.backgroundMusic) {
114
- $AgentBgEnabled = [bool]$Profile.backgroundMusic.enabled
115
- if ($Profile.backgroundMusic.track) { $AgentBgTrack = $Profile.backgroundMusic.track }
116
- if ($null -ne $Profile.backgroundMusic.volume) {
117
- # Voice map stores 0-100; audio-effects.cfg uses 0.0-1.0
118
- $AgentBgVolume = "{0:F2}" -f ([double]$Profile.backgroundMusic.volume / 100.0)
119
- }
120
- }
121
- }
122
- } catch {
123
- # Silently degrade — TTS will still play with global settings
124
- }
125
- }
126
-
127
- # Fallback: parse bmad-voices.md markdown table if JSON voice map had no data
128
- if ((-not $AgentPretext -or -not $AgentVoice) -and $AgentId) {
129
- $VoicesMdPaths = @(
130
- (Join-Path $ProjectRoot ".agentvibes\bmad\bmad-voices.md"),
131
- (Join-Path $env:USERPROFILE ".agentvibes\bmad\bmad-voices.md")
132
- )
133
- $shortId = $AgentId -replace '^bmad-agent-', ''
134
- foreach ($mdPath in $VoicesMdPaths) {
135
- if (-not (Test-Path $mdPath)) { continue }
136
- $mdLines = Get-Content $mdPath -Encoding UTF8
137
- foreach ($mdLine in $mdLines) {
138
- if ($mdLine -notmatch '^\|') { continue }
139
- if ($mdLine -match '^\|-') { continue }
140
- if ($mdLine -match 'Agent ID') { continue }
141
- $cols = $mdLine -split '\|' | ForEach-Object { $_.Trim() }
142
- if ($cols.Count -lt 6) { continue }
143
- $tableId = $cols[1]
144
- if ($tableId -ieq $shortId -or $tableId -ieq $AgentId -or $tableId -ieq $AgentNameOrId) {
145
- if (-not $AgentPretext -and $cols[3]) { $AgentPretext = $cols[3] }
146
- if (-not $AgentVoice -and $cols[5]) { $AgentVoice = $cols[5] }
147
- if (-not $AgentPersonality -and $cols.Count -ge 7 -and $cols[6] -and $cols[6] -ine 'normal') {
148
- $AgentPersonality = $cols[6]
149
- }
150
- break
151
- }
152
- }
153
- if ($AgentPretext) { break }
154
- }
155
- }
156
-
157
- # Fall back to default pretext if none stored: "DisplayName, Title here."
158
- # Matches AgentVoiceStore.getDefaultPretext() in agent-voice-store.js
159
- if (-not $AgentPretext) {
160
- if ($AgentDisplayName -and $AgentTitle) {
161
- $AgentPretext = "$AgentDisplayName, $AgentTitle here."
162
- } elseif ($AgentDisplayName) {
163
- $AgentPretext = "$AgentDisplayName here."
164
- } elseif ($AgentNameOrId) {
165
- $AgentPretext = "$AgentNameOrId here."
166
- }
167
- }
168
-
169
- # ---------------------------------------------------------------------------
170
- # Locate play-tts.ps1 — prefer project-local, fall back to global
171
- $PlayTtsLocal = Join-Path $ProjectRoot ".claude\hooks-windows\play-tts.ps1"
172
- $PlayTtsGlobal = Join-Path $env:USERPROFILE ".claude\hooks-windows\play-tts.ps1"
173
- $PlayTtsScript = if (Test-Path $PlayTtsLocal) { $PlayTtsLocal } else { $PlayTtsGlobal }
174
-
175
- if (-not (Test-Path $PlayTtsScript)) {
176
- exit 0
177
- }
178
-
179
- # ---------------------------------------------------------------------------
180
- # Determine which .claude config dir play-tts.ps1 will read.
181
- # play-tts.ps1 checks CLAUDE_PROJECT_DIR first — match that logic exactly.
182
- $TtsClaudeDir = if ($env:CLAUDE_PROJECT_DIR -and (Test-Path "$env:CLAUDE_PROJECT_DIR\.claude")) {
183
- "$env:CLAUDE_PROJECT_DIR\.claude"
184
- } else {
185
- $ClaudeDir # ~/.claude (this script's own ClaudeDir)
186
- }
187
- $TtsConfigDir = Join-Path $TtsClaudeDir "config"
188
-
189
- # ---------------------------------------------------------------------------
190
- # Apply per-agent personality override if set
191
- $OldPersonality = ""
192
- $PersonalityFile = Join-Path $TtsClaudeDir "config\personality.txt"
193
- if ($AgentPersonality -and (Test-Path (Split-Path $PersonalityFile -Parent))) {
194
- if (Test-Path $PersonalityFile) {
195
- $OldPersonality = (Get-Content $PersonalityFile -Raw).Trim()
196
- }
197
- Set-Content $PersonalityFile $AgentPersonality -NoNewline
198
- }
199
-
200
- # ---------------------------------------------------------------------------
201
- # Temporarily patch background music config for this agent.
202
- # The caller (bmad-party-speak.ps1) holds a named mutex so only one speak
203
- # call runs at a time — these file patches are safe from concurrent clobber.
204
- $BgEnabledFile = Join-Path $TtsConfigDir "background-music-enabled.txt"
205
- $AudioEffectsCfg = Join-Path $TtsConfigDir "audio-effects.cfg"
206
- $OldBgEnabled = $null
207
- $TempCfgLine = ""
208
-
209
- if ($AgentBgEnabled -and $AgentBgTrack) {
210
- # Save + enable background music
211
- if (Test-Path $BgEnabledFile) {
212
- $OldBgEnabled = (Get-Content $BgEnabledFile -Raw -ErrorAction SilentlyContinue).Trim()
213
- }
214
- Set-Content $BgEnabledFile "true" -NoNewline
215
-
216
- # Prepend agent line to audio-effects.cfg so play-tts.ps1 finds it first
217
- # Format: AGENT_NAME|SOX_EFFECTS|BACKGROUND_FILE|BACKGROUND_VOLUME
218
- $TempCfgLine = "${AgentId}||${AgentBgTrack}|${AgentBgVolume}"
219
- $env:AGENTVIBES_AGENT_NAME = $AgentId
220
- $existingCfg = if (Test-Path $AudioEffectsCfg) {
221
- Get-Content $AudioEffectsCfg -Raw -ErrorAction SilentlyContinue
222
- } else { "" }
223
- Set-Content $AudioEffectsCfg "${TempCfgLine}`n${existingCfg}" -NoNewline
224
- }
225
-
226
- try {
227
- # Prepend pretext if configured (e.g. "As your UX designer")
228
- $SpeakText = if ($AgentPretext) { "$AgentPretext. $Dialogue" } else { $Dialogue }
229
-
230
- # Speak with agent's voice (or global voice if none configured)
231
- if ($AgentVoice) {
232
- & powershell -NoProfile -ExecutionPolicy Bypass -File $PlayTtsScript $SpeakText $AgentVoice
233
- } else {
234
- & powershell -NoProfile -ExecutionPolicy Bypass -File $PlayTtsScript $SpeakText
235
- }
236
- } finally {
237
- # Restore personality
238
- if ($AgentPersonality -and $PersonalityFile) {
239
- if ($OldPersonality) {
240
- Set-Content $PersonalityFile $OldPersonality -NoNewline
241
- } elseif (Test-Path $PersonalityFile) {
242
- Remove-Item $PersonalityFile -Force -ErrorAction SilentlyContinue
243
- }
244
- }
245
-
246
- # Restore background music config
247
- if ($AgentBgEnabled -and $AgentBgTrack) {
248
- if ($null -ne $OldBgEnabled) {
249
- Set-Content $BgEnabledFile $OldBgEnabled -NoNewline
250
- } elseif (Test-Path $BgEnabledFile) {
251
- Remove-Item $BgEnabledFile -Force -ErrorAction SilentlyContinue
252
- }
253
-
254
- # Remove the prepended agent line from audio-effects.cfg
255
- if (Test-Path $AudioEffectsCfg) {
256
- $cfgRaw = Get-Content $AudioEffectsCfg -Raw -ErrorAction SilentlyContinue
257
- $escaped = [regex]::Escape($TempCfgLine)
258
- $cfgRaw = $cfgRaw -replace "^${escaped}\r?\n?", ""
259
- Set-Content $AudioEffectsCfg $cfgRaw -NoNewline
260
- }
261
-
262
- $env:AGENTVIBES_AGENT_NAME = ""
263
- }
264
- }
1
+ #
2
+ # File: .claude/hooks-windows/bmad-speak.ps1
3
+ #
4
+ # AgentVibes BMAD Voice Integration - Windows
5
+ # Maps BMAD agent display names or agent IDs to voices and triggers TTS.
6
+ # Windows port of .claude/hooks/bmad-speak.sh
7
+ #
8
+ # Usage: bmad-speak.ps1 "Agent Name" "dialogue text"
9
+ # bmad-speak.ps1 "agent-id" "dialogue text"
10
+ #
11
+
12
+ param(
13
+ [Parameter(Mandatory = $true, Position = 0)]
14
+ [string]$AgentNameOrId,
15
+
16
+ [Parameter(Mandatory = $true, Position = 1)]
17
+ [string]$Dialogue
18
+ )
19
+
20
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
21
+ $ClaudeDir = Split-Path -Parent $ScriptDir
22
+ $ProjectRoot = Split-Path -Parent $ClaudeDir
23
+
24
+ # When running as global script, prefer CLAUDE_PROJECT_DIR for project root
25
+ if ($env:CLAUDE_PROJECT_DIR -and (Test-Path "$env:CLAUDE_PROJECT_DIR\_bmad")) {
26
+ $ProjectRoot = $env:CLAUDE_PROJECT_DIR
27
+ }
28
+
29
+ # Strip markdown formatting — prevent SAPI/Piper from speaking asterisks literally
30
+ $Dialogue = $Dialogue -replace '\*{1,3}', '' # bold, italic, bold-italic
31
+ $Dialogue = $Dialogue -replace '`{1,3}[^`]*`{1,3}', '' # inline code / code blocks
32
+ $Dialogue = $Dialogue -replace '#{1,6}\s*', '' # headings
33
+ $Dialogue = $Dialogue -replace '_{1,2}', '' # underline/italic alt
34
+ $Dialogue = $Dialogue -replace '\[([^\]]+)\]\([^)]+\)', '$1' # links → label only
35
+ $Dialogue = $Dialogue -replace '!\[[^\]]*\]\([^)]+\)', '' # images
36
+ $Dialogue = $Dialogue -replace '(?m)^\s*[-*+]\s+', '' # bullet list markers (multiline)
37
+ $Dialogue = $Dialogue -replace '(?m)^\s*\d+\.\s+', '' # numbered list markers
38
+ $Dialogue = $Dialogue -replace '\\([!$*_`\\])', '$1' # escaped markdown chars
39
+
40
+ # Check if party mode is disabled
41
+ $PartyModeDisabledFlag = Join-Path $ProjectRoot ".agentvibes\bmad\bmad-party-mode-disabled.flag"
42
+ if (Test-Path $PartyModeDisabledFlag) {
43
+ exit 0
44
+ }
45
+
46
+ # Check if BMAD is installed
47
+ $ManifestFile = Join-Path $ProjectRoot "_bmad\_config\agent-manifest.csv"
48
+ if (-not (Test-Path $ManifestFile)) {
49
+ exit 0
50
+ }
51
+
52
+ # ---------------------------------------------------------------------------
53
+ # Read bmad-voice-map.json for per-agent profile
54
+ # Prefer project-local voice map, fall back to global
55
+ $VoiceMapLocal = Join-Path $ProjectRoot ".agentvibes\bmad-voice-map.json"
56
+ $VoiceMapGlobal = Join-Path $env:USERPROFILE ".agentvibes\bmad-voice-map.json"
57
+ $VoiceMapFile = if (Test-Path $VoiceMapLocal) { $VoiceMapLocal } else { $VoiceMapGlobal }
58
+
59
+ $AgentVoice = ""
60
+ $AgentPretext = ""
61
+ $AgentPersonality = ""
62
+ $AgentBgEnabled = $false
63
+ $AgentBgTrack = ""
64
+ $AgentId = $null
65
+
66
+ # Read global background music volume (stored as 0.0-1.0 float)
67
+ $_BgVolFile = Join-Path $ProjectRoot ".claude\config\background-music-volume.txt"
68
+ if (-not (Test-Path $_BgVolFile)) {
69
+ $_BgVolFile = Join-Path $env:USERPROFILE ".claude\config\background-music-volume.txt"
70
+ }
71
+ if (Test-Path $_BgVolFile) {
72
+ $_BgVolRaw = (Get-Content $_BgVolFile -Raw -ErrorAction SilentlyContinue).Trim()
73
+ $_BgVolParsed = 0.0
74
+ if ([double]::TryParse($_BgVolRaw, [System.Globalization.NumberStyles]::Float, [System.Globalization.CultureInfo]::InvariantCulture, [ref]$_BgVolParsed)) {
75
+ $AgentBgVolume = "{0:F2}" -f $_BgVolParsed
76
+ } else {
77
+ $AgentBgVolume = "0.20"
78
+ }
79
+ } else {
80
+ $AgentBgVolume = "0.20"
81
+ }
82
+
83
+ # Resolve agent ID and display name/title from manifest (needed for default pretext)
84
+ $AgentDisplayName = ""
85
+ $AgentTitle = ""
86
+
87
+ if (Test-Path $ManifestFile) {
88
+ try {
89
+ $ManifestRows = Import-Csv $ManifestFile -Encoding UTF8
90
+ foreach ($row in $ManifestRows) {
91
+ $id = ($row.PSObject.Properties | Select-Object -First 1).Value -replace '^"|"$', ''
92
+ $display = ($row.PSObject.Properties | Select-Object -Skip 1 -First 1).Value -replace '^"|"$', ''
93
+ $title = ($row.PSObject.Properties | Select-Object -Skip 2 -First 1).Value -replace '^"|"$', ''
94
+ if ($id -ieq $AgentNameOrId -or $display -like "$AgentNameOrId*") {
95
+ $AgentId = $id
96
+ $AgentDisplayName = $display
97
+ $AgentTitle = $title
98
+ break
99
+ }
100
+ }
101
+ } catch { }
102
+ }
103
+
104
+ if (Test-Path $VoiceMapFile) {
105
+ try {
106
+ $VoiceMap = Get-Content $VoiceMapFile -Raw | ConvertFrom-Json
107
+
108
+ if ($AgentId -and $VoiceMap.agents.$AgentId) {
109
+ $Profile = $VoiceMap.agents.$AgentId
110
+ if ($Profile.voice) { $AgentVoice = $Profile.voice }
111
+ if ($Profile.pretext) { $AgentPretext = $Profile.pretext }
112
+ if ($Profile.personality) { $AgentPersonality = $Profile.personality }
113
+ if ($Profile.backgroundMusic) {
114
+ $AgentBgEnabled = [bool]$Profile.backgroundMusic.enabled
115
+ if ($Profile.backgroundMusic.track) { $AgentBgTrack = $Profile.backgroundMusic.track }
116
+ if ($null -ne $Profile.backgroundMusic.volume) {
117
+ # Voice map stores 0-100; audio-effects.cfg uses 0.0-1.0
118
+ $AgentBgVolume = "{0:F2}" -f ([double]$Profile.backgroundMusic.volume / 100.0)
119
+ }
120
+ }
121
+ }
122
+ } catch {
123
+ # Silently degrade — TTS will still play with global settings
124
+ }
125
+ }
126
+
127
+ # Fallback: parse bmad-voices.md markdown table if JSON voice map had no data
128
+ if ((-not $AgentPretext -or -not $AgentVoice) -and $AgentId) {
129
+ $VoicesMdPaths = @(
130
+ (Join-Path $ProjectRoot ".agentvibes\bmad\bmad-voices.md"),
131
+ (Join-Path $env:USERPROFILE ".agentvibes\bmad\bmad-voices.md")
132
+ )
133
+ $shortId = $AgentId -replace '^bmad-agent-', ''
134
+ foreach ($mdPath in $VoicesMdPaths) {
135
+ if (-not (Test-Path $mdPath)) { continue }
136
+ $mdLines = Get-Content $mdPath -Encoding UTF8
137
+ foreach ($mdLine in $mdLines) {
138
+ if ($mdLine -notmatch '^\|') { continue }
139
+ if ($mdLine -match '^\|-') { continue }
140
+ if ($mdLine -match 'Agent ID') { continue }
141
+ $cols = $mdLine -split '\|' | ForEach-Object { $_.Trim() }
142
+ if ($cols.Count -lt 6) { continue }
143
+ $tableId = $cols[1]
144
+ if ($tableId -ieq $shortId -or $tableId -ieq $AgentId -or $tableId -ieq $AgentNameOrId) {
145
+ if (-not $AgentPretext -and $cols[3]) { $AgentPretext = $cols[3] }
146
+ if (-not $AgentVoice -and $cols[5]) { $AgentVoice = $cols[5] }
147
+ if (-not $AgentPersonality -and $cols.Count -ge 7 -and $cols[6] -and $cols[6] -ine 'normal') {
148
+ $AgentPersonality = $cols[6]
149
+ }
150
+ break
151
+ }
152
+ }
153
+ if ($AgentPretext) { break }
154
+ }
155
+ }
156
+
157
+ # Fall back to default pretext if none stored: "DisplayName, Title here."
158
+ # Matches AgentVoiceStore.getDefaultPretext() in agent-voice-store.js
159
+ if (-not $AgentPretext) {
160
+ if ($AgentDisplayName -and $AgentTitle) {
161
+ $AgentPretext = "$AgentDisplayName, $AgentTitle here."
162
+ } elseif ($AgentDisplayName) {
163
+ $AgentPretext = "$AgentDisplayName here."
164
+ } elseif ($AgentNameOrId) {
165
+ $AgentPretext = "$AgentNameOrId here."
166
+ }
167
+ }
168
+
169
+ # ---------------------------------------------------------------------------
170
+ # Locate play-tts.ps1 — prefer project-local, fall back to global
171
+ $PlayTtsLocal = Join-Path $ProjectRoot ".claude\hooks-windows\play-tts.ps1"
172
+ $PlayTtsGlobal = Join-Path $env:USERPROFILE ".claude\hooks-windows\play-tts.ps1"
173
+ $PlayTtsScript = if (Test-Path $PlayTtsLocal) { $PlayTtsLocal } else { $PlayTtsGlobal }
174
+
175
+ if (-not (Test-Path $PlayTtsScript)) {
176
+ exit 0
177
+ }
178
+
179
+ # ---------------------------------------------------------------------------
180
+ # Determine which .claude config dir play-tts.ps1 will read.
181
+ # play-tts.ps1 checks CLAUDE_PROJECT_DIR first — match that logic exactly.
182
+ $TtsClaudeDir = if ($env:CLAUDE_PROJECT_DIR -and (Test-Path "$env:CLAUDE_PROJECT_DIR\.claude")) {
183
+ "$env:CLAUDE_PROJECT_DIR\.claude"
184
+ } else {
185
+ $ClaudeDir # ~/.claude (this script's own ClaudeDir)
186
+ }
187
+ $TtsConfigDir = Join-Path $TtsClaudeDir "config"
188
+
189
+ # ---------------------------------------------------------------------------
190
+ # Apply per-agent personality override if set
191
+ $OldPersonality = ""
192
+ $PersonalityFile = Join-Path $TtsClaudeDir "config\personality.txt"
193
+ if ($AgentPersonality -and (Test-Path (Split-Path $PersonalityFile -Parent))) {
194
+ if (Test-Path $PersonalityFile) {
195
+ $OldPersonality = (Get-Content $PersonalityFile -Raw).Trim()
196
+ }
197
+ Set-Content $PersonalityFile $AgentPersonality -NoNewline
198
+ }
199
+
200
+ # ---------------------------------------------------------------------------
201
+ # Temporarily patch background music config for this agent.
202
+ # The caller (bmad-party-speak.ps1) holds a named mutex so only one speak
203
+ # call runs at a time — these file patches are safe from concurrent clobber.
204
+ $BgEnabledFile = Join-Path $TtsConfigDir "background-music-enabled.txt"
205
+ $AudioEffectsCfg = Join-Path $TtsConfigDir "audio-effects.cfg"
206
+ $OldBgEnabled = $null
207
+ $TempCfgLine = ""
208
+
209
+ if ($AgentBgEnabled -and $AgentBgTrack) {
210
+ # Save + enable background music
211
+ if (Test-Path $BgEnabledFile) {
212
+ $OldBgEnabled = (Get-Content $BgEnabledFile -Raw -ErrorAction SilentlyContinue).Trim()
213
+ }
214
+ Set-Content $BgEnabledFile "true" -NoNewline
215
+
216
+ # Prepend agent line to audio-effects.cfg so play-tts.ps1 finds it first
217
+ # Format: AGENT_NAME|SOX_EFFECTS|BACKGROUND_FILE|BACKGROUND_VOLUME
218
+ $TempCfgLine = "${AgentId}||${AgentBgTrack}|${AgentBgVolume}"
219
+ $env:AGENTVIBES_AGENT_NAME = $AgentId
220
+ $existingCfg = if (Test-Path $AudioEffectsCfg) {
221
+ Get-Content $AudioEffectsCfg -Raw -ErrorAction SilentlyContinue
222
+ } else { "" }
223
+ Set-Content $AudioEffectsCfg "${TempCfgLine}`n${existingCfg}" -NoNewline
224
+ }
225
+
226
+ try {
227
+ # Prepend pretext if configured (e.g. "As your UX designer")
228
+ $SpeakText = if ($AgentPretext) { "$AgentPretext. $Dialogue" } else { $Dialogue }
229
+
230
+ # Speak with agent's voice (or global voice if none configured)
231
+ if ($AgentVoice) {
232
+ & powershell -NoProfile -ExecutionPolicy Bypass -File $PlayTtsScript $SpeakText $AgentVoice
233
+ } else {
234
+ & powershell -NoProfile -ExecutionPolicy Bypass -File $PlayTtsScript $SpeakText
235
+ }
236
+ } finally {
237
+ # Restore personality
238
+ if ($AgentPersonality -and $PersonalityFile) {
239
+ if ($OldPersonality) {
240
+ Set-Content $PersonalityFile $OldPersonality -NoNewline
241
+ } elseif (Test-Path $PersonalityFile) {
242
+ Remove-Item $PersonalityFile -Force -ErrorAction SilentlyContinue
243
+ }
244
+ }
245
+
246
+ # Restore background music config
247
+ if ($AgentBgEnabled -and $AgentBgTrack) {
248
+ if ($null -ne $OldBgEnabled) {
249
+ Set-Content $BgEnabledFile $OldBgEnabled -NoNewline
250
+ } elseif (Test-Path $BgEnabledFile) {
251
+ Remove-Item $BgEnabledFile -Force -ErrorAction SilentlyContinue
252
+ }
253
+
254
+ # Remove the prepended agent line from audio-effects.cfg
255
+ if (Test-Path $AudioEffectsCfg) {
256
+ $cfgRaw = Get-Content $AudioEffectsCfg -Raw -ErrorAction SilentlyContinue
257
+ $escaped = [regex]::Escape($TempCfgLine)
258
+ $cfgRaw = $cfgRaw -replace "^${escaped}\r?\n?", ""
259
+ Set-Content $AudioEffectsCfg $cfgRaw -NoNewline
260
+ }
261
+
262
+ $env:AGENTVIBES_AGENT_NAME = ""
263
+ }
264
+ }
@@ -1,53 +1,53 @@
1
- #
2
- # File: .claude/hooks-windows/clean-audio-cache.ps1
3
- #
4
- # AgentVibes - Finally, your AI Agents can Talk Back!
5
- # Website: https://agentvibes.org
6
- # Copyright (c) 2025 Paul Preibisch
7
- # Licensed under the Apache License, Version 2.0
8
- #
9
- # Non-Interactive TTS Audio Cache Cleanup
10
- # Used by /agent-vibes:clean skill and MCP clean_audio_cache tool
11
-
12
- $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
13
- $ClaudeDir = Split-Path -Parent $ScriptDir
14
- $AudioDir = Join-Path $ClaudeDir "audio"
15
-
16
- Write-Output "AgentVibes Cache Cleanup (Non-Interactive)"
17
- Write-Output ""
18
-
19
- if (-not (Test-Path $AudioDir)) {
20
- Write-Output "Audio directory not found: $AudioDir"
21
- Write-Output "Nothing to clean."
22
- exit 0
23
- }
24
-
25
- # Count and measure TTS files (preserve tracks/ subdirectory)
26
- $ttsFiles = Get-ChildItem -Path $AudioDir -File -Include "*.wav", "*.mp3", "*.aiff" -Recurse -ErrorAction SilentlyContinue |
27
- Where-Object { $_.DirectoryName -notmatch '\\tracks$' -and $_.DirectoryName -notmatch '\\tracks\\' }
28
-
29
- if (-not $ttsFiles -or $ttsFiles.Count -eq 0) {
30
- Write-Output "No TTS cache files found."
31
- Write-Output "Audio directory is clean."
32
- exit 0
33
- }
34
-
35
- $fileCount = if ($ttsFiles -is [array]) { $ttsFiles.Count } else { 1 }
36
- $totalSize = ($ttsFiles | Measure-Object -Property Length -Sum).Sum
37
- $sizeMB = [math]::Round($totalSize / 1MB, 2)
38
-
39
- # Delete files
40
- $deleted = 0
41
- foreach ($file in $ttsFiles) {
42
- try {
43
- Remove-Item $file.FullName -Force -ErrorAction Stop
44
- $deleted++
45
- } catch {
46
- Write-Output "Warning: Could not delete $($file.Name): $_"
47
- }
48
- }
49
-
50
- Write-Output "Cleaned $deleted TTS cache files"
51
- Write-Output "Freed ${sizeMB} MB of disk space"
52
- Write-Output ""
53
- Write-Output "Background music tracks preserved."
1
+ #
2
+ # File: .claude/hooks-windows/clean-audio-cache.ps1
3
+ #
4
+ # AgentVibes - Finally, your AI Agents can Talk Back!
5
+ # Website: https://agentvibes.org
6
+ # Copyright (c) 2025 Paul Preibisch
7
+ # Licensed under the Apache License, Version 2.0
8
+ #
9
+ # Non-Interactive TTS Audio Cache Cleanup
10
+ # Used by /agent-vibes:clean skill and MCP clean_audio_cache tool
11
+
12
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
13
+ $ClaudeDir = Split-Path -Parent $ScriptDir
14
+ $AudioDir = Join-Path $ClaudeDir "audio"
15
+
16
+ Write-Output "AgentVibes Cache Cleanup (Non-Interactive)"
17
+ Write-Output ""
18
+
19
+ if (-not (Test-Path $AudioDir)) {
20
+ Write-Output "Audio directory not found: $AudioDir"
21
+ Write-Output "Nothing to clean."
22
+ exit 0
23
+ }
24
+
25
+ # Count and measure TTS files (preserve tracks/ subdirectory)
26
+ $ttsFiles = Get-ChildItem -Path $AudioDir -File -Include "*.wav", "*.mp3", "*.aiff" -Recurse -ErrorAction SilentlyContinue |
27
+ Where-Object { $_.DirectoryName -notmatch '\\tracks$' -and $_.DirectoryName -notmatch '\\tracks\\' }
28
+
29
+ if (-not $ttsFiles -or $ttsFiles.Count -eq 0) {
30
+ Write-Output "No TTS cache files found."
31
+ Write-Output "Audio directory is clean."
32
+ exit 0
33
+ }
34
+
35
+ $fileCount = if ($ttsFiles -is [array]) { $ttsFiles.Count } else { 1 }
36
+ $totalSize = ($ttsFiles | Measure-Object -Property Length -Sum).Sum
37
+ $sizeMB = [math]::Round($totalSize / 1MB, 2)
38
+
39
+ # Delete files
40
+ $deleted = 0
41
+ foreach ($file in $ttsFiles) {
42
+ try {
43
+ Remove-Item $file.FullName -Force -ErrorAction Stop
44
+ $deleted++
45
+ } catch {
46
+ Write-Output "Warning: Could not delete $($file.Name): $_"
47
+ }
48
+ }
49
+
50
+ Write-Output "Cleaned $deleted TTS cache files"
51
+ Write-Output "Freed ${sizeMB} MB of disk space"
52
+ Write-Output ""
53
+ Write-Output "Background music tracks preserved."