agentvibes 5.4.0 → 5.6.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.
@@ -28,5 +28,13 @@
28
28
  "voice": "en_US-ljspeech-high",
29
29
  "pretext": "Agent Vibes Here",
30
30
  "setupCompleted": true,
31
- "ttsEngine": "piper"
31
+ "ttsEngine": "piper",
32
+ "thumbsUp": [
33
+ "en_US-libritts-high::Adam",
34
+ "en_US-libritts_r-medium::Adam-2"
35
+ ],
36
+ "favorites": [
37
+ "en_US-libritts-high::Adam",
38
+ "en_US-libritts_r-medium::Adam-2"
39
+ ]
32
40
  }
@@ -50,3 +50,15 @@ _party_mode|compand 0.3,1 6:-70,-60,-20|agent_vibes_dark_chill_step_loop.mp3|0.4
50
50
  |||
51
51
  # Default (no agent specified) - clean with Bachata background|||
52
52
  default|reverb 20 50 50|agentvibes_soft_flamenco_loop.mp3|0.30
53
+ |||
54
+ # Per-LLM routing rows — looked up by play-tts.sh / play-tts.ps1 when -llm is passed|||
55
+ # Format: llm:<name>|REVERB_PRESET|BACKGROUND_FILE|BACKGROUND_VOLUME|VOICE|PRETEXT|ENGINE|||
56
+ |||
57
+ # Claude Code (claude-code CLI via CLAUDECODE=1 env or AGENTVIBES_LLM=claude-code)|||
58
+ llm:claude-code|||0.15||Agent Vibes Here|piper
59
+ |||
60
+ # GitHub Copilot Chat (VS Code MCP or AGENTVIBES_LLM=copilot)|||
61
+ llm:copilot|off||||Agent Vibes Here|piper
62
+ |||
63
+ # OpenAI Codex CLI (AGENTVIBES_LLM=codex)|||
64
+ llm:codex|off||||Agent Vibes Here|piper
@@ -24,4 +24,4 @@ agent_vibes_arabic_v2_loop.mp3:.00000000000000000006132724
24
24
  agent_vibes_chillwave_v2_loop.mp3:14.628390
25
25
  agent_vibes_bachata_v1_loop.mp3:.00000000000000000005344000
26
26
  agent_vibes_goa_trance_v2_loop.mp3:.00000000000000000002499918
27
- agentvibes_soft_flamenco_loop.mp3:10.736417
27
+ agentvibes_soft_flamenco_loop.mp3:9.432018
@@ -1 +1 @@
1
- 20260422
1
+ 20260428
File without changes
@@ -50,11 +50,15 @@ if [[ ! -f "$PROJECT_ROOT/_bmad/_config/agent-manifest.csv" ]]; then
50
50
  fi
51
51
 
52
52
  # ---------------------------------------------------------------------------
53
- # Per-agent profile reader — reads from ~/.agentvibes/bmad-voice-map.json
53
+ # Per-agent profile reader — reads from project .agentvibes/bmad-voice-map.json (falls back to global)
54
54
  # Uses node for reliable JSON parsing (jq may not be installed)
55
55
  # Returns empty string if field not found or file missing
56
56
 
57
- VOICE_MAP_FILE="$HOME/.agentvibes/bmad-voice-map.json"
57
+ if [[ -f "$PROJECT_ROOT/.agentvibes/bmad-voice-map.json" ]]; then
58
+ VOICE_MAP_FILE="$PROJECT_ROOT/.agentvibes/bmad-voice-map.json"
59
+ else
60
+ VOICE_MAP_FILE="$HOME/.agentvibes/bmad-voice-map.json"
61
+ fi
58
62
 
59
63
  # Read a field from the per-agent profile in bmad-voice-map.json
60
64
  # Usage: read_agent_profile <agent_id> <field>
