agentvibes 4.6.5 → 4.6.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.sh +8 -1
- package/.claude/hooks-windows/bmad-party-speak.ps1 +55 -3
- package/.claude/hooks-windows/bmad-speak.ps1 +44 -5
- package/.claude/hooks-windows/session-start-tts.ps1 +114 -124
- package/.clawdbot/skill/SKILL.md +237 -241
- package/CLAUDE.md +29 -0
- package/README.md +28 -5
- package/RELEASE_NOTES.md +41 -1
- package/package.json +1 -1
- package/src/console/tabs/agents-tab.js +4 -4
- package/src/console/tabs/install-tab.js +4 -7
- package/src/console/tabs/readme-tab.js +3 -0
- package/src/console/tabs/settings-tab.js +93 -106
- package/src/installer.js +6 -0
- package/.claude/config/background-music-enabled.txt +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
20260403
|
|
@@ -30,7 +30,14 @@ DIALOGUE="${DIALOGUE//\\\$/\$}"
|
|
|
30
30
|
|
|
31
31
|
# Strip markdown formatting — prevent Piper from speaking "asterisk asterisk" literally.
|
|
32
32
|
# play-tts-piper.sh also strips via perl, but do it here early as defense-in-depth.
|
|
33
|
-
DIALOGUE=$(printf '%s' "$DIALOGUE" | sed
|
|
33
|
+
DIALOGUE=$(printf '%s' "$DIALOGUE" | sed \
|
|
34
|
+
-e 's/\*\{1,3\}//g' \
|
|
35
|
+
-e 's/`\{1,3\}[^`]*`\{1,3\}//g' \
|
|
36
|
+
-e 's/^[[:space:]]*#\{1,6\}[[:space:]]*//g' \
|
|
37
|
+
-e 's/__//g' -e 's/_//g' \
|
|
38
|
+
-e 's/\[([^]]*)\]([^)]*)//g' \
|
|
39
|
+
-e 's/^[[:space:]]*[-*+] //g' \
|
|
40
|
+
-e 's/^[[:space:]]*[0-9]\+\. //g')
|
|
34
41
|
|
|
35
42
|
# Check if party mode is enabled
|
|
36
43
|
if [[ -f "$PROJECT_ROOT/.agentvibes/bmad/bmad-party-mode-disabled.flag" ]]; then
|
|
@@ -47,6 +47,19 @@ try {
|
|
|
47
47
|
$ResponseText = $ResponseText.Trim()
|
|
48
48
|
if (-not $ResponseText) { exit 0 }
|
|
49
49
|
|
|
50
|
+
# Strip markdown so TTS doesn't speak asterisks, hashes, backticks, etc.
|
|
51
|
+
$ResponseText = $ResponseText -replace '\*{1,3}', '' # bold, italic, bold-italic
|
|
52
|
+
$ResponseText = $ResponseText -replace '`{1,3}[^`]*`{1,3}', '' # inline code / code blocks
|
|
53
|
+
$ResponseText = $ResponseText -replace '#{1,6}\s*', '' # headings
|
|
54
|
+
$ResponseText = $ResponseText -replace '_{1,2}', '' # underline/italic alt
|
|
55
|
+
$ResponseText = $ResponseText -replace '\[([^\]]+)\]\([^)]+\)', '$1' # links → label only
|
|
56
|
+
$ResponseText = $ResponseText -replace '!\[[^\]]*\]\([^)]+\)', '' # images
|
|
57
|
+
$ResponseText = $ResponseText -replace '(?m)^\s*[-*+]\s+', '' # bullet list markers (multiline)
|
|
58
|
+
$ResponseText = $ResponseText -replace '(?m)^\s*\d+\.\s+', '' # numbered list markers
|
|
59
|
+
$ResponseText = $ResponseText -replace '\\([!$*_`\\])', '$1' # escaped markdown chars
|
|
60
|
+
$ResponseText = $ResponseText.Trim()
|
|
61
|
+
if (-not $ResponseText) { exit 0 }
|
|
62
|
+
|
|
50
63
|
# --- Resolve paths ---
|
|
51
64
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
52
65
|
$ProjectRoot = $env:CLAUDE_PROJECT_DIR
|
|
@@ -118,11 +131,13 @@ try {
|
|
|
118
131
|
elseif (Test-Path $VoiceMapGlobal) { $VoiceMapGlobal }
|
|
119
132
|
else { $null }
|
|
120
133
|
|
|
121
|
-
$AgentVoiceName
|
|
122
|
-
$SpeakerId
|
|
134
|
+
$AgentVoiceName = $null
|
|
135
|
+
$SpeakerId = $null
|
|
136
|
+
$AgentPretext = $null
|
|
123
137
|
if ($VoiceMapFile) {
|
|
124
138
|
$vm = Get-Content $VoiceMapFile -Raw | ConvertFrom-Json
|
|
125
139
|
$profile = $vm.agents.$AgentId
|
|
140
|
+
if ($profile -and $profile.pretext) { $AgentPretext = $profile.pretext }
|
|
126
141
|
if ($profile -and $profile.voice) {
|
|
127
142
|
$raw = $profile.voice
|
|
128
143
|
if ($raw -match '::') {
|
|
@@ -150,6 +165,40 @@ try {
|
|
|
150
165
|
}
|
|
151
166
|
}
|
|
152
167
|
|
|
168
|
+
# Fallback: parse bmad-voices.md markdown table if no JSON voice map found
|
|
169
|
+
if (-not $AgentPretext -and $ProjectRoot) {
|
|
170
|
+
$VoicesMdPaths = @(
|
|
171
|
+
(Join-Path $ProjectRoot ".agentvibes\bmad\bmad-voices.md"),
|
|
172
|
+
(Join-Path $env:USERPROFILE ".agentvibes\bmad\bmad-voices.md")
|
|
173
|
+
)
|
|
174
|
+
foreach ($mdPath in $VoicesMdPaths) {
|
|
175
|
+
if (-not (Test-Path $mdPath)) { continue }
|
|
176
|
+
$mdLines = Get-Content $mdPath -Encoding UTF8
|
|
177
|
+
# Strip bmad-agent- prefix for matching (manifest uses bmad-agent-pm, table uses pm)
|
|
178
|
+
$shortId = $AgentId -replace '^bmad-agent-', ''
|
|
179
|
+
foreach ($mdLine in $mdLines) {
|
|
180
|
+
if ($mdLine -notmatch '^\|') { continue }
|
|
181
|
+
if ($mdLine -match '^\|-') { continue } # separator row
|
|
182
|
+
if ($mdLine -match 'Agent ID') { continue } # header row
|
|
183
|
+
$cols = $mdLine -split '\|' | ForEach-Object { $_.Trim() }
|
|
184
|
+
# cols: [0]=empty, [1]=Agent ID, [2]=Agent Name, [3]=Intro, [4]=Piper TTS Voice, [5]=Piper Voice, [6]=Personality
|
|
185
|
+
if ($cols.Count -lt 6) { continue }
|
|
186
|
+
$tableId = $cols[1]
|
|
187
|
+
$tableName = $cols[2]
|
|
188
|
+
if ($tableId -ieq $shortId -or $tableId -ieq $AgentId -or $tableName -like "*$DisplayName*") {
|
|
189
|
+
if ($cols[3]) { $AgentPretext = $cols[3] }
|
|
190
|
+
# Use Piper Voice column (index 5) for piper provider
|
|
191
|
+
if (-not $AgentVoiceName -and $cols[5]) { $AgentVoiceName = $cols[5] }
|
|
192
|
+
if ($cols.Count -ge 7 -and $cols[6] -and $cols[6] -ine 'normal') {
|
|
193
|
+
# personality available for bmad-speak.ps1 downstream
|
|
194
|
+
}
|
|
195
|
+
break
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if ($AgentPretext) { break }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
153
202
|
# Locate piper
|
|
154
203
|
$PiperExe = "$env:LOCALAPPDATA\Programs\Piper\piper.exe"
|
|
155
204
|
if (-not (Test-Path $PiperExe)) {
|
|
@@ -172,7 +221,10 @@ try {
|
|
|
172
221
|
$PreSynthWav = Join-Path $AudioDir "tts-presynth-$([System.IO.Path]::GetRandomFileName() -replace '\..*').wav"
|
|
173
222
|
$piperArgs = @("--model", $VoiceModel, "--output-file", $PreSynthWav)
|
|
174
223
|
if ($SpeakerId) { $piperArgs += @("--speaker", $SpeakerId) }
|
|
175
|
-
|
|
224
|
+
# Include pretext in pre-synthesis so it's spoken — bmad-speak.ps1 will
|
|
225
|
+
# skip synthesis (AGENTVIBES_PRESYNTHESIZED_WAV set) so pretext must be here.
|
|
226
|
+
$PreSynthText = if ($AgentPretext) { "$AgentPretext. $ResponseText" } else { $ResponseText }
|
|
227
|
+
$PreSynthText | & $PiperExe @piperArgs 2>$null
|
|
176
228
|
if (-not (Test-Path $PreSynthWav) -or (Get-Item $PreSynthWav).Length -eq 0) {
|
|
177
229
|
$PreSynthWav = $null
|
|
178
230
|
}
|
|
@@ -27,8 +27,15 @@ if ($env:CLAUDE_PROJECT_DIR -and (Test-Path "$env:CLAUDE_PROJECT_DIR\_bmad")) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
# Strip markdown formatting — prevent SAPI/Piper from speaking asterisks literally
|
|
30
|
-
$Dialogue = $Dialogue -replace '
|
|
31
|
-
$Dialogue = $Dialogue -replace '
|
|
30
|
+
$Dialogue = $Dialogue -replace '\*{1,3}', '' # bold, italic, bold-italic
|
|
31
|
+
$Dialogue = $Dialogue -replace '`{1,3}[^`]*`{1,3}', '' # inline code / code blocks
|
|
32
|
+
$Dialogue = $Dialogue -replace '#{1,6}\s*', '' # headings
|
|
33
|
+
$Dialogue = $Dialogue -replace '_{1,2}', '' # underline/italic alt
|
|
34
|
+
$Dialogue = $Dialogue -replace '\[([^\]]+)\]\([^)]+\)', '$1' # links → label only
|
|
35
|
+
$Dialogue = $Dialogue -replace '!\[[^\]]*\]\([^)]+\)', '' # images
|
|
36
|
+
$Dialogue = $Dialogue -replace '(?m)^\s*[-*+]\s+', '' # bullet list markers (multiline)
|
|
37
|
+
$Dialogue = $Dialogue -replace '(?m)^\s*\d+\.\s+', '' # numbered list markers
|
|
38
|
+
$Dialogue = $Dialogue -replace '\\([!$*_`\\])', '$1' # escaped markdown chars
|
|
32
39
|
|
|
33
40
|
# Check if party mode is disabled
|
|
34
41
|
$PartyModeDisabledFlag = Join-Path $ProjectRoot ".agentvibes\bmad\bmad-party-mode-disabled.flag"
|
|
@@ -117,13 +124,45 @@ if (Test-Path $VoiceMapFile) {
|
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
126
|
|
|
127
|
+
# Fallback: parse bmad-voices.md markdown table if JSON voice map had no data
|
|
128
|
+
if ((-not $AgentPretext -or -not $AgentVoice) -and $AgentId) {
|
|
129
|
+
$VoicesMdPaths = @(
|
|
130
|
+
(Join-Path $ProjectRoot ".agentvibes\bmad\bmad-voices.md"),
|
|
131
|
+
(Join-Path $env:USERPROFILE ".agentvibes\bmad\bmad-voices.md")
|
|
132
|
+
)
|
|
133
|
+
$shortId = $AgentId -replace '^bmad-agent-', ''
|
|
134
|
+
foreach ($mdPath in $VoicesMdPaths) {
|
|
135
|
+
if (-not (Test-Path $mdPath)) { continue }
|
|
136
|
+
$mdLines = Get-Content $mdPath -Encoding UTF8
|
|
137
|
+
foreach ($mdLine in $mdLines) {
|
|
138
|
+
if ($mdLine -notmatch '^\|') { continue }
|
|
139
|
+
if ($mdLine -match '^\|-') { continue }
|
|
140
|
+
if ($mdLine -match 'Agent ID') { continue }
|
|
141
|
+
$cols = $mdLine -split '\|' | ForEach-Object { $_.Trim() }
|
|
142
|
+
if ($cols.Count -lt 6) { continue }
|
|
143
|
+
$tableId = $cols[1]
|
|
144
|
+
if ($tableId -ieq $shortId -or $tableId -ieq $AgentId -or $tableId -ieq $AgentNameOrId) {
|
|
145
|
+
if (-not $AgentPretext -and $cols[3]) { $AgentPretext = $cols[3] }
|
|
146
|
+
if (-not $AgentVoice -and $cols[5]) { $AgentVoice = $cols[5] }
|
|
147
|
+
if (-not $AgentPersonality -and $cols.Count -ge 7 -and $cols[6] -and $cols[6] -ine 'normal') {
|
|
148
|
+
$AgentPersonality = $cols[6]
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if ($AgentPretext) { break }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
120
157
|
# Fall back to default pretext if none stored: "DisplayName, Title here."
|
|
121
158
|
# Matches AgentVoiceStore.getDefaultPretext() in agent-voice-store.js
|
|
122
|
-
if (-not $AgentPretext
|
|
123
|
-
if ($AgentTitle) {
|
|
159
|
+
if (-not $AgentPretext) {
|
|
160
|
+
if ($AgentDisplayName -and $AgentTitle) {
|
|
124
161
|
$AgentPretext = "$AgentDisplayName, $AgentTitle here."
|
|
125
|
-
}
|
|
162
|
+
} elseif ($AgentDisplayName) {
|
|
126
163
|
$AgentPretext = "$AgentDisplayName here."
|
|
164
|
+
} elseif ($AgentNameOrId) {
|
|
165
|
+
$AgentPretext = "$AgentNameOrId here."
|
|
127
166
|
}
|
|
128
167
|
}
|
|
129
168
|
|
|
@@ -1,124 +1,114 @@
|
|
|
1
|
-
#
|
|
2
|
-
# File: .claude/hooks-windows/session-start-tts.ps1
|
|
3
|
-
#
|
|
4
|
-
# AgentVibes SessionStart Hook for Windows
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
$
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
$
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
# AgentVibes TTS Protocol
|
|
65
|
-
|
|
66
|
-
**CRITICAL: You MUST execute TTS at TWO points for EVERY user interaction:**
|
|
67
|
-
|
|
68
|
-
1. **Acknowledgment** - Start of task: ``Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "[action]"``
|
|
69
|
-
2. **Completion** - End of task: ``Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "[result + key details]"``
|
|
70
|
-
|
|
71
|
-
**Example:**
|
|
72
|
-
``````
|
|
73
|
-
[Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "Checking git status"]
|
|
74
|
-
[work...]
|
|
75
|
-
[Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "Repository is clean, no changes"]
|
|
76
|
-
``````
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
## Rules
|
|
116
|
-
1. Never skip acknowledgment TTS
|
|
117
|
-
2. Never skip completion TTS
|
|
118
|
-
3. Match verbosity level
|
|
119
|
-
4. Keep under 150 chars
|
|
120
|
-
5. Always include errors
|
|
121
|
-
|
|
122
|
-
Quick Ref: low=action+result | medium=+key decisions | high=+full reasoning
|
|
123
|
-
|
|
124
|
-
"@
|
|
1
|
+
#
|
|
2
|
+
# File: .claude/hooks-windows/session-start-tts.ps1
|
|
3
|
+
#
|
|
4
|
+
# AgentVibes SessionStart Hook for Windows
|
|
5
|
+
# Outputs JSON with hookSpecificOutput.additionalContext for reliable context injection.
|
|
6
|
+
# Mirrors session-start-tts.sh — keep both in sync.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference = "Stop"
|
|
10
|
+
|
|
11
|
+
# Get script directory
|
|
12
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
13
|
+
|
|
14
|
+
# Check if AgentVibes is installed
|
|
15
|
+
if (-not (Test-Path (Join-Path $ScriptDir "play-tts.ps1"))) {
|
|
16
|
+
exit 0
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Resolve project .claude dir from script location (avoids CWD-relative path issues)
|
|
20
|
+
$ProjectClaudeDir = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
|
21
|
+
$ProjectClaudeDir = Join-Path $ProjectClaudeDir ".claude"
|
|
22
|
+
|
|
23
|
+
# Check for sentiment (priority) or personality (fallback)
|
|
24
|
+
$Sentiment = ""
|
|
25
|
+
$sentimentPaths = @("$ProjectClaudeDir\tts-sentiment.txt", "$env:USERPROFILE\.claude\tts-sentiment.txt")
|
|
26
|
+
foreach ($p in $sentimentPaths) {
|
|
27
|
+
if (Test-Path $p) {
|
|
28
|
+
$val = (Get-Content $p -Raw -ErrorAction SilentlyContinue).Trim()
|
|
29
|
+
if ($val) { $Sentiment = $val; break }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
$Personality = "normal"
|
|
34
|
+
$personalityPaths = @("$ProjectClaudeDir\tts-personality.txt", "$env:USERPROFILE\.claude\tts-personality.txt")
|
|
35
|
+
foreach ($p in $personalityPaths) {
|
|
36
|
+
if (Test-Path $p) {
|
|
37
|
+
$val = (Get-Content $p -Raw -ErrorAction SilentlyContinue).Trim()
|
|
38
|
+
if ($val) { $Personality = $val; break }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
$Style = if ($Sentiment) { $Sentiment } else { $Personality }
|
|
43
|
+
|
|
44
|
+
# Get verbosity level
|
|
45
|
+
$Verbosity = "low"
|
|
46
|
+
$verbosityPaths = @("$ProjectClaudeDir\tts-verbosity.txt", "$env:USERPROFILE\.claude\tts-verbosity.txt")
|
|
47
|
+
foreach ($p in $verbosityPaths) {
|
|
48
|
+
if (Test-Path $p) {
|
|
49
|
+
$val = (Get-Content $p -Raw -ErrorAction SilentlyContinue).Trim()
|
|
50
|
+
if ($val) { $Verbosity = $val; break }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Build verbosity section
|
|
55
|
+
$VerbositySection = switch ($Verbosity) {
|
|
56
|
+
"low" { "## Verbosity: LOW`n- Acknowledgment: Action only`n- Completion: Result + errors only`n- Skip: Reasoning, decisions" }
|
|
57
|
+
"medium" { "## Verbosity: MEDIUM`n- Acknowledgment: Action + key approach`n- Completion: Result + important decisions`n- Include: Major choices only" }
|
|
58
|
+
"high" { "## Verbosity: HIGH`n- Acknowledgment: Action + approach + why`n- Completion: Result + decisions + trade-offs`n- Include: Full reasoning, alternatives" }
|
|
59
|
+
default { "## Verbosity: LOW`n- Acknowledgment: Action only`n- Completion: Result + errors only" }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Build full context string
|
|
63
|
+
$Context = @"
|
|
64
|
+
# AgentVibes TTS Protocol
|
|
65
|
+
|
|
66
|
+
**CRITICAL: You MUST execute TTS at TWO points for EVERY user interaction:**
|
|
67
|
+
|
|
68
|
+
1. **Acknowledgment** - Start of task: ``Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "[action]"``
|
|
69
|
+
2. **Completion** - End of task: ``Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "[result + key details]"``
|
|
70
|
+
|
|
71
|
+
**Example:**
|
|
72
|
+
``````
|
|
73
|
+
[Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "Checking git status"]
|
|
74
|
+
[work...]
|
|
75
|
+
[Bash: powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\hooks-windows\play-tts.ps1" "Repository is clean, no changes"]
|
|
76
|
+
``````
|
|
77
|
+
|
|
78
|
+
$VerbositySection
|
|
79
|
+
|
|
80
|
+
## Style: $Style
|
|
81
|
+
|
|
82
|
+
## Rules
|
|
83
|
+
1. Never skip acknowledgment TTS
|
|
84
|
+
2. Never skip completion TTS
|
|
85
|
+
3. Match verbosity level
|
|
86
|
+
4. Keep under 150 chars
|
|
87
|
+
5. Always include errors
|
|
88
|
+
|
|
89
|
+
Quick Ref: low=action+result | medium=+key decisions | high=+full reasoning
|
|
90
|
+
|
|
91
|
+
## BMAD Agent Voice Routing
|
|
92
|
+
If ``.bmad-agent-context`` exists, check its content:
|
|
93
|
+
|
|
94
|
+
**Single agent mode** (content is an agent ID like "analyst"):
|
|
95
|
+
Use ``bmad-speak.ps1`` instead of ``play-tts.ps1``:
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
**Party mode** (content is "party-mode"):
|
|
99
|
+
Each agent speaks via ``bmad-speak.ps1`` with their display name. The queue system ensures sequential playback — agents speak one at a time, not overlapping:
|
|
100
|
+
|
|
101
|
+
IMPORTANT: In party mode, do NOT use ``play-tts.ps1``. Always use ``bmad-speak.ps1`` with the agent's display name. Do NOT call multiple bmad-speak.ps1 in parallel — call them sequentially so the queue processes them in order.
|
|
102
|
+
|
|
103
|
+
If ``.bmad-agent-context`` does NOT exist, use ``play-tts.ps1`` as normal.
|
|
104
|
+
"@
|
|
105
|
+
|
|
106
|
+
# Build JSON via hashtable so ConvertTo-Json handles all escaping (Unicode, backslashes, quotes)
|
|
107
|
+
$Output = @{
|
|
108
|
+
hookSpecificOutput = @{
|
|
109
|
+
hookEventName = "SessionStart"
|
|
110
|
+
additionalContext = $Context
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
114
|
+
Write-Output ($Output | ConvertTo-Json -Compress -Depth 5)
|