agentvibes 2.13.8 → 2.14.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.
@@ -161,20 +161,22 @@ The TTS injection works with **any configured TTS provider**:
161
161
 
162
162
  The system automatically detects your configured provider via `/agent-vibes:provider info` and uses the appropriate TTS engine. You can switch providers anytime with `/agent-vibes:provider switch` and the BMAD agents will continue speaking using the new provider.
163
163
 
164
- ## Available BMAD Agents
165
-
166
- | Agent ID | Role | Default Voice |
167
- |----------|------|---------------|
168
- | pm | Product Manager | Matthew Schmitz |
169
- | dev | Developer | Jessica Anne Bogart |
170
- | qa | QA Engineer | Ralf Eisend |
171
- | architect | Architect | Michael |
172
- | po | Product Owner | Amy |
173
- | analyst | Analyst | Lutz Laugh |
174
- | sm | Scrum Master | Ms. Walker |
175
- | ux-expert | UX Expert | Aria |
176
- | bmad-master | BMAD Master | Aria |
177
- | bmad-orchestrator | Orchestrator | Ms. Walker |
164
+ ## Available BMAD Agents (Provider-Aware)
165
+
166
+ The voice used depends on your active TTS provider. Run `/agent-vibes:provider info` to check your provider.
167
+
168
+ | Agent ID | Role | ElevenLabs Voice | Piper Voice |
169
+ |----------|------|------------------|-------------|
170
+ | pm | Product Manager | Matthew Schmitz | en_US-ryan-high |
171
+ | dev | Developer | Aria | en_US-amy-medium |
172
+ | analyst | Business Analyst | Jessica Anne Bogart | en_US-kristin-medium |
173
+ | architect | Architect | Michael | en_GB-alan-medium |
174
+ | sm | Scrum Master | Matthew Schmitz | en_US-joe-medium |
175
+ | tea | Test Architect | Michael | en_US-arctic-medium |
176
+ | tech-writer | Technical Writer | Aria | en_US-lessac-medium |
177
+ | ux-designer | UX Designer | Jessica Anne Bogart | en_US-lessac-medium |
178
+ | frame-expert | Visual Designer | Matthew Schmitz | en_GB-alan-medium |
179
+ | bmad-master | BMAD Master | Michael | en_US-danny-low |
178
180
 
179
181
  ## Implementation Details
180
182
 
@@ -0,0 +1,68 @@
1
+ ---
2
+ description: 'Configure automatic TTS translation to speak in your preferred language'
3
+ ---
4
+
5
+ # /agent-vibes:translate - Multi-Language TTS Translation
6
+
7
+ Configure AgentVibes to automatically translate English TTS text to your preferred language before speaking.
8
+
9
+ **Usage:**
10
+ - `/agent-vibes:translate` - Show current translation settings
11
+ - `/agent-vibes:translate set <language>` - Set translation language
12
+ - `/agent-vibes:translate auto` - Use BMAD communication_language setting
13
+ - `/agent-vibes:translate off` - Disable translation (speak English)
14
+ - `/agent-vibes:translate status` - Show detailed status
15
+
16
+ **Arguments:** $ARGUMENTS
17
+
18
+ ## How It Works
19
+
20
+ When translation is enabled, AgentVibes will:
21
+ 1. Take the English TTS text
22
+ 2. Translate it to your target language using Google Translate
23
+ 3. Speak the translated text using a language-appropriate voice
24
+
25
+ ## Priority Order
26
+
27
+ 1. **Manual override** (`/agent-vibes:translate set spanish`) - Highest priority
28
+ 2. **BMAD config** (`communication_language` in `.bmad/core/config.yaml`) - Auto-detected
29
+ 3. **Default** - No translation (English)
30
+
31
+ ## Supported Languages
32
+
33
+ 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
34
+
35
+ ## Examples
36
+
37
+ ```bash
38
+ # Translate all TTS to Spanish
39
+ /agent-vibes:translate set spanish
40
+
41
+ # Use BMAD's communication_language setting
42
+ /agent-vibes:translate auto
43
+
44
+ # Disable translation (speak English)
45
+ /agent-vibes:translate off
46
+
47
+ # Check current settings
48
+ /agent-vibes:translate status
49
+ ```
50
+
51
+ ## Integration with BMAD
52
+
53
+ If you have BMAD installed with a `communication_language` setting:
54
+
55
+ ```yaml
56
+ # .bmad/core/config.yaml
57
+ communication_language: Spanish
58
+ ```
59
+
60
+ AgentVibes will automatically detect this and translate TTS to Spanish when you run `/agent-vibes:translate auto`.
61
+
62
+ ---
63
+
64
+ Execute the translate-manager.sh script:
65
+
66
+ ```bash
67
+ .claude/hooks/translate-manager.sh $ARGUMENTS
68
+ ```
@@ -34,10 +34,19 @@
34
34
  # @patterns Dual-voice orchestration, auto-configuration, greeting on activation, provider-aware voice selection
