agentvibes 2.6.0 → 2.7.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.
@@ -0,0 +1,135 @@
1
+ # TTS Queue System for Party Mode
2
+
3
+ ## Overview
4
+
5
+ The TTS Queue System enables BMAD party mode agents to speak sequentially without blocking Claude Code's response generation. This provides the best of both worlds:
6
+
7
+ - ✅ **Non-blocking**: Claude Code continues generating agent responses immediately
8
+ - ✅ **Sequential playback**: Agents speak one at a time in order, with correct voices
9
+ - ✅ **No audio overlap**: The queue ensures voices don't talk over each other
10
+
11
+ ## How It Works
12
+
13
+ ### Architecture
14
+
15
+ ```
16
+ bmad-speak.sh → tts-queue.sh → Queue Directory → tts-queue-worker.sh → play-tts.sh → Audio
17
+ ↓ ↓ ↓
18
+ Returns Returns Processes queue
19
+ immediately immediately sequentially
20
+ ```
21
+
22
+ ### Components
23
+
24
+ 1. **`tts-queue.sh`** - Queue manager (adds requests, shows status, clears queue)
25
+ 2. **`tts-queue-worker.sh`** - Background worker process (plays audio sequentially)
26
+ 3. **`bmad-speak.sh`** - Updated to use queue system with `&` for non-blocking
27
+ 4. **Queue directory**: `/tmp/agentvibes-tts-queue/` - Stores pending TTS requests
28
+
29
+ ### Flow
30
+
31
+ 1. Party mode agent generates response
32
+ 2. `bmad-speak.sh` adds TTS request to queue and returns immediately (`&`)
33
+ 3. Queue worker automatically starts if needed
34
+ 4. Worker processes queue items sequentially (oldest first)
35
+ 5. Each audio file plays to completion before next one starts
36
+ 6. Worker auto-exits after 5 seconds of idle time
37
+
38
+ ## Usage
39
+
40
+ ### Normal Usage (Automatic)
41
+
42
+ Party mode automatically uses the queue system. No manual intervention needed.
43
+
44
+ ### Manual Queue Management
45
+
46
+ ```bash
47
+ # Check queue status
48
+ bash .claude/hooks/tts-queue.sh status
49
+
50
+ # Clear all pending TTS (emergency stop)
51
+ bash .claude/hooks/tts-queue.sh clear
52
+
53
+ # Manually add to queue
54
+ bash .claude/hooks/tts-queue.sh add "Hello world" "en_US-ryan-high"
55
+ ```
56
+
57
+ ## Performance Benefits
58
+
59
+ ### Before (Sequential Blocking):
60
+ ```
61
+ Agent 1 text output → [WAIT 3s for audio] → Agent 2 text → [WAIT 3s] → Agent 3 text
62
+ Total time: ~9+ seconds
63
+ ```
64
+
65
+ ### After (Queue System):
66
+ ```
67
+ Agent 1 text → Agent 2 text → Agent 3 text (all immediate)
68
+
69
+ [Audio plays sequentially in background]
70
+ Total text output time: <1 second
71
+ Total audio time: ~9 seconds (plays while Claude continues working)
72
+ ```
73
+
74
+ ## Technical Details
75
+
76
+ ### Queue File Format
77
+
78
+ Each queue item is a timestamped file containing escaped bash variables:
79
+
80
+ ```bash
81
+ TEXT='First\ message\ from\ John'
82
+ VOICE='en_US-ryan-high'
83
+ ```
84
+
85
+ ### Worker Lifecycle
86
+
87
+ - **Start**: Automatically launched when first item added to empty queue
88
+ - **Processing**: Continues while queue has items
89
+ - **Idle timeout**: Exits after 5 seconds with no new items
90
+ - **Auto-restart**: Next queue addition spawns new worker
91
+
92
+ ### Thread Safety
93
+
94
+ - Queue items use nanosecond timestamps for uniqueness
95
+ - Worker processes oldest items first (sorted by filename)
96
+ - Audio lock mechanism in `play-tts.sh` prevents actual audio overlap
97
+ - Worker PID tracked in `/tmp/agentvibes-tts-queue/worker.pid`
98
+
99
+ ## Troubleshooting
100
+
101
+ ### Queue stuck or voices not playing
102
+
103
+ ```bash
104
+ # Check status
105
+ bash .claude/hooks/tts-queue.sh status
106
+
107
+ # Clear queue and restart
108
+ bash .claude/hooks/tts-queue.sh clear
109
+ ```
110
+
111
+ ### Worker not starting
112
+
113
+ Check for errors in the worker script:
114
+ ```bash
115
+ bash .claude/hooks/tts-queue-worker.sh
116
+ ```
117
+
118
+ ### Audio still overlapping
119
+
120
+ Verify the lock file mechanism is working:
121
+ ```bash
122
+ ls -la /tmp/agentvibes-audio.lock
123
+ ```
124
+
125
+ ## Files Modified
126
+
127
+ - `.claude/hooks/bmad-speak.sh` - Now uses queue system with `&` for non-blocking
128
+ - `.claude/hooks/tts-queue.sh` - New queue manager (added)
129
+ - `.claude/hooks/tts-queue-worker.sh` - New background worker (added)
130
+
131
+ ## Compatibility
132
+
133
+ - Works with both Piper and ElevenLabs TTS providers
134
+ - Compatible with all existing BMAD voice mappings
135
+ - No changes needed to party mode workflow instructions
@@ -59,11 +59,26 @@ map_to_agent_id() {
59
59
  fi
60
60
 
61
61
  # Otherwise map display name to agent ID (for party mode)
62
- # Extract 'name' (column 1) where displayName (column 2) matches
63
- local agent_id=$(grep -i ",\"*${name_or_id}\"*," "$PROJECT_ROOT/.bmad/_cfg/agent-manifest.csv" | \
64
- head -1 | \
65
- cut -d',' -f1 | \
66
- tr -d '"')
62
+ # Extract 'name' (column 1) where displayName (column 2) contains the name
63
+ # displayName format in CSV: "John", "Mary", "Winston", etc. (first word before any parentheses)
64
+ local agent_id=$(awk -F',' -v name="$name_or_id" '
65
+ BEGIN { IGNORECASE=1 }
66
+ NR > 1 {
67
+ # Extract displayName (column 2)
68
+ display = $2
69
+ gsub(/^"|"$/, "", display) # Remove surrounding quotes
70
+
71
+ # Check if display name starts with the search name (case-insensitive)
72
+ # This handles both "John" and "John (Product Manager)"
73
+ if (tolower(display) ~ "^" tolower(name) "($| |\\()") {
74
+ # Extract agent ID (column 1)
75
+ agent = $1
76
+ gsub(/^"|"$/, "", agent)
77
+ print agent
78
+ exit
79
+ }
80
+ }
81
+ ' "$PROJECT_ROOT/.bmad/_cfg/agent-manifest.csv")
67
82
 
68
83
  echo "$agent_id"
69
84
  }
@@ -71,16 +86,25 @@ map_to_agent_id() {
71
86
  # Get agent ID
72
87
  AGENT_ID=$(map_to_agent_id "$AGENT_NAME_OR_ID")
73
88
 
74
- # Get agent's voice
89
+ # Get agent's voice and intro text
75
90
  AGENT_VOICE=""
91
+ AGENT_INTRO=""
76
92
  if [[ -n "$AGENT_ID" ]] && [[ -f "$SCRIPT_DIR/bmad-voice-manager.sh" ]]; then
77
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)
95
+ fi
96
+
97
+ # Prepend intro text if configured (e.g., "John, Product Manager here. [dialogue]")
98
+ FULL_TEXT="$DIALOGUE"
99
+ if [[ -n "$AGENT_INTRO" ]]; then
100
+ FULL_TEXT="${AGENT_INTRO}. ${DIALOGUE}"
78
101
  fi
79
102
 
80
- # Speak with agent's voice
103
+ # Speak with agent's voice using queue system (non-blocking for Claude)
104
+ # Queue system ensures sequential playback while allowing Claude to continue
81
105
  if [[ -n "$AGENT_VOICE" ]]; then
82
- bash "$SCRIPT_DIR/play-tts.sh" "$DIALOGUE" "$AGENT_VOICE" &
106
+ bash "$SCRIPT_DIR/tts-queue.sh" add "$FULL_TEXT" "$AGENT_VOICE" &
83
107
  else
84
108
  # Fallback to default voice
85
- bash "$SCRIPT_DIR/play-tts.sh" "$DIALOGUE" &
109
+ bash "$SCRIPT_DIR/tts-queue.sh" add "$FULL_TEXT" &
86
110
  fi
@@ -34,14 +34,14 @@
34
34
  # @fileoverview BMAD Voice Plugin Manager - Maps BMAD agents to unique TTS voices
35
35
  # @context Enables each BMAD agent to have its own distinct voice for multi-agent sessions
36
36
  # @architecture Markdown table-based voice mapping with enable/disable flag, auto-detection of BMAD
37
- # @dependencies .claude/plugins/bmad-voices.md (voice mappings), bmad-tts-injector.sh, .bmad-core/ (BMAD installation)
37
+ # @dependencies .claude/config/bmad-voices.md (voice mappings), bmad-tts-injector.sh, .bmad-core/ (BMAD installation)
38
38
  # @entrypoints Called by /agent-vibes:bmad commands, auto-enabled on BMAD detection
39
39
  # @patterns Plugin architecture, auto-enable on dependency detection, state backup/restore on toggle
40
- # @related bmad-tts-injector.sh, .claude/plugins/bmad-voices.md, .bmad-agent-context file
40
+ # @related bmad-tts-injector.sh, .claude/config/bmad-voices.md, .bmad-agent-context file
41
41
 
42
- PLUGIN_DIR=".claude/plugins"
43
- PLUGIN_FILE="$PLUGIN_DIR/bmad-voices.md"
44
- ENABLED_FLAG="$PLUGIN_DIR/bmad-voices-enabled.flag"
42
+ CONFIG_DIR=".claude/config"
43
+ VOICE_CONFIG_FILE="$CONFIG_DIR/bmad-voices.md"
44
+ ENABLED_FLAG="$CONFIG_DIR/bmad-voices-enabled.flag"
45
45
 
46
46
  # AI NOTE: Auto-enable pattern - When BMAD is detected via install-manifest.yaml,
47
47
  # automatically enable the voice plugin to provide seamless multi-agent voice support.
@@ -115,7 +115,7 @@ auto_enable_if_bmad_detected() {
115
115
  # Check if BMAD is installed (any version) and plugin not already enabled
116
116
  if [[ "$version" != "0" ]] && [[ ! -f "$ENABLED_FLAG" ]]; then
117
117
  # BMAD detected but plugin not enabled - enable it silently
118
- mkdir -p "$PLUGIN_DIR"
118
+ mkdir -p "$CONFIG_DIR"
119
119
  touch "$ENABLED_FLAG"
120
120
  return 0
121
121
  fi
@@ -144,7 +144,7 @@ get_agent_voice() {
144
144
  return
145
145
  fi
146
146
 
147
- if [[ ! -f "$PLUGIN_FILE" ]]; then
147
+ if [[ ! -f "$VOICE_CONFIG_FILE" ]]; then
148
148
  echo "" # Plugin file missing
149
149
  return
150
150
  fi
@@ -163,19 +163,47 @@ get_agent_voice() {
163
163
  fi
164
164
 
165
165
  # Extract voice from markdown table based on provider
166
- # Column 4 = ElevenLabs Voice, Column 5 = Piper Voice
167
- local column=4 # Default to ElevenLabs (column 4)
166
+ # Table: Agent ID | Agent Name | Intro | ElevenLabs Voice | Piper Voice | Personality
167
+ # AWK columns: $1=empty | $2=ID | $3=Name | $4=Intro | $5=ElevenLabs | $6=Piper | $7=Personality
168
+ local column=5 # Default to ElevenLabs (AWK column 5)
168
169
  if [[ "$active_provider" == "piper" ]]; then
169
- column=5 # Use Piper column
170
+ column=6 # Use Piper (AWK column 6)
170
171
  fi
171
172
 
172
- local voice=$(grep "^| $agent_id " "$PLUGIN_FILE" | \
173
+ local voice=$(grep "^| $agent_id " "$VOICE_CONFIG_FILE" | \
173
174
  awk -F'|' "{print \$$column}" | \
174
175
  sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
175
176
 
176
177
  echo "$voice"
177
178
  }
178
179
 
180
+ # @function get_agent_intro
181
+ # @intent Retrieve intro text for BMAD agent (spoken before their message)
182
+ # @why Helps users identify which agent is speaking in party mode
183
+ # @param $1 {string} agent_id - BMAD agent identifier
184
+ # @returns Echoes intro text to stdout, empty string if not configured
185
+ # @exitcode Always 0
186
+ # @sideeffects None
187
+ # @edgecases Returns empty string if plugin file missing, parses column 3 of markdown table
188
+ # @calledby bmad-speak.sh for agent identification in party mode
189
+ # @calls grep, awk, sed
190
+ # @version 2.1.0 - New function for customizable agent introductions
191
+ get_agent_intro() {
192
+ local agent_id="$1"
193
+
194
+ if [[ ! -f "$VOICE_CONFIG_FILE" ]]; then
195
+ echo ""
196
+ return
197
+ fi
198
+
199
+ # AWK column 4 = Intro text
200
+ local intro=$(grep "^| $agent_id " "$VOICE_CONFIG_FILE" | \
201
+ awk -F'|' '{print $4}' | \
202
+ sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
203
+
204
+ echo "$intro"
205
+ }
206
+
179
207
  # @function get_agent_personality
180
208
  # @intent Retrieve TTS personality assigned to specific BMAD agent
181
209
  # @why Agents may have distinct speaking styles (friendly, professional, energetic, etc.)
@@ -190,14 +218,14 @@ get_agent_voice() {
190
218
  get_agent_personality() {
191
219
  local agent_id="$1"
192
220
 
193
- if [[ ! -f "$PLUGIN_FILE" ]]; then
221
+ if [[ ! -f "$VOICE_CONFIG_FILE" ]]; then
194
222
  echo ""
195
223
  return
196
224
  fi
197
225
 
198
- # Column 6 = Personality (changed from 5 due to new ElevenLabs/Piper columns)
199
- local personality=$(grep "^| $agent_id " "$PLUGIN_FILE" | \
200
- awk -F'|' '{print $6}' | \
226
+ # AWK column 7 = Personality
227
+ local personality=$(grep "^| $agent_id " "$VOICE_CONFIG_FILE" | \
228
+ awk -F'|' '{print $7}' | \
201
229
  sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
202
230
 
203
231
  echo "$personality"
@@ -229,10 +257,10 @@ is_plugin_enabled() {
229
257
  # @calledby Main command dispatcher with "enable" argument
230
258
  # @calls mkdir, cat, source, list_mappings, bmad-tts-injector.sh
231
259
  enable_plugin() {
232
- mkdir -p "$PLUGIN_DIR"
260
+ mkdir -p "$CONFIG_DIR"
233
261
 
234
262
  # Save current settings before enabling
235
- BACKUP_FILE="$PLUGIN_DIR/.bmad-previous-settings"
263
+ BACKUP_FILE="$CONFIG_DIR/.bmad-previous-settings"
236
264
 
237
265
  # Save current voice
238
266
  if [[ -f ".claude/tts-voice.txt" ]]; then
@@ -369,7 +397,7 @@ ACTIVATION_EOF
369
397
  # @calledby Main command dispatcher with "disable" argument
370
398
  # @calls source, rm, echo, bmad-tts-injector.sh
371
399
  disable_plugin() {
372
- BACKUP_FILE="$PLUGIN_DIR/.bmad-previous-settings"
400
+ BACKUP_FILE="$CONFIG_DIR/.bmad-previous-settings"
373
401
 
374
402
  # Check if we have a backup to restore
375
403
  if [[ -f "$BACKUP_FILE" ]]; then
@@ -435,15 +463,15 @@ disable_plugin() {
435
463
  # @calledby enable_plugin, show_status, main command dispatcher with "list"
436
464
  # @calls grep, sed, echo
437
465
  list_mappings() {
438
- if [[ ! -f "$PLUGIN_FILE" ]]; then
439
- echo "❌ Plugin file not found: $PLUGIN_FILE"
466
+ if [[ ! -f "$VOICE_CONFIG_FILE" ]]; then
467
+ echo "❌ Plugin file not found: $VOICE_CONFIG_FILE"
440
468
  return 1
441
469
  fi
442
470
 
443
471
  echo "📊 BMAD Agent Voice Mappings:"
444
472
  echo ""
445
473
 
446
- grep "^| " "$PLUGIN_FILE" | grep -v "Agent ID" | grep -v "^|---" | \
474
+ grep "^| " "$VOICE_CONFIG_FILE" | grep -v "Agent ID" | grep -v "^|---" | \
447
475
  while IFS='|' read -r _ agent_id name voice personality _; do
448
476
  agent_id=$(echo "$agent_id" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
449
477
  name=$(echo "$name" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
@@ -471,19 +499,19 @@ set_agent_voice() {
471
499
  local voice="$2"
472
500
  local personality="${3:-normal}"
473
501
 
474
- if [[ ! -f "$PLUGIN_FILE" ]]; then
475
- echo "❌ Plugin file not found: $PLUGIN_FILE"
502
+ if [[ ! -f "$VOICE_CONFIG_FILE" ]]; then
503
+ echo "❌ Plugin file not found: $VOICE_CONFIG_FILE"
476
504
  return 1
477
505
  fi
478
506
 
479
507
  # Check if agent exists
480
- if ! grep -q "^| $agent_id " "$PLUGIN_FILE"; then
508
+ if ! grep -q "^| $agent_id " "$VOICE_CONFIG_FILE"; then
481
509
  echo "❌ Agent '$agent_id' not found in plugin"
482
510
  return 1
483
511
  fi
484
512
 
485
513
  # Update the voice and personality in the table
486
- sed -i.bak "s/^| $agent_id |.*| .* | .* |$/| $agent_id | $(grep "^| $agent_id " "$PLUGIN_FILE" | awk -F'|' '{print $3}') | $voice | $personality |/" "$PLUGIN_FILE"
514
+ sed -i.bak "s/^| $agent_id |.*| .* | .* |$/| $agent_id | $(grep "^| $agent_id " "$VOICE_CONFIG_FILE" | awk -F'|' '{print $3}') | $voice | $personality |/" "$VOICE_CONFIG_FILE"
487
515
 
488
516
  echo "✅ Updated $agent_id → $voice [$personality]"
489
517
  }
@@ -531,12 +559,12 @@ show_status() {
531
559
  # @calledby Main command dispatcher with "edit" argument
532
560
  # @calls echo
533
561
  edit_plugin() {
534
- if [[ ! -f "$PLUGIN_FILE" ]]; then
535
- echo "❌ Plugin file not found: $PLUGIN_FILE"
562
+ if [[ ! -f "$VOICE_CONFIG_FILE" ]]; then
563
+ echo "❌ Plugin file not found: $VOICE_CONFIG_FILE"
536
564
  return 1
537
565
  fi
538
566
 
539
- echo "Opening $PLUGIN_FILE for editing..."
567
+ echo "Opening $VOICE_CONFIG_FILE for editing..."
540
568
  echo "Edit the markdown table to change voice mappings"
541
569
  }
542
570
 
@@ -564,6 +592,9 @@ case "${1:-help}" in
564
592
  get-voice)
565
593
  get_agent_voice "$2"
566
594
  ;;
595
+ get-intro)
596
+ get_agent_intro "$2"
597
+ ;;
567
598
  get-personality)
568
599
  get_agent_personality "$2"
569
600
  ;;
@@ -571,7 +602,7 @@ case "${1:-help}" in
571
602
  edit_plugin
572
603
  ;;
573
604
  *)
574
- echo "Usage: bmad-voice-manager.sh {enable|disable|status|list|set|get-voice|get-personality|edit}"
605
+ echo "Usage: bmad-voice-manager.sh {enable|disable|status|list|set|get-voice|get-intro|get-personality|edit}"
575
606
  echo ""
576
607
  echo "Commands:"
577
608
  echo " enable Enable BMAD voice plugin"
@@ -580,6 +611,7 @@ case "${1:-help}" in
580
611
  echo " list List all agent voice mappings"
581
612
  echo " set <id> <voice> Set voice for agent"
582
613
  echo " get-voice <id> Get voice for agent"
614
+ echo " get-intro <id> Get intro text for agent"
583
615
  echo " get-personality <id> Get personality for agent"
584
616
  echo " edit Edit plugin configuration"
585
617
  exit 1
@@ -46,6 +46,11 @@ export LC_ALL=C
46
46
  TEXT="$1"
47
47
  VOICE_OVERRIDE="$2" # Optional: voice name or ID
48
48
 
49
+ # Remove backslash escaping that Claude might add for special chars like ! and $
50
+ # In single quotes these don't need escaping, but Claude sometimes adds \! anyway
51
+ TEXT="${TEXT//\\!/!}"
52
+ TEXT="${TEXT//\\\$/\$}"
53
+
49
54
  # Get script directory
50
55
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
51
56
 
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # File: .claude/hooks/tts-queue-worker.sh
4
+ #
5
+ # TTS Queue Worker - Background process that plays queued TTS sequentially
6
+ # Automatically exits when queue is empty for 5 seconds
7
+
8
+ set -euo pipefail
9
+
10
+ QUEUE_DIR="/tmp/agentvibes-tts-queue"
11
+ WORKER_PID_FILE="$QUEUE_DIR/worker.pid"
12
+ IDLE_TIMEOUT=5 # Exit after 5 seconds of no new requests
13
+
14
+ # Get script directory
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+
17
+ # Trap to clean up on exit
18
+ trap "rm -f $WORKER_PID_FILE" EXIT
19
+
20
+ # Process queue items
21
+ process_queue() {
22
+ local idle_count=0
23
+
24
+ while true; do
25
+ # Find oldest queue item
26
+ local queue_item=$(ls -1 "$QUEUE_DIR"/*.queue 2>/dev/null | sort | head -1)
27
+
28
+ if [[ -z "$queue_item" ]]; then
29
+ # Queue is empty, increment idle counter
30
+ idle_count=$((idle_count + 1))
31
+
32
+ if [[ $idle_count -ge $IDLE_TIMEOUT ]]; then
33
+ # No new items for timeout period, exit worker
34
+ exit 0
35
+ fi
36
+
37
+ # Wait 1 second and check again
38
+ sleep 1
39
+ continue
40
+ fi
41
+
42
+ # Reset idle counter - we have work
43
+ idle_count=0
44
+
45
+ # Load TTS request
46
+ source "$queue_item"
47
+
48
+ # Decode base64 values
49
+ TEXT=$(echo -n "$TEXT_B64" | base64 -d)
50
+ VOICE=$(echo -n "$VOICE_B64" | base64 -d)
51
+
52
+ # Play TTS (this blocks until audio finishes due to lock mechanism)
53
+ if [[ -n "${VOICE:-}" ]]; then
54
+ bash "$SCRIPT_DIR/play-tts.sh" "$TEXT" "$VOICE" 2>/dev/null || true
55
+ else
56
+ bash "$SCRIPT_DIR/play-tts.sh" "$TEXT" 2>/dev/null || true
57
+ fi
58
+
59
+ # Add 2-second pause between speakers for natural conversation flow
60
+ sleep 2
61
+
62
+ # Remove processed item
63
+ rm -f "$queue_item"
64
+ done
65
+ }
66
+
67
+ # Start processing
68
+ process_queue
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # File: .claude/hooks/tts-queue.sh
4
+ #
5
+ # TTS Queue Manager for Party Mode
6
+ # Queues TTS requests and plays them sequentially in the background
7
+ # This allows Claude to continue generating responses while audio plays in order
8
+
9
+ set -euo pipefail
10
+
11
+ QUEUE_DIR="/tmp/agentvibes-tts-queue"
12
+ QUEUE_LOCK="$QUEUE_DIR/queue.lock"
13
+ WORKER_PID_FILE="$QUEUE_DIR/worker.pid"
14
+
15
+ # Get script directory
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+
18
+ # Initialize queue directory
19
+ mkdir -p "$QUEUE_DIR"
20
+
21
+ # @function add_to_queue
22
+ # @intent Add a TTS request to the queue for sequential playback
23
+ # @param $1 dialogue text
24
+ # @param $2 voice name (optional)
25
+ add_to_queue() {
26
+ local text="$1"
27
+ local voice="${2:-}"
28
+
29
+ # Create unique queue item with timestamp
30
+ local timestamp=$(date +%s%N)
31
+ local queue_file="$QUEUE_DIR/$timestamp.queue"
32
+
33
+ # Write request to queue file (base64 encoded to handle all special chars)
34
+ cat > "$queue_file" <<EOF
35
+ TEXT_B64=$(echo -n "$text" | base64 -w0)
36
+ VOICE_B64=$(echo -n "$voice" | base64 -w0)
37
+ EOF
38
+
39
+ # Start queue worker if not already running
40
+ start_worker_if_needed
41
+ }
42
+
43
+ # @function start_worker_if_needed
44
+ # @intent Start the queue worker process if it's not already running
45
+ start_worker_if_needed() {
46
+ # Check if worker is already running
47
+ if [[ -f "$WORKER_PID_FILE" ]]; then
48
+ local pid=$(cat "$WORKER_PID_FILE")
49
+ if kill -0 "$pid" 2>/dev/null; then
50
+ # Worker is running
51
+ return 0
52
+ fi
53
+ fi
54
+
55
+ # Start worker in background
56
+ "$SCRIPT_DIR/tts-queue-worker.sh" &
57
+ echo $! > "$WORKER_PID_FILE"
58
+ }
59
+
60
+ # @function clear_queue
61
+ # @intent Clear all pending TTS requests (emergency stop)
62
+ clear_queue() {
63
+ rm -f "$QUEUE_DIR"/*.queue
64
+ echo "✅ Queue cleared"
65
+ }
66
+
67
+ # @function show_queue
68
+ # @intent Display current queue status
69
+ show_queue() {
70
+ local count=$(ls -1 "$QUEUE_DIR"/*.queue 2>/dev/null | wc -l)
71
+ echo "📊 Queue status: $count items pending"
72
+
73
+ if [[ -f "$WORKER_PID_FILE" ]]; then
74
+ local pid=$(cat "$WORKER_PID_FILE")
75
+ if kill -0 "$pid" 2>/dev/null; then
76
+ echo "✅ Worker process running (PID: $pid)"
77
+ else
78
+ echo "❌ Worker process not running"
79
+ fi
80
+ else
81
+ echo "❌ Worker process not running"
82
+ fi
83
+ }
84
+
85
+ # Main command dispatcher
86
+ case "${1:-help}" in
87
+ add)
88
+ add_to_queue "${2:-}" "${3:-}"
89
+ ;;
90
+ clear)
91
+ clear_queue
92
+ ;;
93
+ status)
94
+ show_queue
95
+ ;;
96
+ *)
97
+ echo "Usage: tts-queue.sh {add|clear|status}"
98
+ echo ""
99
+ echo "Commands:"
100
+ echo " add <text> [voice] Add TTS request to queue"
101
+ echo " clear Clear all pending requests"
102
+ echo " status Show queue status"
103
+ exit 1
104
+ ;;
105
+ esac
@@ -0,0 +1 @@
1
+ high
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  [![Publish](https://github.com/paulpreibisch/AgentVibes/actions/workflows/publish.yml/badge.svg)](https://github.com/paulpreibisch/AgentVibes/actions/workflows/publish.yml)
12
12
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
13
13
 
14
- **Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v2.5.0
14
+ **Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v2.7.0
15
15
 
16
16
  ---
17
17
 
@@ -94,16 +94,16 @@ Whether you're coding in Claude Code, chatting in Claude Desktop, or using Warp
94
94
 
95
95
  ## 📰 Latest Release
96
96
 
97
- **[v2.6.0 - BMAD Integration & Voice Management CLI](https://github.com/paulpreibisch/AgentVibes/releases/tag/v2.6.0)** 🎉
97
+ **[v2.7.0 - Party Mode Voice Improvements](https://github.com/paulpreibisch/AgentVibes/releases/tag/v2.7.0)** 🎉
98
98
 
99
- AgentVibes v2.6.0 brings comprehensive BMAD integration with unique AI voices for all agents! BMAD is a revolutionary AI-driven agile framework that automatically adapts from single bug fixes to enterprise-scale systems.
99
+ AgentVibes v2.7.0 transforms BMAD party mode into a professional multi-agent voice conversation system! This release introduces a sophisticated TTS queue architecture enabling sequential voice playback without blocking Claude Code, natural 2-second pauses between speakers, and customizable agent introductions.
100
100
 
101
101
  **Key highlights:**
102
- - 🎙️ **BMAD TTS Integration** - All BMAD agents can now speak with unique voices
103
- - 🛠️ **Voice Management CLI** - 5 new commands for managing agent voices
104
- - 🔍 **Fuzzy Voice Matching** - Use short names like "ryan" instead of full voice IDs
105
- - 📚 **Improved Help** - Built-in help command lists all available commands
106
- - 🔧 **BMAD v6 Support** - Detects and works with latest BMAD folder structure
102
+ - 🎭 **TTS Queue System** - Sequential non-blocking voice playback for party mode
103
+ - ⏸️ **Natural Speaker Pauses** - 2-second delay between agents for conversation flow
104
+ - 🎤 **Speaker Introductions** - Configurable intro text (e.g., "John, Product Manager here")
105
+ - 📁 **Config Reorganization** - Moved from `.claude/plugins/` to official `.claude/config/`
106
+ - 🐛 **Text Escaping Fixes** - No more "backslash exclamation" in speech
107
107
 
108
108
  [→ View All Releases](https://github.com/paulpreibisch/AgentVibes/releases)
109
109