agentvibes 5.12.0 โ 5.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agentvibes/install-manifest.json +111 -91
- package/.claude/commands/agent-vibes/commands.json +0 -20
- package/.claude/commands/agent-vibes/unmute.md +6 -2
- package/.claude/config/audio-effects.cfg +6 -6
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/agentvibes-session-id.sh +69 -0
- package/.claude/hooks/bmad-party-speak.sh +20 -4
- package/.claude/hooks/bmad-speak.sh +60 -2
- package/.claude/hooks/bmad-tts-injector.sh +20 -1
- package/.claude/hooks/bmad-voice-manager.sh +25 -3
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +21 -2
- package/.claude/hooks/clawdbot-receiver.sh +19 -1
- package/.claude/hooks/elevenlabs-voices.sh +62 -0
- package/.claude/hooks/kokoro-installer.sh +20 -10
- package/.claude/hooks/language-manager.sh +10 -3
- package/.claude/hooks/party-set-room.sh +71 -0
- package/.claude/hooks/party-stage-roster.py +328 -0
- package/.claude/hooks/personality-manager.sh +19 -2
- package/.claude/hooks/piper-voice-manager.sh +3 -2
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +24 -5
- package/.claude/hooks/play-tts-elevenlabs.sh +38 -118
- package/.claude/hooks/play-tts-kokoro.sh +33 -6
- package/.claude/hooks/play-tts-soprano.sh +3 -2
- package/.claude/hooks/play-tts-ssh-remote.sh +37 -29
- package/.claude/hooks/play-tts-termux-ssh.sh +5 -4
- package/.claude/hooks/play-tts.sh +66 -61
- package/.claude/hooks/provider-catalog.json +352 -0
- package/.claude/hooks/provider-catalog.sh +161 -0
- package/.claude/hooks/provider-commands.sh +2 -1
- package/.claude/hooks/provider-manager.sh +47 -9
- package/.claude/hooks/python-resolver.sh +117 -0
- package/.claude/hooks/session-id.sh +56 -0
- package/.claude/hooks/session-start-tts.sh +39 -0
- package/.claude/hooks/speed-manager.sh +1 -1
- package/.claude/hooks/translate-manager.sh +3 -2
- package/.claude/hooks/translator.py +1 -1
- package/.claude/hooks/voice-manager.sh +242 -10
- package/.claude/hooks-windows/language-manager.ps1 +7 -1
- package/.claude/hooks-windows/personality-manager.ps1 +16 -1
- package/.claude/hooks-windows/play-tts-kokoro.ps1 +20 -4
- package/.claude/hooks-windows/play-tts.ps1 +32 -3
- package/.claude/hooks-windows/provider-catalog.ps1 +140 -0
- package/.claude/hooks-windows/provider-manager.ps1 +63 -8
- package/.claude/hooks-windows/tts-watcher.ps1 +33 -12
- package/.claude/hooks-windows/voice-manager-windows.ps1 +49 -0
- package/.mcp.json +0 -7
- package/README.md +12 -3
- package/RELEASE_NOTES.md +61 -0
- package/mcp-server/server.py +146 -49
- package/mcp-server/test_mcp_correctness.py +20 -2
- package/mcp-server/test_windows_script_parity.py +0 -2
- package/package.json +2 -2
- package/src/cli/list-voices.js +218 -114
- package/src/console/bling.js +71 -0
- package/src/console/music-preview.js +79 -0
- package/src/console/tabs/music-tab.js +16 -39
- package/src/console/tabs/settings-tab.js +195 -13
- package/src/console/tabs/setup-tab.js +9 -34
- package/src/console/tabs/voices-tab.js +83 -14
- package/src/console/widgets/track-picker.js +82 -0
- package/src/installer.js +136 -18
- package/src/services/provider-catalog.js +412 -0
- package/src/services/provider-voice-catalog.js +52 -73
- package/src/services/tts-engine-service.js +29 -0
- package/src/utils/provider-validator.js +62 -12
- package/.claude/commands/agent-vibes/language.md +0 -23
- package/.claude/commands/agent-vibes/learn.md +0 -67
- package/.claude/commands/agent-vibes/replay-target.md +0 -14
- package/.claude/commands/agent-vibes/target-voice.md +0 -26
- package/.claude/commands/agent-vibes/target.md +0 -30
- package/.claude/hooks/learn-manager.sh +0 -492
- package/.claude/hooks/replay-target-audio.sh +0 -95
- package/.claude/hooks-windows/learn-manager.ps1 +0 -241
|
@@ -27,6 +27,20 @@ $ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
|
27
27
|
$ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
|
|
28
28
|
if (Test-Path $ProjectClaudeDir) { $ClaudeDir = $ProjectClaudeDir } else { $ClaudeDir = "$env:USERPROFILE\.claude" }
|
|
29
29
|
|
|
30
|
+
# --- Default voice from the generated Provider Catalog (SSOT) -----------------
|
|
31
|
+
# FAIL-SAFE: keep the literal fallback for installed-tree skew (mirrors play-tts.sh
|
|
32
|
+
# PLAN_OK). The synth-time shape check below stays LENIENT (design ยง3.3) so a voice
|
|
33
|
+
# from a newer kokoro model still degrades audibly instead of bricking.
|
|
34
|
+
$KokoroDefault = "af_heart"
|
|
35
|
+
$CatalogPs1 = Join-Path $ScriptPath 'provider-catalog.ps1'
|
|
36
|
+
if (Test-Path $CatalogPs1) {
|
|
37
|
+
. $CatalogPs1
|
|
38
|
+
if (Get-Command Get-CatalogDefaultVoice -ErrorAction SilentlyContinue) {
|
|
39
|
+
$d = Get-CatalogDefaultVoice -Provider 'kokoro'
|
|
40
|
+
if ($d) { $KokoroDefault = $d }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
$AudioDir = "$ClaudeDir\audio"
|
|
31
45
|
$ConfigDir = "$ClaudeDir\config"
|
|
32
46
|
if (-not (Test-Path $AudioDir)) { New-Item -ItemType Directory -Path $AudioDir -Force | Out-Null }
|
|
@@ -70,13 +84,15 @@ if ($VoiceOverride) {
|
|
|
70
84
|
}
|
|
71
85
|
# Kokoro voice ids look like af_heart, am_michael, bf_emma. Strip any ::display suffix.
|
|
72
86
|
if ($VoiceName -match '::') { $VoiceName = ($VoiceName -split '::')[0] }
|
|
73
|
-
if (-not $VoiceName) { $VoiceName =
|
|
87
|
+
if (-not $VoiceName) { $VoiceName = $KokoroDefault }
|
|
74
88
|
|
|
75
89
|
# Security: validate voice id (lowercase prefix + underscore + name).
|
|
76
|
-
#
|
|
90
|
+
# LENIENT shape check (design ยง3.3) โ rejects path-traversal / injection but lets
|
|
91
|
+
# an unknown-but-shape-valid voice from a newer kokoro model through; falls back
|
|
92
|
+
# to the catalog default only on a shape violation.
|
|
77
93
|
if ($VoiceName -notmatch '^[a-z]{2}_[a-z0-9_]+$') {
|
|
78
|
-
Write-Host "[WARNING] Invalid Kokoro voice '$VoiceName' - falling back to
|
|
79
|
-
$VoiceName =
|
|
94
|
+
Write-Host "[WARNING] Invalid Kokoro voice '$VoiceName' - falling back to $KokoroDefault" -ForegroundColor Yellow
|
|
95
|
+
$VoiceName = $KokoroDefault
|
|
80
96
|
}
|
|
81
97
|
|
|
82
98
|
# --- Optional speed ----------------------------------------------------------
|
|
@@ -116,8 +116,9 @@ switch ($ActiveProvider) {
|
|
|
116
116
|
# by the SSH-receiver watcher via -ProviderOverride). This lets the Linux-side
|
|
117
117
|
# audio-effects.cfg row for llm:claude-code specify "piper" and have it honoured
|
|
118
118
|
# on Windows without requiring the Windows tts-provider.txt to be reconfigured.
|
|
119
|
-
# Priority:
|
|
120
|
-
#
|
|
119
|
+
# Priority: an explicit -ProviderOverride is AUTHORITATIVE โ it wins over both the
|
|
120
|
+
# per-LLM $_LlmEngine column and the global tts-provider.txt default (see the
|
|
121
|
+
# $ProviderOverride guard in the engine-resolution block below).
|
|
121
122
|
if ($ProviderOverride) {
|
|
122
123
|
switch ($ProviderOverride) {
|
|
123
124
|
{ $_ -in "windows-piper", "piper" } {
|
|
@@ -308,8 +309,30 @@ $PlanVoiceIsOverride = $false
|
|
|
308
309
|
if ($ProviderOverride) {
|
|
309
310
|
# A fresh -ProviderOverride for THIS request must win over any stale/inherited
|
|
310
311
|
# AGENTVIBES_FORCE_PROVIDER in the environment (a validated allowlist only).
|
|
312
|
+
#
|
|
313
|
+
# The allowlist DERIVES from the Provider Catalog (SSOT): the Windows platform
|
|
314
|
+
# set PLUS the cross-platform forwarding aliases this script normalizes
|
|
315
|
+
# (piperโwindows-piper, sapiโwindows-sapi, and macos forwarded verbatim for
|
|
316
|
+
# SSH-relayed senders). FAIL-SAFE: the literal below is the legacy fallback
|
|
317
|
+
# used when the generated provider-catalog.ps1 is missing (installed-tree skew).
|
|
318
|
+
$ProviderOverrideAllowlist = @('piper','soprano','macos','windows-sapi','sapi','kokoro','windows-piper')
|
|
319
|
+
$__CatalogPs1 = Join-Path $ScriptPath 'provider-catalog.ps1'
|
|
320
|
+
if (Test-Path $__CatalogPs1) {
|
|
321
|
+
try {
|
|
322
|
+
. $__CatalogPs1
|
|
323
|
+
if (Get-Command Get-CatalogProvidersForPlatform -ErrorAction SilentlyContinue) {
|
|
324
|
+
$__WinSet = @(Get-CatalogProvidersForPlatform 'windows')
|
|
325
|
+
if ($__WinSet.Count -gt 0) {
|
|
326
|
+
# Windows synth providers + the forwarding aliases play-tts.ps1 normalizes.
|
|
327
|
+
$ProviderOverrideAllowlist = @($__WinSet + @('piper','sapi','macos') | Select-Object -Unique)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
} catch {
|
|
331
|
+
# Keep the legacy fallback allowlist on any catalog load error.
|
|
332
|
+
}
|
|
333
|
+
}
|
|
311
334
|
switch ($ProviderOverride) {
|
|
312
|
-
{ $_ -in
|
|
335
|
+
{ $_ -in $ProviderOverrideAllowlist } {
|
|
313
336
|
$env:AGENTVIBES_FORCE_PROVIDER = $ProviderOverride
|
|
314
337
|
}
|
|
315
338
|
}
|
|
@@ -522,6 +545,12 @@ else {
|
|
|
522
545
|
# ENGINE column or the global tts-provider.txt default.
|
|
523
546
|
$ProviderScript = "$HooksDir\play-tts-kokoro.ps1"
|
|
524
547
|
}
|
|
548
|
+
elseif ($ProviderOverride) {
|
|
549
|
+
# An explicit -ProviderOverride (forwarded from the SSH payload's "provider"
|
|
550
|
+
# field, or a preview) is AUTHORITATIVE and was already applied above. Do NOT
|
|
551
|
+
# let the per-LLM ENGINE column override it, or a receiver whose llm row
|
|
552
|
+
# defaults to piper silently swallows a forwarded windows-sapi request.
|
|
553
|
+
}
|
|
525
554
|
elseif ($_LlmEngine) {
|
|
526
555
|
# Accept both canonical Windows names and the cross-platform aliases the TUI
|
|
527
556
|
# writes (e.g. "piper" saved on a Linux/WSL install that is later read on
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# provider-catalog.ps1 โ GENERATED FILE. DO NOT EDIT.
|
|
2
|
+
# DO NOT EDIT โ generated from src/services/provider-catalog.js
|
|
3
|
+
# Regenerate with: node scripts/generate-provider-catalog.mjs
|
|
4
|
+
# content-hash: sha256:5e717024f1250a8f54d07291256e532606dba7b4a15ab9589305d1af6bba7f35
|
|
5
|
+
# Dot-source this file to load the catalog accessors; do not execute it.
|
|
6
|
+
|
|
7
|
+
$script:AgentVibesCatalogVersion = '5e717024f1250a8f'
|
|
8
|
+
|
|
9
|
+
$script:CatalogDefaults = @{
|
|
10
|
+
'soprano' = 'soprano-default'
|
|
11
|
+
'piper' = 'en_US-lessac-medium'
|
|
12
|
+
'kokoro' = 'af_heart'
|
|
13
|
+
'elevenlabs' = 'Sarah'
|
|
14
|
+
'macos' = 'Samantha'
|
|
15
|
+
'windows-sapi' = ''
|
|
16
|
+
'windows-piper' = 'en_US-lessac-medium'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
$script:CatalogDisplayNames = @{
|
|
20
|
+
'soprano' = 'Soprano TTS'
|
|
21
|
+
'piper' = 'Piper TTS'
|
|
22
|
+
'kokoro' = 'Kokoro TTS'
|
|
23
|
+
'elevenlabs' = 'ElevenLabs'
|
|
24
|
+
'macos' = 'macOS Say'
|
|
25
|
+
'windows-sapi' = 'Windows SAPI'
|
|
26
|
+
'windows-piper' = 'Piper TTS'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$script:CatalogAlias = @{
|
|
30
|
+
'macos-say' = 'macos'
|
|
31
|
+
'say' = 'macos'
|
|
32
|
+
'sapi' = 'windows-sapi'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
$script:CatalogPlatform = @{
|
|
36
|
+
'unix' = @('soprano','piper','kokoro','elevenlabs')
|
|
37
|
+
'darwin' = @('soprano','piper','kokoro','elevenlabs','macos')
|
|
38
|
+
'windows' = @('soprano','kokoro','windows-sapi','windows-piper')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
$script:CatalogVoices = @{
|
|
42
|
+
'soprano' = @('soprano-default')
|
|
43
|
+
'piper' = @()
|
|
44
|
+
'kokoro' = @('af_heart','af_alloy','af_aoede','af_bella','af_jessica','af_kore','af_nicole','af_nova','af_river','af_sarah','af_sky','am_adam','am_echo','am_eric','am_fenrir','am_liam','am_michael','am_onyx','am_puck','bf_alice','bf_emma','bf_isabella','bf_lily','bm_daniel','bm_fable','bm_george','bm_lewis','jf_alpha','jf_gongitsune','jf_nezumi','jf_tebukuro','jm_kumo','zf_xiaobei','zf_xiaoni','zf_xiaoxiao','zf_xiaoyi','zm_yunxi','zm_yunxia','zm_yunyang','ef_dora','em_alex','em_santa','ff_siwis','hf_alpha','hm_omega','if_sara','im_nicola','pf_dora','pm_alex','pm_santa','kf_alpha','km_hyunsu')
|
|
45
|
+
'elevenlabs' = @('Sarah','Roger','Laura','Charlie','George','Callum','River','Harry','Liam','Alice','Matilda','Will','Jessica','Eric','Bella','Chris','Brian','Daniel','Lily','Adam','Bill')
|
|
46
|
+
'macos' = @()
|
|
47
|
+
'windows-sapi' = @()
|
|
48
|
+
'windows-piper' = @()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
$script:CatalogElevenLabs = @{
|
|
52
|
+
'sarah' = 'EXAVITQu4vr4xnSDxMaL'
|
|
53
|
+
'roger' = 'CwhRBWXzGAHq8TQ4Fs17'
|
|
54
|
+
'laura' = 'FGY2WhTYpPnrIDTdsKH5'
|
|
55
|
+
'charlie' = 'IKne3meq5aSn9XLyUdCD'
|
|
56
|
+
'george' = 'JBFqnCBsd6RMkjVDRZzb'
|
|
57
|
+
'callum' = 'N2lVS1w4EtoT3dr4eOWO'
|
|
58
|
+
'river' = 'SAz9YHcvj6GT2YYXdXww'
|
|
59
|
+
'harry' = 'SOYHLrjzK2X1ezoPC6cr'
|
|
60
|
+
'liam' = 'TX3LPaxmHKxFdv7VOQHJ'
|
|
61
|
+
'alice' = 'Xb7hH8MSUJpSbSDYk0k2'
|
|
62
|
+
'matilda' = 'XrExE9yKIg1WjnnlVkGX'
|
|
63
|
+
'will' = 'bIHbv24MWmeRgasZH58o'
|
|
64
|
+
'jessica' = 'cgSgspJ2msm6clMCkdW9'
|
|
65
|
+
'eric' = 'cjVigY5qzO86Huf0OWal'
|
|
66
|
+
'bella' = 'hpp4J3VqNfWAUOO0d1Us'
|
|
67
|
+
'chris' = 'iP95p4xoKVk53GoZ742B'
|
|
68
|
+
'brian' = 'nPczCjzI2devNBz1zQrb'
|
|
69
|
+
'daniel' = 'onwK4e9ZLuTAKqWW03F9'
|
|
70
|
+
'lily' = 'pFZP5JQG7iQjIQuC4Bku'
|
|
71
|
+
'adam' = 'pNInz6obpgDQGcFmaJgB'
|
|
72
|
+
'bill' = 'pqHfZKP75CvOlQylNhV4'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function Get-CatalogCanonicalProvider {
|
|
76
|
+
param([Parameter(Mandatory)][string]$Provider)
|
|
77
|
+
$key = $Provider.Trim().ToLowerInvariant()
|
|
78
|
+
if ($script:CatalogDefaults.ContainsKey($key)) { return $key }
|
|
79
|
+
if ($script:CatalogAlias.ContainsKey($key)) { return $script:CatalogAlias[$key] }
|
|
80
|
+
return $null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function Get-CatalogDefaultVoice {
|
|
84
|
+
param([Parameter(Mandatory)][string]$Provider)
|
|
85
|
+
$p = Get-CatalogCanonicalProvider $Provider
|
|
86
|
+
if ($null -eq $p) { return $null }
|
|
87
|
+
return $script:CatalogDefaults[$p]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Get-CatalogDisplayName {
|
|
91
|
+
param([Parameter(Mandatory)][string]$Provider)
|
|
92
|
+
$p = Get-CatalogCanonicalProvider $Provider
|
|
93
|
+
if ($null -eq $p) { return $Provider }
|
|
94
|
+
return $script:CatalogDisplayNames[$p]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function Get-CatalogProvidersForPlatform {
|
|
98
|
+
param([Parameter(Mandatory)][string]$Platform)
|
|
99
|
+
$key = $Platform.Trim().ToLowerInvariant()
|
|
100
|
+
if ($script:CatalogPlatform.ContainsKey($key)) { return $script:CatalogPlatform[$key] }
|
|
101
|
+
return @()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function Get-CatalogVoices {
|
|
105
|
+
param([Parameter(Mandatory)][string]$Provider)
|
|
106
|
+
$p = Get-CatalogCanonicalProvider $Provider
|
|
107
|
+
if ($null -eq $p) { return @() }
|
|
108
|
+
return $script:CatalogVoices[$p]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function Test-CatalogVoice {
|
|
112
|
+
param([Parameter(Mandatory)][string]$Provider, [Parameter(Mandatory)][AllowEmptyString()][string]$Voice)
|
|
113
|
+
$p = Get-CatalogCanonicalProvider $Provider
|
|
114
|
+
if ($null -eq $p) { return $null }
|
|
115
|
+
$lc = $Voice.Trim().ToLowerInvariant()
|
|
116
|
+
switch ($p) {
|
|
117
|
+
'kokoro' {
|
|
118
|
+
if ($script:CatalogVoices['kokoro'] -contains $lc) { return $lc }
|
|
119
|
+
return $null
|
|
120
|
+
}
|
|
121
|
+
'elevenlabs' {
|
|
122
|
+
if ($script:CatalogElevenLabs.ContainsKey($lc)) { return $script:CatalogElevenLabs[$lc] }
|
|
123
|
+
if ($Voice -match '^[A-Za-z0-9]{20}$') { return $Voice }
|
|
124
|
+
return $null
|
|
125
|
+
}
|
|
126
|
+
'soprano' {
|
|
127
|
+
if ($lc -eq '' -or $lc -eq 'soprano' -or $lc -eq 'soprano-default') { return 'soprano-default' }
|
|
128
|
+
return $null
|
|
129
|
+
}
|
|
130
|
+
{ $_ -eq 'piper' -or $_ -eq 'windows-piper' } {
|
|
131
|
+
if ($Voice -match '^[a-z]{2,3}_[A-Z]{2}-' -or $Voice -like '*::*') { return $Voice }
|
|
132
|
+
return $null
|
|
133
|
+
}
|
|
134
|
+
default {
|
|
135
|
+
if ($Voice -ne '') { return $Voice }
|
|
136
|
+
if ($p -eq 'windows-sapi') { return '' }
|
|
137
|
+
return $null
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -15,7 +15,25 @@ param(
|
|
|
15
15
|
|
|
16
16
|
$ClaudeDir = "$env:USERPROFILE\.claude"
|
|
17
17
|
$ProviderFile = "$ClaudeDir\tts-provider.txt"
|
|
18
|
-
$ValidProviders
|
|
18
|
+
# $ValidProviders DERIVES from the generated Provider Catalog (SSOT): the Windows
|
|
19
|
+
# platform set (kokoro is cross-platform โ play-tts-kokoro.ps1 exists; elevenlabs
|
|
20
|
+
# is NOT playable on Windows and is therefore absent). Dot-source the generated
|
|
21
|
+
# provider-catalog.ps1 and pull `windows`. FAIL-SAFE: the literal below is the
|
|
22
|
+
# legacy fallback used when the catalog artifact is missing (installed-tree skew)
|
|
23
|
+
# โ mirrors AVI-S9.3's probe/fallback pattern. See AVI-S8.1 / AVI-S9.5.
|
|
24
|
+
$ValidProviders = @('windows-piper', 'windows-sapi', 'soprano', 'kokoro')
|
|
25
|
+
$__CatalogPs1 = Join-Path $PSScriptRoot 'provider-catalog.ps1'
|
|
26
|
+
if (Test-Path $__CatalogPs1) {
|
|
27
|
+
try {
|
|
28
|
+
. $__CatalogPs1
|
|
29
|
+
if (Get-Command Get-CatalogProvidersForPlatform -ErrorAction SilentlyContinue) {
|
|
30
|
+
$__WinSet = @(Get-CatalogProvidersForPlatform 'windows')
|
|
31
|
+
if ($__WinSet.Count -gt 0) { $ValidProviders = $__WinSet }
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
# Keep the legacy fallback literal on any catalog load error.
|
|
35
|
+
}
|
|
36
|
+
}
|
|
19
37
|
|
|
20
38
|
# Ensure claude directory exists
|
|
21
39
|
if (-not (Test-Path $ClaudeDir)) {
|
|
@@ -35,6 +53,14 @@ function Get-ActiveProvider {
|
|
|
35
53
|
function Get-AvailableProviders {
|
|
36
54
|
$available = @()
|
|
37
55
|
|
|
56
|
+
# Fast path: skip the live install probes (soprano HTTP + kokoro python
|
|
57
|
+
# spawns). Those probes are what make `provider list` occasionally stall for
|
|
58
|
+
# tens of seconds under load; when the caller only needs the provider NAMES
|
|
59
|
+
# (e.g. the parallel test harness, or an offline listing) set
|
|
60
|
+
# AGENTVIBES_PROVIDER_LIST_NO_PROBE=1 to report installed=$false without
|
|
61
|
+
# touching the network or spawning interpreters. Default behavior unchanged.
|
|
62
|
+
$noProbe = ($env:AGENTVIBES_PROVIDER_LIST_NO_PROBE -eq '1')
|
|
63
|
+
|
|
38
64
|
# Always available
|
|
39
65
|
$available += @{
|
|
40
66
|
name = "windows-sapi"
|
|
@@ -59,15 +85,18 @@ function Get-AvailableProviders {
|
|
|
59
85
|
$null = Get-Command soprano -ErrorAction Stop
|
|
60
86
|
$sopranoInstalled = $true
|
|
61
87
|
} catch {
|
|
62
|
-
# Also check if a Soprano server is running (try both API paths)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
$sopranoInstalled = $true
|
|
66
|
-
} catch {
|
|
88
|
+
# Also check if a Soprano server is running (try both API paths) โ unless
|
|
89
|
+
# the fast path is requested, in which case skip the network probes.
|
|
90
|
+
if (-not $noProbe) {
|
|
67
91
|
try {
|
|
68
|
-
$null = Invoke-WebRequest -Uri "http://127.0.0.1:${sopranoPort}/info" -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop
|
|
92
|
+
$null = Invoke-WebRequest -Uri "http://127.0.0.1:${sopranoPort}/gradio_api/info" -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop
|
|
69
93
|
$sopranoInstalled = $true
|
|
70
|
-
} catch {
|
|
94
|
+
} catch {
|
|
95
|
+
try {
|
|
96
|
+
$null = Invoke-WebRequest -Uri "http://127.0.0.1:${sopranoPort}/info" -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop
|
|
97
|
+
$sopranoInstalled = $true
|
|
98
|
+
} catch {}
|
|
99
|
+
}
|
|
71
100
|
}
|
|
72
101
|
}
|
|
73
102
|
|
|
@@ -77,6 +106,32 @@ function Get-AvailableProviders {
|
|
|
77
106
|
installed = $sopranoInstalled
|
|
78
107
|
}
|
|
79
108
|
|
|
109
|
+
# Check if Kokoro is installed. Mirror validateKokoroInstallation() in
|
|
110
|
+
# src/utils/provider-validator.js, but use importlib.util.find_spec so we do
|
|
111
|
+
# NOT actually import kokoro โ importing the 82M-param neural lib takes
|
|
112
|
+
# several seconds and would make `provider list` hang (AVI-S8.1). find_spec
|
|
113
|
+
# only confirms the packages are importable, which is all we need here.
|
|
114
|
+
$kokoroInstalled = $false
|
|
115
|
+
$kokoroProbe = "import importlib.util as u,sys; sys.exit(0 if all(u.find_spec(m) for m in ('kokoro','soundfile','numpy')) else 1)"
|
|
116
|
+
foreach ($py in ($(if ($noProbe) { @() } else { @('py', 'python', 'python3') }))) {
|
|
117
|
+
if (-not (Get-Command $py -ErrorAction SilentlyContinue)) { continue }
|
|
118
|
+
try {
|
|
119
|
+
$null = & $py -c $kokoroProbe 2>$null
|
|
120
|
+
# Only stop once an interpreter actually HAS the packages โ mirrors
|
|
121
|
+
# validateKokoroInstallation(), which tries every interpreter (the
|
|
122
|
+
# packages may live under python/python3, not the `py` launcher).
|
|
123
|
+
if ($LASTEXITCODE -eq 0) { $kokoroInstalled = $true; break }
|
|
124
|
+
} catch {
|
|
125
|
+
# interpreter present but failed to run the probe โ try next
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
$available += @{
|
|
130
|
+
name = "kokoro"
|
|
131
|
+
description = "Kokoro TTS (Neural, pip install kokoro-onnx soundfile numpy)"
|
|
132
|
+
installed = $kokoroInstalled
|
|
133
|
+
}
|
|
134
|
+
|
|
80
135
|
return $available
|
|
81
136
|
}
|
|
82
137
|
|
|
@@ -52,7 +52,7 @@ try {
|
|
|
52
52
|
}
|
|
53
53
|
if ($req.kind -eq 'music') {
|
|
54
54
|
$trackName = [string]$req.music
|
|
55
|
-
if ($trackName -match '^[A-Za-z0-9._][A-Za-z0-9._\-]*\.mp3$') {
|
|
55
|
+
if ($trackName -match '^[A-Za-z0-9._][A-Za-z0-9._ \-]*\.mp3$') {
|
|
56
56
|
$tracksDir = Join-Path $env:USERPROFILE '.claude\audio\tracks'
|
|
57
57
|
$full = [System.IO.Path]::GetFullPath((Join-Path $tracksDir $trackName))
|
|
58
58
|
$baseFull = [System.IO.Path]::GetFullPath($tracksDir)
|
|
@@ -61,6 +61,17 @@ try {
|
|
|
61
61
|
$ffplay = Get-Command ffplay -ErrorAction SilentlyContinue
|
|
62
62
|
if ($ffplay) {
|
|
63
63
|
Write-WatcherLog "INFO" "music-preview id=$($req.id) track=$trackName"
|
|
64
|
+
# Readiness bling โ a short cue played in THIS (audio-capable) watcher
|
|
65
|
+
# session BEFORE the track so a listener knows music is incoming. Launched
|
|
66
|
+
# async (NOT -Wait โ the wav's shimmer tail is long); a fixed 0.3s gap then
|
|
67
|
+
# lets the music follow tightly. Best-effort: a missing wav / player error
|
|
68
|
+
# never blocks the track.
|
|
69
|
+
$blingWav = Join-Path $env:USERPROFILE '.claude\audio\ui\bling-success.wav'
|
|
70
|
+
if (-not (Test-Path $blingWav)) { $blingWav = Join-Path $env:USERPROFILE '.agentvibes\bling-success.wav' }
|
|
71
|
+
if (Test-Path $blingWav) {
|
|
72
|
+
try { Start-Process -FilePath $ffplay.Source -ArgumentList @('-autoexit','-nodisp','-loglevel','quiet',$blingWav) -WindowStyle Hidden | Out-Null } catch { }
|
|
73
|
+
Start-Sleep -Milliseconds 300
|
|
74
|
+
}
|
|
64
75
|
$mp = Start-Process -FilePath $ffplay.Source -ArgumentList @('-autoexit','-nodisp','-loglevel','quiet','-volume','80',$full) -WindowStyle Hidden -PassThru
|
|
65
76
|
if ($mp) { Set-Content -Path $pidFile -Value $mp.Id -NoNewline -ErrorAction SilentlyContinue }
|
|
66
77
|
} else {
|
|
@@ -83,9 +94,9 @@ try {
|
|
|
83
94
|
$safeVoice = if ($req.voice -and $req.voice -match '^[a-zA-Z0-9_\-\. :]+$') { $req.voice } else { "" }
|
|
84
95
|
$env:CLAUDE_PROJECT_DIR = $env:USERPROFILE
|
|
85
96
|
$env:AGENTVIBES_NO_PRETEXT = "1"
|
|
86
|
-
# Carry the sender's project (folder name/path) through
|
|
87
|
-
#
|
|
88
|
-
#
|
|
97
|
+
# Carry the sender's project (folder name/path) through so a
|
|
98
|
+
# downstream receiver shows the real remote origin instead of
|
|
99
|
+
# this machine's own profile dir.
|
|
89
100
|
if ($req.project) { $env:AGENTVIBES_PROJECT = $req.project }
|
|
90
101
|
else { [System.Environment]::SetEnvironmentVariable("AGENTVIBES_PROJECT", $null, "Process") }
|
|
91
102
|
if ($req.projectPath) { $env:AGENTVIBES_PROJECT_PATH = $req.projectPath }
|
|
@@ -99,16 +110,26 @@ try {
|
|
|
99
110
|
else { [System.Environment]::SetEnvironmentVariable("AGENTVIBES_OVERRIDE_EFFECTS", $null, "Process") }
|
|
100
111
|
|
|
101
112
|
if (Test-Path $PlayTts) {
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
# Always play a crisp local "incoming" bling so the user KNOWS audio is
|
|
114
|
+
# on the way โ even when audio is routed to a downstream receiver
|
|
115
|
+
# instead of the local speakers. Standard bling-success.wav, async
|
|
116
|
+
# with a 0.3s gap (same as the music-preview path); fall back to the
|
|
117
|
+
# user-configured remote-prefix-sound.txt if the bling wav is missing.
|
|
118
|
+
$ffplay = Get-Command ffplay -ErrorAction SilentlyContinue
|
|
119
|
+
if ($ffplay) {
|
|
120
|
+
$blingWav = Join-Path $env:USERPROFILE '.claude\audio\ui\bling-success.wav'
|
|
121
|
+
if (-not (Test-Path $blingWav)) { $blingWav = Join-Path $env:USERPROFILE '.agentvibes\bling-success.wav' }
|
|
122
|
+
if (-not (Test-Path $blingWav)) {
|
|
123
|
+
$prefixSoundFile = "$env:USERPROFILE\.agentvibes\remote-prefix-sound.txt"
|
|
124
|
+
if (Test-Path $prefixSoundFile) {
|
|
125
|
+
$ps = (Get-Content $prefixSoundFile -Raw).Trim()
|
|
126
|
+
if ($ps -and (Test-Path $ps)) { $blingWav = $ps }
|
|
110
127
|
}
|
|
111
128
|
}
|
|
129
|
+
if (Test-Path $blingWav) {
|
|
130
|
+
try { Start-Process -FilePath $ffplay.Source -ArgumentList @('-autoexit','-nodisp','-loglevel','quiet',$blingWav) -WindowStyle Hidden | Out-Null } catch { }
|
|
131
|
+
Start-Sleep -Milliseconds 300
|
|
132
|
+
}
|
|
112
133
|
}
|
|
113
134
|
|
|
114
135
|
$tempText = Join-Path $env:TEMP "agentvibes-tts-$($req.id).txt"
|
|
@@ -17,6 +17,14 @@ $ClaudeDir = "$env:USERPROFILE\.claude"
|
|
|
17
17
|
$ProviderFile = "$ClaudeDir\tts-provider.txt"
|
|
18
18
|
$VoiceSapiFile = "$ClaudeDir\tts-voice-sapi.txt"
|
|
19
19
|
$VoicePiperFile = "$ClaudeDir\tts-voice-piper.txt"
|
|
20
|
+
$VoiceKokoroFile = "$ClaudeDir\tts-voice-kokoro.txt"
|
|
21
|
+
|
|
22
|
+
# Load the generated Provider Catalog (SSOT) for kokoro switch-time validation.
|
|
23
|
+
# FAIL-SAFE: consumers probe `Get-Command Test-CatalogVoice` and fall back to the
|
|
24
|
+
# legacy shape regex when the artifact is missing (installed-tree skew) โ mirrors
|
|
25
|
+
# play-tts.sh's PLAN_OK legacy fallback. Switch never breaks on a missing catalog.
|
|
26
|
+
$CatalogPs1 = Join-Path $PSScriptRoot 'provider-catalog.ps1'
|
|
27
|
+
if (Test-Path $CatalogPs1) { . $CatalogPs1 }
|
|
20
28
|
|
|
21
29
|
# Get active provider
|
|
22
30
|
$ActiveProvider = "windows-sapi"
|
|
@@ -129,6 +137,47 @@ function Switch-Voice {
|
|
|
129
137
|
Write-Host "[INFO] Soprano uses a single fixed voice (Soprano-1.1-80M)" -ForegroundColor Cyan
|
|
130
138
|
return $true
|
|
131
139
|
}
|
|
140
|
+
elseif ($ActiveProvider -eq "kokoro") {
|
|
141
|
+
# Kokoro switch-time validation via the generated Provider Catalog (SSOT):
|
|
142
|
+
# MEMBERSHIP + canonical case-fold, so a typo like af_hart is rejected HERE
|
|
143
|
+
# and never reaches tts-voice-kokoro.txt to die silently at the model.
|
|
144
|
+
# Escape hatch AGENTVIBES_ALLOW_UNLISTED_VOICE=1 bypasses MEMBERSHIP (not
|
|
145
|
+
# shape) so a voice from a newer kokoro model still switches. FAIL-SAFE:
|
|
146
|
+
# fall back to the legacy shape regex when the catalog artifact is missing.
|
|
147
|
+
$kokoroVoice = $NewVoice.ToLower()
|
|
148
|
+
$allowUnlisted = ($env:AGENTVIBES_ALLOW_UNLISTED_VOICE -eq '1')
|
|
149
|
+
if (Get-Command Test-CatalogVoice -ErrorAction SilentlyContinue) {
|
|
150
|
+
$canon = Test-CatalogVoice -Provider 'kokoro' -Voice $NewVoice
|
|
151
|
+
if ($canon) {
|
|
152
|
+
Set-Content -Path $VoiceKokoroFile -Value $canon
|
|
153
|
+
Write-Host "[OK] Voice set to: $canon" -ForegroundColor Green
|
|
154
|
+
return $true
|
|
155
|
+
}
|
|
156
|
+
elseif ($allowUnlisted -and $kokoroVoice -match '^[a-z]{2}_[a-z0-9_]+$') {
|
|
157
|
+
Write-Host "[WARN] '$NewVoice' is not in the shipped Kokoro catalog; allowing it (AGENTVIBES_ALLOW_UNLISTED_VOICE=1)." -ForegroundColor Yellow
|
|
158
|
+
Set-Content -Path $VoiceKokoroFile -Value $kokoroVoice
|
|
159
|
+
Write-Host "[OK] Voice set to: $kokoroVoice" -ForegroundColor Green
|
|
160
|
+
return $true
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
Write-Host "[ERROR] Kokoro voice not found: $NewVoice" -ForegroundColor Red
|
|
164
|
+
Write-Host "That is not a known Kokoro voice. Examples: af_heart, am_michael, bf_emma, bm_george, jf_alpha, zf_xiaoxiao, ef_dora." -ForegroundColor Yellow
|
|
165
|
+
Write-Host "Set AGENTVIBES_ALLOW_UNLISTED_VOICE=1 to allow a newer-model voice." -ForegroundColor Yellow
|
|
166
|
+
return $false
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
# FAIL-SAFE legacy path (catalog artifact missing): shape-only regex.
|
|
171
|
+
if ($kokoroVoice -notmatch '^[a-z]{2}_[a-z0-9_]+$') {
|
|
172
|
+
Write-Host "[ERROR] Kokoro voice not found: $NewVoice" -ForegroundColor Red
|
|
173
|
+
Write-Host "Kokoro ids look like <lang><sex>_name, e.g. af_heart, am_michael, bf_emma." -ForegroundColor Yellow
|
|
174
|
+
return $false
|
|
175
|
+
}
|
|
176
|
+
Set-Content -Path $VoiceKokoroFile -Value $kokoroVoice
|
|
177
|
+
Write-Host "[OK] Voice set to: $kokoroVoice" -ForegroundColor Green
|
|
178
|
+
return $true
|
|
179
|
+
}
|
|
180
|
+
}
|
|
132
181
|
|
|
133
182
|
if ($ValidVoices -notcontains $NewVoice) {
|
|
134
183
|
Write-Host "[ERROR] Voice not found: $NewVoice" -ForegroundColor Red
|
package/.mcp.json
CHANGED
package/README.md
CHANGED
|
@@ -58,9 +58,18 @@ New here? The [**Quick Start guide**](docs/quick-start.md) walks you through you
|
|
|
58
58
|
|
|
59
59
|
---
|
|
60
60
|
|
|
61
|
-
## ๐
|
|
61
|
+
## ๐ Your voices everywhere (v5.13.0)
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Pick the voices built into **Windows** or **Mac** and hear them wherever you're listening โ even when your agents run on another computer. Plus a friendly heads-up chime so you always know sound is coming.
|
|
64
|
+
|
|
65
|
+
- **๐ฅ๏ธ Your computer's own voices, from anywhere** โ choose Windows or Mac voices and hear them on your machine; every voice is shown, with unavailable ones clearly marked.
|
|
66
|
+
- **๐๏ธ All voices in one list** โ Piper, Kokoro, ElevenLabs, Windows, Mac, and Soprano in one place, so what you see is what you can use.
|
|
67
|
+
- **๐ Heads-up chime** โ a short sound plays just before a voice or music preview, so you know audio is on the way.
|
|
68
|
+
- **๐ Agents that introduce themselves** โ optional self-introductions so you know who's talking in a team.
|
|
69
|
+
|
|
70
|
+
### v5.12.0 โ A stronger core
|
|
71
|
+
|
|
72
|
+
During a week of early access to Anthropic's new **Fable** model, we rebuilt the heart of AgentVibes into **one shared core**. The voice / engine / routing / volume / mute logic now lives in a single place โ simpler, more consistent, and steadier.
|
|
64
73
|
|
|
65
74
|
- **๐ Previews play in the right place** โ with SSH remote configured, voice and **music previews** play on your receiver; otherwise they play locally.
|
|
66
75
|
- **๐ง One shared core** โ Kokoro-on-Linux silence and per-voice drift fixed at the source, with a safe fallback if needed.
|
|
@@ -224,7 +233,7 @@ Running a full BMAD agent team? **Every agent gets its own distinct voice**, aut
|
|
|
224
233
|
|
|
225
234
|
## About
|
|
226
235
|
|
|
227
|
-
**AgentVibes** ยท v5.
|
|
236
|
+
**AgentVibes** ยท v5.13.1 ยท Licensed under [Apache-2.0](LICENSE)
|
|
228
237
|
|
|
229
238
|
Built by **Paul Preibisch** โ [@997Fire on X](https://x.com/997Fire) ยท [agentvibes.org](https://agentvibes.org) ยท [github.com/paulpreibisch/AgentVibes](https://github.com/paulpreibisch/AgentVibes)
|
|
230
239
|
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# AgentVibes Release Notes
|
|
2
2
|
|
|
3
|
+
## ๐ง v5.13.1 โ Windows updates that actually update
|
|
4
|
+
|
|
5
|
+
**Released:** 2026-07-16 ยท on `latest` โ `npm install agentvibes@latest`
|
|
6
|
+
|
|
7
|
+
### ๐ช Your Windows scripts now really do update
|
|
8
|
+
|
|
9
|
+
On Windows, the little scripts that make your agents talk live in your `.claude/hooks` folder. Updating said it refreshed them โ but on Windows it quietly didn't, so they could sit on the version you first installed for months.
|
|
10
|
+
|
|
11
|
+
Now they update for real. Run `npx agentvibes update` and you'll pick up every fix you've been missing. Anything you'd customized yourself is still kept safe beside it as a `.user.bak` file, exactly as before.
|
|
12
|
+
|
|
13
|
+
If you're on macOS or Linux, nothing changes โ updates were already working for you.
|
|
14
|
+
|
|
15
|
+
### ๐ A security tune-up under the hood
|
|
16
|
+
|
|
17
|
+
We updated one of the building blocks AgentVibes uses to read settings files. A specially-crafted settings file could have made it grind to a halt. Nothing could ever have been stolen or snooped on โ but now it can't get stuck either. Nothing for you to do; it's just in.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ๐ v5.13.0 โ Your Voices Everywhere, With a Heads-Up
|
|
22
|
+
|
|
23
|
+
**Released:** 2026-07-16 ยท on `latest` โ `npm install agentvibes`
|
|
24
|
+
|
|
25
|
+
What's new:
|
|
26
|
+
|
|
27
|
+
### ๐ฅ๏ธ Use your computer's own voices, from anywhere
|
|
28
|
+
|
|
29
|
+
Run your agents on one machine and listen on another? You can now pick the voices built into **Windows** (David, Zira, Mark) or **Mac**, and hear them right where you're sitting. AgentVibes shows you every voice and clearly marks the ones your listening device can play.
|
|
30
|
+
|
|
31
|
+
### ๐๏ธ All your voices in one tidy list
|
|
32
|
+
|
|
33
|
+
Piper, Kokoro, ElevenLabs, Windows, Mac, Soprano โ every voice now comes from a single list, so what you see is always what you can use.
|
|
34
|
+
|
|
35
|
+
### ๐ A "heads-up" chime before sound plays
|
|
36
|
+
|
|
37
|
+
Just before a voice line or music preview starts, you'll hear a short chime โ so you always know audio is on the way, even if it takes a moment.
|
|
38
|
+
|
|
39
|
+
### ๐ต Music previews follow your sound
|
|
40
|
+
|
|
41
|
+
Preview a track and it plays wherever your audio is set to go โ including on another computer.
|
|
42
|
+
|
|
43
|
+
### ๐ Agents that introduce themselves
|
|
44
|
+
|
|
45
|
+
Turn on self-introductions and each agent says who it is when it starts โ handy when a whole team is talking.
|
|
46
|
+
|
|
47
|
+
### ๐ Your own edits are kept safe when you update
|
|
48
|
+
|
|
49
|
+
Tinkered with one of the AgentVibes files in your `.claude/hooks` folder? From this version on, updating never throws your work away. If we need to update a file you'd changed, we tuck your copy in beside it with `.user.bak` on the end โ like `play-tts.sh.user.bak`.
|
|
50
|
+
|
|
51
|
+
**That file is made by AgentVibes โ nothing is broken and nothing else put it there.** It's simply your old version, saved so you can peek at it or copy your changes back into the new one. Delete it whenever you're done with it.
|
|
52
|
+
|
|
53
|
+
If you customized files in an older version, it's worth a quick look in `.claude/hooks` for anything you'd want to put back.
|
|
54
|
+
|
|
55
|
+
### โจ More voices, smoother ride
|
|
56
|
+
|
|
57
|
+
- **ElevenLabs** voices fully supported
|
|
58
|
+
- More **Kokoro** voices, working great on Windows
|
|
59
|
+
- Faster, more reliable setup on Windows
|
|
60
|
+
- **3,263 automated tests passing** โ steady and dependable
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
3
64
|
## ๐ v5.12.0 โ The Fable Week Overhaul (Stable)
|
|
4
65
|
|
|
5
66
|
**Released:** 2026-07-05 ยท now on `latest` โ `npm install agentvibes`
|