35
35
  # @related language-manager.sh, play-tts.sh, .claude/tts-learn-mode.txt, .claude/tts-target-language.txt
36
36
 
37
- set -e
37
+ # Only set strict mode when executed directly, not when sourced
38
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
39
+ set -e
40
+ fi
38
41
 
39
42
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
40
- PROJECT_DIR="$SCRIPT_DIR/../.."
43
+
44
+ # Use PWD for project dir when called from project context, fall back to script-relative
45
+ if [[ -d "$PWD/.claude" ]]; then
46
+ PROJECT_DIR="$PWD"
47
+ else
48
+ PROJECT_DIR="$SCRIPT_DIR/../.."
49
+ fi
41
50
 
42
51
  # Configuration files (project-local first, then global fallback)
43
52
  MAIN_LANG_FILE="$PROJECT_DIR/.claude/tts-main-language.txt"
@@ -430,7 +439,8 @@ show_status() {
430
439
  echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
431
440
  }
432
441
 
433
- # Main command handler
442
+ # Main command handler - only run if script is executed directly, not sourced
443
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
434
444
  case "${1:-}" in
435
445
  get-main-language)
436
446
  get_main_language
@@ -473,3 +483,4 @@ case "${1:-}" in
473
483
  exit 1
474
484
  ;;
475
485
  esac
486
+ fi
@@ -198,8 +198,10 @@ TEMP_FILE="$AUDIO_DIR/tts-$(date +%s).mp3"
198
198
  # @sideeffects Creates MP3 file in audio directory
199
199
  # @edgecases Handles network failures, API errors, rate limiting
200
200
  # Choose model based on language
201
+ # Note: eleven_monolingual_v1 deprecated for free tier as of Nov 2025
202
+ # Using eleven_turbo_v2_5 for English (fast, high quality, free tier compatible)
201
203
  if [[ "$LANGUAGE_CODE" == "en" ]]; then
202
- MODEL_ID="eleven_monolingual_v1"
204
+ MODEL_ID="eleven_turbo_v2_5"
203
205
  else
204
206
  MODEL_ID="eleven_multilingual_v2"
205
207
  fi
@@ -31,13 +31,13 @@
31
31
  #
32
32
  # ---
33
33
  #
34
- # @fileoverview TTS Provider Router with Language Learning Support
35
- # @context Routes TTS requests to active provider (ElevenLabs or Piper)
36
- # @architecture Provider abstraction layer - single entry point for all TTS
37
- # @dependencies provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh, github-star-reminder.sh
34
+ # @fileoverview TTS Provider Router with Translation and Language Learning Support
35
+ # @context Routes TTS requests to active provider (ElevenLabs or Piper) with optional translation
36
+ # @architecture Provider abstraction layer - single entry point for all TTS, handles translation and learning mode
37
+ # @dependencies provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh, translator.py, translate-manager.sh, learn-manager.sh
38
38
  # @entrypoints Called by hooks, slash commands, personality-manager.sh, and all TTS features
39
39
  # @patterns Provider pattern - delegates to provider-specific implementations, auto-detects provider from voice name
40
- # @related provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh, learn-manager.sh
40
+ # @related provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh, learn-manager.sh, translate-manager.sh
41
41
  #
42
42
 
43
43
  # Fix locale warnings
@@ -98,10 +98,133 @@ if [[ -n "$VOICE_OVERRIDE" ]]; then
98
98
  fi
