agentvibes 5.2.1 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +4 -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-speak-enhanced.sh +0 -0
  88. package/.claude/hooks/bmad-speak.sh +6 -13
  89. package/.claude/hooks/bmad-tts-injector.sh +0 -0
  90. package/.claude/hooks/bmad-voice-manager.sh +0 -0
  91. package/.claude/hooks/clawdbot-receiver-SECURE.sh +25 -23
  92. package/.claude/hooks/clawdbot-receiver.sh +4 -28
  93. package/.claude/hooks/clean-audio-cache.sh +0 -0
  94. package/.claude/hooks/cleanup-cache.sh +0 -0
  95. package/.claude/hooks/configure-rdp-mode.sh +0 -0
  96. package/.claude/hooks/download-extra-voices.sh +0 -0
  97. package/.claude/hooks/effects-manager.sh +0 -0
  98. package/.claude/hooks/github-star-reminder.sh +0 -0
  99. package/.claude/hooks/language-manager.sh +0 -0
  100. package/.claude/hooks/learn-manager.sh +0 -0
  101. package/.claude/hooks/macos-voice-manager.sh +0 -0
  102. package/.claude/hooks/migrate-background-music.sh +0 -0
  103. package/.claude/hooks/migrate-to-agentvibes.sh +0 -0
  104. package/.claude/hooks/optimize-background-music.sh +0 -0
  105. package/.claude/hooks/personality-manager.sh +0 -0
  106. package/.claude/hooks/piper-download-voices.sh +0 -0
  107. package/.claude/hooks/piper-installer.sh +1 -1
  108. package/.claude/hooks/piper-multispeaker-registry.sh +0 -0
  109. package/.claude/hooks/piper-voice-manager.sh +0 -0
  110. package/.claude/hooks/play-tts-enhanced.sh +0 -0
  111. package/.claude/hooks/play-tts-macos.sh +6 -12
  112. package/.claude/hooks/play-tts-piper.sh +50 -79
  113. package/.claude/hooks/play-tts-soprano.sh +9 -43
  114. package/.claude/hooks/play-tts-ssh-remote.sh +42 -120
  115. package/.claude/hooks/play-tts-termux-ssh.sh +0 -0
  116. package/.claude/hooks/play-tts.sh +48 -37
  117. package/.claude/hooks/post-response.sh +41 -0
  118. package/.claude/hooks/prepare-release.sh +0 -0
  119. package/.claude/hooks/provider-commands.sh +0 -0
  120. package/.claude/hooks/provider-manager.sh +0 -0
  121. package/.claude/hooks/replay-target-audio.sh +0 -0
  122. package/.claude/hooks/requirements.txt +6 -6
  123. package/.claude/hooks/sentiment-manager.sh +0 -0
  124. package/.claude/hooks/session-start-tts.sh +56 -39
  125. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  126. package/.claude/hooks/speed-manager.sh +0 -0
  127. package/.claude/hooks/stop.sh +63 -0
  128. package/.claude/hooks/termux-installer.sh +0 -0
  129. package/.claude/hooks/translate-manager.sh +0 -0
  130. package/.claude/hooks/translator.py +237 -237
  131. package/.claude/hooks/tts-queue-worker.sh +0 -0
  132. package/.claude/hooks/tts-queue.sh +0 -0
  133. package/.claude/hooks/verbosity-manager.sh +0 -0
  134. package/.claude/hooks/voice-manager.sh +26 -4
  135. package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
  136. package/.claude/hooks-windows/bmad-party-speak.ps1 +278 -274
  137. package/.claude/hooks-windows/bmad-speak.ps1 +264 -264
  138. package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -53
  139. package/.claude/hooks-windows/effects-manager.ps1 +294 -294
  140. package/.claude/hooks-windows/language-manager.ps1 +193 -193
  141. package/.claude/hooks-windows/learn-manager.ps1 +241 -241
  142. package/.claude/hooks-windows/personality-manager.ps1 +266 -266
  143. package/.claude/hooks-windows/play-tts-soprano.ps1 +5 -5
  144. package/.claude/hooks-windows/play-tts-termux-ssh.ps1 +138 -138
  145. package/.claude/hooks-windows/play-tts-windows-piper.ps1 +164 -0
  146. package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -0
  147. package/.claude/hooks-windows/play-tts.ps1 +104 -481
  148. package/.claude/hooks-windows/provider-manager.ps1 +158 -192
  149. package/.claude/hooks-windows/session-start-tts.ps1 +55 -46
  150. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  151. package/.claude/hooks-windows/speed-manager.ps1 +166 -166
  152. package/.claude/hooks-windows/voice-manager-windows.ps1 +176 -260
  153. package/.claude/output-styles/agent-vibes.md +202 -202
  154. package/.claude/personalities/angry.md +14 -14
  155. package/.claude/personalities/annoying.md +14 -14
  156. package/.claude/personalities/crass.md +14 -14
  157. package/.claude/personalities/dramatic.md +14 -14
  158. package/.claude/personalities/dry-humor.md +50 -50
  159. package/.claude/personalities/flirty.md +20 -20
  160. package/.claude/personalities/funny.md +14 -14
  161. package/.claude/personalities/grandpa.md +32 -32
  162. package/.claude/personalities/millennial.md +14 -14
  163. package/.claude/personalities/moody.md +14 -14
  164. package/.claude/personalities/normal.md +16 -16
  165. package/.claude/personalities/pirate.md +14 -14
  166. package/.claude/personalities/poetic.md +14 -14
  167. package/.claude/personalities/professional.md +14 -14
  168. package/.claude/personalities/rapper.md +55 -55
  169. package/.claude/personalities/robot.md +14 -14
  170. package/.claude/personalities/sarcastic.md +38 -38
  171. package/.claude/personalities/sassy.md +14 -14
  172. package/.claude/personalities/surfer-dude.md +14 -14
  173. package/.claude/personalities/zen.md +14 -14
  174. package/.claude/piper-voices-dir.txt +1 -0
  175. package/.claude/settings.json +25 -15
  176. package/.claude/verbosity.txt +1 -1
  177. package/.clawdbot/README.md +105 -105
  178. package/.clawdbot/skill/SKILL.md +149 -145
  179. package/.mcp.json +30 -11
  180. package/CLAUDE.md +170 -215
  181. package/README.md +206 -515
  182. package/RELEASE_NOTES.md +1132 -1884
  183. package/WINDOWS-SETUP.md +208 -208
  184. package/bin/agent-vibes +0 -0
  185. package/bin/agentvibes-voice-browser.js +64 -1289
  186. package/bin/agentvibes.js +0 -0
  187. package/bin/ensure-soprano-running.sh +43 -0
  188. package/bin/mcp-server.js +121 -121
  189. package/bin/mcp-server.sh +0 -0
  190. package/bin/test-bmad-pr +78 -78
  191. package/mcp-server/QUICK_START.md +203 -203
  192. package/mcp-server/README.md +345 -345
  193. package/mcp-server/WINDOWS_SETUP.md +260 -260
  194. package/mcp-server/docs/troubleshooting-audio.md +313 -313
  195. package/mcp-server/examples/claude_desktop_config.json +11 -11
  196. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  197. package/mcp-server/examples/custom_instructions.md +169 -169
  198. package/mcp-server/install-deps.js +130 -130
  199. package/mcp-server/pyproject.toml +52 -52
  200. package/mcp-server/requirements.txt +2 -2
  201. package/mcp-server/server.py +1451 -1578
  202. package/mcp-server/test_server.py +395 -395
  203. package/package.json +1 -3
  204. package/setup-windows.ps1 +815 -815
  205. package/src/console/tabs/setup-tab.js +9 -6
  206. package/src/console/tabs/voices-tab.js +9 -3
  207. package/src/installer.js +42 -5
  208. package/src/services/llm-provider-service.js +13 -0
  209. package/templates/agentvibes-receiver.sh +158 -483
  210. package/templates/audio/welcome-music.mp3 +0 -0
  211. package/.agentvibes/bmad-voice-map.json +0 -104
  212. package/.agentvibes/copilot-sessions.log +0 -4
  213. package/.claude/config/audio-effects-bmad.cfg +0 -50
  214. package/.claude/config/background-music-enabled.txt +0 -1
  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,138 +1,138 @@
