agentvibes 4.2.0 → 4.4.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.
Files changed (219) hide show
  1. package/.agentvibes/bmad/bmad-voices.md +69 -69
  2. package/.agentvibes/config.json +12 -0
  3. package/.claude/activation-instructions +54 -54
  4. package/.claude/audio/tracks/README.md +52 -52
  5. package/.claude/commands/agent-vibes/add.md +21 -21
  6. package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
  7. package/.claude/commands/agent-vibes/agent.md +79 -79
  8. package/.claude/commands/agent-vibes/background-music.md +111 -111
  9. package/.claude/commands/agent-vibes/bmad.md +198 -198
  10. package/.claude/commands/agent-vibes/clean.md +18 -18
  11. package/.claude/commands/agent-vibes/cleanup.md +18 -18
  12. package/.claude/commands/agent-vibes/commands.json +145 -145
  13. package/.claude/commands/agent-vibes/effects.md +97 -97
  14. package/.claude/commands/agent-vibes/get.md +9 -9
  15. package/.claude/commands/agent-vibes/hide.md +91 -91
  16. package/.claude/commands/agent-vibes/language.md +23 -23
  17. package/.claude/commands/agent-vibes/learn.md +67 -67
  18. package/.claude/commands/agent-vibes/list.md +13 -13
  19. package/.claude/commands/agent-vibes/mute.md +37 -37
  20. package/.claude/commands/agent-vibes/preview.md +17 -17
  21. package/.claude/commands/agent-vibes/provider.md +68 -68
  22. package/.claude/commands/agent-vibes/replay-target.md +14 -14
  23. package/.claude/commands/agent-vibes/sample.md +12 -12
  24. package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
  25. package/.claude/commands/agent-vibes/set-pretext.md +65 -65
  26. package/.claude/commands/agent-vibes/set-speed.md +41 -41
  27. package/.claude/commands/agent-vibes/show.md +84 -84
  28. package/.claude/commands/agent-vibes/switch.md +87 -87
  29. package/.claude/commands/agent-vibes/target-voice.md +26 -26
  30. package/.claude/commands/agent-vibes/target.md +30 -30
  31. package/.claude/commands/agent-vibes/translate.md +68 -68
  32. package/.claude/commands/agent-vibes/unmute.md +45 -45
  33. package/.claude/commands/agent-vibes/verbosity.md +89 -89
  34. package/.claude/commands/agent-vibes/whoami.md +7 -7
  35. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  36. package/.claude/commands/agent-vibes-rdp.md +24 -24
  37. package/.claude/config/agentvibes.json +1 -0
  38. package/.claude/config/audio-effects.cfg +2 -2
  39. package/.claude/config/audio-effects.cfg.sample +52 -52
  40. package/.claude/config/background-music-volume.txt +1 -0
  41. package/.claude/config/intro-text.txt +1 -0
  42. package/.claude/config/piper-speech-rate.txt +4 -0
  43. package/.claude/config/piper-target-speech-rate.txt +1 -0
  44. package/.claude/config/reverb-level.txt +1 -0
  45. package/.claude/config/tts-speech-rate.txt +4 -0
  46. package/.claude/config/tts-target-speech-rate.txt +1 -0
  47. package/.claude/docs/TERMUX_SETUP.md +408 -408
  48. package/.claude/github-star-reminder.txt +1 -1
  49. package/.claude/hooks/README-TTS-QUEUE.md +135 -135
  50. package/.claude/hooks/audio-cache-utils.sh +246 -246
  51. package/.claude/hooks/audio-processor.sh +433 -433
  52. package/.claude/hooks/background-music-manager.sh +404 -404
  53. package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
  54. package/.claude/hooks/bmad-speak.sh +269 -269
  55. package/.claude/hooks/bmad-tts-injector.sh +568 -568
  56. package/.claude/hooks/bmad-voice-manager.sh +928 -928
  57. package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
  58. package/.claude/hooks/clawdbot-receiver.sh +107 -107
  59. package/.claude/hooks/clean-audio-cache.sh +22 -22
  60. package/.claude/hooks/cleanup-cache.sh +106 -106
  61. package/.claude/hooks/configure-rdp-mode.sh +137 -137
  62. package/.claude/hooks/download-extra-voices.sh +244 -244
  63. package/.claude/hooks/effects-manager.sh +268 -268
  64. package/.claude/hooks/github-star-reminder.sh +154 -154
  65. package/.claude/hooks/language-manager.sh +362 -362
  66. package/.claude/hooks/learn-manager.sh +492 -492
  67. package/.claude/hooks/macos-voice-manager.sh +205 -205
  68. package/.claude/hooks/migrate-background-music.sh +125 -125
  69. package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
  70. package/.claude/hooks/optimize-background-music.sh +87 -87
  71. package/.claude/hooks/path-resolver.sh +60 -60
  72. package/.claude/hooks/personality-manager.sh +448 -448
  73. package/.claude/hooks/piper-download-voices.sh +225 -225
  74. package/.claude/hooks/piper-installer.sh +292 -292
  75. package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
  76. package/.claude/hooks/piper-voice-manager.sh +24 -3
  77. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
  78. package/.claude/hooks/play-tts-enhanced.sh +105 -105
  79. package/.claude/hooks/play-tts-macos.sh +368 -368
  80. package/.claude/hooks/play-tts-piper.sh +679 -679
  81. package/.claude/hooks/play-tts-soprano.sh +356 -356
  82. package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
  83. package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
  84. package/.claude/hooks/play-tts.sh +301 -301
  85. package/.claude/hooks/prepare-release.sh +54 -54
  86. package/.claude/hooks/provider-commands.sh +617 -617
  87. package/.claude/hooks/provider-manager.sh +399 -399
  88. package/.claude/hooks/replay-target-audio.sh +95 -95
  89. package/.claude/hooks/requirements.txt +6 -6
  90. package/.claude/hooks/sentiment-manager.sh +201 -201
  91. package/.claude/hooks/session-start-tts.sh +81 -81
  92. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  93. package/.claude/hooks/speed-manager.sh +291 -291
  94. package/.claude/hooks/stop-tts.sh +84 -84
  95. package/.claude/hooks/termux-installer.sh +261 -261
  96. package/.claude/hooks/translate-manager.sh +341 -341
  97. package/.claude/hooks/translator.py +237 -237
  98. package/.claude/hooks/tts-queue-worker.sh +145 -145
  99. package/.claude/hooks/tts-queue.sh +165 -165
  100. package/.claude/hooks/verbosity-manager.sh +178 -178
  101. package/.claude/hooks/voice-manager.sh +548 -548
  102. package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
  103. package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
  104. package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
  105. package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
  106. package/.claude/hooks-windows/effects-manager.ps1 +294 -0
  107. package/.claude/hooks-windows/language-manager.ps1 +193 -0
  108. package/.claude/hooks-windows/learn-manager.ps1 +241 -0
  109. package/.claude/hooks-windows/personality-manager.ps1 +266 -0
  110. package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
  111. package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
  112. package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
  113. package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
  114. package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
  115. package/.claude/hooks-windows/play-tts.ps1 +344 -266
  116. package/.claude/hooks-windows/provider-manager.ps1 +29 -10
  117. package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
  118. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  119. package/.claude/hooks-windows/speed-manager.ps1 +166 -0
  120. package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
  121. package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
  122. package/.claude/output-styles/agent-vibes.md +202 -202
  123. package/.claude/personalities/angry.md +14 -14
  124. package/.claude/personalities/annoying.md +14 -14
  125. package/.claude/personalities/crass.md +14 -14
  126. package/.claude/personalities/dramatic.md +14 -14
  127. package/.claude/personalities/dry-humor.md +50 -50
  128. package/.claude/personalities/flirty.md +20 -20
  129. package/.claude/personalities/funny.md +14 -14
  130. package/.claude/personalities/grandpa.md +32 -32
  131. package/.claude/personalities/millennial.md +14 -14
  132. package/.claude/personalities/moody.md +14 -14
  133. package/.claude/personalities/normal.md +16 -16
  134. package/.claude/personalities/pirate.md +14 -14
  135. package/.claude/personalities/poetic.md +14 -14
  136. package/.claude/personalities/professional.md +14 -14
  137. package/.claude/personalities/rapper.md +55 -55
  138. package/.claude/personalities/robot.md +14 -14
  139. package/.claude/personalities/sarcastic.md +38 -38
  140. package/.claude/personalities/sassy.md +14 -14
  141. package/.claude/personalities/surfer-dude.md +14 -14
  142. package/.claude/personalities/zen.md +14 -14
  143. package/.claude/settings.json +15 -15
  144. package/.claude/verbosity.txt +1 -1
  145. package/.clawdbot/README.md +105 -105
  146. package/.clawdbot/skill/SKILL.md +241 -241
  147. package/.mcp.json +12 -0
  148. package/CLAUDE.md +170 -170
  149. package/README.md +2029 -2007
  150. package/RELEASE_NOTES.md +1310 -1203
  151. package/WINDOWS-SETUP.md +208 -208
  152. package/bin/agent-vibes +39 -39
  153. package/bin/agentvibes-voice-browser.js +1840 -1840
  154. package/bin/agentvibes.js +48 -2
  155. package/bin/mcp-server.js +121 -121
  156. package/bin/mcp-server.sh +206 -206
  157. package/bin/test-bmad-pr +78 -78
  158. package/mcp-server/QUICK_START.md +203 -203
  159. package/mcp-server/README.md +345 -345
  160. package/mcp-server/WINDOWS_SETUP.md +260 -260
  161. package/mcp-server/docs/troubleshooting-audio.md +313 -313
  162. package/mcp-server/examples/claude_desktop_config.json +11 -11
  163. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  164. package/mcp-server/examples/custom_instructions.md +169 -169
  165. package/mcp-server/install-deps.js +130 -130
  166. package/mcp-server/pyproject.toml +52 -52
  167. package/mcp-server/requirements.txt +2 -2
  168. package/mcp-server/server.py +1465 -1453
  169. package/mcp-server/test_server.py +395 -395
  170. package/mcp-server/test_windows_script_parity.py +336 -0
  171. package/package.json +110 -110
  172. package/setup-windows.ps1 +815 -815
  173. package/src/bmad-detector.js +71 -71
  174. package/src/cli/list-personalities.js +110 -110
  175. package/src/cli/list-voices.js +114 -114
  176. package/src/commands/bmad-voices.js +394 -394
  177. package/src/commands/install-mcp.js +476 -476
  178. package/src/console/app.js +824 -824
  179. package/src/console/audio-env.js +20 -1
  180. package/src/console/brand-colors.js +13 -13
  181. package/src/console/constants/personalities.js +44 -44
  182. package/src/console/footer-config.js +50 -50
  183. package/src/console/modals/modal-overlay.js +247 -247
  184. package/src/console/navigation.js +62 -62
  185. package/src/console/tabs/agents-tab.js +1684 -1516
  186. package/src/console/tabs/help-tab.js +261 -261
  187. package/src/console/tabs/install-tab.js +1007 -991
  188. package/src/console/tabs/music-tab.js +22 -8
  189. package/src/console/tabs/placeholder-tab.js +53 -53
  190. package/src/console/tabs/readme-tab.js +267 -267
  191. package/src/console/tabs/receiver-tab.js +1472 -1212
  192. package/src/console/tabs/settings-tab.js +152 -79
  193. package/src/console/tabs/voices-tab.js +100 -21
  194. package/src/console/widgets/destroy-list.js +25 -25
  195. package/src/console/widgets/format-utils.js +89 -89
  196. package/src/console/widgets/notice.js +55 -55
  197. package/src/console/widgets/personality-picker.js +185 -185
  198. package/src/console/widgets/reverb-picker.js +94 -94
  199. package/src/console/widgets/track-picker.js +285 -285
  200. package/src/installer/music-file-input.js +304 -304
  201. package/src/installer.js +5882 -5829
  202. package/src/services/agent-voice-store.js +423 -423
  203. package/src/services/config-service.js +264 -264
  204. package/src/services/navigation-service.js +123 -123
  205. package/src/services/provider-service.js +132 -132
  206. package/src/services/verbosity-service.js +157 -157
  207. package/src/utils/audio-duration-validator.js +298 -298
  208. package/src/utils/audio-format-validator.js +277 -277
  209. package/src/utils/dependency-checker.js +469 -466
  210. package/src/utils/file-ownership-verifier.js +358 -358
  211. package/src/utils/list-formatter.js +194 -194
  212. package/src/utils/music-file-validator.js +285 -285
  213. package/src/utils/preview-list-prompt.js +136 -136
  214. package/src/utils/provider-validator.js +96 -12
  215. package/src/utils/secure-music-storage.js +412 -412
  216. package/templates/agentvibes-receiver.sh +482 -482
  217. package/templates/audio/welcome-music.mp3 +0 -0
  218. package/voice-assignments.json +8244 -8244
  219. package/.claude/config/background-music-position.txt +0 -1