99
99
  fi
100
100
 
101
+ # @function speak_text
102
+ # @intent Route text to appropriate TTS provider
103
+ # @why Reusable function for speaking, used by both single and learning modes
104
+ # @param $1 text to speak
105
+ # @param $2 voice override (optional)
106
+ # @param $3 provider override (optional)
107
+ speak_text() {
108
+ local text="$1"
109
+ local voice="${2:-}"
110
+ local provider="${3:-$ACTIVE_PROVIDER}"
111
+
112
+ case "$provider" in
113
+ elevenlabs)
114
+ "$SCRIPT_DIR/play-tts-elevenlabs.sh" "$text" "$voice"
115
+ ;;
116
+ piper)
117
+ "$SCRIPT_DIR/play-tts-piper.sh" "$text" "$voice"
118
+ ;;
119
+ *)
120
+ echo "❌ Unknown provider: $provider" >&2
121
+ return 1
122
+ ;;
123
+ esac
124
+ }
125
+
126
+ # Note: learn-manager.sh and translate-manager.sh are sourced inside their
127
+ # respective handler functions to avoid triggering their main handlers
128
+
129
+ # @function handle_learning_mode
130
+ # @intent Speak in both main language and target language for learning
131
+ # @why Issue #51 - Auto-translate and speak twice for immersive language learning
132
+ # @returns 0 if learning mode handled, 1 if not in learning mode
133
+ handle_learning_mode() {
134
+ # Source learn-manager for learning mode functions
135
+ source "$SCRIPT_DIR/learn-manager.sh" 2>/dev/null || return 1
136
+
137
+ # Check if learning mode is enabled
138
+ if ! is_learn_mode_enabled 2>/dev/null; then
139
+ return 1
140
+ fi
141
+
142
+ local target_lang
143
+ target_lang=$(get_target_language 2>/dev/null || echo "")
144
+ local target_voice
145
+ target_voice=$(get_target_voice 2>/dev/null || echo "")
146
+
147
+ # Need both target language and voice for learning mode
148
+ if [[ -z "$target_lang" ]] || [[ -z "$target_voice" ]]; then
149
+ return 1
150
+ fi
151
+
152
+ # 1. Speak in main language (current voice)
153
+ speak_text "$TEXT" "$VOICE_OVERRIDE" "$ACTIVE_PROVIDER"
154
+
155
+ # 2. Auto-translate to target language
156
+ local translated
157
+ translated=$(python3 "$SCRIPT_DIR/translator.py" "$TEXT" "$target_lang" 2>/dev/null) || translated="$TEXT"
158
+
159
+ # Small pause between languages
160
+ sleep 0.5
161
+
162
+ # 3. Speak translated text with target voice
163
+ local target_provider
164
+ target_provider=$(detect_voice_provider "$target_voice")
165
+ speak_text "$translated" "$target_voice" "$target_provider"
166
+
167
+ return 0
168
+ }
169
+
170
+ # @function handle_translation_mode
171
+ # @intent Translate and speak in target language (non-learning mode)
172
+ # @why Issue #50 - BMAD multi-language TTS support
173
+ # @returns 0 if translation handled, 1 if not translating
174
+ handle_translation_mode() {
175
+ # Source translate-manager to get translation settings
176
+ source "$SCRIPT_DIR/translate-manager.sh" 2>/dev/null || return 1
177
+
178
+ # Check if translation is enabled
179
+ if ! is_translation_enabled 2>/dev/null; then
180
+ return 1
181
+ fi
182
+
183
+ local translate_to
184
+ translate_to=$(get_translate_to 2>/dev/null || echo "")
185
+
186
+ if [[ -z "$translate_to" ]] || [[ "$translate_to" == "english" ]]; then
187
+ return 1
188
+ fi
189
+
190
+ # Translate text
191
+ local translated
192
+ translated=$(python3 "$SCRIPT_DIR/translator.py" "$TEXT" "$translate_to" 2>/dev/null) || translated="$TEXT"
193
+
194
+ # Get voice for target language if no override specified
195
+ local voice_to_use="$VOICE_OVERRIDE"
196
+ if [[ -z "$voice_to_use" ]]; then
197
+ source "$SCRIPT_DIR/language-manager.sh" 2>/dev/null || true
198
+ voice_to_use=$(get_voice_for_language "$translate_to" "$ACTIVE_PROVIDER" 2>/dev/null || echo "")
199
+ fi
200
+
201
+ # Update provider if voice indicates different provider
202
+ local provider_to_use="$ACTIVE_PROVIDER"
203
+ if [[ -n "$voice_to_use" ]]; then
204
+ provider_to_use=$(detect_voice_provider "$voice_to_use")
205
+ fi
206
+
207
+ # Speak translated text
208
+ speak_text "$translated" "$voice_to_use" "$provider_to_use"
209
+ return 0
210
+ }
211
+
212
+ # Mode priority:
213
+ # 1. Learning mode (speaks twice: main + translated)
214
+ # 2. Translation mode (speaks translated only)
215
+ # 3. Normal mode (speaks as-is)
216
+
217
+ # Try learning mode first (Issue #51)
218
+ if handle_learning_mode; then
219
+ exit 0
220
+ fi
221
+
222
+ # Try translation mode (Issue #50)
223
+ if handle_translation_mode; then
224
+ exit 0
225
+ fi
226
+
101
227
  # Normal single-language mode - route to appropriate provider implementation