@@ -551,8 +551,8 @@ if [[ "${AGENTVIBES_TEST_MODE:-false}" != "true" ]] && [[ "${AGENTVIBES_NO_PLAYB
551
551
  termux-media-player play "$TEMP_FILE" >/dev/null 2>&1 &
552
552
  PLAYER_PID=$!
553
553
  else
554
- # Linux/WSL: Prefer paplay (PulseAudio) for best WSL audio quality
555
- (paplay "$TEMP_FILE" || mpv "$TEMP_FILE" || aplay "$TEMP_FILE") >/dev/null 2>&1 &
554
+ # Linux/WSL: paplay with 500ms latency buffer prevents choppiness over RDP/network audio
555
+ (paplay --latency-msec=500 "$TEMP_FILE" || mpv "$TEMP_FILE" || aplay -B 2000000 "$TEMP_FILE") >/dev/null 2>&1 &
556
556
  PLAYER_PID=$!
557
557
  fi
558
558
  fi
@@ -103,8 +103,29 @@ elif [[ -f "$GLOBAL_MUTE_FILE" ]]; then
103
103
  exit 0
104
104
  fi
105
105
 
106
+ # Parse named flags (e.g. --llm) before positional arguments.
107
+ # This allows callers to pass: play-tts.sh --llm claude-code "text to speak"
108
+ # Named args are extracted; remaining positional args are shifted into $1/$2/$3.
109
+ LLM_PROVIDER="${LLM_PROVIDER:-}"
110
+ _POSITIONAL_ARGS=()
111
+ while [[ $# -gt 0 ]]; do
112
+ case "$1" in
113
+ --llm)
114
+ LLM_PROVIDER="${2:-}"
115
+ shift 2
116
+ ;;
117
+ *)
118
+ _POSITIONAL_ARGS+=("$1")
119
+ shift
120
+ ;;
121
+ esac
122
+ done
123
+ set -- "${_POSITIONAL_ARGS[@]+"${_POSITIONAL_ARGS[@]}"}"
124
+ unset _POSITIONAL_ARGS
125
+
106
126
  TEXT="${1:-}"
107
127
  VOICE_OVERRIDE="${2:-}" # Optional: voice name or ID
128
+ AGENT_PROFILE_FILE="${3:-}" # Optional: path to agent profile file
108
129
 
109
130
  # Security: Validate inputs
110
131
  if [[ -z "$TEXT" ]]; then
@@ -397,7 +418,7 @@ fi
397
418
  # Normal single-language mode - route to appropriate provider implementation
398
419
  case "$ACTIVE_PROVIDER" in
399
420
  piper)
400
- exec bash "$SCRIPT_DIR/play-tts-piper.sh" "$TEXT" "$VOICE_OVERRIDE" "$AGENT_PROFILE_FILE"
421
+ exec bash "$SCRIPT_DIR/play-tts-piper.sh" "$TEXT" "$VOICE_OVERRIDE" "${AGENT_PROFILE_FILE:-}"
401
422
  ;;
402
423
  soprano)
403
424
  exec bash "$SCRIPT_DIR/play-tts-soprano.sh" "$TEXT" "$VOICE_OVERRIDE"
