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.
- package/.agentvibes/LITE-MODE.md +236 -0
- package/.agentvibes/README.md +136 -0
- package/.agentvibes/backup/session-start-tts.sh.20251210_212814 +141 -0
- package/.agentvibes/backups/agents/analyst_20260204_144958.md +78 -0
- package/.agentvibes/backups/agents/architect_20260204_144958.md +72 -0
- package/.agentvibes/backups/agents/dev_20260204_144958.md +74 -0
- package/.agentvibes/backups/agents/pm_20260204_144958.md +72 -0
- package/.agentvibes/backups/agents/quick-flow-solo-dev_20260204_144958.md +64 -0
- package/.agentvibes/backups/agents/sm_20260204_144958.md +87 -0
- package/.agentvibes/backups/agents/tea_20260204_144958.md +79 -0
- package/.agentvibes/backups/agents/tech-writer_20260204_144958.md +82 -0
- package/.agentvibes/backups/agents/ux-designer_20260204_144958.md +80 -0
- package/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config/README-personality-defaults.md +162 -0
- package/.agentvibes/config/mode.txt +1 -0
- package/.agentvibes/config/personality-voice-defaults.default.json +21 -0
- package/.agentvibes/config/save-audio.txt +1 -0
- package/.agentvibes/config/voice-metadata.json +160 -0
- package/.agentvibes/config.json +24 -15
- package/.agentvibes/hooks/help.sh +191 -0
- package/.agentvibes/hooks/post-tool-use-lite.sh +111 -0
- package/.agentvibes/hooks/save-audio-manager.sh +162 -0
- package/.agentvibes/hooks/session-start-full-optimized.sh +102 -0
- package/.agentvibes/hooks/session-start-full.sh +142 -0
- package/.agentvibes/hooks/session-start-lite-v2.sh +34 -0
- package/.agentvibes/hooks/session-start-lite.sh +29 -0
- package/.agentvibes/hooks/stop-lite.sh +115 -0
- package/.agentvibes/hooks/switch-mode.sh +215 -0
- package/.agentvibes/output-styles/audio-summary.md +30 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/voice-samples/piper/alan.wav +0 -0
- package/.claude/audio/voice-samples/piper/amy.wav +0 -0
- package/.claude/audio/voice-samples/piper/charlotte.wav +0 -0
- package/.claude/audio/voice-samples/piper/joe.wav +0 -0
- package/.claude/audio/voice-samples/piper/john.wav +0 -0
- package/.claude/audio/voice-samples/piper/katherine.wav +0 -0
- package/.claude/audio/voice-samples/piper/kristin.wav +0 -0
- package/.claude/audio/voice-samples/piper/linda.wav +0 -0
- package/.claude/audio/voice-samples/piper/marcus.wav +0 -0
- package/.claude/audio/voice-samples/piper/ryan.wav +0 -0
- 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/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/audio-effects.cfg +16 -11
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-position.txt +27 -0
- package/.claude/config/background-music-volume.txt +1 -1
- package/.claude/config/background-music.cfg +1 -0
- package/.claude/config/background-music.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +1 -4
- package/.claude/config/tts-verbosity.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 +0 -0
- package/.claude/hooks/audio-processor.sh +60 -14
- package/.claude/hooks/background-music-manager.sh +0 -0
- package/.claude/hooks/bmad-party-manager.sh +225 -0
- package/.claude/hooks/bmad-party-speak.sh +0 -0
- package/.claude/hooks/bmad-speak-enhanced.sh +0 -0
- package/.claude/hooks/bmad-speak.sh +12 -15
- package/.claude/hooks/bmad-tts-injector.sh +0 -0
- package/.claude/hooks/bmad-voice-manager.sh +0 -0
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +25 -23
- package/.claude/hooks/clawdbot-receiver.sh +4 -28
- package/.claude/hooks/clean-audio-cache.sh +0 -0
- package/.claude/hooks/cleanup-cache.sh +0 -0
- package/.claude/hooks/configure-rdp-mode.sh +0 -0
- package/.claude/hooks/download-extra-voices.sh +0 -0
- package/.claude/hooks/effects-manager.sh +0 -0
- package/.claude/hooks/github-star-reminder.sh +0 -0
- package/.claude/hooks/language-manager.sh +0 -0
- package/.claude/hooks/learn-manager.sh +0 -0
- package/.claude/hooks/macos-voice-manager.sh +0 -0
- package/.claude/hooks/migrate-background-music.sh +0 -0
- package/.claude/hooks/migrate-to-agentvibes.sh +0 -0
- package/.claude/hooks/optimize-background-music.sh +0 -0
- package/.claude/hooks/personality-manager.sh +0 -0
- package/.claude/hooks/piper-download-voices.sh +0 -0
- package/.claude/hooks/piper-installer.sh +1 -1
- package/.claude/hooks/piper-multispeaker-registry.sh +0 -0
- package/.claude/hooks/piper-voice-manager.sh +0 -0
- package/.claude/hooks/play-tts-enhanced.sh +0 -0
- package/.claude/hooks/play-tts-macos.sh +6 -12
- package/.claude/hooks/play-tts-piper.sh +52 -81
- package/.claude/hooks/play-tts-soprano.sh +9 -43
- package/.claude/hooks/play-tts-ssh-remote.sh +43 -215
- package/.claude/hooks/play-tts-termux-ssh.sh +0 -0
- package/.claude/hooks/play-tts.sh +41 -20
- package/.claude/hooks/post-response.sh +41 -0
- package/.claude/hooks/prepare-release.sh +0 -0
- package/.claude/hooks/provider-commands.sh +0 -0
- package/.claude/hooks/provider-manager.sh +0 -0
- package/.claude/hooks/replay-target-audio.sh +0 -0
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +0 -0
- package/.claude/hooks/session-start-tts.sh +56 -39
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +0 -0
- package/.claude/hooks/stop.sh +63 -0
- package/.claude/hooks/termux-installer.sh +0 -0
- package/.claude/hooks/translate-manager.sh +0 -0
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +0 -0
- package/.claude/hooks/tts-queue.sh +0 -0
- package/.claude/hooks/verbosity-manager.sh +0 -0
- package/.claude/hooks/voice-manager.sh +26 -4
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/bmad-party-speak.ps1 +278 -278
- package/.claude/hooks-windows/bmad-speak.ps1 +264 -264
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -53
- package/.claude/hooks-windows/effects-manager.ps1 +294 -294
- package/.claude/hooks-windows/language-manager.ps1 +193 -193
- package/.claude/hooks-windows/learn-manager.ps1 +241 -241
- package/.claude/hooks-windows/personality-manager.ps1 +266 -266
- package/.claude/hooks-windows/play-tts-soprano.ps1 +5 -5
- package/.claude/hooks-windows/play-tts-termux-ssh.ps1 +138 -138
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +178 -0
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts.ps1 +265 -507
- package/.claude/hooks-windows/provider-manager.ps1 +158 -192
- package/.claude/hooks-windows/session-start-tts.ps1 +55 -46
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -166
- package/.claude/hooks-windows/voice-manager-windows.ps1 +176 -260
- 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/piper-voices-dir.txt +1 -0
- package/.claude/settings.json +25 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +149 -145
- package/.mcp.json +30 -11
- package/CLAUDE.md +170 -215
- package/README.md +207 -521
- package/RELEASE_NOTES.md +1172 -1976
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +0 -0
- package/bin/agentvibes-voice-browser.js +64 -1289
- package/bin/agentvibes.js +28 -0
- package/bin/ensure-soprano-running.sh +43 -0
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +0 -0
- 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 +1467 -1578
- package/mcp-server/test_server.py +395 -395
- package/package.json +1 -3
- package/setup-windows.ps1 +815 -815
- package/src/console/tabs/music-tab.js +5 -2
- package/src/console/tabs/voices-tab.js +71 -37
- package/src/installer.js +52 -5
- package/src/services/llm-provider-service.js +1 -1
- package/templates/agentvibes-receiver.sh +158 -483
- package/templates/audio/welcome-music.mp3 +0 -0
- package/.agentvibes/bmad-voice-map.json +0 -104
- package/.agentvibes/copilot-sessions.log +0 -4
- package/.claude/config/audio-effects-bmad.cfg +0 -50
- package/.claude/config/intro-text.txt +0 -1
- package/.claude/config/personality.txt +0 -1
- package/.claude/config/piper-speech-rate.txt +0 -4
- package/.claude/config/piper-target-speech-rate.txt +0 -1
- package/.claude/config/reverb-level.txt +0 -1
- package/.claude/config/tts-target-speech-rate.txt +0 -1
- package/voice-assignments.json +0 -8245
- /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,178 @@
|
|
|
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 (skip if AGENTVIBES_NO_PLAY is set)
|
|
146
|
+
if (-not $env:AGENTVIBES_NO_PLAY) {
|
|
147
|
+
# Prefer ffplay: handles 22050 Hz → 48000 Hz resampling cleanly (SoundPlayer uses
|
|
148
|
+
# WinMM's low-quality resampler which produces choppy audio at non-native rates).
|
|
149
|
+
$ffplayPath = (Get-Command ffplay -ErrorAction SilentlyContinue)?.Source
|
|
150
|
+
if (-not $ffplayPath) {
|
|
151
|
+
# SSH/watcher sessions may have a minimal PATH — refresh from registry
|
|
152
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" +
|
|
153
|
+
[System.Environment]::GetEnvironmentVariable("Path","User")
|
|
154
|
+
$ffplayPath = (Get-Command ffplay -ErrorAction SilentlyContinue)?.Source
|
|
155
|
+
}
|
|
156
|
+
if ($ffplayPath) {
|
|
157
|
+
& $ffplayPath -autoexit -nodisp -loglevel quiet $AudioFile 2>$null
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
$player = $null
|
|
161
|
+
try {
|
|
162
|
+
$player = New-Object System.Media.SoundPlayer $AudioFile
|
|
163
|
+
$player.PlaySync()
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
|
|
167
|
+
Write-Host "Audio saved to: $AudioFile" -ForegroundColor Gray
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
if ($player) { $player.Dispose() }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
Write-Host "[ERROR] Error running Piper: $_" -ForegroundColor Red
|
|
177
|
+
exit 1
|
|
178
|
+
}
|
|
@@ -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
|
+
}
|