102
- # Note: For learning mode, the output style will call this script TWICE:
103
- # 1. First call with main language text and current voice
104
- # 2. Second call with translated text and target voice
105
228
  case "$ACTIVE_PROVIDER" in
106
229
  elevenlabs)
107
230
  exec "$SCRIPT_DIR/play-tts-elevenlabs.sh" "$TEXT" "$VOICE_OVERRIDE"
@@ -141,31 +141,120 @@ set_active_provider() {
141
141
  voice_file="$HOME/.claude/tts-voice.txt"
142
142
  fi
143
143
 
144
- # Set default voice for the new provider
145
- local default_voice
146
- case "$provider" in
147
- piper)
148
- # Default Piper voice
149
- default_voice="en_US-lessac-medium"
150
- ;;
151
- elevenlabs)
152
- # Default ElevenLabs voice (first in alphabetical order from voices-config.sh)
153
- default_voice="Amy"
154
- ;;
155
- *)
156
- # Unknown provider - remove voice file
157
- if [[ -f "$voice_file" ]]; then
158
- rm -f "$voice_file"
159
- fi
160
- echo "✓ Active provider set to: $provider (voice reset)"
161
- return 0
162
- ;;
163
- esac
144
+ # Migrate voice to equivalent in new provider
145
+ local current_voice=""
146
+ if [[ -f "$voice_file" ]]; then
147
+ # Strip only leading/trailing whitespace and newlines, preserve internal spaces
148
+ current_voice=$(cat "$voice_file" | tr -d '\n\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
149
+ fi
150
+
151
+ local new_voice
152
+ new_voice=$(migrate_voice_to_provider "$current_voice" "$provider")
153
+
154
+ # Write new voice to file
155
+ echo "$new_voice" > "$voice_file"
164
156
 
165
- # Write default voice to file
166
- echo "$default_voice" > "$voice_file"
157
+ if [[ -n "$current_voice" ]] && [[ "$current_voice" != "$new_voice" ]]; then
158
+ echo " Active provider set to: $provider"
159
+ echo "🔄 Voice migrated: $current_voice → $new_voice"
160
+ else
161
+ echo "✓ Active provider set to: $provider (voice: $new_voice)"
162
+ fi
163
+ }
164
+
165
+ # @function migrate_voice_to_provider
166
+ # @intent Migrate a voice from one provider to an equivalent in the target provider
167
+ # @why Users shouldn't have to manually reconfigure voices when switching providers
168
+ # @param $1 {string} current_voice - Current voice name (may be from any provider)
169
+ # @param $2 {string} target_provider - Target provider to migrate to
170
+ # @returns Echoes equivalent voice name for target provider
171
+ # @exitcode 0=always succeeds (returns default if no mapping found)
172
+ # @sideeffects None
173
+ # @edgecases Returns provider default if voice not found in mapping table
174
+ migrate_voice_to_provider() {
175
+ local current_voice="$1"
176
+ local target_provider="$2"
177
+
178
+ # Voice mapping table: ElevenLabs <-> Piper equivalents
179
+ # Format: "elevenlabs_voice:piper_voice"
180
+ local voice_mappings=(
181
+ "Amy:en_US-amy-medium"
182
+ "Aria:en_US-amy-medium"
183
+ "Matthew Schmitz:en_US-ryan-high"
184
+ "Michael:en_GB-alan-medium"
185
+ "Jessica Anne Bogart:en_US-kristin-medium"
186
+ "Ms. Walker:en_US-lessac-medium"
187
+ "Cowboy Bob:en_US-joe-medium"
188
+ "Ralf Eisend:en_US-arctic-medium"
189
+ "Northern Terry:en_GB-alan-medium"
190
+ "Lutz Laugh:en_US-joe-medium"
191
+ "Dr. Von Fusion:en_US-danny-low"
192
+ "Demon Monster:en_US-danny-low"
193
+ "Drill Sergeant:en_US-ryan-high"
194
+ "Grandpa Spuds Oxley:en_US-joe-medium"
195
+ )
196
+
197
+ # Default voices by provider
198
+ local elevenlabs_default="Amy"
199
+ local piper_default="en_US-lessac-medium"
200
+
201
+ # If no current voice, return default for target provider
202
+ if [[ -z "$current_voice" ]]; then
203
+ case "$target_provider" in
204
+ piper) echo "$piper_default" ;;
205
+ elevenlabs) echo "$elevenlabs_default" ;;
206
+ *) echo "$piper_default" ;;
207
+ esac
208
+ return 0
209
+ fi
167
210
 
