agentvibes 2.17.6 → 2.17.7
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/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/bmad-speak-enhanced.sh +2 -2
- package/.claude/hooks/bmad-speak.sh +2 -2
- package/.claude/hooks/bmad-tts-injector.sh +8 -7
- package/.claude/hooks/session-start-tts.sh +39 -79
- package/README.md +7 -7
- package/package.json +1 -1
- package/src/installer.js +61 -11
- package/.claude/hooks/play-tts.sh.bak +0 -272
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
20251218
|
|
@@ -110,8 +110,8 @@ AGENT_FOR_EFFECTS="${DISPLAY_NAME:-$AGENT_NAME_OR_ID}"
|
|
|
110
110
|
AGENT_VOICE=""
|
|
111
111
|
AGENT_INTRO=""
|
|
112
112
|
if [[ -n "$AGENT_ID" ]] && [[ -f "$SCRIPT_DIR/bmad-voice-manager.sh" ]]; then
|
|
113
|
-
AGENT_VOICE=$("$SCRIPT_DIR/bmad-voice-manager.sh" get-voice "$AGENT_ID" 2>/dev/null || echo "")
|
|
114
|
-
AGENT_INTRO=$("$SCRIPT_DIR/bmad-voice-manager.sh" get-intro "$AGENT_ID" 2>/dev/null || echo "")
|
|
113
|
+
AGENT_VOICE=$(cd "$PROJECT_ROOT" && "$SCRIPT_DIR/bmad-voice-manager.sh" get-voice "$AGENT_ID" 2>/dev/null || echo "")
|
|
114
|
+
AGENT_INTRO=$(cd "$PROJECT_ROOT" && "$SCRIPT_DIR/bmad-voice-manager.sh" get-intro "$AGENT_ID" 2>/dev/null || echo "")
|
|
115
115
|
fi
|
|
116
116
|
|
|
117
117
|
# Prepend intro text if configured
|
|
@@ -90,8 +90,8 @@ AGENT_ID=$(map_to_agent_id "$AGENT_NAME_OR_ID")
|
|
|
90
90
|
AGENT_VOICE=""
|
|
91
91
|
AGENT_INTRO=""
|
|
92
92
|
if [[ -n "$AGENT_ID" ]] && [[ -f "$SCRIPT_DIR/bmad-voice-manager.sh" ]]; then
|
|
93
|
-
AGENT_VOICE=$("$SCRIPT_DIR/bmad-voice-manager.sh" get-voice "$AGENT_ID" 2>/dev/null)
|
|
94
|
-
AGENT_INTRO=$("$SCRIPT_DIR/bmad-voice-manager.sh" get-intro "$AGENT_ID" 2>/dev/null)
|
|
93
|
+
AGENT_VOICE=$(cd "$PROJECT_ROOT" && "$SCRIPT_DIR/bmad-voice-manager.sh" get-voice "$AGENT_ID" 2>/dev/null)
|
|
94
|
+
AGENT_INTRO=$(cd "$PROJECT_ROOT" && "$SCRIPT_DIR/bmad-voice-manager.sh" get-intro "$AGENT_ID" 2>/dev/null)
|
|
95
95
|
fi
|
|
96
96
|
|
|
97
97
|
# Prepend intro text if configured (e.g., "John, Product Manager here. [dialogue]")
|
|
@@ -247,18 +247,19 @@ inject_tts() {
|
|
|
247
247
|
if [[ -n "$agent_voice" ]]; then
|
|
248
248
|
tts_step=" <step n=\"4.5\" tts=\"agentvibes\">🎤 AGENTVIBES TTS INJECTION:
|
|
249
249
|
- Create context: echo \"${agent_id}\" > .bmad-agent-context (Bash tool)
|
|
250
|
-
- Speak greeting: .claude/hooks/play-tts.sh \"Hello! I'm ready to help you.\" \"${agent_voice}\" (Bash tool)
|
|
250
|
+
- Speak greeting: bash .claude/hooks/play-tts.sh \"Hello! I'm ready to help you.\" \"${agent_voice}\" (Bash tool)
|
|
251
251
|
- CRITICAL: Before EVERY response, scan for questions/prompts and speak them using Bash tool</step>"
|
|
252
252
|
else
|
|
253
253
|
tts_step=" <step n=\"4.5\" tts=\"agentvibes\">🎤 AGENTVIBES TTS INJECTION:
|
|
254
254
|
- Create context: echo \"${agent_id}\" > .bmad-agent-context (Bash tool)
|
|
255
|
-
- Speak greeting: .claude/hooks/play-tts.sh \"Hello! I'm ready to help you.\" (Bash tool)
|
|
255
|
+
- Speak greeting: bash .claude/hooks/play-tts.sh \"Hello! I'm ready to help you.\" (Bash tool)
|
|
256
256
|
- CRITICAL: Before EVERY response, scan for questions/prompts and speak them using Bash tool</step>"
|
|
257
257
|
fi
|
|
258
258
|
|
|
259
|
-
# Insert after step 4
|
|
259
|
+
# Insert after step 4 - only first match
|
|
260
|
+
# Note: Greeting is in step 5, but we inject after step 4 for proper ordering
|
|
260
261
|
awk -v tts="$tts_step" '
|
|
261
|
-
!done && /<step n="4"
|
|
262
|
+
!done && /<step n="4">/ {
|
|
262
263
|
print
|
|
263
264
|
print tts
|
|
264
265
|
done=1
|
|
@@ -283,7 +284,7 @@ inject_tts() {
|
|
|
283
284
|
# No changes - step 4 pattern didn't match
|
|
284
285
|
rm "$agent_file.tmp"
|
|
285
286
|
mv "$agent_file.backup-pre-tts" "$agent_file"
|
|
286
|
-
echo -e "${RED}❌ Could not find step 4
|
|
287
|
+
echo -e "${RED}❌ Could not find step 4 in: $(basename "$agent_file")${NC}"
|
|
287
288
|
return 1
|
|
288
289
|
fi
|
|
289
290
|
|
|
@@ -293,12 +294,12 @@ inject_tts() {
|
|
|
293
294
|
if [[ -n "$agent_voice" ]]; then
|
|
294
295
|
activation_injection=" - # AGENTVIBES-TTS-INJECTION: STEP 3.5 - Announce activation with TTS
|
|
295
296
|
- STEP 3.5a: Use Bash tool to create context file: echo \"${agent_id}\" > .bmad-agent-context
|
|
296
|
-
- STEP 3.5b: Use Bash tool to speak: .claude/hooks/play-tts.sh \"Agent ${agent_id} activated and ready\" \"${agent_voice}\"
|
|
297
|
+
- STEP 3.5b: Use Bash tool to speak: bash .claude/hooks/play-tts.sh \"Agent ${agent_id} activated and ready\" \"${agent_voice}\"
|
|
297
298
|
- AGENTVIBES-TTS-INJECTION: Before every response, scan for questions and speak them using Bash tool"
|
|
298
299
|
else
|
|
299
300
|
activation_injection=" - # AGENTVIBES-TTS-INJECTION: STEP 3.5 - Announce activation with TTS
|
|
300
301
|
- STEP 3.5a: Use Bash tool to create context file: echo \"${agent_id}\" > .bmad-agent-context
|
|
301
|
-
- STEP 3.5b: Use Bash tool to speak: .claude/hooks/play-tts.sh \"Agent ${agent_id} activated and ready\"
|
|
302
|
+
- STEP 3.5b: Use Bash tool to speak: bash .claude/hooks/play-tts.sh \"Agent ${agent_id} activated and ready\"
|
|
302
303
|
- AGENTVIBES-TTS-INJECTION: Before every response, scan for questions and speak them using Bash tool"
|
|
303
304
|
fi
|
|
304
305
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
2
3
|
#
|
|
3
4
|
# File: .claude/hooks/session-start-tts.sh
|
|
4
5
|
#
|
|
5
|
-
# AgentVibes SessionStart Hook -
|
|
6
|
-
#
|
|
7
|
-
# This hook outputs TTS protocol instructions to stdout, which Claude Code
|
|
8
|
-
# adds to the conversation context at session start.
|
|
6
|
+
# AgentVibes SessionStart Hook - Optimized (Issue #80, Phase 1)
|
|
7
|
+
# Token target: ~250 (down from ~500)
|
|
9
8
|
#
|
|
10
9
|
|
|
11
10
|
# Fix locale warnings
|
|
@@ -24,50 +23,31 @@ fi
|
|
|
24
23
|
SENTIMENT=$(cat .claude/tts-sentiment.txt 2>/dev/null || cat ~/.claude/tts-sentiment.txt 2>/dev/null || echo "")
|
|
25
24
|
PERSONALITY=$(cat .claude/tts-personality.txt 2>/dev/null || cat ~/.claude/tts-personality.txt 2>/dev/null || echo "normal")
|
|
26
25
|
|
|
27
|
-
# Determine
|
|
26
|
+
# Determine style
|
|
28
27
|
if [[ -n "$SENTIMENT" ]]; then
|
|
29
|
-
|
|
30
|
-
STYLE_NAME="$SENTIMENT"
|
|
28
|
+
STYLE="$SENTIMENT"
|
|
31
29
|
else
|
|
32
|
-
|
|
33
|
-
STYLE_NAME="$PERSONALITY"
|
|
30
|
+
STYLE="$PERSONALITY"
|
|
34
31
|
fi
|
|
35
32
|
|
|
36
33
|
# Get verbosity level (Issue #32)
|
|
37
34
|
VERBOSITY=$(cat .claude/tts-verbosity.txt 2>/dev/null || cat ~/.claude/tts-verbosity.txt 2>/dev/null || echo "low")
|
|
38
35
|
|
|
39
|
-
# Output TTS protocol
|
|
40
|
-
# Claude Code will add this to the conversation context
|
|
36
|
+
# Output optimized TTS protocol
|
|
41
37
|
cat <<'EOF'
|
|
42
38
|
|
|
43
39
|
# AgentVibes TTS Protocol
|
|
44
40
|
|
|
45
41
|
**CRITICAL: You MUST execute TTS at TWO points for EVERY user interaction:**
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
1. Generate a brief, unique acknowledgment message
|
|
50
|
-
2. Execute: `Bash: .claude/hooks/play-tts.sh "[your message]"`
|
|
51
|
-
3. Then proceed with the work
|
|
52
|
-
|
|
53
|
-
## 2. COMPLETION (End of Every Task)
|
|
54
|
-
After finishing the task:
|
|
55
|
-
1. Generate a brief, unique completion message
|
|
56
|
-
2. Execute: `Bash: .claude/hooks/play-tts.sh "[your message]"`
|
|
57
|
-
|
|
58
|
-
## Rules
|
|
59
|
-
- Use Bash tool to execute play-tts.sh
|
|
60
|
-
- Keep messages under 150 characters
|
|
61
|
-
- Generate unique messages each time
|
|
62
|
-
- Use relative path: .claude/hooks/play-tts.sh
|
|
63
|
-
- This is NOT optional - follow for EVERY interaction
|
|
43
|
+
1. **Acknowledgment** - Start of task: `Bash: .claude/hooks/play-tts.sh "[action]"`
|
|
44
|
+
2. **Completion** - End of task: `Bash: .claude/hooks/play-tts.sh "[result + key details]"`
|
|
64
45
|
|
|
65
|
-
|
|
46
|
+
**Example:**
|
|
66
47
|
```
|
|
67
|
-
|
|
68
|
-
[
|
|
69
|
-
[
|
|
70
|
-
[Bash: .claude/hooks/play-tts.sh "Done! All clean."]
|
|
48
|
+
[Bash: .claude/hooks/play-tts.sh "Checking git status"]
|
|
49
|
+
[work...]
|
|
50
|
+
[Bash: .claude/hooks/play-tts.sh "Repository is clean, no changes"]
|
|
71
51
|
```
|
|
72
52
|
|
|
73
53
|
EOF
|
|
@@ -76,66 +56,46 @@ EOF
|
|
|
76
56
|
case "$VERBOSITY" in
|
|
77
57
|
low)
|
|
78
58
|
cat <<'EOF'
|
|
79
|
-
## Verbosity: LOW
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
59
|
+
## Verbosity: LOW
|
|
60
|
+
- Acknowledgment: Action only
|
|
61
|
+
- Completion: Result + errors only
|
|
62
|
+
- Skip: Reasoning, decisions
|
|
83
63
|
|
|
84
64
|
EOF
|
|
85
65
|
;;
|
|
86
66
|
|
|
87
67
|
medium)
|
|
88
68
|
cat <<'EOF'
|
|
89
|
-
## Verbosity: MEDIUM
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
🤔 [decision text] - Major decisions (e.g., "🤔 I'll use grep to search all files")
|
|
94
|
-
✓ [finding text] - Key findings (e.g., "✓ Found 12 instances at line 1323")
|
|
95
|
-
|
|
96
|
-
Example:
|
|
97
|
-
```
|
|
98
|
-
User: "Find all TODO comments"
|
|
99
|
-
[TTS: Acknowledgment]
|
|
100
|
-
🤔 I'll use grep to search for TODO comments
|
|
101
|
-
[Work happens...]
|
|
102
|
-
✓ Found 12 TODO comments across 5 files
|
|
103
|
-
[TTS: Completion]
|
|
104
|
-
```
|
|
69
|
+
## Verbosity: MEDIUM
|
|
70
|
+
- Acknowledgment: Action + key approach
|
|
71
|
+
- Completion: Result + important decisions
|
|
72
|
+
- Include: Major choices only
|
|
105
73
|
|
|
106
74
|
EOF
|
|
107
75
|
;;
|
|
108
76
|
|
|
109
77
|
high)
|
|
110
78
|
cat <<'EOF'
|
|
111
|
-
## Verbosity: HIGH
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
💭 [reasoning text] - Thought process (e.g., "💭 Let me search for all instances")
|
|
116
|
-
🤔 [decision text] - Decisions (e.g., "🤔 I'll use grep for this")
|
|
117
|
-
✓ [finding text] - Findings (e.g., "✓ Found it at line 1323")
|
|
118
|
-
|
|
119
|
-
Example:
|
|
120
|
-
```
|
|
121
|
-
User: "Find all TODO comments"
|
|
122
|
-
[TTS: Acknowledgment]
|
|
123
|
-
💭 Let me search through the codebase for TODO comments
|
|
124
|
-
🤔 I'll use the Grep tool with pattern "TODO"
|
|
125
|
-
[Grep runs...]
|
|
126
|
-
✓ Found 12 TODO comments across 5 files
|
|
127
|
-
💭 Let me organize these results by file
|
|
128
|
-
[Processing...]
|
|
129
|
-
[TTS: Completion]
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
IMPORTANT: Use emoji markers naturally in your reasoning text. They trigger automatic TTS.
|
|
79
|
+
## Verbosity: HIGH
|
|
80
|
+
- Acknowledgment: Action + approach + why
|
|
81
|
+
- Completion: Result + decisions + trade-offs
|
|
82
|
+
- Include: Full reasoning, alternatives
|
|
133
83
|
|
|
134
84
|
EOF
|
|
135
85
|
;;
|
|
136
86
|
esac
|
|
137
87
|
|
|
138
|
-
# Add
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
88
|
+
# Add style info and rules
|
|
89
|
+
cat << EOF
|
|
90
|
+
## Style: $STYLE
|
|
91
|
+
|
|
92
|
+
## Rules
|
|
93
|
+
1. Never skip acknowledgment TTS
|
|
94
|
+
2. Never skip completion TTS
|
|
95
|
+
3. Match verbosity level
|
|
96
|
+
4. Keep under 150 chars
|
|
97
|
+
5. Always include errors
|
|
98
|
+
|
|
99
|
+
Quick Ref: low=action+result | medium=+key decisions | high=+full reasoning
|
|
100
|
+
|
|
101
|
+
EOF
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://github.com/paulpreibisch/AgentVibes/actions/workflows/publish.yml)
|
|
12
12
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
13
13
|
|
|
14
|
-
**Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v2.17.
|
|
14
|
+
**Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v2.17.7
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -114,15 +114,15 @@ All 50+ Piper voices AgentVibes provides are sourced from Hugging Face's open-so
|
|
|
114
114
|
|
|
115
115
|
## 📰 Latest Release
|
|
116
116
|
|
|
117
|
-
**[v2.17.
|
|
117
|
+
**[v2.17.7 - BMAD Party Mode Voice Fix](https://github.com/paulpreibisch/AgentVibes/releases/tag/v2.17.7)** 🎭
|
|
118
118
|
|
|
119
|
-
AgentVibes v2.17.
|
|
119
|
+
AgentVibes v2.17.7 fixes a critical bug preventing BMAD party mode agents from using their unique voices. All agents were incorrectly using the same default voice instead of their assigned voices (Mary/Kristin, John/Ryan, Winston/Alan, etc.). This release also includes 50% token optimization for the session-start TTS hook.
|
|
120
120
|
|
|
121
121
|
**Key Highlights:**
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
122
|
+
- 🎭 **Party Mode Voice Fix** - All BMAD agents now speak with their unique assigned voices
|
|
123
|
+
- ⚡ **Token Optimization** - Session-start TTS hook reduced from ~500 to ~250 tokens (50% reduction)
|
|
124
|
+
- 🎤 **Interactive TTS Prompt** - Installer automatically detects BMAD and offers voice injection
|
|
125
|
+
- 🔧 **Hook Path Improvements** - Fixed TTS injector to use correct path resolution
|
|
126
126
|
|
|
127
127
|
💡 **Tip:** If `npx agentvibes` shows an older version or missing commands, clear your npm cache: `npm cache clean --force && npx agentvibes@latest --help`
|
|
128
128
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "agentvibes",
|
|
4
|
-
"version": "2.17.
|
|
4
|
+
"version": "2.17.7",
|
|
5
5
|
"description": "Now your AI Agents can finally talk back! Professional TTS voice for Claude Code and Claude Desktop (via MCP) with multi-provider support.",
|
|
6
6
|
"homepage": "https://agentvibes.org",
|
|
7
7
|
"keywords": [
|
package/src/installer.js
CHANGED
|
@@ -823,17 +823,17 @@ function showWelcome() {
|
|
|
823
823
|
* Shown during install and update commands
|
|
824
824
|
*/
|
|
825
825
|
function getReleaseInfoBoxen() {
|
|
826
|
-
return chalk.cyan.bold('📦 AgentVibes v2.17.
|
|
826
|
+
return chalk.cyan.bold('📦 AgentVibes v2.17.7 - BMAD Party Mode Voice Fix\n\n') +
|
|
827
827
|
chalk.green.bold('🎙️ WHAT\'S NEW:\n\n') +
|
|
828
|
-
chalk.cyan('AgentVibes v2.17.
|
|
829
|
-
chalk.cyan('
|
|
830
|
-
chalk.cyan('
|
|
831
|
-
chalk.cyan('
|
|
828
|
+
chalk.cyan('AgentVibes v2.17.7 fixes a critical bug preventing BMAD party mode agents from\n') +
|
|
829
|
+
chalk.cyan('using their unique voices. All agents were incorrectly using the same default voice\n') +
|
|
830
|
+
chalk.cyan('instead of their assigned voices (Mary/Kristin, John/Ryan, Winston/Alan, etc.).\n') +
|
|
831
|
+
chalk.cyan('This release also includes 50% token optimization for session-start hook.\n\n') +
|
|
832
832
|
chalk.green.bold('✨ KEY HIGHLIGHTS:\n\n') +
|
|
833
|
-
chalk.gray('
|
|
834
|
-
chalk.gray('
|
|
835
|
-
chalk.gray('
|
|
836
|
-
chalk.gray('
|
|
833
|
+
chalk.gray(' 🎭 Party Mode Voice Fix - All BMAD agents now speak with unique assigned voices\n') +
|
|
834
|
+
chalk.gray(' ⚡ Token Optimization - Session-start TTS hook reduced from ~500 to ~250 tokens\n') +
|
|
835
|
+
chalk.gray(' 🎤 Interactive TTS Prompt - Installer detects BMAD and offers voice injection\n') +
|
|
836
|
+
chalk.gray(' 🔧 Hook Path Improvements - Fixed TTS injector path resolution\n\n') +
|
|
837
837
|
chalk.gray('📖 Full Release Notes: RELEASE_NOTES.md\n') +
|
|
838
838
|
chalk.gray('🌐 Website: https://agentvibes.org\n') +
|
|
839
839
|
chalk.gray('📦 Repository: https://github.com/paulpreibisch/AgentVibes\n\n') +
|
|
@@ -2444,9 +2444,10 @@ async function detectAndMigrateOldConfig(targetDir, spinner) {
|
|
|
2444
2444
|
/**
|
|
2445
2445
|
* Handle BMAD integration (detection and TTS injection)
|
|
2446
2446
|
* @param {string} targetDir - Target installation directory
|
|
2447
|
+
* @param {Object} options - Installation options (e.g., yes flag for non-interactive)
|
|
2447
2448
|
* @returns {Promise<Object>} BMAD detection result
|
|
2448
2449
|
*/
|
|
2449
|
-
async function handleBmadIntegration(targetDir) {
|
|
2450
|
+
async function handleBmadIntegration(targetDir, options = {}) {
|
|
2450
2451
|
const bmadDetection = await detectBMAD(targetDir);
|
|
2451
2452
|
const bmadDetected = bmadDetection.installed;
|
|
2452
2453
|
|
|
@@ -2485,6 +2486,55 @@ async function handleBmadIntegration(targetDir) {
|
|
|
2485
2486
|
// Create default voice assignments if they don't exist
|
|
2486
2487
|
await createDefaultBmadVoiceAssignmentsProactive(targetDir);
|
|
2487
2488
|
|
|
2489
|
+
// Prompt user to inject TTS into BMAD agents (or auto-inject with --yes flag)
|
|
2490
|
+
let enableTtsInjection = options.yes; // Auto-enable with --yes flag
|
|
2491
|
+
|
|
2492
|
+
if (!options.yes) {
|
|
2493
|
+
console.log(''); // Add spacing
|
|
2494
|
+
console.log(chalk.cyan.bold('🎤 AgentVibes TTS Integration for BMAD Agents\n'));
|
|
2495
|
+
console.log(chalk.white('AgentVibes can inject Text-to-Speech into your BMAD agents'));
|
|
2496
|
+
console.log(chalk.white('so each agent speaks with their own unique voice!\n'));
|
|
2497
|
+
console.log(chalk.gray('What this does:'));
|
|
2498
|
+
console.log(chalk.gray(' • Modifies agent activation instructions to include TTS'));
|
|
2499
|
+
console.log(chalk.gray(' • Each agent gets a unique voice (e.g., Mary, John, Winston)'));
|
|
2500
|
+
console.log(chalk.gray(' • Agents will speak when activated and during responses'));
|
|
2501
|
+
console.log(chalk.gray(' • Creates backups before making any changes\n'));
|
|
2502
|
+
console.log(chalk.cyan('Agents that will get unique voices:'));
|
|
2503
|
+
console.log(chalk.gray(' • Mary (analyst) → Female voice'));
|
|
2504
|
+
console.log(chalk.gray(' • John (pm) → Male voice'));
|
|
2505
|
+
console.log(chalk.gray(' • Winston (architect) → British voice'));
|
|
2506
|
+
console.log(chalk.gray(' • And 6+ more agents...\n'));
|
|
2507
|
+
console.log(chalk.yellow('You can disable this later with:'));
|
|
2508
|
+
console.log(chalk.gray(' .claude/hooks/bmad-tts-injector.sh disable\n'));
|
|
2509
|
+
|
|
2510
|
+
const { enableTts } = await inquirer.prompt([{
|
|
2511
|
+
type: 'confirm',
|
|
2512
|
+
name: 'enableTts',
|
|
2513
|
+
message: chalk.yellow('Enable TTS for BMAD agents?'),
|
|
2514
|
+
default: true
|
|
2515
|
+
}]);
|
|
2516
|
+
|
|
2517
|
+
enableTtsInjection = enableTts;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
if (enableTtsInjection) {
|
|
2521
|
+
const injectorScript = path.join(claudeDir, 'hooks', 'bmad-tts-injector.sh');
|
|
2522
|
+
try {
|
|
2523
|
+
// Run bmad-tts-injector.sh enable
|
|
2524
|
+
execSync(`bash "${injectorScript}" enable`, {
|
|
2525
|
+
cwd: targetDir,
|
|
2526
|
+
stdio: 'inherit'
|
|
2527
|
+
});
|
|
2528
|
+
console.log(chalk.green('✅ TTS injection completed successfully'));
|
|
2529
|
+
} catch (error) {
|
|
2530
|
+
console.log(chalk.yellow('⚠️ TTS injection encountered issues'));
|
|
2531
|
+
console.log(chalk.gray(' You can retry manually with: .claude/hooks/bmad-tts-injector.sh enable'));
|
|
2532
|
+
}
|
|
2533
|
+
} else {
|
|
2534
|
+
console.log(chalk.gray(' Skipped TTS injection. You can enable it later with:'));
|
|
2535
|
+
console.log(chalk.gray(' .claude/hooks/bmad-tts-injector.sh enable'));
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2488
2538
|
console.log(chalk.green('✅ BMAD agents will use agent-specific voices via bmad-speak.sh hook'));
|
|
2489
2539
|
|
|
2490
2540
|
return bmadDetection;
|
|
@@ -3185,7 +3235,7 @@ async function install(options = {}) {
|
|
|
3185
3235
|
await createDefaultBmadVoiceAssignmentsProactive(targetDir);
|
|
3186
3236
|
|
|
3187
3237
|
// Handle BMAD integration
|
|
3188
|
-
const bmadDetection = await handleBmadIntegration(targetDir);
|
|
3238
|
+
const bmadDetection = await handleBmadIntegration(targetDir, options);
|
|
3189
3239
|
const bmadDetected = bmadDetection.installed;
|
|
3190
3240
|
|
|
3191
3241
|
if (bmadDetected) {
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# File: .claude/hooks/play-tts.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, including but not limited to the warranties of
|
|
26
|
-
# merchantability, fitness for a particular purpose and noninfringement.
|
|
27
|
-
# In no event shall the authors or copyright holders be liable for any claim,
|
|
28
|
-
# damages or other liability, whether in an action of contract, tort or
|
|
29
|
-
# otherwise, arising from, out of or in connection with the software or the
|
|
30
|
-
# use or other dealings in the software.
|
|
31
|
-
#
|
|
32
|
-
# ---
|
|
33
|
-
#
|
|
34
|
-
# @fileoverview TTS Provider Router with Translation and Language Learning Support
|
|
35
|
-
# @context Routes TTS requests to active provider (Piper or macOS) 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-piper.sh, translator.py, translate-manager.sh, learn-manager.sh
|
|
38
|
-
# @entrypoints Called by hooks, slash commands, personality-manager.sh, and all TTS features
|
|
39
|
-
# @patterns Provider pattern - delegates to provider-specific implementations, auto-detects provider from voice name
|
|
40
|
-
# @related provider-manager.sh, play-tts-piper.sh, learn-manager.sh, translate-manager.sh
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
# Fix locale warnings
|
|
44
|
-
export LC_ALL=C
|
|
45
|
-
|
|
46
|
-
# Get script directory (needed for mute file check)
|
|
47
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
48
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
49
|
-
|
|
50
|
-
# Check if muted (persists across sessions)
|
|
51
|
-
# Project settings always override global settings:
|
|
52
|
-
# - .claude/agentvibes-unmuted = project explicitly unmuted (overrides global mute)
|
|
53
|
-
# - .claude/agentvibes-muted = project muted (overrides global unmute)
|
|
54
|
-
# - ~/.agentvibes-muted = global mute (only if no project-level setting)
|
|
55
|
-
GLOBAL_MUTE_FILE="$HOME/.agentvibes-muted"
|
|
56
|
-
PROJECT_MUTE_FILE="$PROJECT_ROOT/.claude/agentvibes-muted"
|
|
57
|
-
PROJECT_UNMUTE_FILE="$PROJECT_ROOT/.claude/agentvibes-unmuted"
|
|
58
|
-
|
|
59
|
-
# Check project-level settings first (project overrides global)
|
|
60
|
-
if [[ -f "$PROJECT_UNMUTE_FILE" ]]; then
|
|
61
|
-
# Project explicitly unmuted - ignore global mute
|
|
62
|
-
: # Continue (do nothing, will not exit)
|
|
63
|
-
elif [[ -f "$PROJECT_MUTE_FILE" ]]; then
|
|
64
|
-
# Project explicitly muted
|
|
65
|
-
if [[ -f "$GLOBAL_MUTE_FILE" ]]; then
|
|
66
|
-
echo "🔇 TTS muted (project + global)"
|
|
67
|
-
else
|
|
68
|
-
echo "🔇 TTS muted (project)"
|
|
69
|
-
fi
|
|
70
|
-
exit 0
|
|
71
|
-
elif [[ -f "$GLOBAL_MUTE_FILE" ]]; then
|
|
72
|
-
# Global mute and no project-level override
|
|
73
|
-
echo "🔇 TTS muted (global)"
|
|
74
|
-
exit 0
|
|
75
|
-
fi
|
|
76
|
-
|
|
77
|
-
TEXT="$1"
|
|
78
|
-
VOICE_OVERRIDE="$2" # Optional: voice name or ID
|
|
79
|
-
|
|
80
|
-
# Security: Validate inputs
|
|
81
|
-
if [[ -z "$TEXT" ]]; then
|
|
82
|
-
echo "Error: No text provided" >&2
|
|
83
|
-
exit 1
|
|
84
|
-
fi
|
|
85
|
-
|
|
86
|
-
# Security: Validate voice override doesn't contain dangerous characters
|
|
87
|
-
if [[ -n "$VOICE_OVERRIDE" ]] && [[ "$VOICE_OVERRIDE" =~ [';|&$`<>(){}'] ]]; then
|
|
88
|
-
echo "Error: Invalid characters in voice parameter" >&2
|
|
89
|
-
exit 1
|
|
90
|
-
fi
|
|
91
|
-
|
|
92
|
-
# Remove backslash escaping that Claude might add for special chars
|
|
93
|
-
# In single quotes these don't need escaping, but Claude sometimes adds backslashes
|
|
94
|
-
TEXT="${TEXT//\\!/!}" # Remove \!
|
|
95
|
-
TEXT="${TEXT//\\\$/\$}" # Remove \$
|
|
96
|
-
TEXT="${TEXT//\\?/?}" # Remove \?
|
|
97
|
-
TEXT="${TEXT//\\,/,}" # Remove \,
|
|
98
|
-
TEXT="${TEXT//\\./.}" # Remove \. (keep the period)
|
|
99
|
-
TEXT="${TEXT//\\\\/\\}" # Remove \\ (escaped backslash)
|
|
100
|
-
|
|
101
|
-
# Source provider manager to get active provider
|
|
102
|
-
source "$SCRIPT_DIR/provider-manager.sh"
|
|
103
|
-
|
|
104
|
-
# Get active provider
|
|
105
|
-
ACTIVE_PROVIDER=$(get_active_provider)
|
|
106
|
-
|
|
107
|
-
# Show GitHub star reminder (once per day)
|
|
108
|
-
"$SCRIPT_DIR/github-star-reminder.sh" 2>/dev/null || true
|
|
109
|
-
|
|
110
|
-
# @function detect_voice_provider
|
|
111
|
-
# @intent Auto-detect provider from voice name (for mixed-provider support)
|
|
112
|
-
# @why Allow Piper for main language + macOS for target language
|
|
113
|
-
# @param $1 voice name/ID
|
|
114
|
-
# @returns Provider name (piper or macos)
|
|
115
|
-
detect_voice_provider() {
|
|
116
|
-
local voice="$1"
|
|
117
|
-
# Piper voice names contain underscore and dash (e.g., es_ES-davefx-medium)
|
|
118
|
-
if [[ "$voice" == *"_"*"-"* ]]; then
|
|
119
|
-
echo "piper"
|
|
120
|
-
else
|
|
121
|
-
echo "$ACTIVE_PROVIDER"
|
|
122
|
-
fi
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
# Override provider if voice indicates different provider (mixed-provider mode)
|
|
126
|
-
if [[ -n "$VOICE_OVERRIDE" ]]; then
|
|
127
|
-
DETECTED_PROVIDER=$(detect_voice_provider "$VOICE_OVERRIDE")
|
|
128
|
-
if [[ "$DETECTED_PROVIDER" != "$ACTIVE_PROVIDER" ]]; then
|
|
129
|
-
ACTIVE_PROVIDER="$DETECTED_PROVIDER"
|
|
130
|
-
fi
|
|
131
|
-
fi
|
|
132
|
-
|
|
133
|
-
# @function speak_text
|
|
134
|
-
# @intent Route text to appropriate TTS provider
|
|
135
|
-
# @why Reusable function for speaking, used by both single and learning modes
|
|
136
|
-
# @param $1 text to speak
|
|
137
|
-
# @param $2 voice override (optional)
|
|
138
|
-
# @param $3 provider override (optional)
|
|
139
|
-
speak_text() {
|
|
140
|
-
local text="$1"
|
|
141
|
-
local voice="${2:-}"
|
|
142
|
-
local provider="${3:-$ACTIVE_PROVIDER}"
|
|
143
|
-
|
|
144
|
-
case "$provider" in
|
|
145
|
-
piper)
|
|
146
|
-
"$SCRIPT_DIR/play-tts-piper.sh" "$text" "$voice"
|
|
147
|
-
;;
|
|
148
|
-
macos)
|
|
149
|
-
"$SCRIPT_DIR/play-tts-macos.sh" "$text" "$voice"
|
|
150
|
-
;;
|
|
151
|
-
*)
|
|
152
|
-
echo "❌ Unknown provider: $provider" >&2
|
|
153
|
-
return 1
|
|
154
|
-
;;
|
|
155
|
-
esac
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# Note: learn-manager.sh and translate-manager.sh are sourced inside their
|
|
159
|
-
# respective handler functions to avoid triggering their main handlers
|
|
160
|
-
|
|
161
|
-
# @function handle_learning_mode
|
|
162
|
-
# @intent Speak in both main language and target language for learning
|
|
163
|
-
# @why Issue #51 - Auto-translate and speak twice for immersive language learning
|
|
164
|
-
# @returns 0 if learning mode handled, 1 if not in learning mode
|
|
165
|
-
handle_learning_mode() {
|
|
166
|
-
# Source learn-manager for learning mode functions
|
|
167
|
-
source "$SCRIPT_DIR/learn-manager.sh" 2>/dev/null || return 1
|
|
168
|
-
|
|
169
|
-
# Check if learning mode is enabled
|
|
170
|
-
if ! is_learn_mode_enabled 2>/dev/null; then
|
|
171
|
-
return 1
|
|
172
|
-
fi
|
|
173
|
-
|
|
174
|
-
local target_lang
|
|
175
|
-
target_lang=$(get_target_language 2>/dev/null || echo "")
|
|
176
|
-
local target_voice
|
|
177
|
-
target_voice=$(get_target_voice 2>/dev/null || echo "")
|
|
178
|
-
|
|
179
|
-
# Need both target language and voice for learning mode
|
|
180
|
-
if [[ -z "$target_lang" ]] || [[ -z "$target_voice" ]]; then
|
|
181
|
-
return 1
|
|
182
|
-
fi
|
|
183
|
-
|
|
184
|
-
# 1. Speak in main language (current voice)
|
|
185
|
-
speak_text "$TEXT" "$VOICE_OVERRIDE" "$ACTIVE_PROVIDER"
|
|
186
|
-
|
|
187
|
-
# 2. Auto-translate to target language
|
|
188
|
-
local translated
|
|
189
|
-
translated=$(python3 "$SCRIPT_DIR/translator.py" "$TEXT" "$target_lang" 2>/dev/null) || translated="$TEXT"
|
|
190
|
-
|
|
191
|
-
# Small pause between languages
|
|
192
|
-
sleep 0.5
|
|
193
|
-
|
|
194
|
-
# 3. Speak translated text with target voice
|
|
195
|
-
local target_provider
|
|
196
|
-
target_provider=$(detect_voice_provider "$target_voice")
|
|
197
|
-
speak_text "$translated" "$target_voice" "$target_provider"
|
|
198
|
-
|
|
199
|
-
return 0
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
# @function handle_translation_mode
|
|
203
|
-
# @intent Translate and speak in target language (non-learning mode)
|
|
204
|
-
# @why Issue #50 - BMAD multi-language TTS support
|
|
205
|
-
# @returns 0 if translation handled, 1 if not translating
|
|
206
|
-
handle_translation_mode() {
|
|
207
|
-
# Source translate-manager to get translation settings
|
|
208
|
-
source "$SCRIPT_DIR/translate-manager.sh" 2>/dev/null || return 1
|
|
209
|
-
|
|
210
|
-
# Check if translation is enabled
|
|
211
|
-
if ! is_translation_enabled 2>/dev/null; then
|
|
212
|
-
return 1
|
|
213
|
-
fi
|
|
214
|
-
|
|
215
|
-
local translate_to
|
|
216
|
-
translate_to=$(get_translate_to 2>/dev/null || echo "")
|
|
217
|
-
|
|
218
|
-
if [[ -z "$translate_to" ]] || [[ "$translate_to" == "english" ]]; then
|
|
219
|
-
return 1
|
|
220
|
-
fi
|
|
221
|
-
|
|
222
|
-
# Translate text
|
|
223
|
-
local translated
|
|
224
|
-
translated=$(python3 "$SCRIPT_DIR/translator.py" "$TEXT" "$translate_to" 2>/dev/null) || translated="$TEXT"
|
|
225
|
-
|
|
226
|
-
# Get voice for target language if no override specified
|
|
227
|
-
local voice_to_use="$VOICE_OVERRIDE"
|
|
228
|
-
if [[ -z "$voice_to_use" ]]; then
|
|
229
|
-
source "$SCRIPT_DIR/language-manager.sh" 2>/dev/null || true
|
|
230
|
-
voice_to_use=$(get_voice_for_language "$translate_to" "$ACTIVE_PROVIDER" 2>/dev/null || echo "")
|
|
231
|
-
fi
|
|
232
|
-
|
|
233
|
-
# Update provider if voice indicates different provider
|
|
234
|
-
local provider_to_use="$ACTIVE_PROVIDER"
|
|
235
|
-
if [[ -n "$voice_to_use" ]]; then
|
|
236
|
-
provider_to_use=$(detect_voice_provider "$voice_to_use")
|
|
237
|
-
fi
|
|
238
|
-
|
|
239
|
-
# Speak translated text
|
|
240
|
-
speak_text "$translated" "$voice_to_use" "$provider_to_use"
|
|
241
|
-
return 0
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
# Mode priority:
|
|
245
|
-
# 1. Learning mode (speaks twice: main + translated)
|
|
246
|
-
# 2. Translation mode (speaks translated only)
|
|
247
|
-
# 3. Normal mode (speaks as-is)
|
|
248
|
-
|
|
249
|
-
# Try learning mode first (Issue #51)
|
|
250
|
-
if handle_learning_mode; then
|
|
251
|
-
exit 0
|
|
252
|
-
fi
|
|
253
|
-
|
|
254
|
-
# Try translation mode (Issue #50)
|
|
255
|
-
if handle_translation_mode; then
|
|
256
|
-
exit 0
|
|
257
|
-
fi
|
|
258
|
-
|
|
259
|
-
# Normal single-language mode - route to appropriate provider implementation
|
|
260
|
-
case "$ACTIVE_PROVIDER" in
|
|
261
|
-
piper)
|
|
262
|
-
exec "$SCRIPT_DIR/play-tts-piper.sh" "$TEXT" "$VOICE_OVERRIDE"
|
|
263
|
-
;;
|
|
264
|
-
macos)
|
|
265
|
-
exec "$SCRIPT_DIR/play-tts-macos.sh" "$TEXT" "$VOICE_OVERRIDE"
|
|
266
|
-
;;
|
|
267
|
-
*)
|
|
268
|
-
echo "❌ Unknown provider: $ACTIVE_PROVIDER"
|
|
269
|
-
echo " Run: /agent-vibes:provider list"
|
|
270
|
-
exit 1
|
|
271
|
-
;;
|
|
272
|
-
esac
|