1
- #
2
- # File: .claude/hooks-windows/play-tts-termux-ssh.ps1
3
- #
4
- # AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
5
- # Website: https://agentvibes.org
6
- # Repository: https://github.com/paulpreibisch/AgentVibes
7
- #
8
- # Co-created by Paul Preibisch with Claude AI
9
- # Copyright (c) 2025 Paul Preibisch
10
- #
11
- # Licensed under the Apache License, Version 2.0 (the "License");
12
- # you may not use this file except in compliance with the License.
13
- # You may obtain a copy of the License at
14
- #
15
- # http://www.apache.org/licenses/LICENSE-2.0
16
- #
17
- # ---
18
- #
19
- # @fileoverview Termux SSH TTS Provider (Windows) - Android TTS via SSH tunnel
20
- # @context Enables TTS output on Android devices when connected via SSH from Windows
21
- # @architecture SSH-based remote TTS invocation using termux-tts-speak on Android
22
- # @dependencies ssh.exe (OpenSSH for Windows), termux-tts-speak (on Android), termux-api (on Android)
23
- # @entrypoints Called by play-tts.ps1 router when provider=termux-ssh
24
- # @patterns Remote TTS invocation, SSH host alias configuration, graceful fallback
25
- # @related play-tts.ps1, provider-manager.ps1
26
- #
27
- # SETUP INSTRUCTIONS:
28
- # ===================
29
- # 1. On Android device (Termux):
30
- # - Install: pkg install termux-api openssh
31
- # - Install Termux:API app from F-Droid or Google Play
32
- # - Start SSH server: sshd
33
- #
34
- # 2. On Windows:
35
- # - Add to %USERPROFILE%\.ssh\config:
36
- # Host android
37
- # HostName <your-android-ip>
38
- # User <your-termux-username>
39
- # Port 8022
40
- # IdentityFile ~/.ssh/id_rsa
41
- #
42
- # 3. Configure AgentVibes:
43
- # - echo android > %USERPROFILE%\.claude\termux-ssh-host.txt
44
- # OR
45
- # - echo android > .claude\termux-ssh-host.txt (project-local)
46
- #
47
- # 4. Set provider:
48
- # - echo termux-ssh > %USERPROFILE%\.claude\tts-provider.txt
49
- #
50
-
51
- param(
52
- [Parameter(Mandatory = $true, Position = 0)]
53
- [string]$Text,
54
-
55
- [Parameter(Mandatory = $false, Position = 1)]
56
- [string]$VoiceOverride # Not used for termux-ssh, kept for interface compatibility
57
- )
58
-
59
- # Resolve ClaudeDir (project-local preferred, fallback to global)
60
- $ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
61
- $ProjectClaudeDir = Split-Path -Parent $ScriptPath
62
- if (Test-Path (Join-Path $ProjectClaudeDir "config")) {
63
- $ClaudeDir = $ProjectClaudeDir
64
- } else {
65
- $ClaudeDir = "$env:USERPROFILE\.claude"
66
- }
67
-
68
- # @function Get-SshHost
69
- # @intent Determine SSH host alias for Android device
70
- # @why Allows users to configure their own SSH connection without hardcoded values
71
- # Priority: env var > project config > script-dir config > global config
72
- function Get-SshHost {
73
- if ($env:TERMUX_SSH_HOST) { return $env:TERMUX_SSH_HOST }
74
-
75
- $projectFile = Join-Path $ClaudeDir "termux-ssh-host.txt"
76
- if (Test-Path $projectFile) {
77
- $val = (Get-Content $projectFile -Raw).Trim()
78
- if ($val) { return $val }
79
- }
80
-
81
- $globalFile = "$env:USERPROFILE\.claude\termux-ssh-host.txt"
82
- if (Test-Path $globalFile) {
83
- $val = (Get-Content $globalFile -Raw).Trim()
84
- if ($val) { return $val }
85
- }
86
-
87
- return ""
88
- }
89
-
90
- # @function Test-SshConnection
91
- # @intent Quick reachability check before sending TTS
92
- # @why Prevents long hangs if Android is offline
93
- function Test-SshConnection {
94
- param([string]$SshTarget)
95
- try {
96
- $null = ssh -o ConnectTimeout=2 -o BatchMode=yes $SshTarget "echo ok" 2>&1
97
- return $LASTEXITCODE -eq 0
98
- } catch {
99
- return $false
100
- }
101
- }
102
-
103
- # --- Main ---
104
-
105
- if (-not $Text) {
106
- Write-Host "[ERROR] No text provided for TTS" -ForegroundColor Red
107
- exit 1
108
- }
109
-
110
- $SshAlias = Get-SshHost
111
-
112
- if (-not $SshAlias) {
113
- Write-Host "[ERROR] Termux SSH provider not configured" -ForegroundColor Red
114
- Write-Host " Set SSH host alias in one of:" -ForegroundColor Yellow
115
- Write-Host " Environment: `$env:TERMUX_SSH_HOST = 'android'" -ForegroundColor Yellow
116
- Write-Host " Global: echo android > `"$env:USERPROFILE\.claude\termux-ssh-host.txt`"" -ForegroundColor Yellow
117
- Write-Host " Project: echo android > .claude\termux-ssh-host.txt" -ForegroundColor Yellow
118
- exit 1
119
- }
120
-
121
- if (-not (Test-SshConnection -SshTarget $SshAlias)) {
122
- Write-Host "[WARNING] Cannot connect to SSH host '$SshAlias' - Android offline?" -ForegroundColor Yellow
123
- exit 1
124
- }
125
-
126
- # Escape single quotes for safe shell transmission
127
- $SafeText = $Text -replace "'", "'\'''"
128
-
129
- # Send TTS to Android asynchronously (audio plays on device)
130
- $job = Start-Job -ScriptBlock {
131
- param($alias, $text)
132
- ssh -o ConnectTimeout=5 $alias "termux-tts-speak '$text'" 2>&1
133
- } -ArgumentList $SshAlias, $SafeText
134
-
135
- Write-Host "[OK] TTS sent to Android ($SshAlias) via SSH" -ForegroundColor Green
136
-
137
- # Output empty string — audio plays on Android, not locally
138
- Write-Output ""
1
+ #
2
+ # File: .claude/hooks-windows/play-tts-termux-ssh.ps1
3
+ #
4
+ # AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
5
+ # Website: https://agentvibes.org
6
+ # Repository: https://github.com/paulpreibisch/AgentVibes
7
+ #
8
+ # Co-created by Paul Preibisch with Claude AI
9
+ # Copyright (c) 2025 Paul Preibisch
10
+ #
11
+ # Licensed under the Apache License, Version 2.0 (the "License");
12
+ # you may not use this file except in compliance with the License.
13
+ # You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # ---
18
+ #
19
+ # @fileoverview Termux SSH TTS Provider (Windows) - Android TTS via SSH tunnel
20
+ # @context Enables TTS output on Android devices when connected via SSH from Windows
21
+ # @architecture SSH-based remote TTS invocation using termux-tts-speak on Android
22
+ # @dependencies ssh.exe (OpenSSH for Windows), termux-tts-speak (on Android), termux-api (on Android)
23
+ # @entrypoints Called by play-tts.ps1 router when provider=termux-ssh
24
+ # @patterns Remote TTS invocation, SSH host alias configuration, graceful fallback
25
+ # @related play-tts.ps1, provider-manager.ps1
26
+ #
27
+ # SETUP INSTRUCTIONS:
28
+ # ===================
29
+ # 1. On Android device (Termux):
30
+ # - Install: pkg install termux-api openssh
31
+ # - Install Termux:API app from F-Droid or Google Play
32
+ # - Start SSH server: sshd
33
+ #
34
+ # 2. On Windows:
35
+ # - Add to %USERPROFILE%\.ssh\config:
36
+ # Host android
37
+ # HostName <your-android-ip>
38
+ # User <your-termux-username>
39
+ # Port 8022
40
+ # IdentityFile ~/.ssh/id_rsa
41
+ #
42
+ # 3. Configure AgentVibes:
43
+ # - echo android > %USERPROFILE%\.claude\termux-ssh-host.txt
44
+ # OR
45
+ # - echo android > .claude\termux-ssh-host.txt (project-local)
46
+ #
47
+ # 4. Set provider:
48
+ # - echo termux-ssh > %USERPROFILE%\.claude\tts-provider.txt
49
+ #
50
+
51
+ param(
52
+ [Parameter(Mandatory = $true, Position = 0)]
53
+ [string]$Text,
54
+
55
+ [Parameter(Mandatory = $false, Position = 1)]
56
+ [string]$VoiceOverride # Not used for termux-ssh, kept for interface compatibility
57
+ )
58
+
59
+ # Resolve ClaudeDir (project-local preferred, fallback to global)
60
+ $ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
61
+ $ProjectClaudeDir = Split-Path -Parent $ScriptPath
62
+ if (Test-Path (Join-Path $ProjectClaudeDir "config")) {
63
+ $ClaudeDir = $ProjectClaudeDir
64
+ } else {
65
+ $ClaudeDir = "$env:USERPROFILE\.claude"
66
+ }
67
+
68
+ # @function Get-SshHost
69
+ # @intent Determine SSH host alias for Android device
70
+ # @why Allows users to configure their own SSH connection without hardcoded values
71
+ # Priority: env var > project config > script-dir config > global config
72
+ function Get-SshHost {
73
+ if ($env:TERMUX_SSH_HOST) { return $env:TERMUX_SSH_HOST }
74
+
75
+ $projectFile = Join-Path $ClaudeDir "termux-ssh-host.txt"
76
+ if (Test-Path $projectFile) {
77
+ $val = (Get-Content $projectFile -Raw).Trim()
78
+ if ($val) { return $val }
79
+ }
80
+
81
+ $globalFile = "$env:USERPROFILE\.claude\termux-ssh-host.txt"
82
+ if (Test-Path $globalFile) {
83
+ $val = (Get-Content $globalFile -Raw).Trim()
84
+ if ($val) { return $val }
85
+ }
86
+
87
+ return ""
88
+ }
89
+
90
+ # @function Test-SshConnection
91
+ # @intent Quick reachability check before sending TTS
92
+ # @why Prevents long hangs if Android is offline
93
+ function Test-SshConnection {
94
+ param([string]$SshTarget)
95
+ try {
96
+ $null = ssh -o ConnectTimeout=2 -o BatchMode=yes $SshTarget "echo ok" 2>&1
97
+ return $LASTEXITCODE -eq 0
98
+ } catch {
99
+ return $false
100
+ }
101
+ }
102
+
103
+ # --- Main ---
104
+
105
+ if (-not $Text) {
106
+ Write-Host "[ERROR] No text provided for TTS" -ForegroundColor Red
107
+ exit 1
108
+ }
109
+
110
+ $SshAlias = Get-SshHost
111
+
112
+ if (-not $SshAlias) {
113
+ Write-Host "[ERROR] Termux SSH provider not configured" -ForegroundColor Red
114
+ Write-Host " Set SSH host alias in one of:" -ForegroundColor Yellow
115
+ Write-Host " Environment: `$env:TERMUX_SSH_HOST = 'android'" -ForegroundColor Yellow
116
+ Write-Host " Global: echo android > `"$env:USERPROFILE\.claude\termux-ssh-host.txt`"" -ForegroundColor Yellow
117
+ Write-Host " Project: echo android > .claude\termux-ssh-host.txt" -ForegroundColor Yellow
118
+ exit 1
119
+ }
120
+
121
+ if (-not (Test-SshConnection -SshTarget $SshAlias)) {
122
+ Write-Host "[WARNING] Cannot connect to SSH host '$SshAlias' - Android offline?" -ForegroundColor Yellow
123
+ exit 1
124
+ }
125
+
126
+ # Escape single quotes for safe shell transmission
127
+ $SafeText = $Text -replace "'", "'\'''"
128
+
129
+ # Send TTS to Android asynchronously (audio plays on device)
130
+ $job = Start-Job -ScriptBlock {
131
+ param($alias, $text)
132
+ ssh -o ConnectTimeout=5 $alias "termux-tts-speak '$text'" 2>&1
133
+ } -ArgumentList $SshAlias, $SafeText
134
+
135
+ Write-Host "[OK] TTS sent to Android ($SshAlias) via SSH" -ForegroundColor Green
136
+
137
+ # Output empty string — audio plays on Android, not locally
138
+ Write-Output ""
@@ -0,0 +1,164 @@
1
+ #
2
+ # File: .claude/hooks-windows/play-tts-windows-piper.ps1
3
+ #
4
+ # AgentVibes - Windows Piper TTS Provider
5
+ # High-quality neural TTS using Piper.exe
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
+ # Audio cache and voice config use project-local .claude
27
+ $AudioDir = "$ClaudeDir\audio"
28
+ $VoiceFile = "$ClaudeDir\tts-voice-piper.txt"
29
+
30
+ # Voices and Piper binary are global (shared across projects, ~100MB+)
31
+ $UserClaudeDir = "$env:USERPROFILE\.claude"
32
+ $VoicesDir = "$UserClaudeDir\piper-voices"
33
+ $PiperExe = "$env:LOCALAPPDATA\Programs\Piper\piper.exe"
34
+
35
+ # Ensure directories exist
36
+ foreach ($dir in @($AudioDir, $VoicesDir)) {
37
+ if (-not (Test-Path $dir)) {
38
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
39
+ }
40
+ }
41
+
42
+ # Check if Piper is installed
43
+ if (-not (Test-Path $PiperExe)) {
44
+ Write-Host "[ERROR] Piper not found at: $PiperExe" -ForegroundColor Red
45
+ Write-Host "Run: .\setup-windows.ps1 to install Piper" -ForegroundColor Yellow
46
+ exit 1
47
+ }
48
+
49
+ # Determine voice to use
50
+ $VoiceName = ""
51
+
52
+ if ($VoiceOverride) {
53
+ $VoiceName = $VoiceOverride
54
+ }
55
+ elseif (Test-Path $VoiceFile) {
56
+ $VoiceName = (Get-Content $VoiceFile -Raw).Trim()
57
+ }
58
+
59
+ # Default voice if not specified
60
+ if (-not $VoiceName) {
61
+ $VoiceName = "en_US-ryan-high"
62
+ }
63
+
64
+ # Security: Validate voice name to prevent path traversal
65
+ # Only allow alphanumeric, underscore, hyphen, and period
66
+ if ($VoiceName -notmatch '^[a-zA-Z0-9_\-\.]+$') {
67
+ Write-Host "[ERROR] Invalid voice name: $VoiceName" -ForegroundColor Red
68
+ exit 1
69
+ }
70
+
71
+ # Resolve voice model path and validate it stays within VoicesDir
72
+ $VoiceModelFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx")
73
+ $VoiceJsonFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx.json")
74
+ $ResolvedVoicesDir = [System.IO.Path]::GetFullPath($VoicesDir)
75
+ if (-not $VoiceModelFile.StartsWith($ResolvedVoicesDir)) {
76
+ Write-Host "[ERROR] Voice path outside voices directory" -ForegroundColor Red
77
+ exit 1
78
+ }
79
+
80
+ # Check if voice model exists, download if missing
81
+ if (-not (Test-Path $VoiceModelFile)) {
82
+ Write-Host "[DOWNLOAD] Voice model: $VoiceName" -ForegroundColor Yellow
83
+
84
+ # Try to download from Hugging Face
85
+ # Voice name format: {lang}_{region}-{speaker}-{quality}
86
+ # HF path format: {lang}/{lang}_{region}/{speaker}/{quality}/{voicename}.onnx
87
+ try {
88
+ # Parse voice name to build correct HF path
89
+ # e.g. en_US-ryan-high -> en/en_US/ryan/high/en_US-ryan-high.onnx
90
+ if ($VoiceName -match '^([a-z]{2})_([A-Z]{2})-([a-zA-Z0-9_]+)-([a-z]+)$') {
91
+ $Lang = $Matches[1]
92
+ $LangRegion = "$($Matches[1])_$($Matches[2])"
93
+ $Speaker = $Matches[3]
94
+ $Quality = $Matches[4]
95
+ $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/$Lang/$LangRegion/$Speaker/$Quality"
96
+ } else {
97
+ # Fallback for non-standard voice names
98
+ $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/ryan/high"
99
+ }
100
+ $ModelUrl = "$HFBase/$VoiceName.onnx"
101
+ $JsonUrl = "$HFBase/$VoiceName.onnx.json"
102
+
103
+ Write-Host " Downloading model..." -ForegroundColor Cyan
104
+ Invoke-WebRequest -Uri $ModelUrl -OutFile $VoiceModelFile -ErrorAction Stop
105
+ Write-Host " Downloading config..." -ForegroundColor Cyan
106
+ Invoke-WebRequest -Uri $JsonUrl -OutFile $VoiceJsonFile -ErrorAction Stop
107
+ Write-Host "[OK] Voice model downloaded" -ForegroundColor Green
108
+ }
109
+ catch {
110
+ Write-Host "[ERROR] Failed to download voice model: $_" -ForegroundColor Red
111
+ Write-Host "Make sure you have internet connection" -ForegroundColor Yellow
112
+ exit 1
113
+ }
114
+ }
115
+
116
+ # Sanitize text for speech - strip shell metacharacters and PS special chars
117
+ $Text = $Text -replace '\\', ' '
118
+ $Text = $Text -replace '[{}<>|`~^$;"''()]', ''
119
+ $Text = $Text -replace '\s+', ' '
120
+ $Text = $Text.Trim()
121
+
122
+ # Create audio file path
123
+ $Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
124
+ $AudioFile = "$AudioDir\tts-$Timestamp.wav"
125
+
126
+ # Synthesize with Piper
127
+ try {
128
+ Write-Host "[SYNTH] Synthesizing with Piper..." -ForegroundColor Cyan
129
+
130
+ # Run Piper with text input
131
+ $Text | & $PiperExe `
132
+ --model $VoiceModelFile `
133
+ --output-file $AudioFile `
134
+ 2>$null
135
+
136
+ if (-not (Test-Path $AudioFile)) {
137
+ Write-Host "[ERROR] Piper synthesis failed" -ForegroundColor Red
138
+ exit 1
139
+ }
140
+
141
+ # Display results
142
+ Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
143
+ Write-Host "[VOICE] Voice used: $VoiceName (Piper)" -ForegroundColor Green
144
+
145
+ # Play the audio using built-in Windows audio player (skip if AGENTVIBES_NO_PLAY is set)
146
+ if (-not $env:AGENTVIBES_NO_PLAY) {
147
+ $player = $null
148
+ try {
149
+ $player = New-Object System.Media.SoundPlayer $AudioFile
150
+ $player.PlaySync()
151
+ }
152
+ catch {
153
+ Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
154
+ Write-Host "Audio saved to: $AudioFile" -ForegroundColor Gray
155
+ }
156
+ finally {
157
+ if ($player) { $player.Dispose() }
158
+ }
159
+ }
160
+ }
161
+ catch {
162
+ Write-Host "[ERROR] Error running Piper: $_" -ForegroundColor Red
163
+ exit 1
164
+ }
@@ -0,0 +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, PS special chars, 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
+ }