agentvibes 5.6.9 → 5.7.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.
Files changed (99) hide show
  1. package/.agentvibes/config.json +3 -38
  2. package/.claude/commands/agent-vibes/provider.md +0 -0
  3. package/.claude/config/audio-effects.cfg +1 -1
  4. package/.claude/config/background-music-position.txt +6 -8
  5. package/.claude/config/reverb-level.txt +0 -0
  6. package/.claude/github-star-reminder.txt +1 -1
  7. package/.claude/hooks/bmad-tts-injector.sh +49 -21
  8. package/.claude/hooks/migrate-to-agentvibes.sh +24 -16
  9. package/.claude/hooks/personality-manager.sh +15 -2
  10. package/.claude/hooks/play-tts.sh +6 -0
  11. package/.claude/hooks/provider-commands.sh +16 -4
  12. package/.claude/hooks/provider-manager.sh +38 -0
  13. package/.claude/hooks/stop.sh +2 -27
  14. package/.claude/hooks/voice-manager.sh +50 -2
  15. package/.claude/hooks-windows/play-tts.ps1 +34 -1
  16. package/.claude/hooks-windows/tts-watcher.ps1 +122 -0
  17. package/.claude/piper-voices-dir.txt +1 -1
  18. package/.mcp.json +13 -33
  19. package/README.md +6 -8
  20. package/RELEASE_NOTES.md +32 -0
  21. package/bin/agent-vibes +39 -39
  22. package/package.json +1 -1
  23. package/src/bmad-detector.js +85 -71
  24. package/src/cli/list-personalities.js +110 -110
  25. package/src/cli/list-voices.js +114 -114
  26. package/src/commands/bmad-voices.js +394 -394
  27. package/src/commands/install-mcp.js +476 -476
  28. package/src/console/brand-colors.js +13 -13
  29. package/src/console/constants/personalities.js +44 -44
  30. package/src/console/tabs/help-tab.js +314 -314
  31. package/src/console/tabs/readme-tab.js +272 -272
  32. package/src/console/widgets/destroy-list.js +25 -25
  33. package/src/console/widgets/notice.js +55 -55
  34. package/src/console/widgets/personality-picker.js +213 -213
  35. package/src/i18n/de.js +202 -202
  36. package/src/i18n/es.js +202 -202
  37. package/src/i18n/fr.js +202 -202
  38. package/src/i18n/hi.js +202 -202
  39. package/src/i18n/ja.js +202 -202
  40. package/src/i18n/ko.js +202 -202
  41. package/src/i18n/pt.js +202 -202
  42. package/src/i18n/strings.js +54 -54
  43. package/src/i18n/zh-CN.js +202 -202
  44. package/src/installer/language-screen.js +31 -31
  45. package/src/installer/music-file-input.js +304 -304
  46. package/src/installer.js +330 -64
  47. package/src/services/agent-voice-store.js +59 -12
  48. package/src/services/config-service.js +264 -264
  49. package/src/services/language-service.js +47 -47
  50. package/src/services/llm-provider-service.js +57 -12
  51. package/src/services/provider-service.js +143 -143
  52. package/src/utils/audio-duration-validator.js +298 -298
  53. package/src/utils/audio-format-validator.js +277 -277
  54. package/src/utils/dependency-checker.js +469 -469
  55. package/src/utils/file-ownership-verifier.js +358 -358
  56. package/src/utils/list-formatter.js +194 -194
  57. package/src/utils/music-file-validator.js +285 -285
  58. package/src/utils/preview-list-prompt.js +136 -136
  59. package/src/utils/secure-music-storage.js +412 -412
  60. package/.agentvibes/LITE-MODE.md +0 -236
  61. package/.agentvibes/README.md +0 -136
  62. package/.agentvibes/backup/session-start-tts.sh.20251210_212814 +0 -141
  63. package/.agentvibes/backups/agents/analyst_20260204_144958.md +0 -78
  64. package/.agentvibes/backups/agents/architect_20260204_144958.md +0 -72
  65. package/.agentvibes/backups/agents/dev_20260204_144958.md +0 -74
  66. package/.agentvibes/backups/agents/pm_20260204_144958.md +0 -72
  67. package/.agentvibes/backups/agents/quick-flow-solo-dev_20260204_144958.md +0 -64
  68. package/.agentvibes/backups/agents/sm_20260204_144958.md +0 -87
  69. package/.agentvibes/backups/agents/tea_20260204_144958.md +0 -79
  70. package/.agentvibes/backups/agents/tech-writer_20260204_144958.md +0 -82
  71. package/.agentvibes/backups/agents/ux-designer_20260204_144958.md +0 -80
  72. package/.agentvibes/config/README-personality-defaults.md +0 -162
  73. package/.agentvibes/config/agentvibes.json +0 -1
  74. package/.agentvibes/config/mode.txt +0 -1
  75. package/.agentvibes/config/personality-voice-defaults.default.json +0 -21
  76. package/.agentvibes/config/save-audio.txt +0 -1
  77. package/.agentvibes/config/voice-metadata.json +0 -160
  78. package/.agentvibes/hooks/help.sh +0 -191
  79. package/.agentvibes/hooks/post-tool-use-lite.sh +0 -111
  80. package/.agentvibes/hooks/save-audio-manager.sh +0 -162
  81. package/.agentvibes/hooks/session-start-full-optimized.sh +0 -102
  82. package/.agentvibes/hooks/session-start-full.sh +0 -142
  83. package/.agentvibes/hooks/session-start-lite-v2.sh +0 -34
  84. package/.agentvibes/hooks/session-start-lite.sh +0 -29
  85. package/.agentvibes/hooks/stop-lite.sh +0 -115
  86. package/.agentvibes/hooks/switch-mode.sh +0 -215
  87. package/.agentvibes/output-styles/audio-summary.md +0 -30
  88. package/.claude/audio/voice-samples/piper/alan.wav +0 -0
  89. package/.claude/audio/voice-samples/piper/amy.wav +0 -0
  90. package/.claude/audio/voice-samples/piper/charlotte.wav +0 -0
  91. package/.claude/audio/voice-samples/piper/joe.wav +0 -0
  92. package/.claude/audio/voice-samples/piper/john.wav +0 -0
  93. package/.claude/audio/voice-samples/piper/katherine.wav +0 -0
  94. package/.claude/audio/voice-samples/piper/kristin.wav +0 -0
  95. package/.claude/audio/voice-samples/piper/linda.wav +0 -0
  96. package/.claude/audio/voice-samples/piper/marcus.wav +0 -0
  97. package/.claude/audio/voice-samples/piper/ryan.wav +0 -0
  98. package/.claude/hooks/post-response.sh +0 -41
  99. package/bin/ensure-soprano-running.sh +0 -43