@@ -1,164 +1,178 @@
1
- #
2
- # File: .claude/hooks-windows/play-tts-windows-piper.ps1
3
- #
4
- # AgentVibes - Windows Piper TTS Provider
5
- # High-quality neural TTS using Piper.exe
6
- #
7
-
8
- param(
9
- [Parameter(Mandatory = $true)]
10
- [string]$Text,
11
-
12
- [Parameter(Mandatory = $false)]
13
- [string]$VoiceOverride
14
- )
15
-
16
- # Configuration paths
17
- $ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
18
- $ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
19
-
20
- if (Test-Path $ProjectClaudeDir) {
21
- $ClaudeDir = $ProjectClaudeDir
22
- } else {
23
- $ClaudeDir = "$env:USERPROFILE\.claude"
24
- }
25
-
26
- # Audio cache and voice config use project-local .claude
27
- $AudioDir = "$ClaudeDir\audio"
28
- $VoiceFile = "$ClaudeDir\tts-voice-piper.txt"
29
-
30
- # Voices and Piper binary are global (shared across projects, ~100MB+)
31
- $UserClaudeDir = "$env:USERPROFILE\.claude"
32
- $VoicesDir = "$UserClaudeDir\piper-voices"
33
- $PiperExe = "$env:LOCALAPPDATA\Programs\Piper\piper.exe"
34
-
35
- # Ensure directories exist
36
- foreach ($dir in @($AudioDir, $VoicesDir)) {
37
- if (-not (Test-Path $dir)) {
38
- New-Item -ItemType Directory -Path $dir -Force | Out-Null
39
- }
40
- }
41
-
42
- # Check if Piper is installed
43
- if (-not (Test-Path $PiperExe)) {
44
- Write-Host "[ERROR] Piper not found at: $PiperExe" -ForegroundColor Red
45
- Write-Host "Run: .\setup-windows.ps1 to install Piper" -ForegroundColor Yellow
46
- exit 1
47
- }
48
-
49
- # Determine voice to use
50
- $VoiceName = ""
51
-
52
- if ($VoiceOverride) {
53
- $VoiceName = $VoiceOverride
54
- }
55
- elseif (Test-Path $VoiceFile) {
56
- $VoiceName = (Get-Content $VoiceFile -Raw).Trim()
57
- }
58
-
59
- # Default voice if not specified
60
- if (-not $VoiceName) {
61
- $VoiceName = "en_US-ryan-high"
62
- }
63
-
64
- # Security: Validate voice name to prevent path traversal
65
- # Only allow alphanumeric, underscore, hyphen, and period
66
- if ($VoiceName -notmatch '^[a-zA-Z0-9_\-\.]+$') {
67
- Write-Host "[ERROR] Invalid voice name: $VoiceName" -ForegroundColor Red
68
- exit 1
69
- }
70
-
71
- # Resolve voice model path and validate it stays within VoicesDir
72
- $VoiceModelFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx")
73
- $VoiceJsonFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx.json")
74
- $ResolvedVoicesDir = [System.IO.Path]::GetFullPath($VoicesDir)
75
- if (-not $VoiceModelFile.StartsWith($ResolvedVoicesDir)) {
76
- Write-Host "[ERROR] Voice path outside voices directory" -ForegroundColor Red
77
- exit 1
78
- }
79
-
80
- # Check if voice model exists, download if missing
81
- if (-not (Test-Path $VoiceModelFile)) {
82
- Write-Host "[DOWNLOAD] Voice model: $VoiceName" -ForegroundColor Yellow
83
-
84
- # Try to download from Hugging Face
85
- # Voice name format: {lang}_{region}-{speaker}-{quality}
86
- # HF path format: {lang}/{lang}_{region}/{speaker}/{quality}/{voicename}.onnx
87
- try {
88
- # Parse voice name to build correct HF path
89
- # e.g. en_US-ryan-high -> en/en_US/ryan/high/en_US-ryan-high.onnx
90
- if ($VoiceName -match '^([a-z]{2})_([A-Z]{2})-([a-zA-Z0-9_]+)-([a-z]+)$') {
91
- $Lang = $Matches[1]
92
- $LangRegion = "$($Matches[1])_$($Matches[2])"
93
- $Speaker = $Matches[3]
94
- $Quality = $Matches[4]
95
- $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/$Lang/$LangRegion/$Speaker/$Quality"
96
- } else {
97
- # Fallback for non-standard voice names
98
- $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/ryan/high"
99
- }
100
- $ModelUrl = "$HFBase/$VoiceName.onnx"
101
- $JsonUrl = "$HFBase/$VoiceName.onnx.json"
102
-
103
- Write-Host " Downloading model..." -ForegroundColor Cyan
104
- Invoke-WebRequest -Uri $ModelUrl -OutFile $VoiceModelFile -ErrorAction Stop
105
- Write-Host " Downloading config..." -ForegroundColor Cyan
106
- Invoke-WebRequest -Uri $JsonUrl -OutFile $VoiceJsonFile -ErrorAction Stop
107
- Write-Host "[OK] Voice model downloaded" -ForegroundColor Green
108
- }
109
- catch {
110
- Write-Host "[ERROR] Failed to download voice model: $_" -ForegroundColor Red
111
- Write-Host "Make sure you have internet connection" -ForegroundColor Yellow
112
- exit 1
113
- }
114
- }
115
-
116
- # Sanitize text for speech - strip shell metacharacters and PS special chars
117
- $Text = $Text -replace '\\', ' '
118
- $Text = $Text -replace '[{}<>|`~^$;"''()]', ''
119
- $Text = $Text -replace '\s+', ' '
120
- $Text = $Text.Trim()
121
-
122
- # Create audio file path
123
- $Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
124
- $AudioFile = "$AudioDir\tts-$Timestamp.wav"
125
-
126
- # Synthesize with Piper
127
- try {
128
- Write-Host "[SYNTH] Synthesizing with Piper..." -ForegroundColor Cyan
129
-
130
- # Run Piper with text input
131
- $Text | & $PiperExe `
132
- --model $VoiceModelFile `
133
- --output-file $AudioFile `
134
- 2>$null
135
-
136
- if (-not (Test-Path $AudioFile)) {
137
- Write-Host "[ERROR] Piper synthesis failed" -ForegroundColor Red
138
- exit 1
139
- }
140
-
141
- # Display results
142
- Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
143
- Write-Host "[VOICE] Voice used: $VoiceName (Piper)" -ForegroundColor Green
144
-
145
- # Play the audio using built-in Windows audio player (skip if AGENTVIBES_NO_PLAY is set)
146
- if (-not $env:AGENTVIBES_NO_PLAY) {
147
- $player = $null
148
- try {
149
- $player = New-Object System.Media.SoundPlayer $AudioFile
150
- $player.PlaySync()
151
- }
152
- catch {
153
- Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
154
- Write-Host "Audio saved to: $AudioFile" -ForegroundColor Gray
155
- }
156
- finally {
157
- if ($player) { $player.Dispose() }
158
- }
159
- }
160
- }
161
- catch {
162
- Write-Host "[ERROR] Error running Piper: $_" -ForegroundColor Red
163
- exit 1
164
- }
1
+ #
2
+ # File: .claude/hooks-windows/play-tts-windows-piper.ps1
3
+ #
4
+ # AgentVibes - Windows Piper TTS Provider
5
+ # High-quality neural TTS using Piper.exe
6
+ #
7
+
8
+ param(
9
+ [Parameter(Mandatory = $true)]
10
+ [string]$Text,
11
+
12
+ [Parameter(Mandatory = $false)]
13
+ [string]$VoiceOverride
14
+ )
15
+
16
+ # Configuration paths
17
+ $ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
18
+ $ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
19
+
20
+ if (Test-Path $ProjectClaudeDir) {
21
+ $ClaudeDir = $ProjectClaudeDir
22
+ } else {
23
+ $ClaudeDir = "$env:USERPROFILE\.claude"
24
+ }
25
+
26
+ # Audio cache and voice config use project-local .claude
27
+ $AudioDir = "$ClaudeDir\audio"
28
+ $VoiceFile = "$ClaudeDir\tts-voice-piper.txt"
29
+
30
+ # Voices and Piper binary are global (shared across projects, ~100MB+)
31
+ $UserClaudeDir = "$env:USERPROFILE\.claude"
32
+ $VoicesDir = "$UserClaudeDir\piper-voices"
33
+ $PiperExe = "$env:LOCALAPPDATA\Programs\Piper\piper.exe"
34
+
35
+ # Ensure directories exist
36
+ foreach ($dir in @($AudioDir, $VoicesDir)) {
37
+ if (-not (Test-Path $dir)) {
38
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
39
+ }
40
+ }
41
+
42
+ # Check if Piper is installed
43
+ if (-not (Test-Path $PiperExe)) {
44
+ Write-Host "[ERROR] Piper not found at: $PiperExe" -ForegroundColor Red
45
+ Write-Host "Run: .\setup-windows.ps1 to install Piper" -ForegroundColor Yellow
46
+ exit 1
47
+ }
48
+
49
+ # Determine voice to use
50
+ $VoiceName = ""
51
+
52
+ if ($VoiceOverride) {
53
+ $VoiceName = $VoiceOverride
54
+ }
55
+ elseif (Test-Path $VoiceFile) {
56
+ $VoiceName = (Get-Content $VoiceFile -Raw).Trim()
57
+ }
58
+
59
+ # Default voice if not specified
60
+ if (-not $VoiceName) {
61
+ $VoiceName = "en_US-ryan-high"
62
+ }
63
+
64
+ # Security: Validate voice name to prevent path traversal
65
+ # Only allow alphanumeric, underscore, hyphen, and period
66
+ if ($VoiceName -notmatch '^[a-zA-Z0-9_\-\.]+$') {
67
+ Write-Host "[ERROR] Invalid voice name: $VoiceName" -ForegroundColor Red
68
+ exit 1
69
+ }
70
+
71
+ # Resolve voice model path and validate it stays within VoicesDir
72
+ $VoiceModelFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx")
73
+ $VoiceJsonFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx.json")
74
+ $ResolvedVoicesDir = [System.IO.Path]::GetFullPath($VoicesDir)
75
+ if (-not $VoiceModelFile.StartsWith($ResolvedVoicesDir)) {
76
+ Write-Host "[ERROR] Voice path outside voices directory" -ForegroundColor Red
77
+ exit 1
78
+ }
79
+
80
+ # Check if voice model exists, download if missing
81
+ if (-not (Test-Path $VoiceModelFile)) {
82
+ Write-Host "[DOWNLOAD] Voice model: $VoiceName" -ForegroundColor Yellow
83
+
84
+ # Try to download from Hugging Face
85
+ # Voice name format: {lang}_{region}-{speaker}-{quality}
86
+ # HF path format: {lang}/{lang}_{region}/{speaker}/{quality}/{voicename}.onnx
87
+ try {
88
+ # Parse voice name to build correct HF path
89
+ # e.g. en_US-ryan-high -> en/en_US/ryan/high/en_US-ryan-high.onnx
90
+ if ($VoiceName -match '^([a-z]{2})_([A-Z]{2})-([a-zA-Z0-9_]+)-([a-z]+)$') {
91
+ $Lang = $Matches[1]
92
+ $LangRegion = "$($Matches[1])_$($Matches[2])"
93
+ $Speaker = $Matches[3]
94
+ $Quality = $Matches[4]
95
+ $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/$Lang/$LangRegion/$Speaker/$Quality"
96
+ } else {
97
+ # Fallback for non-standard voice names
98
+ $HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/ryan/high"
99
+ }
100
+ $ModelUrl = "$HFBase/$VoiceName.onnx"
101
+ $JsonUrl = "$HFBase/$VoiceName.onnx.json"
102
+
103
+ Write-Host " Downloading model..." -ForegroundColor Cyan
104
+ Invoke-WebRequest -Uri $ModelUrl -OutFile $VoiceModelFile -ErrorAction Stop
105
+ Write-Host " Downloading config..." -ForegroundColor Cyan
106
+ Invoke-WebRequest -Uri $JsonUrl -OutFile $VoiceJsonFile -ErrorAction Stop
107
+ Write-Host "[OK] Voice model downloaded" -ForegroundColor Green
108
+ }
109
+ catch {
110
+ Write-Host "[ERROR] Failed to download voice model: $_" -ForegroundColor Red
111
+ Write-Host "Make sure you have internet connection" -ForegroundColor Yellow
112
+ exit 1
113
+ }
114
+ }
115
+
116
+ # Sanitize text for speech - strip shell metacharacters and PS special chars
117
+ $Text = $Text -replace '\\', ' '
118
+ $Text = $Text -replace '[{}<>|`~^$;"''()]', ''
119
+ $Text = $Text -replace '\s+', ' '
120
+ $Text = $Text.Trim()
121
+
122
+ # Create audio file path
123
+ $Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
124
+ $AudioFile = "$AudioDir\tts-$Timestamp.wav"
125
+
126
+ # Synthesize with Piper
127
+ try {
128
+ Write-Host "[SYNTH] Synthesizing with Piper..." -ForegroundColor Cyan
129
+
130
+ # Run Piper with text input
131
+ $Text | & $PiperExe `
132
+ --model $VoiceModelFile `
133
+ --output-file $AudioFile `
134
+ 2>$null
135
+
136
+ if (-not (Test-Path $AudioFile)) {
137
+ Write-Host "[ERROR] Piper synthesis failed" -ForegroundColor Red
138
+ exit 1
139
+ }
140
+
141
+ # Display results
142
+ Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
143
+ Write-Host "[VOICE] Voice used: $VoiceName (Piper)" -ForegroundColor Green
144
+
145
+ # Play the audio (skip if AGENTVIBES_NO_PLAY is set)
146
+ if (-not $env:AGENTVIBES_NO_PLAY) {
147
+ # Prefer ffplay: handles 22050 Hz → 48000 Hz resampling cleanly (SoundPlayer uses
148
+ # WinMM's low-quality resampler which produces choppy audio at non-native rates).
149
+ $ffplayPath = (Get-Command ffplay -ErrorAction SilentlyContinue)?.Source
150
+ if (-not $ffplayPath) {
151
+ # SSH/watcher sessions may have a minimal PATH — refresh from registry
152
+ $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" +
153
+ [System.Environment]::GetEnvironmentVariable("Path","User")
154
+ $ffplayPath = (Get-Command ffplay -ErrorAction SilentlyContinue)?.Source
155
+ }
156
+ if ($ffplayPath) {
157
+ & $ffplayPath -autoexit -nodisp -loglevel quiet $AudioFile 2>$null
158
+ }
159
+ else {
160
+ $player = $null
161
+ try {
162
+ $player = New-Object System.Media.SoundPlayer $AudioFile
163
+ $player.PlaySync()
164
+ }
165
+ catch {
166
+ Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
167
+ Write-Host "Audio saved to: $AudioFile" -ForegroundColor Gray
168
+ }
169
+ finally {
170
+ if ($player) { $player.Dispose() }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ catch {
176
+ Write-Host "[ERROR] Error running Piper: $_" -ForegroundColor Red
177
+ exit 1
178
+ }