168
- echo "✓ Active provider set to: $provider (voice set to: $default_voice)"
211
+ # Convert to lowercase for case-insensitive comparison (portable)
212
+ local current_voice_lower
213
+ current_voice_lower=$(echo "$current_voice" | tr '[:upper:]' '[:lower:]')
214
+
215
+ # Search for mapping
216
+ for mapping in "${voice_mappings[@]}"; do
217
+ local el_voice="${mapping%%:*}"
218
+ local piper_voice="${mapping#*:}"
219
+ local el_voice_lower
220
+ local piper_voice_lower
221
+ el_voice_lower=$(echo "$el_voice" | tr '[:upper:]' '[:lower:]')
222
+ piper_voice_lower=$(echo "$piper_voice" | tr '[:upper:]' '[:lower:]')
223
+
224
+ case "$target_provider" in
225
+ piper)
226
+ # Switching to Piper: look for ElevenLabs voice match
227
+ if [[ "$current_voice_lower" == "$el_voice_lower" ]]; then
228
+ echo "$piper_voice"
229
+ return 0
230
+ fi
231
+ # Already a Piper voice? Keep it if valid format
232
+ if [[ "$current_voice" =~ ^en_ ]]; then
233
+ echo "$current_voice"
234
+ return 0
235
+ fi
236
+ ;;
237
+ elevenlabs)
238
+ # Switching to ElevenLabs: look for Piper voice match
239
+ if [[ "$current_voice_lower" == "$piper_voice_lower" ]]; then
240
+ echo "$el_voice"
241
+ return 0
242
+ fi
243
+ # Already an ElevenLabs voice? Keep it
244
+ if [[ ! "$current_voice" =~ ^en_ ]]; then
245
+ echo "$current_voice"
246
+ return 0
247
+ fi
248
+ ;;
249
+ esac
250
+ done
251
+
252
+ # No mapping found - return default for target provider
253
+ case "$target_provider" in
254
+ piper) echo "$piper_default" ;;
255
+ elevenlabs) echo "$elevenlabs_default" ;;
256
+ *) echo "$piper_default" ;;
257
+ esac
169
258
  }
170
259
 
171
260
  # @function list_providers
@@ -0,0 +1,6 @@
1
+ # AgentVibes TTS Hooks Requirements
2
+ # Install with: pip install -r requirements.txt
3
+
4
+ # Translation support for multi-language TTS and learning mode
5
+ deep-translator>=1.11.4
6
+ langdetect>=1.0.9