@@ -0,0 +1,122 @@
1
+ #
2
+ # File: .claude/hooks-windows/tts-watcher.ps1
3
+ #
4
+ # AgentVibes TTS Queue Watcher — runs in the user's interactive session for audio access.
5
+ # The SSH receiver (session 0, no audio) writes JSON request files to the queue; this
6
+ # watcher picks them up and calls play-tts.ps1 in the user's desktop session.
7
+ #
8
+ # Single-instance guard: exit immediately if another watcher instance is already running.
9
+ $mutex = New-Object System.Threading.Mutex($false, 'Global\AgentVibesTtsWatcher')
10
+ if (-not $mutex.WaitOne(0)) { $mutex.Dispose(); exit 0 }
11
+
12
+ $QueueDir = "$env:USERPROFILE\.agentvibes\tts-queue"
13
+ $LogFile = "$env:USERPROFILE\.agentvibes\watcher.log"
14
+ $PlayTts = "$env:USERPROFILE\.claude\hooks-windows\play-tts.ps1"
15
+ if (-not (Test-Path $QueueDir)) { New-Item -ItemType Directory -Path $QueueDir -Force | Out-Null }
16
+
17
+ function Write-WatcherLog {
18
+ param([string]$Level, [string]$Msg)
19
+ $ts = Get-Date -Format 'yyyy-MM-ddTHH:mm:ss'
20
+ Add-Content -Path $LogFile -Value "$ts [$Level] $Msg" -ErrorAction SilentlyContinue
21
+ }
22
+
23
+ Write-WatcherLog "INFO" "Watcher started. PlayTts=$PlayTts exists=$(Test-Path $PlayTts)"
24
+
25
+ try {
26
+ while ($true) {
27
+ $files = Get-ChildItem "$QueueDir\req-*.json" -ErrorAction SilentlyContinue | Sort-Object CreationTime
28
+ foreach ($f in $files) {
29
+ # Rename to proc-* before processing — crash recovery on restart
30
+ $procFile = $f.FullName -replace '\\req-', '\proc-'
31
+ try { Rename-Item $f.FullName $procFile -ErrorAction Stop } catch { continue }
32
+ try {
33
+ $req = Get-Content $procFile -Raw | ConvertFrom-Json
34
+ # Validate voice before passing to command line
35
+ $safeVoice = if ($req.voice -and $req.voice -match '^[a-zA-Z0-9_\-\. :]+$') { $req.voice } else { "" }
36
+ $env:CLAUDE_PROJECT_DIR = $env:USERPROFILE
37
+ $env:AGENTVIBES_NO_PRETEXT = "1"
38
+ # Use SetEnvironmentVariable to truly unset (assignment to $null leaves empty string)
39
+ if ($req.music) { $env:AGENTVIBES_OVERRIDE_MUSIC = $req.music }
40
+ else { [System.Environment]::SetEnvironmentVariable("AGENTVIBES_OVERRIDE_MUSIC", $null, "Process") }
41
+ if ($req.volume) { $env:AGENTVIBES_OVERRIDE_VOLUME = $req.volume }
42
+ else { [System.Environment]::SetEnvironmentVariable("AGENTVIBES_OVERRIDE_VOLUME", $null, "Process") }
43
+ if ($req.effects) { $env:AGENTVIBES_OVERRIDE_EFFECTS = $req.effects }
44
+ else { [System.Environment]::SetEnvironmentVariable("AGENTVIBES_OVERRIDE_EFFECTS", $null, "Process") }
45
+
46
+ if (Test-Path $PlayTts) {
47
+ # Play remote arrival prefix sound if configured
48
+ $prefixSoundFile = "$env:USERPROFILE\.agentvibes\remote-prefix-sound.txt"
49
+ if (Test-Path $prefixSoundFile) {
50
+ $prefixSound = (Get-Content $prefixSoundFile -Raw).Trim()
51
+ if ($prefixSound -and (Test-Path $prefixSound)) {
52
+ $ffplay = Get-Command ffplay -ErrorAction SilentlyContinue
53
+ if ($ffplay) {
54
+ & $ffplay.Source -autoexit -nodisp -loglevel quiet $prefixSound 2>$null
55
+ }
56
+ }
57
+ }
58
+
59
+ $tempText = Join-Path $env:TEMP "agentvibes-tts-$($req.id).txt"
60
+ try {
61
+ [System.IO.File]::WriteAllText($tempText, $req.text, [System.Text.UTF8Encoding]::new($false))
62
+ $env:AGENTVIBES_TEXT_FILE = $tempText
63
+
64
+ $llmArg = @()
65
+ if ($req.llm) {
66
+ if ($req.llm -match '^[a-zA-Z0-9][a-zA-Z0-9_-]*$') {
67
+ $llmArg = @('-llm', $req.llm)
68
+ } else {
69
+ Write-WatcherLog "WARN" "Invalid LLM name '$($req.llm)' - using default"
70
+ }
71
+ }
72
+
73
+ # Provider override: the Linux sender embeds its configured provider
74
+ # (from receiver-provider.txt / audio-effects.cfg ENGINE column) in the
75
+ # JSON payload so the Windows receiver uses the Linux-side engine choice.
76
+ $providerArg = @()
77
+ if ($req.provider) {
78
+ $safeProvider = $req.provider.Trim()
79
+ if ($safeProvider -match '^[a-zA-Z0-9][a-zA-Z0-9_-]*$') {
80
+ $providerArg = @('-ProviderOverride', $safeProvider)
81
+ } else {
82
+ Write-WatcherLog "WARN" "Invalid provider '$safeProvider' in payload - ignored"
83
+ }
84
+ }
85
+
86
+ Write-WatcherLog "INFO" "play-tts id=$($req.id) voice=$safeVoice llm=$($req.llm) provider=$safeProvider"
87
+ $playOutput = & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $PlayTts "__from_file__" $safeVoice @llmArg @providerArg 2>&1
88
+ if ($LASTEXITCODE -ne 0) {
89
+ Write-WatcherLog "ERROR" "play-tts exit=$LASTEXITCODE id=$($req.id) output=$($playOutput -join ' | ')"
90
+ } else {
91
+ Write-WatcherLog "INFO" "play-tts ok exit=0 id=$($req.id)"
92
+ }
93
+ } finally {
94
+ [System.Environment]::SetEnvironmentVariable("AGENTVIBES_TEXT_FILE", $null, "Process")
95
+ Remove-Item $tempText -Force -ErrorAction SilentlyContinue
96
+ }
97
+ } else {
98
+ # Fallback: Windows SAPI (built-in, no installation required)
99
+ Write-WatcherLog "WARN" "play-tts.ps1 not found - using SAPI fallback for id=$($req.id)"
100
+ Add-Type -AssemblyName System.Speech
101
+ $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
102
+ $synth.Speak($req.text)
103
+ $synth.Dispose()
104
+ }
105
+ Remove-Item $procFile -Force -ErrorAction SilentlyContinue
106
+ } catch {
107
+ Write-WatcherLog "ERROR" "id=$($req.id) err=$_"
108
+ Remove-Item $procFile -Force -ErrorAction SilentlyContinue
109
+ }
110
+ }
111
+ # Crash recovery: re-queue any proc-* files left from a previous watcher crash
112
+ $stale = Get-ChildItem "$QueueDir\proc-*.json" -ErrorAction SilentlyContinue
113
+ foreach ($s in $stale) {
114
+ $recovered = $s.FullName -replace '\\proc-', '\req-'
115
+ try { Rename-Item $s.FullName $recovered -ErrorAction SilentlyContinue } catch {}
116
+ }
117
+ Start-Sleep -Milliseconds 200
118
+ }
119
+ } finally {
120
+ $mutex.ReleaseMutex()
121
+ $mutex.Dispose()
122
+ }
@@ -1 +1 @@
1
- /home/fire/.claude/piper-voices
1
+ /home/administrator/.claude/piper-voices
package/.mcp.json CHANGED
@@ -1,50 +1,30 @@
1
1
  {
2
2
  "mcpServers": {
3
- "context7": {
3
+ "agentvibes": {
4
4
  "command": "npx",
5
5
  "args": [
6
- "@upstash/context7-mcp"
7
- ]
8
- },
9
- "sonarqube": {
10
- "command": "docker",
11
- "args": [
12
- "run",
13
- "-i",
14
- "--name",
15
- "sonarqube-mcp-server-agentvibes",
16
- "--rm",
17
- "--dns",
18
- "8.8.8.8",
19
- "--dns",
20
- "8.8.4.4",
21
- "-e",
22
- "SONARQUBE_TOKEN",
23
- "-e",
24
- "SONARQUBE_ORG",
25
- "-e",
26
- "STORAGE_PATH",
27
- "mcp/sonarqube"
6
+ "-y",
7
+ "--package=agentvibes",
8
+ "agentvibes-mcp-server"
28
9
  ],
29
10
  "env": {
30
- "SONARQUBE_TOKEN": "${SONARQUBE_TOKEN}",
31
- "SONARQUBE_ORG": "${SONARQUBE_ORG}",
32
- "STORAGE_PATH": "${STORAGE_PATH}"
11
+ "AGENTVIBES_MCP_FALLBACK": "copilot"
33
12
  }
34
13
  },
35
- "vercel": {
36
- "type": "sse",
37
- "url": "https://mcp.vercel.com"
14
+ "firecrawl": {
15
+ "command": "npx",
16
+ "args": [
17
+ "firecrawl-mcp"
18
+ ]
38
19
  },
39
- "agentvibes": {
20
+ "context7": {
40
21
  "command": "npx",
41
22
  "args": [
42
23
  "-y",
43
- "--package=agentvibes",
44
- "agentvibes-mcp-server"
24
+ "@upstash/context7-mcp"
45
25
  ],
46
26
  "env": {
47
- "AGENTVIBES_MCP_FALLBACK": "copilot"
27
+ "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}"
48
28
  }
49
29
  }
50
30
  }
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**: v5.6.9
14
+ **Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v5.7.1
15
15
 
16
16
  ---
17
17
 
@@ -40,17 +40,15 @@ Whether you're coding in Claude Code, chatting in Claude Desktop, using Warp Ter
40
40
 
41
41
  ---
42
42
 
43
- ## 🌟 NEW IN v5.6.9Reverb & Background Music Silent in NPX Installs
43
+ ## 🌟 NEW IN v5.7.0BMAD v6.6 Support + Windows Auto-Restart Watcher
44
44
 
45
- **NPX users:** Reverb and background music were silently broken for all `npx`-installed users. Hook files extracted from the npm tarball lacked execute bits (644), causing `audio-processor.sh` to exit with code 126. Fixed via `bash` prefix in the caller and a postinstall `chmod 755` step.
45
+ **BMAD v6.6.0:** AgentVibes now detects the new `.claude/skills/*/agents/` agent structure, correctly handles globally-installed BMAD at `~/_bmad`, and gracefully skips v6.6+ plain-Markdown agents during TTS injection instead of erroring. The BMAD tab now shows detection correctly for global installs.
46
46
 
47
- **Voice Browser:** The Preview button now applies your configured reverb and background musicit was playing raw audio with no effects.
47
+ **Windows watcher:** `tts-watcher.ps1` is now a standalone file at `~/.agentvibes/tts-watcher.ps1`. Running `npx agentvibes update` now copies the latest watcher **and** restarts it automatically both the file and the process are updated in one step, no manual restart needed.
48
48
 
49
- **MCP tool:** `text_to_speech` now returns the correct audio file path (no trailing emoji garbage) and includes the voice name in its response.
49
+ **Windows provider:** `play-tts.ps1` now respects the `ProviderOverride` from the Linux server config when receiving remote audio.
50
50
 
51
- **Background music toggle:** Enabling music in the TUI now actually enables it the flag file read by bash hooks is now kept in sync.
52
-
53
- ## v5.6.8 — WSL Voice Routing Fixed + Session Lifecycle Reliability
51
+ ## v5.6.9Reverb & Background Music Silent in NPX Installs
54
52
 
55
53
  **WSL users:** AgentVibes was playing `en_US-lessac-medium` regardless of your configured voice. Fixed — Piper is now found in non-interactive shells by explicitly prepending `~/.local/bin` to `PATH` before the binary check.
56
54
 
package/RELEASE_NOTES.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # AgentVibes Release Notes
2
2
 
3
+ ## 🎭 v5.7.0 — BMAD v6.6 Support + Windows Auto-Restart Watcher
4
+
5
+ **Released:** 2026-05-11
6
+
7
+ ### 🆕 BMAD v6.6.0 Compatibility
8
+
9
+ BMAD v6.6 restructured where agents live — they moved from `_bmad/bmm/agents/` to `.claude/skills/*/agents/`. AgentVibes now detects and scans these new paths correctly.
10
+
11
+ **TTS injection** gracefully skips v6.6+ agents (which use plain Markdown without XML/YAML activation sections) instead of throwing errors. The install summary now clearly reports how many agents were skipped vs. modified.
12
+
13
+ **BMAD tab detection** now finds globally-installed BMAD at `~/_bmad` (home-dir install) in addition to project-local installs. Previously the BMAD tab showed "Not detected" even when BMAD was installed globally.
14
+
15
+ **Security:** The installer's path validation now correctly permits BMAD paths under the user's home directory, fixing a false-positive "Invalid BMAD path" error for global installs.
16
+
17
+ ### 🆕 Windows TTS Watcher — Standalone File + Auto-Restart
18
+
19
+ `tts-watcher.ps1` is now extracted to `~/.agentvibes/tts-watcher.ps1` as a standalone file. Running `npx agentvibes update` now copies the latest watcher to that location **and** automatically restarts it — so both the watcher script itself and its running process are updated in one step. No manual file replacement or restart needed after updates.
20
+
21
+ ### 🐛 Windows Provider Override Respected on Laptop
22
+
23
+ `play-tts.ps1` now reads the `ProviderOverride` setting from the Linux-side config when receiving audio via SSH. Previously the laptop always used its locally-configured provider even if the server specified a different one.
24
+
25
+ ### 🐛 Sample Command Added to Voice Manager
26
+
27
+ `voice-manager.sh sample` was missing its handler — calling it fell through to the usage/exit path silently. Fixed.
28
+
29
+ ### 🐛 Preview SSH Routing Detects Correct Endpoint
30
+
31
+ `provider-manager.sh` now includes `detect_routing_llm()` which checks `AGENTVIBES_LLM_KEY` then `transport-config.json` for the first `mode=remote` entry, so preview audio reaches the correct SSH host.
32
+
33
+ ---
34
+
3
35
  ## 🔇 v5.6.9 — Reverb & Background Music Silent in NPX Installs
4
36
 
5
37
  **Released:** 2026-05-09
package/bin/agent-vibes CHANGED
@@ -1,40 +1,40 @@
1
1
  #!/usr/bin/env node
2
-
3
- /**
4
- * AgentVibes - Beautiful ElevenLabs TTS voice commands for Claude Code
5
- * This file ensures proper execution when run via npx
6
- */
7
-
8
- import { execFileSync } from 'node:child_process';
9
- import path from 'node:path';
10
- import fs from 'node:fs';
11
- import { fileURLToPath } from 'node:url';
12
-
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = path.dirname(__filename);
15
-
16
- // Check if we're running in an npx temporary directory
17
- const isNpxExecution = __dirname.includes('_npx') || __dirname.includes('.npm');
18
-
19
- // Get CLI arguments
20
- const arguments_ = process.argv.slice(2);
21
-
22
- // Route through the TUI console (agentvibes.js) which handles install/config/etc
23
- const installerPath = path.join(__dirname, 'agentvibes.js');
24
-
25
- if (!fs.existsSync(installerPath)) {
26
- console.error('Error: Could not find installer.js at', installerPath);
27
- console.error('Current directory:', __dirname);
28
- process.exit(1);
29
- }
30
-
31
- try {
32
- // Security: Use execFileSync with array args to prevent command injection
33
- // Arguments are passed as array elements, not string interpolation
34
- execFileSync('node', [installerPath, ...arguments_], {
35
- stdio: 'inherit',
36
- cwd: path.dirname(__dirname),
37
- });
38
- } catch (error) {
39
- process.exit(error.status || 1);
40
- }
2
+
3
+ /**
4
+ * AgentVibes - Beautiful ElevenLabs TTS voice commands for Claude Code
5
+ * This file ensures proper execution when run via npx
6
+ */
7
+
8
+ import { execFileSync } from 'node:child_process';
9
+ import path from 'node:path';
10
+ import fs from 'node:fs';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ // Check if we're running in an npx temporary directory
17
+ const isNpxExecution = __dirname.includes('_npx') || __dirname.includes('.npm');
18
+
19
+ // Get CLI arguments
20
+ const arguments_ = process.argv.slice(2);
21
+
22
+ // Route through the TUI console (agentvibes.js) which handles install/config/etc
23
+ const installerPath = path.join(__dirname, 'agentvibes.js');
24
+
25
+ if (!fs.existsSync(installerPath)) {
26
+ console.error('Error: Could not find installer.js at', installerPath);
27
+ console.error('Current directory:', __dirname);
28
+ process.exit(1);
29
+ }
30
+
31
+ try {
32
+ // Security: Use execFileSync with array args to prevent command injection
33
+ // Arguments are passed as array elements, not string interpolation
34
+ execFileSync('node', [installerPath, ...arguments_], {
35
+ stdio: 'inherit',
36
+ cwd: path.dirname(__dirname),
37
+ });
38
+ } catch (error) {
39
+ process.exit(error.status || 1);
40
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "agentvibes",
4
- "version": "5.6.9",
4
+ "version": "5.7.1",
5
5
  "description": "Now your AI Agents can finally talk back! Professional TTS voice for Claude Code, Claude Desktop (via MCP), and Clawdbot with multi-provider support.",
6
6
  "homepage": "https://agentvibes.org",
7
7
  "keywords": [
@@ -1,71 +1,85 @@
1
- import path from 'node:path';
2
- import fs from 'node:fs/promises';
3
- import yaml from 'js-yaml';
4
-
5
- /**
6
- * Detect BMAD installation and version
7
- * @param {string} targetDir - Directory to check
8
- * @returns {Promise<Object>} Detection result with version info
9
- */
10
- export async function detectBMAD(targetDir) {
11
- // Check v6 first (newer version) - support both .bmad and bmad paths
12
- // Try .bmad (standard path with dot prefix) first
13
- let v6Manifest = path.join(targetDir, '.bmad/_cfg/manifest.yaml');
14
- let bmadPath = '.bmad';
15
-
16
- try {
17
- await fs.access(v6Manifest);
18
- } catch {
19
- // Try bmad (alternative path without dot prefix)
20
- v6Manifest = path.join(targetDir, 'bmad/_cfg/manifest.yaml');
21
- bmadPath = 'bmad';
22
- try {
23
- await fs.access(v6Manifest);
24
- } catch {
25
- // Neither path found, continue to v4 check
26
- bmadPath = null;
27
- }
28
- }
29
-
30
- if (bmadPath) {
31
- try {
32
- const manifestContent = await fs.readFile(v6Manifest, 'utf8');
33
- const manifest = yaml.load(manifestContent);
34
-
35
- return {
36
- version: 6,
37
- detailedVersion: manifest.installation?.version || '6.0.0-alpha.x',
38
- manifestPath: v6Manifest,
39
- configPath: path.join(targetDir, bmadPath, 'core/config.yaml'),
40
- bmadPath: path.join(targetDir, bmadPath),
41
- installed: true
42
- };
43
- } catch {}
44
- }
45
-
46
- // Check v4 (legacy)
47
- const v4Manifest = path.join(targetDir, '.bmad-core/install-manifest.yaml');
48
- try {
49
- await fs.access(v4Manifest);
50
- return {
51
- version: 4,
52
- detailedVersion: '4.x',
53
- manifestPath: v4Manifest,
54
- configPath: path.join(targetDir, '.bmad-core/config.yaml'),
55
- bmadPath: path.join(targetDir, '.bmad-core'),
56
- installed: true
57
- };
58
- } catch {}
59
-
60
- // Not installed
61
- return { version: null, installed: false };
62
- }
63
-
64
- /**
65
- * Get BMAD configuration file path for detected version
66
- * @param {Object} detection - Result from detectBMAD()
67
- * @returns {string|null} Path to config.yaml or null
68
- */
69
- export function getBMADConfigPath(detection) {
70
- return detection.installed ? detection.configPath : null;
71
- }
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import yaml from 'js-yaml';
5
+
6
+ /**
7
+ * Detect BMAD installation and version
8
+ * @param {string} targetDir - Directory to check
9
+ * @returns {Promise<Object>} Detection result with version info
10
+ */
11
+ export async function detectBMAD(targetDir) {
12
+ // Check v6 first (newer version).
13
+ // Search order: project-local variants first, then home-dir (_bmad is the current BMAD installer default)
14
+ const homeDir = os.homedir();
15
+ const v6Candidates = [
16
+ // Project-local checks first
17
+ { manifest: path.join(targetDir, '.bmad/_cfg/manifest.yaml'), bmadPath: '.bmad' },
18
+ { manifest: path.join(targetDir, 'bmad/_cfg/manifest.yaml'), bmadPath: 'bmad' },
19
+ { manifest: path.join(targetDir, '_bmad/_cfg/manifest.yaml'), bmadPath: '_bmad' },
20
+ { manifest: path.join(targetDir, '_bmad/_config/manifest.yaml'), bmadPath: '_bmad' },
21
+ // Home-dir installs (global BMAD not inside a project) — detected but NOT injected
22
+ { manifest: path.join(homeDir, '_bmad/_config/manifest.yaml'), bmadPath: '_bmad', root: homeDir, isGlobal: true },
23
+ { manifest: path.join(homeDir, '_bmad/_cfg/manifest.yaml'), bmadPath: '_bmad', root: homeDir, isGlobal: true },
24
+ { manifest: path.join(homeDir, '.bmad/_cfg/manifest.yaml'), bmadPath: '.bmad', root: homeDir, isGlobal: true },
25
+ ];
26
+
27
+ let v6Manifest = null;
28
+ let bmadPath = null;
29
+ let bmadRoot = targetDir;
30
+ let isGlobal = false;
31
+
32
+ for (const candidate of v6Candidates) {
33
+ try {
34
+ await fs.access(candidate.manifest);
35
+ v6Manifest = candidate.manifest;
36
+ bmadPath = candidate.bmadPath;
37
+ bmadRoot = candidate.root ?? targetDir;
38
+ isGlobal = candidate.isGlobal ?? false;
39
+ break;
40
+ } catch { /* try next */ }
41
+ }
42
+
43
+ if (bmadPath) {
44
+ try {
45
+ const manifestContent = await fs.readFile(v6Manifest, 'utf8');
46
+ const manifest = yaml.load(manifestContent);
47
+
48
+ return {
49
+ version: 6,
50
+ detailedVersion: manifest.installation?.version || '6.0.0-alpha.x',
51
+ manifestPath: v6Manifest,
52
+ configPath: path.join(bmadRoot, bmadPath, 'core/config.yaml'),
53
+ bmadPath: path.join(bmadRoot, bmadPath),
54
+ installed: true,
55
+ isGlobal,
56
+ };
57
+ } catch {}
58
+ }
59
+
60
+ // Check v4 (legacy)
61
+ const v4Manifest = path.join(targetDir, '.bmad-core/install-manifest.yaml');
62
+ try {
63
+ await fs.access(v4Manifest);
64
+ return {
65
+ version: 4,
66
+ detailedVersion: '4.x',
67
+ manifestPath: v4Manifest,
68
+ configPath: path.join(targetDir, '.bmad-core/config.yaml'),
69
+ bmadPath: path.join(targetDir, '.bmad-core'),
70
+ installed: true
71
+ };
72
+ } catch {}
73
+
74
+ // Not installed
75
+ return { version: null, installed: false };
76
+ }
77
+
78
+ /**
79
+ * Get BMAD configuration file path for detected version
80
+ * @param {Object} detection - Result from detectBMAD()
81
+ * @returns {string|null} Path to config.yaml or null
82
+ */
83
+ export function getBMADConfigPath(detection) {
84
+ return detection.installed ? detection.configPath : null;
85
+ }