agentvibes 4.2.0 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config.json +12 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/tracks/README.md +52 -52
- package/.claude/commands/agent-vibes/add.md +21 -21
- package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
- package/.claude/commands/agent-vibes/agent.md +79 -79
- package/.claude/commands/agent-vibes/background-music.md +111 -111
- package/.claude/commands/agent-vibes/bmad.md +198 -198
- package/.claude/commands/agent-vibes/clean.md +18 -18
- package/.claude/commands/agent-vibes/cleanup.md +18 -18
- package/.claude/commands/agent-vibes/commands.json +145 -145
- package/.claude/commands/agent-vibes/effects.md +97 -97
- package/.claude/commands/agent-vibes/get.md +9 -9
- package/.claude/commands/agent-vibes/hide.md +91 -91
- package/.claude/commands/agent-vibes/language.md +23 -23
- package/.claude/commands/agent-vibes/learn.md +67 -67
- package/.claude/commands/agent-vibes/list.md +13 -13
- package/.claude/commands/agent-vibes/mute.md +37 -37
- package/.claude/commands/agent-vibes/preview.md +17 -17
- package/.claude/commands/agent-vibes/provider.md +68 -68
- package/.claude/commands/agent-vibes/replay-target.md +14 -14
- package/.claude/commands/agent-vibes/sample.md +12 -12
- package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
- package/.claude/commands/agent-vibes/set-pretext.md +65 -65
- package/.claude/commands/agent-vibes/set-speed.md +41 -41
- package/.claude/commands/agent-vibes/show.md +84 -84
- package/.claude/commands/agent-vibes/switch.md +87 -87
- package/.claude/commands/agent-vibes/target-voice.md +26 -26
- package/.claude/commands/agent-vibes/target.md +30 -30
- package/.claude/commands/agent-vibes/translate.md +68 -68
- package/.claude/commands/agent-vibes/unmute.md +45 -45
- package/.claude/commands/agent-vibes/verbosity.md +89 -89
- package/.claude/commands/agent-vibes/whoami.md +7 -7
- package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
- package/.claude/commands/agent-vibes-rdp.md +24 -24
- package/.claude/config/agentvibes.json +1 -0
- package/.claude/config/audio-effects.cfg +2 -2
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-volume.txt +1 -0
- package/.claude/config/intro-text.txt +1 -0
- package/.claude/config/piper-speech-rate.txt +4 -0
- package/.claude/config/piper-target-speech-rate.txt +1 -0
- package/.claude/config/reverb-level.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +4 -0
- package/.claude/config/tts-target-speech-rate.txt +1 -0
- package/.claude/docs/TERMUX_SETUP.md +408 -408
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/README-TTS-QUEUE.md +135 -135
- package/.claude/hooks/audio-cache-utils.sh +246 -246
- package/.claude/hooks/audio-processor.sh +433 -433
- package/.claude/hooks/background-music-manager.sh +404 -404
- package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
- package/.claude/hooks/bmad-speak.sh +269 -269
- package/.claude/hooks/bmad-tts-injector.sh +568 -568
- package/.claude/hooks/bmad-voice-manager.sh +928 -928
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
- package/.claude/hooks/clawdbot-receiver.sh +107 -107
- package/.claude/hooks/clean-audio-cache.sh +22 -22
- package/.claude/hooks/cleanup-cache.sh +106 -106
- package/.claude/hooks/configure-rdp-mode.sh +137 -137
- package/.claude/hooks/download-extra-voices.sh +244 -244
- package/.claude/hooks/effects-manager.sh +268 -268
- package/.claude/hooks/github-star-reminder.sh +154 -154
- package/.claude/hooks/language-manager.sh +362 -362
- package/.claude/hooks/learn-manager.sh +492 -492
- package/.claude/hooks/macos-voice-manager.sh +205 -205
- package/.claude/hooks/migrate-background-music.sh +125 -125
- package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
- package/.claude/hooks/optimize-background-music.sh +87 -87
- package/.claude/hooks/path-resolver.sh +60 -60
- package/.claude/hooks/personality-manager.sh +448 -448
- package/.claude/hooks/piper-download-voices.sh +225 -225
- package/.claude/hooks/piper-installer.sh +292 -292
- package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
- package/.claude/hooks/piper-voice-manager.sh +24 -3
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
- package/.claude/hooks/play-tts-enhanced.sh +105 -105
- package/.claude/hooks/play-tts-macos.sh +368 -368
- package/.claude/hooks/play-tts-piper.sh +679 -679
- package/.claude/hooks/play-tts-soprano.sh +356 -356
- package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
- package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
- package/.claude/hooks/play-tts.sh +301 -301
- package/.claude/hooks/prepare-release.sh +54 -54
- package/.claude/hooks/provider-commands.sh +617 -617
- package/.claude/hooks/provider-manager.sh +399 -399
- package/.claude/hooks/replay-target-audio.sh +95 -95
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +201 -201
- package/.claude/hooks/session-start-tts.sh +81 -81
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +291 -291
- package/.claude/hooks/stop-tts.sh +84 -84
- package/.claude/hooks/termux-installer.sh +261 -261
- package/.claude/hooks/translate-manager.sh +341 -341
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +145 -145
- package/.claude/hooks/tts-queue.sh +165 -165
- package/.claude/hooks/verbosity-manager.sh +178 -178
- package/.claude/hooks/voice-manager.sh +548 -548
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
- package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
- package/.claude/hooks-windows/effects-manager.ps1 +294 -0
- package/.claude/hooks-windows/language-manager.ps1 +193 -0
- package/.claude/hooks-windows/learn-manager.ps1 +241 -0
- package/.claude/hooks-windows/personality-manager.ps1 +266 -0
- package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
- package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
- package/.claude/hooks-windows/play-tts.ps1 +344 -266
- package/.claude/hooks-windows/provider-manager.ps1 +29 -10
- package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -0
- package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
- package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
- package/.claude/output-styles/agent-vibes.md +202 -202
- package/.claude/personalities/angry.md +14 -14
- package/.claude/personalities/annoying.md +14 -14
- package/.claude/personalities/crass.md +14 -14
- package/.claude/personalities/dramatic.md +14 -14
- package/.claude/personalities/dry-humor.md +50 -50
- package/.claude/personalities/flirty.md +20 -20
- package/.claude/personalities/funny.md +14 -14
- package/.claude/personalities/grandpa.md +32 -32
- package/.claude/personalities/millennial.md +14 -14
- package/.claude/personalities/moody.md +14 -14
- package/.claude/personalities/normal.md +16 -16
- package/.claude/personalities/pirate.md +14 -14
- package/.claude/personalities/poetic.md +14 -14
- package/.claude/personalities/professional.md +14 -14
- package/.claude/personalities/rapper.md +55 -55
- package/.claude/personalities/robot.md +14 -14
- package/.claude/personalities/sarcastic.md +38 -38
- package/.claude/personalities/sassy.md +14 -14
- package/.claude/personalities/surfer-dude.md +14 -14
- package/.claude/personalities/zen.md +14 -14
- package/.claude/settings.json +15 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +241 -241
- package/.mcp.json +12 -0
- package/CLAUDE.md +170 -170
- package/README.md +2029 -2007
- package/RELEASE_NOTES.md +1310 -1203
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/agentvibes-voice-browser.js +1840 -1840
- package/bin/agentvibes.js +48 -2
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +206 -206
- package/bin/test-bmad-pr +78 -78
- package/mcp-server/QUICK_START.md +203 -203
- package/mcp-server/README.md +345 -345
- package/mcp-server/WINDOWS_SETUP.md +260 -260
- package/mcp-server/docs/troubleshooting-audio.md +313 -313
- package/mcp-server/examples/claude_desktop_config.json +11 -11
- package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
- package/mcp-server/examples/custom_instructions.md +169 -169
- package/mcp-server/install-deps.js +130 -130
- package/mcp-server/pyproject.toml +52 -52
- package/mcp-server/requirements.txt +2 -2
- package/mcp-server/server.py +1465 -1453
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +336 -0
- package/package.json +110 -110
- package/setup-windows.ps1 +815 -815
- package/src/bmad-detector.js +71 -71
- package/src/cli/list-personalities.js +110 -110
- package/src/cli/list-voices.js +114 -114
- package/src/commands/bmad-voices.js +394 -394
- package/src/commands/install-mcp.js +476 -476
- package/src/console/app.js +824 -824
- package/src/console/audio-env.js +20 -1
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/footer-config.js +50 -50
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +62 -62
- package/src/console/tabs/agents-tab.js +1684 -1516
- package/src/console/tabs/help-tab.js +261 -261
- package/src/console/tabs/install-tab.js +1007 -991
- package/src/console/tabs/music-tab.js +22 -8
- package/src/console/tabs/placeholder-tab.js +53 -53
- package/src/console/tabs/readme-tab.js +267 -267
- package/src/console/tabs/receiver-tab.js +1472 -1212
- package/src/console/tabs/settings-tab.js +208 -84
- package/src/console/tabs/voices-tab.js +100 -21
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/format-utils.js +89 -89
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/personality-picker.js +185 -185
- package/src/console/widgets/reverb-picker.js +94 -94
- package/src/console/widgets/track-picker.js +285 -285
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +5895 -5829
- package/src/services/agent-voice-store.js +423 -423
- package/src/services/config-service.js +264 -264
- package/src/services/navigation-service.js +123 -123
- package/src/services/provider-service.js +143 -132
- package/src/services/verbosity-service.js +157 -157
- package/src/utils/audio-duration-validator.js +298 -298
- package/src/utils/audio-format-validator.js +277 -277
- package/src/utils/dependency-checker.js +469 -466
- package/src/utils/file-ownership-verifier.js +358 -358
- package/src/utils/list-formatter.js +194 -194
- package/src/utils/music-file-validator.js +285 -285
- package/src/utils/preview-list-prompt.js +136 -136
- package/src/utils/provider-validator.js +96 -12
- package/src/utils/secure-music-storage.js +412 -412
- package/templates/agentvibes-receiver.sh +482 -482
- package/templates/audio/welcome-music.mp3 +0 -0
- package/voice-assignments.json +8244 -8244
- package/.claude/config/background-music-position.txt +0 -1
|
@@ -1,362 +1,362 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# File: .claude/hooks/language-manager.sh
|
|
4
|
-
#
|
|
5
|
-
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
6
|
-
# Website: https://agentvibes.org
|
|
7
|
-
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
8
|
-
#
|
|
9
|
-
# Co-created by Paul Preibisch with Claude AI
|
|
10
|
-
# Copyright (c) 2025 Paul Preibisch
|
|
11
|
-
#
|
|
12
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
-
# you may not use this file except in compliance with the License.
|
|
14
|
-
# You may obtain a copy of the License at
|
|
15
|
-
#
|
|
16
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
-
#
|
|
18
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
19
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
-
# See the License for the specific language governing permissions and
|
|
22
|
-
# limitations under the License.
|
|
23
|
-
#
|
|
24
|
-
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
25
|
-
# express or implied. Use at your own risk. See the Apache License for details.
|
|
26
|
-
#
|
|
27
|
-
# ---
|
|
28
|
-
#
|
|
29
|
-
# @fileoverview Language Manager - Manages multilingual TTS with 30+ language support
|
|
30
|
-
# @context Enables TTS in multiple languages with provider-specific voice recommendations (Piper native voices)
|
|
31
|
-
# @architecture Dual-map system: PIPER_VOICES for provider-aware voice selection
|
|
32
|
-
# @dependencies provider-manager.sh for active provider detection, .claude/tts-language.txt for state
|
|
33
|
-
# @entrypoints Called by /agent-vibes:language commands, play-tts-*.sh for voice resolution
|
|
34
|
-
# @patterns Provider abstraction, language-to-voice mapping, backward compatibility with legacy LANGUAGE_VOICES
|
|
35
|
-
# @related play-tts-piper.sh, provider-manager.sh, learn-manager.sh
|
|
36
|
-
|
|
37
|
-
# Determine target .claude directory based on context
|
|
38
|
-
# Priority:
|
|
39
|
-
# 1. CLAUDE_PROJECT_DIR env var (set by MCP for project-specific settings)
|
|
40
|
-
# 2. Script location (for direct slash command usage)
|
|
41
|
-
# 3. Global ~/.claude (fallback)
|
|
42
|
-
|
|
43
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
44
|
-
|
|
45
|
-
if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]] && [[ -d "${CLAUDE_PROJECT_DIR:-}/.claude" ]]; then
|
|
46
|
-
# MCP context: Use the project directory where MCP was invoked
|
|
47
|
-
CLAUDE_DIR="$CLAUDE_PROJECT_DIR/.claude"
|
|
48
|
-
else
|
|
49
|
-
# Direct usage context: Use script location
|
|
50
|
-
CLAUDE_DIR="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
|
|
51
|
-
|
|
52
|
-
# If script is in global ~/.claude, use that
|
|
53
|
-
if [[ "$CLAUDE_DIR" == "$HOME/.claude" ]]; then
|
|
54
|
-
CLAUDE_DIR="$HOME/.claude"
|
|
55
|
-
elif [[ ! -d "$CLAUDE_DIR" ]]; then
|
|
56
|
-
# Fallback to global if directory doesn't exist
|
|
57
|
-
CLAUDE_DIR="$HOME/.claude"
|
|
58
|
-
fi
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
LANGUAGE_FILE="$CLAUDE_DIR/tts-language.txt"
|
|
62
|
-
mkdir -p "$CLAUDE_DIR"
|
|
63
|
-
|
|
64
|
-
# Source provider manager to detect active provider
|
|
65
|
-
source "$SCRIPT_DIR/provider-manager.sh" 2>/dev/null || true
|
|
66
|
-
|
|
67
|
-
# =============================================================================
|
|
68
|
-
# BASH 3.2 COMPATIBILITY: Function-based lookups instead of associative arrays
|
|
69
|
-
# macOS ships with Bash 3.2 which doesn't support declare -A (added in Bash 4.0)
|
|
70
|
-
# =============================================================================
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# Get Piper voice for a language
|
|
74
|
-
_get_piper_voice() {
|
|
75
|
-
local lang="$1"
|
|
76
|
-
case "$lang" in
|
|
77
|
-
spanish) echo "es_ES-davefx-medium" ;;
|
|
78
|
-
french) echo "fr_FR-siwis-medium" ;;
|
|
79
|
-
german) echo "de_DE-thorsten-medium" ;;
|
|
80
|
-
italian) echo "it_IT-riccardo-x_low" ;;
|
|
81
|
-
portuguese) echo "pt_BR-faber-medium" ;;
|
|
82
|
-
chinese) echo "zh_CN-huayan-medium" ;;
|
|
83
|
-
japanese) echo "ja_JP-hikari-medium" ;;
|
|
84
|
-
korean) echo "ko_KR-eunyoung-medium" ;;
|
|
85
|
-
russian) echo "ru_RU-dmitri-medium" ;;
|
|
86
|
-
polish) echo "pl_PL-darkman-medium" ;;
|
|
87
|
-
dutch) echo "nl_NL-rdh-medium" ;;
|
|
88
|
-
turkish) echo "tr_TR-dfki-medium" ;;
|
|
89
|
-
arabic) echo "ar_JO-kareem-medium" ;;
|
|
90
|
-
hindi) echo "hi_IN-amitabh-medium" ;;
|
|
91
|
-
swedish) echo "sv_SE-nst-medium" ;;
|
|
92
|
-
danish) echo "da_DK-talesyntese-medium" ;;
|
|
93
|
-
norwegian) echo "no_NO-talesyntese-medium" ;;
|
|
94
|
-
finnish) echo "fi_FI-harri-medium" ;;
|
|
95
|
-
czech) echo "cs_CZ-jirka-medium" ;;
|
|
96
|
-
romanian) echo "ro_RO-mihai-medium" ;;
|
|
97
|
-
ukrainian) echo "uk_UA-lada-x_low" ;;
|
|
98
|
-
greek) echo "el_GR-rapunzelina-low" ;;
|
|
99
|
-
bulgarian) echo "bg_BG-valentin-medium" ;;
|
|
100
|
-
croatian) echo "hr_HR-gorana-medium" ;;
|
|
101
|
-
slovak) echo "sk_SK-lili-medium" ;;
|
|
102
|
-
*) echo "" ;;
|
|
103
|
-
esac
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
# Get default (Piper) voice for a language - backward compatibility
|
|
107
|
-
_get_language_voice() {
|
|
108
|
-
_get_piper_voice "$1"
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
# Check if language is supported
|
|
112
|
-
_is_language_supported() {
|
|
113
|
-
local lang="$1"
|
|
114
|
-
local voice
|
|
115
|
-
voice=$(_get_piper_voice "$lang")
|
|
116
|
-
[[ -n "$voice" ]]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
# Supported languages list
|
|
120
|
-
SUPPORTED_LANGUAGES="spanish, french, german, italian, portuguese, chinese, japanese, korean, polish, dutch, turkish, russian, arabic, hindi, swedish, danish, norwegian, finnish, czech, romanian, ukrainian, greek, bulgarian, croatian, slovak"
|
|
121
|
-
|
|
122
|
-
# Function to set language
|
|
123
|
-
set_language() {
|
|
124
|
-
local lang="$1"
|
|
125
|
-
|
|
126
|
-
# Convert to lowercase
|
|
127
|
-
lang=$(echo "$lang" | tr '[:upper:]' '[:lower:]')
|
|
128
|
-
|
|
129
|
-
# Handle reset/english
|
|
130
|
-
if [[ "$lang" == "reset" ]] || [[ "$lang" == "english" ]] || [[ "$lang" == "en" ]]; then
|
|
131
|
-
if [[ -f "$LANGUAGE_FILE" ]]; then
|
|
132
|
-
rm "$LANGUAGE_FILE"
|
|
133
|
-
echo "✓ Language reset to English (default)"
|
|
134
|
-
else
|
|
135
|
-
echo "Already using English (default)"
|
|
136
|
-
fi
|
|
137
|
-
return 0
|
|
138
|
-
fi
|
|
139
|
-
|
|
140
|
-
# Check if language is supported (Bash 3.2 compatible)
|
|
141
|
-
if ! _is_language_supported "$lang"; then
|
|
142
|
-
echo "❌ Language '$lang' not supported"
|
|
143
|
-
echo ""
|
|
144
|
-
echo "Supported languages:"
|
|
145
|
-
echo "$SUPPORTED_LANGUAGES"
|
|
146
|
-
return 1
|
|
147
|
-
fi
|
|
148
|
-
|
|
149
|
-
# Save language
|
|
150
|
-
echo "$lang" > "$LANGUAGE_FILE"
|
|
151
|
-
|
|
152
|
-
# Detect active provider and get recommended voice
|
|
153
|
-
local provider=""
|
|
154
|
-
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
155
|
-
provider=$(cat "$CLAUDE_DIR/tts-provider.txt")
|
|
156
|
-
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
157
|
-
provider=$(cat "$HOME/.claude/tts-provider.txt")
|
|
158
|
-
else
|
|
159
|
-
provider="piper"
|
|
160
|
-
fi
|
|
161
|
-
|
|
162
|
-
local recommended_voice
|
|
163
|
-
recommended_voice=$(get_voice_for_language "$lang" "$provider")
|
|
164
|
-
|
|
165
|
-
# Fallback to default mapping if provider-aware function returns empty
|
|
166
|
-
if [[ -z "$recommended_voice" ]]; then
|
|
167
|
-
recommended_voice=$(_get_language_voice "$lang")
|
|
168
|
-
fi
|
|
169
|
-
|
|
170
|
-
echo "✓ Language set to: $lang"
|
|
171
|
-
echo "📢 Recommended voice for $provider TTS: $recommended_voice"
|
|
172
|
-
echo ""
|
|
173
|
-
echo "TTS will now speak in $lang."
|
|
174
|
-
echo "Switch voice with: /agent-vibes:switch \"$recommended_voice\""
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
# Function to get current language
|
|
178
|
-
get_language() {
|
|
179
|
-
if [[ -f "$LANGUAGE_FILE" ]]; then
|
|
180
|
-
local lang=$(cat "$LANGUAGE_FILE")
|
|
181
|
-
|
|
182
|
-
# Detect active provider
|
|
183
|
-
local provider=""
|
|
184
|
-
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
185
|
-
provider=$(cat "$CLAUDE_DIR/tts-provider.txt")
|
|
186
|
-
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
187
|
-
provider=$(cat "$HOME/.claude/tts-provider.txt")
|
|
188
|
-
else
|
|
189
|
-
provider="piper"
|
|
190
|
-
fi
|
|
191
|
-
|
|
192
|
-
local recommended_voice
|
|
193
|
-
recommended_voice=$(get_voice_for_language "$lang" "$provider")
|
|
194
|
-
|
|
195
|
-
# Fallback to default mapping
|
|
196
|
-
if [[ -z "$recommended_voice" ]]; then
|
|
197
|
-
recommended_voice=$(_get_language_voice "$lang")
|
|
198
|
-
fi
|
|
199
|
-
|
|
200
|
-
echo "Current language: $lang"
|
|
201
|
-
echo "Recommended voice ($provider): $recommended_voice"
|
|
202
|
-
else
|
|
203
|
-
echo "Current language: english (default)"
|
|
204
|
-
echo "No multilingual voice required"
|
|
205
|
-
fi
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
# Function to get language for use in other scripts
|
|
209
|
-
get_language_code() {
|
|
210
|
-
if [[ -f "$LANGUAGE_FILE" ]]; then
|
|
211
|
-
cat "$LANGUAGE_FILE"
|
|
212
|
-
else
|
|
213
|
-
echo "english"
|
|
214
|
-
fi
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
# Function to check if current voice supports language
|
|
218
|
-
is_voice_multilingual() {
|
|
219
|
-
local voice="$1"
|
|
220
|
-
|
|
221
|
-
# List of multilingual voices
|
|
222
|
-
local multilingual_voices=("Antoni" "Rachel" "Domi" "Bella" "Charlotte" "Matilda")
|
|
223
|
-
|
|
224
|
-
for mv in "${multilingual_voices[@]}"; do
|
|
225
|
-
if [[ "$voice" == "$mv" ]]; then
|
|
226
|
-
return 0
|
|
227
|
-
fi
|
|
228
|
-
done
|
|
229
|
-
|
|
230
|
-
return 1
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
# Function to get best voice for current language
|
|
234
|
-
get_best_voice_for_language() {
|
|
235
|
-
local lang=$(get_language_code)
|
|
236
|
-
|
|
237
|
-
if [[ "$lang" == "english" ]]; then
|
|
238
|
-
# No specific multilingual voice needed for English
|
|
239
|
-
echo ""
|
|
240
|
-
return
|
|
241
|
-
fi
|
|
242
|
-
|
|
243
|
-
# Return recommended voice for language
|
|
244
|
-
_get_language_voice "$lang"
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
# Function to get voice for a specific language and provider
|
|
248
|
-
# Usage: get_voice_for_language <language> [provider]
|
|
249
|
-
# Provider: "piper" or "macos" (auto-detected if not provided)
|
|
250
|
-
get_voice_for_language() {
|
|
251
|
-
local language="$1"
|
|
252
|
-
local provider="${2:-}"
|
|
253
|
-
|
|
254
|
-
# Convert to lowercase
|
|
255
|
-
language=$(echo "$language" | tr '[:upper:]' '[:lower:]')
|
|
256
|
-
|
|
257
|
-
# Auto-detect provider if not specified
|
|
258
|
-
if [[ -z "$provider" ]]; then
|
|
259
|
-
if command -v get_active_provider &>/dev/null; then
|
|
260
|
-
provider=$(get_active_provider 2>/dev/null)
|
|
261
|
-
else
|
|
262
|
-
# Fallback to checking provider file directly
|
|
263
|
-
# Try current directory first, then search up the tree
|
|
264
|
-
local search_dir="$PWD"
|
|
265
|
-
local found=false
|
|
266
|
-
|
|
267
|
-
while [[ "$search_dir" != "/" ]]; do
|
|
268
|
-
if [[ -f "$search_dir/.claude/tts-provider.txt" ]]; then
|
|
269
|
-
provider=$(cat "$search_dir/.claude/tts-provider.txt")
|
|
270
|
-
found=true
|
|
271
|
-
break
|
|
272
|
-
fi
|
|
273
|
-
search_dir=$(dirname "$search_dir")
|
|
274
|
-
done
|
|
275
|
-
|
|
276
|
-
# If not found in project tree, check global
|
|
277
|
-
if [[ "$found" = false ]]; then
|
|
278
|
-
if [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
279
|
-
provider=$(cat "$HOME/.claude/tts-provider.txt")
|
|
280
|
-
else
|
|
281
|
-
provider="piper" # Default
|
|
282
|
-
fi
|
|
283
|
-
fi
|
|
284
|
-
fi
|
|
285
|
-
fi
|
|
286
|
-
|
|
287
|
-
# Return appropriate voice based on provider (Bash 3.2 compatible)
|
|
288
|
-
case "$provider" in
|
|
289
|
-
piper)
|
|
290
|
-
_get_piper_voice "$language"
|
|
291
|
-
;;
|
|
292
|
-
macos)
|
|
293
|
-
# macOS doesn't have per-language voices, use default
|
|
294
|
-
echo ""
|
|
295
|
-
;;
|
|
296
|
-
*)
|
|
297
|
-
_get_piper_voice "$language"
|
|
298
|
-
;;
|
|
299
|
-
esac
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
# Main command handler - only run if script is executed directly, not sourced
|
|
303
|
-
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
304
|
-
case "${1:-}" in
|
|
305
|
-
set)
|
|
306
|
-
if [[ -z "$2" ]]; then
|
|
307
|
-
echo "Usage: language-manager.sh set <language>"
|
|
308
|
-
exit 1
|
|
309
|
-
fi
|
|
310
|
-
set_language "$2"
|
|
311
|
-
;;
|
|
312
|
-
get)
|
|
313
|
-
get_language
|
|
314
|
-
;;
|
|
315
|
-
code)
|
|
316
|
-
get_language_code
|
|
317
|
-
;;
|
|
318
|
-
check-voice)
|
|
319
|
-
if [[ -z "$2" ]]; then
|
|
320
|
-
echo "Usage: language-manager.sh check-voice <voice-name>"
|
|
321
|
-
exit 1
|
|
322
|
-
fi
|
|
323
|
-
if is_voice_multilingual "$2"; then
|
|
324
|
-
echo "yes"
|
|
325
|
-
else
|
|
326
|
-
echo "no"
|
|
327
|
-
fi
|
|
328
|
-
;;
|
|
329
|
-
best-voice)
|
|
330
|
-
get_best_voice_for_language
|
|
331
|
-
;;
|
|
332
|
-
voice-for-language)
|
|
333
|
-
if [[ -z "$2" ]]; then
|
|
334
|
-
echo "Usage: language-manager.sh voice-for-language <language> [provider]"
|
|
335
|
-
exit 1
|
|
336
|
-
fi
|
|
337
|
-
get_voice_for_language "$2" "$3"
|
|
338
|
-
;;
|
|
339
|
-
list)
|
|
340
|
-
echo "Supported languages and recommended voices:"
|
|
341
|
-
echo ""
|
|
342
|
-
# Bash 3.2 compatible - use explicit list instead of associative array keys
|
|
343
|
-
# Note: 'local' can't be used outside functions in Bash 3.2
|
|
344
|
-
for lang in spanish french german italian portuguese chinese japanese korean russian polish dutch turkish arabic hindi swedish danish norwegian finnish czech romanian ukrainian greek bulgarian croatian slovak; do
|
|
345
|
-
printf "%-15s → %s\n" "$lang" "$(_get_language_voice "$lang")"
|
|
346
|
-
done | sort
|
|
347
|
-
;;
|
|
348
|
-
*)
|
|
349
|
-
echo "AgentVibes Language Manager"
|
|
350
|
-
echo ""
|
|
351
|
-
echo "Usage:"
|
|
352
|
-
echo " language-manager.sh set <language> Set language"
|
|
353
|
-
echo " language-manager.sh get Get current language"
|
|
354
|
-
echo " language-manager.sh code Get language code only"
|
|
355
|
-
echo " language-manager.sh check-voice <name> Check if voice is multilingual"
|
|
356
|
-
echo " language-manager.sh best-voice Get best voice for current language"
|
|
357
|
-
echo " language-manager.sh voice-for-language <lang> [prov] Get voice for language & provider"
|
|
358
|
-
echo " language-manager.sh list List all supported languages"
|
|
359
|
-
exit 1
|
|
360
|
-
;;
|
|
361
|
-
esac
|
|
362
|
-
fi
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# File: .claude/hooks/language-manager.sh
|
|
4
|
+
#
|
|
5
|
+
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
6
|
+
# Website: https://agentvibes.org
|
|
7
|
+
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
8
|
+
#
|
|
9
|
+
# Co-created by Paul Preibisch with Claude AI
|
|
10
|
+
# Copyright (c) 2025 Paul Preibisch
|
|
11
|
+
#
|
|
12
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
# you may not use this file except in compliance with the License.
|
|
14
|
+
# You may obtain a copy of the License at
|
|
15
|
+
#
|
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
#
|
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
# See the License for the specific language governing permissions and
|
|
22
|
+
# limitations under the License.
|
|
23
|
+
#
|
|
24
|
+
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
25
|
+
# express or implied. Use at your own risk. See the Apache License for details.
|
|
26
|
+
#
|
|
27
|
+
# ---
|
|
28
|
+
#
|
|
29
|
+
# @fileoverview Language Manager - Manages multilingual TTS with 30+ language support
|
|
30
|
+
# @context Enables TTS in multiple languages with provider-specific voice recommendations (Piper native voices)
|
|
31
|
+
# @architecture Dual-map system: PIPER_VOICES for provider-aware voice selection
|
|
32
|
+
# @dependencies provider-manager.sh for active provider detection, .claude/tts-language.txt for state
|
|
33
|
+
# @entrypoints Called by /agent-vibes:language commands, play-tts-*.sh for voice resolution
|
|
34
|
+
# @patterns Provider abstraction, language-to-voice mapping, backward compatibility with legacy LANGUAGE_VOICES
|
|
35
|
+
# @related play-tts-piper.sh, provider-manager.sh, learn-manager.sh
|
|
36
|
+
|
|
37
|
+
# Determine target .claude directory based on context
|
|
38
|
+
# Priority:
|
|
39
|
+
# 1. CLAUDE_PROJECT_DIR env var (set by MCP for project-specific settings)
|
|
40
|
+
# 2. Script location (for direct slash command usage)
|
|
41
|
+
# 3. Global ~/.claude (fallback)
|
|
42
|
+
|
|
43
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
44
|
+
|
|
45
|
+
if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]] && [[ -d "${CLAUDE_PROJECT_DIR:-}/.claude" ]]; then
|
|
46
|
+
# MCP context: Use the project directory where MCP was invoked
|
|
47
|
+
CLAUDE_DIR="$CLAUDE_PROJECT_DIR/.claude"
|
|
48
|
+
else
|
|
49
|
+
# Direct usage context: Use script location
|
|
50
|
+
CLAUDE_DIR="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
|
|
51
|
+
|
|
52
|
+
# If script is in global ~/.claude, use that
|
|
53
|
+
if [[ "$CLAUDE_DIR" == "$HOME/.claude" ]]; then
|
|
54
|
+
CLAUDE_DIR="$HOME/.claude"
|
|
55
|
+
elif [[ ! -d "$CLAUDE_DIR" ]]; then
|
|
56
|
+
# Fallback to global if directory doesn't exist
|
|
57
|
+
CLAUDE_DIR="$HOME/.claude"
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
LANGUAGE_FILE="$CLAUDE_DIR/tts-language.txt"
|
|
62
|
+
mkdir -p "$CLAUDE_DIR"
|
|
63
|
+
|
|
64
|
+
# Source provider manager to detect active provider
|
|
65
|
+
source "$SCRIPT_DIR/provider-manager.sh" 2>/dev/null || true
|
|
66
|
+
|
|
67
|
+
# =============================================================================
|
|
68
|
+
# BASH 3.2 COMPATIBILITY: Function-based lookups instead of associative arrays
|
|
69
|
+
# macOS ships with Bash 3.2 which doesn't support declare -A (added in Bash 4.0)
|
|
70
|
+
# =============================================================================
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# Get Piper voice for a language
|
|
74
|
+
_get_piper_voice() {
|
|
75
|
+
local lang="$1"
|
|
76
|
+
case "$lang" in
|
|
77
|
+
spanish) echo "es_ES-davefx-medium" ;;
|
|
78
|
+
french) echo "fr_FR-siwis-medium" ;;
|
|
79
|
+
german) echo "de_DE-thorsten-medium" ;;
|
|
80
|
+
italian) echo "it_IT-riccardo-x_low" ;;
|
|
81
|
+
portuguese) echo "pt_BR-faber-medium" ;;
|
|
82
|
+
chinese) echo "zh_CN-huayan-medium" ;;
|
|
83
|
+
japanese) echo "ja_JP-hikari-medium" ;;
|
|
84
|
+
korean) echo "ko_KR-eunyoung-medium" ;;
|
|
85
|
+
russian) echo "ru_RU-dmitri-medium" ;;
|
|
86
|
+
polish) echo "pl_PL-darkman-medium" ;;
|
|
87
|
+
dutch) echo "nl_NL-rdh-medium" ;;
|
|
88
|
+
turkish) echo "tr_TR-dfki-medium" ;;
|
|
89
|
+
arabic) echo "ar_JO-kareem-medium" ;;
|
|
90
|
+
hindi) echo "hi_IN-amitabh-medium" ;;
|
|
91
|
+
swedish) echo "sv_SE-nst-medium" ;;
|
|
92
|
+
danish) echo "da_DK-talesyntese-medium" ;;
|
|
93
|
+
norwegian) echo "no_NO-talesyntese-medium" ;;
|
|
94
|
+
finnish) echo "fi_FI-harri-medium" ;;
|
|
95
|
+
czech) echo "cs_CZ-jirka-medium" ;;
|
|
96
|
+
romanian) echo "ro_RO-mihai-medium" ;;
|
|
97
|
+
ukrainian) echo "uk_UA-lada-x_low" ;;
|
|
98
|
+
greek) echo "el_GR-rapunzelina-low" ;;
|
|
99
|
+
bulgarian) echo "bg_BG-valentin-medium" ;;
|
|
100
|
+
croatian) echo "hr_HR-gorana-medium" ;;
|
|
101
|
+
slovak) echo "sk_SK-lili-medium" ;;
|
|
102
|
+
*) echo "" ;;
|
|
103
|
+
esac
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Get default (Piper) voice for a language - backward compatibility
|
|
107
|
+
_get_language_voice() {
|
|
108
|
+
_get_piper_voice "$1"
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Check if language is supported
|
|
112
|
+
_is_language_supported() {
|
|
113
|
+
local lang="$1"
|
|
114
|
+
local voice
|
|
115
|
+
voice=$(_get_piper_voice "$lang")
|
|
116
|
+
[[ -n "$voice" ]]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Supported languages list
|
|
120
|
+
SUPPORTED_LANGUAGES="spanish, french, german, italian, portuguese, chinese, japanese, korean, polish, dutch, turkish, russian, arabic, hindi, swedish, danish, norwegian, finnish, czech, romanian, ukrainian, greek, bulgarian, croatian, slovak"
|
|
121
|
+
|
|
122
|
+
# Function to set language
|
|
123
|
+
set_language() {
|
|
124
|
+
local lang="$1"
|
|
125
|
+
|
|
126
|
+
# Convert to lowercase
|
|
127
|
+
lang=$(echo "$lang" | tr '[:upper:]' '[:lower:]')
|
|
128
|
+
|
|
129
|
+
# Handle reset/english
|
|
130
|
+
if [[ "$lang" == "reset" ]] || [[ "$lang" == "english" ]] || [[ "$lang" == "en" ]]; then
|
|
131
|
+
if [[ -f "$LANGUAGE_FILE" ]]; then
|
|
132
|
+
rm "$LANGUAGE_FILE"
|
|
133
|
+
echo "✓ Language reset to English (default)"
|
|
134
|
+
else
|
|
135
|
+
echo "Already using English (default)"
|
|
136
|
+
fi
|
|
137
|
+
return 0
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# Check if language is supported (Bash 3.2 compatible)
|
|
141
|
+
if ! _is_language_supported "$lang"; then
|
|
142
|
+
echo "❌ Language '$lang' not supported"
|
|
143
|
+
echo ""
|
|
144
|
+
echo "Supported languages:"
|
|
145
|
+
echo "$SUPPORTED_LANGUAGES"
|
|
146
|
+
return 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Save language
|
|
150
|
+
echo "$lang" > "$LANGUAGE_FILE"
|
|
151
|
+
|
|
152
|
+
# Detect active provider and get recommended voice
|
|
153
|
+
local provider=""
|
|
154
|
+
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
155
|
+
provider=$(cat "$CLAUDE_DIR/tts-provider.txt")
|
|
156
|
+
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
157
|
+
provider=$(cat "$HOME/.claude/tts-provider.txt")
|
|
158
|
+
else
|
|
159
|
+
provider="piper"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
local recommended_voice
|
|
163
|
+
recommended_voice=$(get_voice_for_language "$lang" "$provider")
|
|
164
|
+
|
|
165
|
+
# Fallback to default mapping if provider-aware function returns empty
|
|
166
|
+
if [[ -z "$recommended_voice" ]]; then
|
|
167
|
+
recommended_voice=$(_get_language_voice "$lang")
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
echo "✓ Language set to: $lang"
|
|
171
|
+
echo "📢 Recommended voice for $provider TTS: $recommended_voice"
|
|
172
|
+
echo ""
|
|
173
|
+
echo "TTS will now speak in $lang."
|
|
174
|
+
echo "Switch voice with: /agent-vibes:switch \"$recommended_voice\""
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Function to get current language
|
|
178
|
+
get_language() {
|
|
179
|
+
if [[ -f "$LANGUAGE_FILE" ]]; then
|
|
180
|
+
local lang=$(cat "$LANGUAGE_FILE")
|
|
181
|
+
|
|
182
|
+
# Detect active provider
|
|
183
|
+
local provider=""
|
|
184
|
+
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
185
|
+
provider=$(cat "$CLAUDE_DIR/tts-provider.txt")
|
|
186
|
+
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
187
|
+
provider=$(cat "$HOME/.claude/tts-provider.txt")
|
|
188
|
+
else
|
|
189
|
+
provider="piper"
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
local recommended_voice
|
|
193
|
+
recommended_voice=$(get_voice_for_language "$lang" "$provider")
|
|
194
|
+
|
|
195
|
+
# Fallback to default mapping
|
|
196
|
+
if [[ -z "$recommended_voice" ]]; then
|
|
197
|
+
recommended_voice=$(_get_language_voice "$lang")
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
echo "Current language: $lang"
|
|
201
|
+
echo "Recommended voice ($provider): $recommended_voice"
|
|
202
|
+
else
|
|
203
|
+
echo "Current language: english (default)"
|
|
204
|
+
echo "No multilingual voice required"
|
|
205
|
+
fi
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# Function to get language for use in other scripts
|
|
209
|
+
get_language_code() {
|
|
210
|
+
if [[ -f "$LANGUAGE_FILE" ]]; then
|
|
211
|
+
cat "$LANGUAGE_FILE"
|
|
212
|
+
else
|
|
213
|
+
echo "english"
|
|
214
|
+
fi
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Function to check if current voice supports language
|
|
218
|
+
is_voice_multilingual() {
|
|
219
|
+
local voice="$1"
|
|
220
|
+
|
|
221
|
+
# List of multilingual voices
|
|
222
|
+
local multilingual_voices=("Antoni" "Rachel" "Domi" "Bella" "Charlotte" "Matilda")
|
|
223
|
+
|
|
224
|
+
for mv in "${multilingual_voices[@]}"; do
|
|
225
|
+
if [[ "$voice" == "$mv" ]]; then
|
|
226
|
+
return 0
|
|
227
|
+
fi
|
|
228
|
+
done
|
|
229
|
+
|
|
230
|
+
return 1
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Function to get best voice for current language
|
|
234
|
+
get_best_voice_for_language() {
|
|
235
|
+
local lang=$(get_language_code)
|
|
236
|
+
|
|
237
|
+
if [[ "$lang" == "english" ]]; then
|
|
238
|
+
# No specific multilingual voice needed for English
|
|
239
|
+
echo ""
|
|
240
|
+
return
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Return recommended voice for language
|
|
244
|
+
_get_language_voice "$lang"
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
# Function to get voice for a specific language and provider
|
|
248
|
+
# Usage: get_voice_for_language <language> [provider]
|
|
249
|
+
# Provider: "piper" or "macos" (auto-detected if not provided)
|
|
250
|
+
get_voice_for_language() {
|
|
251
|
+
local language="$1"
|
|
252
|
+
local provider="${2:-}"
|
|
253
|
+
|
|
254
|
+
# Convert to lowercase
|
|
255
|
+
language=$(echo "$language" | tr '[:upper:]' '[:lower:]')
|
|
256
|
+
|
|
257
|
+
# Auto-detect provider if not specified
|
|
258
|
+
if [[ -z "$provider" ]]; then
|
|
259
|
+
if command -v get_active_provider &>/dev/null; then
|
|
260
|
+
provider=$(get_active_provider 2>/dev/null)
|
|
261
|
+
else
|
|
262
|
+
# Fallback to checking provider file directly
|
|
263
|
+
# Try current directory first, then search up the tree
|
|
264
|
+
local search_dir="$PWD"
|
|
265
|
+
local found=false
|
|
266
|
+
|
|
267
|
+
while [[ "$search_dir" != "/" ]]; do
|
|
268
|
+
if [[ -f "$search_dir/.claude/tts-provider.txt" ]]; then
|
|
269
|
+
provider=$(cat "$search_dir/.claude/tts-provider.txt")
|
|
270
|
+
found=true
|
|
271
|
+
break
|
|
272
|
+
fi
|
|
273
|
+
search_dir=$(dirname "$search_dir")
|
|
274
|
+
done
|
|
275
|
+
|
|
276
|
+
# If not found in project tree, check global
|
|
277
|
+
if [[ "$found" = false ]]; then
|
|
278
|
+
if [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
279
|
+
provider=$(cat "$HOME/.claude/tts-provider.txt")
|
|
280
|
+
else
|
|
281
|
+
provider="piper" # Default
|
|
282
|
+
fi
|
|
283
|
+
fi
|
|
284
|
+
fi
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
# Return appropriate voice based on provider (Bash 3.2 compatible)
|
|
288
|
+
case "$provider" in
|
|
289
|
+
piper)
|
|
290
|
+
_get_piper_voice "$language"
|
|
291
|
+
;;
|
|
292
|
+
macos)
|
|
293
|
+
# macOS doesn't have per-language voices, use default
|
|
294
|
+
echo ""
|
|
295
|
+
;;
|
|
296
|
+
*)
|
|
297
|
+
_get_piper_voice "$language"
|
|
298
|
+
;;
|
|
299
|
+
esac
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# Main command handler - only run if script is executed directly, not sourced
|
|
303
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
304
|
+
case "${1:-}" in
|
|
305
|
+
set)
|
|
306
|
+
if [[ -z "$2" ]]; then
|
|
307
|
+
echo "Usage: language-manager.sh set <language>"
|
|
308
|
+
exit 1
|
|
309
|
+
fi
|
|
310
|
+
set_language "$2"
|
|
311
|
+
;;
|
|
312
|
+
get)
|
|
313
|
+
get_language
|
|
314
|
+
;;
|
|
315
|
+
code)
|
|
316
|
+
get_language_code
|
|
317
|
+
;;
|
|
318
|
+
check-voice)
|
|
319
|
+
if [[ -z "$2" ]]; then
|
|
320
|
+
echo "Usage: language-manager.sh check-voice <voice-name>"
|
|
321
|
+
exit 1
|
|
322
|
+
fi
|
|
323
|
+
if is_voice_multilingual "$2"; then
|
|
324
|
+
echo "yes"
|
|
325
|
+
else
|
|
326
|
+
echo "no"
|
|
327
|
+
fi
|
|
328
|
+
;;
|
|
329
|
+
best-voice)
|
|
330
|
+
get_best_voice_for_language
|
|
331
|
+
;;
|
|
332
|
+
voice-for-language)
|
|
333
|
+
if [[ -z "$2" ]]; then
|
|
334
|
+
echo "Usage: language-manager.sh voice-for-language <language> [provider]"
|
|
335
|
+
exit 1
|
|
336
|
+
fi
|
|
337
|
+
get_voice_for_language "$2" "$3"
|
|
338
|
+
;;
|
|
339
|
+
list)
|
|
340
|
+
echo "Supported languages and recommended voices:"
|
|
341
|
+
echo ""
|
|
342
|
+
# Bash 3.2 compatible - use explicit list instead of associative array keys
|
|
343
|
+
# Note: 'local' can't be used outside functions in Bash 3.2
|
|
344
|
+
for lang in spanish french german italian portuguese chinese japanese korean russian polish dutch turkish arabic hindi swedish danish norwegian finnish czech romanian ukrainian greek bulgarian croatian slovak; do
|
|
345
|
+
printf "%-15s → %s\n" "$lang" "$(_get_language_voice "$lang")"
|
|
346
|
+
done | sort
|
|
347
|
+
;;
|
|
348
|
+
*)
|
|
349
|
+
echo "AgentVibes Language Manager"
|
|
350
|
+
echo ""
|
|
351
|
+
echo "Usage:"
|
|
352
|
+
echo " language-manager.sh set <language> Set language"
|
|
353
|
+
echo " language-manager.sh get Get current language"
|
|
354
|
+
echo " language-manager.sh code Get language code only"
|
|
355
|
+
echo " language-manager.sh check-voice <name> Check if voice is multilingual"
|
|
356
|
+
echo " language-manager.sh best-voice Get best voice for current language"
|
|
357
|
+
echo " language-manager.sh voice-for-language <lang> [prov] Get voice for language & provider"
|
|
358
|
+
echo " language-manager.sh list List all supported languages"
|
|
359
|
+
exit 1
|
|
360
|
+
;;
|
|
361
|
+
esac
|
|
362
|
+
fi
|