@@ -1,466 +1,469 @@
1
- #!/usr/bin/env node
2
- /**
3
- * AgentVibes Dependency Checker
4
- *
5
- * Checks for required and optional system dependencies
6
- * Displays missing dependencies with platform-specific install commands
7
- */
8
-
9
- import { execFileSync } from 'child_process';
10
- import os from 'os';
11
- import chalk from 'chalk';
12
- import boxen from 'boxen';
13
-
14
- /**
15
- * Check if a command exists in the system
16
- */
17
- function commandExists(command) {
18
- try {
19
- // Try --version first (most common)
20
- execFileSync(command, ['--version'], { stdio: 'pipe' });
21
- return true;
22
- } catch {
23
- // Some commands like ffmpeg use -version (single dash)
24
- try {
25
- execFileSync(command, ['-version'], { stdio: 'pipe' });
26
- return true;
27
- } catch {
28
- return false;
29
- }
30
- }
31
- }
32
-
33
- /**
34
- * Check bash version (macOS specific requirement)
35
- */
36
- function checkBashVersion() {
37
- try {
38
- const version = execFileSync('bash', ['--version'], { encoding: 'utf8' }); // NOSONAR - Safe: checking bash version from system PATH
39
- const match = version.match(/version (\d+)\.(\d+)/);
40
- if (match) {
41
- const major = parseInt(match[1]);
42
- return { installed: true, version: `${major}.${match[2]}`, isModern: major >= 5 };
43
- }
44
- return { installed: true, version: 'unknown', isModern: false };
45
- } catch {
46
- return { installed: false, version: null, isModern: false };
47
- }
48
- }
49
-
50
- /**
51
- * Check Python version
52
- */
53
- function checkPythonVersion() {
54
- const commands = ['python3', 'python', 'py'];
55
-
56
- for (const cmd of commands) {
57
- try {
58
- const version = execFileSync(cmd, ['--version'], { encoding: 'utf8', stdio: 'pipe' });
59
- const match = version.match(/Python (\d+)\.(\d+)/);
60
- if (match) {
61
- const major = parseInt(match[1]);
62
- const minor = parseInt(match[2]);
63
- const versionStr = `${major}.${minor}`;
64
- const isCompatible = major === 3 && minor >= 10;
65
- return { installed: true, command: cmd, version: versionStr, isCompatible };
66
- }
67
- } catch {
68
- continue;
69
- }
70
- }
71
-
72
- return { installed: false, command: null, version: null, isCompatible: false };
73
- }
74
-
75
- /**
76
- * Check Node.js version
77
- */
78
- function checkNodeVersion() {
79
- try {
80
- const version = process.version;
81
- const match = version.match(/v(\d+)\.(\d+)/);
82
- if (match) {
83
- const major = parseInt(match[1]);
84
- const versionStr = `${major}.${match[2]}`;
85
- const isCompatible = major >= 16;
86
- return { installed: true, version: versionStr, isCompatible };
87
- }
88
- return { installed: true, version: 'unknown', isCompatible: false };
89
- } catch {
90
- return { installed: false, version: null, isCompatible: false };
91
- }
92
- }
93
-
94
- /**
95
- * Check for audio players (Linux/WSL)
96
- */
97
- function checkAudioPlayers() {
98
- const players = ['paplay', 'aplay', 'mpg123', 'mpv'];
99
- const found = [];
100
-
101
- for (const player of players) {
102
- if (commandExists(player)) {
103
- found.push(player);
104
- }
105
- }
106
-
107
- return { hasAny: found.length > 0, players: found };
108
- }
109
-
110
- /**
111
- * Get platform-specific install commands for missing dependencies
112
- */
113
- /**
114
- * Build homebrew package list for macOS
115
- * @param {Object} missing - Missing dependencies
116
- * @returns {string[]} Homebrew packages to install
117
- */
118
- function buildBrewPackages(missing) {
119
- const packages = [];
120
- const packageMap = {
121
- bash: 'bash',
122
- sox: 'sox',
123
- ffmpeg: 'ffmpeg',
124
- pipx: 'pipx',
125
- flock: 'util-linux',
126
- curl: 'curl',
127
- bc: 'bc'
128
- };
129
-
130
- for (const [key, pkg] of Object.entries(packageMap)) {
131
- if (missing[key]) {
132
- packages.push(pkg);
133
- }
134
- }
135
-
136
- return packages;
137
- }
138
-
139
- /**
140
- * Build Linux package lists for different package managers
141
- * @param {Object} missing - Missing dependencies
142
- * @returns {Object} Package lists for apt, dnf, and pacman
143
- */
144
- function buildLinuxPackages(missing) {
145
- const apt = [];
146
- const dnf = [];
147
- const pacman = [];
148
-
149
- const packageMap = {
150
- sox: { apt: 'sox libsox-fmt-mp3', dnf: 'sox', pacman: 'sox' },
151
- ffmpeg: { apt: 'ffmpeg', dnf: 'ffmpeg', pacman: 'ffmpeg' },
152
- python: { apt: 'python3-pip', dnf: 'python3-pip', pacman: 'python-pip' },
153
- pipx: { apt: 'pipx', dnf: 'pipx', pacman: 'python-pipx' },
154
- audioPlayer: { apt: 'pulseaudio-utils', dnf: 'pulseaudio-utils', pacman: 'libpulse' },
155
- flock: { apt: 'util-linux', dnf: 'util-linux', pacman: 'util-linux' },
156
- curl: { apt: 'curl', dnf: 'curl', pacman: 'curl' },
157
- bc: { apt: 'bc', dnf: 'bc', pacman: 'bc' }
158
- };
159
-
160
- for (const [key, packages] of Object.entries(packageMap)) {
161
- if (missing[key]) {
162
- apt.push(packages.apt);
163
- dnf.push(packages.dnf);
164
- pacman.push(packages.pacman);
165
- }
166
- }
167
-
168
- return { apt, dnf, pacman };
169
- }
170
-
171
- /**
172
- * Generate macOS installation commands
173
- * @param {Object} missing - Missing dependencies
174
- * @returns {Array} Installation command objects
175
- */
176
- function getMacOSCommands(missing) {
177
- const commands = [];
178
- const brewPackages = buildBrewPackages(missing);
179
-
180
- if (brewPackages.length > 0) {
181
- commands.push({
182
- label: 'macOS (Homebrew)',
183
- command: `brew install ${brewPackages.join(' ')}`
184
- });
185
- }
186
-
187
- if (missing.python) {
188
- commands.push({
189
- label: 'Python 3.10+',
190
- command: 'brew install python@3.11'
191
- });
192
- }
193
-
194
- return commands;
195
- }
196
-
197
- /**
198
- * Generate Linux installation commands
199
- * @param {Object} missing - Missing dependencies
200
- * @returns {Array} Installation command objects
201
- */
202
- function getLinuxCommands(missing) {
203
- const commands = [];
204
- const packages = buildLinuxPackages(missing);
205
-
206
- if (packages.apt.length > 0) {
207
- commands.push({
208
- label: 'Ubuntu/Debian',
209
- command: `sudo apt-get update && sudo apt-get install -y ${packages.apt.join(' ')}`
210
- });
211
- }
212
-
213
- if (packages.dnf.length > 0) {
214
- commands.push({
215
- label: 'Fedora/RHEL',
216
- command: `sudo dnf install -y ${packages.dnf.join(' ')}`
217
- });
218
- }
219
-
220
- if (packages.pacman.length > 0) {
221
- commands.push({
222
- label: 'Arch Linux',
223
- command: `sudo pacman -S ${packages.pacman.join(' ')}`
224
- });
225
- }
226
-
227
- return commands;
228
- }
229
-
230
- export function getInstallCommands(missing, platform) {
231
- if (platform === 'darwin') {
232
- return getMacOSCommands(missing);
233
- } else if (platform === 'linux' || platform === 'wsl') {
234
- return getLinuxCommands(missing);
235
- } else if (platform === 'win32') {
236
- return [{
237
- label: 'Windows (Native)',
238
- command: 'npx agentvibes install',
239
- note: 'Windows Piper and SAPI providers are supported natively'
240
- }];
241
- }
242
-
243
- return [];
244
- }
245
-
246
- /**
247
- * Main dependency check function
248
- */
249
- export function checkDependencies(options = {}) {
250
- const platform = os.platform();
251
- const isMac = platform === 'darwin';
252
- const isWindows = platform === 'win32';
253
- const isLinux = !isMac && !isWindows;
254
-
255
- const results = {
256
- core: {},
257
- optional: {},
258
- missing: {},
259
- warnings: []
260
- };
261
-
262
- // Core requirements
263
- const nodeCheck = checkNodeVersion();
264
- results.core.node = nodeCheck;
265
- if (!nodeCheck.isCompatible) {
266
- results.missing.node = true;
267
- results.warnings.push(`Node.js ${nodeCheck.version || 'not found'} - requires ≥16.0`);
268
- }
269
-
270
- const pythonCheck = checkPythonVersion();
271
- results.core.python = pythonCheck;
272
- if (!pythonCheck.isCompatible) {
273
- results.missing.python = true;
274
- results.warnings.push(`Python ${pythonCheck.version || 'not found'} - requires ≥3.10`);
275
- }
276
-
277
- // macOS-specific: bash 5.x requirement
278
- if (isMac) {
279
- const bashCheck = checkBashVersion();
280
- results.core.bash = bashCheck;
281
- if (!bashCheck.isModern) {
282
- results.missing.bash = true;
283
- results.warnings.push(`Bash ${bashCheck.version || 'not found'} - macOS requires ≥5.0`);
284
- }
285
- }
286
-
287
- // Optional tools (Unix-only — Windows uses native providers)
288
- if (!isWindows) {
289
- results.optional.sox = commandExists('sox');
290
- if (!results.optional.sox) {
291
- results.missing.sox = true;
292
- }
293
-
294
- results.optional.ffmpeg = commandExists('ffmpeg');
295
- if (!results.optional.ffmpeg) {
296
- results.missing.ffmpeg = true;
297
- }
298
-
299
- results.optional.pipx = commandExists('pipx');
300
- if (!results.optional.pipx) {
301
- results.missing.pipx = true;
302
- }
303
-
304
- // Check for flock (used for TTS queue file locking)
305
- results.optional.flock = commandExists('flock');
306
- if (!results.optional.flock) {
307
- results.missing.flock = true;
308
- results.warnings.push('flock command not found (required for TTS queue file locking)');
309
- }
310
-
311
- // Check for curl (used for downloading Piper TTS and voices)
312
- results.optional.curl = commandExists('curl');
313
- if (!results.optional.curl) {
314
- results.missing.curl = true;
315
- results.warnings.push('curl command not found (required for downloading Piper TTS)');
316
- }
317
-
318
- // Check for bc (used for audio processing calculations)
319
- results.optional.bc = commandExists('bc');
320
- if (!results.optional.bc) {
321
- results.missing.bc = true;
322
- results.warnings.push('bc command not found (used for audio processing calculations)');
323
- }
324
-
325
- // Audio player check (Linux/WSL only)
326
- if (isLinux || process.env.WSL_DISTRO_NAME) {
327
- const audioCheck = checkAudioPlayers();
328
- results.optional.audioPlayer = audioCheck.hasAny;
329
- if (!audioCheck.hasAny) {
330
- results.missing.audioPlayer = true;
331
- results.warnings.push('No audio player found (paplay, aplay, mpg123, or mpv)');
332
- }
333
- }
334
- }
335
-
336
- return results;
337
- }
338
-
339
- /**
340
- * Build list of missing core dependencies
341
- * @param {Object} missing - Missing dependencies object
342
- * @param {Object} results - Full check results
343
- * @returns {string[]} List of missing core dependencies
344
- */
345
- function buildCoreMissingList(missing, results) {
346
- const list = [];
347
- const coreMap = {
348
- node: { label: 'Node.js ≥16.0', key: 'node' },
349
- python: { label: 'Python ≥3.10', key: 'python' },
350
- bash: { label: 'Bash ≥5.0', key: 'bash' }
351
- };
352
-
353
- for (const [dep, { label, key }] of Object.entries(coreMap)) {
354
- if (missing[dep]) {
355
- const version = results.core[key]?.version;
356
- list.push(`• ${label} ${version ? `(found: ${version})` : ''}`);
357
- }
358
- }
359
-
360
- return list;
361
- }
362
-
363
- /**
364
- * Build list of missing optional dependencies
365
- * @param {Object} missing - Missing dependencies object
366
- * @returns {string[]} List of missing optional dependencies
367
- */
368
- function buildOptionalMissingList(missing) {
369
- const optionalMap = {
370
- curl: '• curl (downloading Piper TTS and voices)',
371
- sox: '• sox (background music mixing, audio effects)',
372
- ffmpeg: '• ffmpeg (audio processing, RDP optimization)',
373
- bc: '• bc (audio processing calculations)',
374
- pipx: '• pipx (Piper TTS installation)',
375
- flock: '• flock (TTS queue file locking)',
376
- audioPlayer: '• paplay/aplay (audio playback)'
377
- };
378
-
379
- const list = [];
380
- for (const [dep, description] of Object.entries(optionalMap)) {
381
- if (missing[dep]) {
382
- list.push(description);
383
- }
384
- }
385
-
386
- return list;
387
- }
388
-
389
- /**
390
- * Format install commands section
391
- * @param {Array} commands - Install commands
392
- * @returns {string} Formatted commands section
393
- */
394
- function formatInstallCommands(commands) {
395
- if (commands.length === 0) {
396
- return '';
397
- }
398
-
399
- let section = chalk.cyan.bold('Installation Commands:\n\n');
400
- commands.forEach(({ label, command, note }) => {
401
- section += chalk.cyan(`${label}:\n`);
402
- section += chalk.white(` ${command}\n`);
403
- if (note) {
404
- section += chalk.gray(` ${note}\n`);
405
- }
406
- section += '\n';
407
- });
408
-
409
- return section;
410
- }
411
-
412
- /**
413
- * Display missing dependencies in a formatted box
414
- */
415
- export function displayMissingDependencies(results) {
416
- const platform = os.platform();
417
- const missing = results.missing;
418
- const hasMissing = Object.keys(missing).length > 0;
419
-
420
- if (!hasMissing) {
421
- return false; // No missing dependencies
422
- }
423
-
424
- let content = chalk.bold.yellow('⚠️ Missing Dependencies Detected\n\n');
425
-
426
- // Core requirements
427
- const coreMissing = buildCoreMissingList(missing, results);
428
- if (coreMissing.length > 0) {
429
- content += chalk.red('Required:\n');
430
- content += coreMissing.map(item => chalk.red(item)).join('\n') + '\n\n';
431
- }
432
-
433
- // Optional tools
434
- const optionalMissing = buildOptionalMissingList(missing);
435
- if (optionalMissing.length > 0) {
436
- content += chalk.yellow('Optional (recommended):\n');
437
- content += optionalMissing.map(item => chalk.yellow(item)).join('\n') + '\n\n';
438
- }
439
-
440
- // Install commands
441
- const commands = getInstallCommands(missing, platform);
442
- content += formatInstallCommands(commands);
443
-
444
- // Impact notice
445
- if (optionalMissing.length > 0 && coreMissing.length === 0) {
446
- content += chalk.gray('Note: TTS will still work without optional tools,\n');
447
- content += chalk.gray('but some features will be disabled.\n');
448
- }
449
-
450
- console.log(boxen(content, {
451
- padding: 1,
452
- margin: 1,
453
- borderStyle: 'round',
454
- borderColor: coreMissing.length > 0 ? 'red' : 'yellow'
455
- }));
456
-
457
- return hasMissing;
458
- }
459
-
460
- /**
461
- * Check and display dependencies (convenience function)
462
- */
463
- export function checkAndDisplay() {
464
- const results = checkDependencies();
465
- return displayMissingDependencies(results);
466
- }
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentVibes Dependency Checker
4
+ *
5
+ * Checks for required and optional system dependencies
6
+ * Displays missing dependencies with platform-specific install commands
7
+ */
8
+
9
+ import { execFileSync } from 'child_process';
10
+ import os from 'os';
11
+ import chalk from 'chalk';
12
+ import boxen from 'boxen';
13
+
14
+ /**
15
+ * Check if a command exists in the system
16
+ */
17
+ function commandExists(command) {
18
+ try {
19
+ // Try --version first (most common)
20
+ execFileSync(command, ['--version'], { stdio: 'pipe' });
21
+ return true;
22
+ } catch {
23
+ // Some commands like ffmpeg use -version (single dash)
24
+ try {
25
+ execFileSync(command, ['-version'], { stdio: 'pipe' });
26
+ return true;
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Check bash version (macOS specific requirement)
35
+ */
36
+ function checkBashVersion() {
37
+ try {
38
+ const version = execFileSync('bash', ['--version'], { encoding: 'utf8' }); // NOSONAR - Safe: checking bash version from system PATH
39
+ const match = version.match(/version (\d+)\.(\d+)/);
40
+ if (match) {
41
+ const major = parseInt(match[1]);
42
+ return { installed: true, version: `${major}.${match[2]}`, isModern: major >= 5 };
43
+ }
44
+ return { installed: true, version: 'unknown', isModern: false };
45
+ } catch {
46
+ return { installed: false, version: null, isModern: false };
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Check Python version
52
+ */
53
+ function checkPythonVersion() {
54
+ const commands = ['python3', 'python', 'py'];
55
+
56
+ for (const cmd of commands) {
57
+ try {
58
+ const version = execFileSync(cmd, ['--version'], { encoding: 'utf8', stdio: 'pipe' });
59
+ const match = version.match(/Python (\d+)\.(\d+)/);
60
+ if (match) {
61
+ const major = parseInt(match[1]);
62
+ const minor = parseInt(match[2]);
63
+ const versionStr = `${major}.${minor}`;
64
+ const isCompatible = major === 3 && minor >= 10;
65
+ return { installed: true, command: cmd, version: versionStr, isCompatible };
66
+ }
67
+ } catch {
68
+ continue;
69
+ }
70
+ }
71
+
72
+ return { installed: false, command: null, version: null, isCompatible: false };
73
+ }
74
+
75
+ /**
76
+ * Check Node.js version
77
+ */
78
+ function checkNodeVersion() {
79
+ try {
80
+ const version = process.version;
81
+ const match = version.match(/v(\d+)\.(\d+)/);
82
+ if (match) {
83
+ const major = parseInt(match[1]);
84
+ const versionStr = `${major}.${match[2]}`;
85
+ const isCompatible = major >= 16;
86
+ return { installed: true, version: versionStr, isCompatible };
87
+ }
88
+ return { installed: true, version: 'unknown', isCompatible: false };
89
+ } catch {
90
+ return { installed: false, version: null, isCompatible: false };
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Check for audio players (Linux/WSL)
96
+ */
97
+ function checkAudioPlayers() {
98
+ const players = ['paplay', 'aplay', 'mpg123', 'mpv'];
99
+ const found = [];
100
+
101
+ for (const player of players) {
102
+ if (commandExists(player)) {
103
+ found.push(player);
104
+ }
105
+ }
106
+
107
+ return { hasAny: found.length > 0, players: found };
108
+ }
109
+
110
+ /**
111
+ * Get platform-specific install commands for missing dependencies
112
+ */
113
+ /**
114
+ * Build homebrew package list for macOS
115
+ * @param {Object} missing - Missing dependencies
116
+ * @returns {string[]} Homebrew packages to install
117
+ */
118
+ function buildBrewPackages(missing) {
119
+ const packages = [];
120
+ const packageMap = {
121
+ bash: 'bash',
122
+ sox: 'sox',
123
+ ffmpeg: 'ffmpeg',
124
+ pipx: 'pipx',
125
+ flock: 'util-linux',
126
+ curl: 'curl',
127
+ bc: 'bc'
128
+ };
129
+
130
+ for (const [key, pkg] of Object.entries(packageMap)) {
131
+ if (missing[key]) {
132
+ packages.push(pkg);
133
+ }
134
+ }
135
+
136
+ return packages;
137
+ }
138
+
139
+ /**
140
+ * Build Linux package lists for different package managers
141
+ * @param {Object} missing - Missing dependencies
142
+ * @returns {Object} Package lists for apt, dnf, and pacman
143
+ */
144
+ function buildLinuxPackages(missing) {
145
+ const apt = [];
146
+ const dnf = [];
147
+ const pacman = [];
148
+
149
+ const packageMap = {
150
+ sox: { apt: 'sox libsox-fmt-mp3', dnf: 'sox', pacman: 'sox' },
151
+ ffmpeg: { apt: 'ffmpeg', dnf: 'ffmpeg', pacman: 'ffmpeg' },
152
+ python: { apt: 'python3-pip', dnf: 'python3-pip', pacman: 'python-pip' },
153
+ pipx: { apt: 'pipx', dnf: 'pipx', pacman: 'python-pipx' },
154
+ audioPlayer: { apt: 'pulseaudio-utils', dnf: 'pulseaudio-utils', pacman: 'libpulse' },
155
+ flock: { apt: 'util-linux', dnf: 'util-linux', pacman: 'util-linux' },
156
+ curl: { apt: 'curl', dnf: 'curl', pacman: 'curl' },
157
+ bc: { apt: 'bc', dnf: 'bc', pacman: 'bc' }
158
+ };
159
+
160
+ for (const [key, packages] of Object.entries(packageMap)) {
161
+ if (missing[key]) {
162
+ apt.push(packages.apt);
163
+ dnf.push(packages.dnf);
164
+ pacman.push(packages.pacman);
165
+ }
166
+ }
167
+
168
+ return { apt, dnf, pacman };
169
+ }
170
+
171
+ /**
172
+ * Generate macOS installation commands
173
+ * @param {Object} missing - Missing dependencies
174
+ * @returns {Array} Installation command objects
175
+ */
176
+ function getMacOSCommands(missing) {
177
+ const commands = [];
178
+ const brewPackages = buildBrewPackages(missing);
179
+
180
+ if (brewPackages.length > 0) {
181
+ commands.push({
182
+ label: 'macOS (Homebrew)',
183
+ command: `brew install ${brewPackages.join(' ')}`
184
+ });
185
+ }
186
+
187
+ if (missing.python) {
188
+ commands.push({
189
+ label: 'Python 3.10+',
190
+ command: 'brew install python@3.11'
191
+ });
192
+ }
193
+
194
+ return commands;
195
+ }
196
+
197
+ /**
198
+ * Generate Linux installation commands
199
+ * @param {Object} missing - Missing dependencies
200
+ * @returns {Array} Installation command objects
201
+ */
202
+ function getLinuxCommands(missing) {
203
+ const commands = [];
204
+ const packages = buildLinuxPackages(missing);
205
+
206
+ if (packages.apt.length > 0) {
207
+ commands.push({
208
+ label: 'Ubuntu/Debian',
209
+ command: `sudo apt-get update && sudo apt-get install -y ${packages.apt.join(' ')}`
210
+ });
211
+ }
212
+
213
+ if (packages.dnf.length > 0) {
214
+ commands.push({
215
+ label: 'Fedora/RHEL',
216
+ command: `sudo dnf install -y ${packages.dnf.join(' ')}`
217
+ });
218
+ }
219
+
220
+ if (packages.pacman.length > 0) {
221
+ commands.push({
222
+ label: 'Arch Linux',
223
+ command: `sudo pacman -S ${packages.pacman.join(' ')}`
224
+ });
225
+ }
226
+
227
+ return commands;
228
+ }
229
+
230
+ export function getInstallCommands(missing, platform) {
231
+ if (platform === 'darwin') {
232
+ return getMacOSCommands(missing);
233
+ } else if (platform === 'linux' || platform === 'wsl') {
234
+ return getLinuxCommands(missing);
235
+ } else if (platform === 'win32') {
236
+ return [{
237
+ label: 'Windows (Native)',
238
+ command: 'npx agentvibes install',
239
+ note: 'Windows Piper and SAPI providers are supported natively'
240
+ }];
241
+ }
242
+
243
+ return [];
244
+ }
245
+
246
+ /**
247
+ * Main dependency check function
248
+ */
249
+ export function checkDependencies(options = {}) {
250
+ const platform = os.platform();
251
+ const isMac = platform === 'darwin';
252
+ const isWindows = platform === 'win32';
253
+ const isLinux = !isMac && !isWindows;
254
+
255
+ const results = {
256
+ core: {},
257
+ optional: {},
258
+ missing: {},
259
+ warnings: []
260
+ };
261
+
262
+ // Core requirements
263
+ const nodeCheck = checkNodeVersion();
264
+ results.core.node = nodeCheck;
265
+ if (!nodeCheck.isCompatible) {
266
+ results.missing.node = true;
267
+ results.warnings.push(`Node.js ${nodeCheck.version || 'not found'} - requires ≥16.0`);
268
+ }
269
+
270
+ const pythonCheck = checkPythonVersion();
271
+ results.core.python = pythonCheck;
272
+ if (!pythonCheck.isCompatible) {
273
+ results.missing.python = true;
274
+ results.warnings.push(`Python ${pythonCheck.version || 'not found'} - requires ≥3.10`);
275
+ }
276
+
277
+ // macOS-specific: bash 5.x requirement
278
+ if (isMac) {
279
+ const bashCheck = checkBashVersion();
280
+ results.core.bash = bashCheck;
281
+ if (!bashCheck.isModern) {
282
+ results.missing.bash = true;
283
+ results.warnings.push(`Bash ${bashCheck.version || 'not found'} - macOS requires ≥5.0`);
284
+ }
285
+ }
286
+
287
+ // Optional tools
288
+ if (!isWindows) {
289
+ results.optional.sox = commandExists('sox');
290
+ if (!results.optional.sox) {
291
+ results.missing.sox = true;
292
+ }
293
+ }
294
+
295
+ // ffmpeg is needed on ALL platforms for background music mixing
296
+ {
297
+ results.optional.ffmpeg = commandExists('ffmpeg');
298
+ if (!results.optional.ffmpeg) {
299
+ results.missing.ffmpeg = true;
300
+ }
301
+
302
+ results.optional.pipx = commandExists('pipx');
303
+ if (!results.optional.pipx) {
304
+ results.missing.pipx = true;
305
+ }
306
+
307
+ // Check for flock (used for TTS queue file locking)
308
+ results.optional.flock = commandExists('flock');
309
+ if (!results.optional.flock) {
310
+ results.missing.flock = true;
311
+ results.warnings.push('flock command not found (required for TTS queue file locking)');
312
+ }
313
+
314
+ // Check for curl (used for downloading Piper TTS and voices)
315
+ results.optional.curl = commandExists('curl');
316
+ if (!results.optional.curl) {
317
+ results.missing.curl = true;
318
+ results.warnings.push('curl command not found (required for downloading Piper TTS)');
319
+ }
320
+
321
+ // Check for bc (used for audio processing calculations)
322
+ results.optional.bc = commandExists('bc');
323
+ if (!results.optional.bc) {
324
+ results.missing.bc = true;
325
+ results.warnings.push('bc command not found (used for audio processing calculations)');
326
+ }
327
+
328
+ // Audio player check (Linux/WSL only)
329
+ if (isLinux || process.env.WSL_DISTRO_NAME) {
330
+ const audioCheck = checkAudioPlayers();
331
+ results.optional.audioPlayer = audioCheck.hasAny;
332
+ if (!audioCheck.hasAny) {
333
+ results.missing.audioPlayer = true;
334
+ results.warnings.push('No audio player found (paplay, aplay, mpg123, or mpv)');
335
+ }
336
+ }
337
+ }
338
+
339
+ return results;
340
+ }
341
+
342
+ /**
343
+ * Build list of missing core dependencies
344
+ * @param {Object} missing - Missing dependencies object
345
+ * @param {Object} results - Full check results
346
+ * @returns {string[]} List of missing core dependencies
347
+ */
348
+ function buildCoreMissingList(missing, results) {
349
+ const list = [];
350
+ const coreMap = {
351
+ node: { label: 'Node.js ≥16.0', key: 'node' },
352
+ python: { label: 'Python ≥3.10', key: 'python' },
353
+ bash: { label: 'Bash ≥5.0', key: 'bash' }
354
+ };
355
+
356
+ for (const [dep, { label, key }] of Object.entries(coreMap)) {
357
+ if (missing[dep]) {
358
+ const version = results.core[key]?.version;
359
+ list.push(`• ${label} ${version ? `(found: ${version})` : ''}`);
360
+ }
361
+ }
362
+
363
+ return list;
364
+ }
365
+
366
+ /**
367
+ * Build list of missing optional dependencies
368
+ * @param {Object} missing - Missing dependencies object
369
+ * @returns {string[]} List of missing optional dependencies
370
+ */
371
+ function buildOptionalMissingList(missing) {
372
+ const optionalMap = {
373
+ curl: '• curl (downloading Piper TTS and voices)',
374
+ sox: '• sox (background music mixing, audio effects)',
375
+ ffmpeg: '• ffmpeg (audio processing, RDP optimization)',
376
+ bc: '• bc (audio processing calculations)',
377
+ pipx: '• pipx (Piper TTS installation)',
378
+ flock: '• flock (TTS queue file locking)',
379
+ audioPlayer: '• paplay/aplay (audio playback)'
380
+ };
381
+
382
+ const list = [];
383
+ for (const [dep, description] of Object.entries(optionalMap)) {
384
+ if (missing[dep]) {
385
+ list.push(description);
386
+ }
387
+ }
388
+
389
+ return list;
390
+ }
391
+
392
+ /**
393
+ * Format install commands section
394
+ * @param {Array} commands - Install commands
395
+ * @returns {string} Formatted commands section
396
+ */
397
+ function formatInstallCommands(commands) {
398
+ if (commands.length === 0) {
399
+ return '';
400
+ }
401
+
402
+ let section = chalk.cyan.bold('Installation Commands:\n\n');
403
+ commands.forEach(({ label, command, note }) => {
404
+ section += chalk.cyan(`${label}:\n`);
405
+ section += chalk.white(` ${command}\n`);
406
+ if (note) {
407
+ section += chalk.gray(` ${note}\n`);
408
+ }
409
+ section += '\n';
410
+ });
411
+
412
+ return section;
413
+ }
414
+
415
+ /**
416
+ * Display missing dependencies in a formatted box
417
+ */
418
+ export function displayMissingDependencies(results) {
419
+ const platform = os.platform();
420
+ const missing = results.missing;
421
+ const hasMissing = Object.keys(missing).length > 0;
422
+
423
+ if (!hasMissing) {
424
+ return false; // No missing dependencies
425
+ }
426
+
427
+ let content = chalk.bold.yellow('⚠️ Missing Dependencies Detected\n\n');
428
+
429
+ // Core requirements
430
+ const coreMissing = buildCoreMissingList(missing, results);
431
+ if (coreMissing.length > 0) {
432
+ content += chalk.red('Required:\n');
433
+ content += coreMissing.map(item => chalk.red(item)).join('\n') + '\n\n';
434
+ }
435
+
436
+ // Optional tools
437
+ const optionalMissing = buildOptionalMissingList(missing);
438
+ if (optionalMissing.length > 0) {
439
+ content += chalk.yellow('Optional (recommended):\n');
440
+ content += optionalMissing.map(item => chalk.yellow(item)).join('\n') + '\n\n';
441
+ }
442
+
443
+ // Install commands
444
+ const commands = getInstallCommands(missing, platform);
445
+ content += formatInstallCommands(commands);
446
+
447
+ // Impact notice
448
+ if (optionalMissing.length > 0 && coreMissing.length === 0) {
449
+ content += chalk.gray('Note: TTS will still work without optional tools,\n');
450
+ content += chalk.gray('but some features will be disabled.\n');
451
+ }
452
+
453
+ console.log(boxen(content, {
454
+ padding: 1,
455
+ margin: 1,
456
+ borderStyle: 'round',
457
+ borderColor: coreMissing.length > 0 ? 'red' : 'yellow'
458
+ }));
459
+
460
+ return hasMissing;
461
+ }
462
+
463
+ /**
464
+ * Check and display dependencies (convenience function)
465
+ */
466
+ export function checkAndDisplay() {
467
+ const results = checkDependencies();
468
+ return displayMissingDependencies(results);
469
+ }