agentvibes 5.10.1 → 5.11.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 (160) hide show
  1. package/.agentvibes/config.json +15 -1
  2. package/.agentvibes/install-manifest.json +342 -0
  3. package/.claude/audio/ui/CREDITS.txt +16 -0
  4. package/.claude/audio/ui/bling-success.wav +0 -0
  5. package/.claude/commands/agent-vibes/receiver.md +64 -0
  6. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  7. package/.claude/commands/agent-vibes-rdp.md +24 -24
  8. package/.claude/config/audio-effects.cfg +5 -4
  9. package/.claude/config/audio-effects.cfg.sample +52 -52
  10. package/.claude/config/background-music-enabled.txt +1 -1
  11. package/.claude/config/background-music-position.txt +27 -0
  12. package/.claude/config/background-music-volume.txt +1 -0
  13. package/.claude/config/background-music.cfg +1 -0
  14. package/.claude/config/background-music.txt +1 -0
  15. package/.claude/config/language.txt +1 -0
  16. package/.claude/config/personality.txt +1 -0
  17. package/.claude/config/reverb-level.txt +1 -0
  18. package/.claude/config/tts-speech-rate.txt +1 -0
  19. package/.claude/config/tts-verbosity.txt +1 -0
  20. package/.claude/docs/TERMUX_SETUP.md +408 -408
  21. package/.claude/github-star-reminder.txt +1 -1
  22. package/.claude/hooks/audio-cache-utils.sh +0 -0
  23. package/.claude/hooks/audio-processor.sh +57 -18
  24. package/.claude/hooks/background-music-manager.sh +0 -0
  25. package/.claude/hooks/bmad-party-speak.sh +0 -0
  26. package/.claude/hooks/bmad-speak-enhanced.sh +0 -0
  27. package/.claude/hooks/bmad-speak.sh +0 -0
  28. package/.claude/hooks/bmad-tts-injector.sh +0 -0
  29. package/.claude/hooks/bmad-voice-manager.sh +0 -0
  30. package/.claude/hooks/clawdbot-receiver-SECURE.sh +0 -0
  31. package/.claude/hooks/clawdbot-receiver.sh +0 -0
  32. package/.claude/hooks/clean-audio-cache.sh +0 -0
  33. package/.claude/hooks/cleanup-cache.sh +0 -0
  34. package/.claude/hooks/configure-rdp-mode.sh +0 -0
  35. package/.claude/hooks/download-extra-voices.sh +0 -0
  36. package/.claude/hooks/effects-manager.sh +0 -0
  37. package/.claude/hooks/github-star-reminder.sh +0 -0
  38. package/.claude/hooks/kokoro-installer.sh +117 -0
  39. package/.claude/hooks/kokoro-server.py +219 -0
  40. package/.claude/hooks/kokoro-tts.py +141 -0
  41. package/.claude/hooks/language-manager.sh +0 -0
  42. package/.claude/hooks/learn-manager.sh +0 -0
  43. package/.claude/hooks/macos-voice-manager.sh +0 -0
  44. package/.claude/hooks/migrate-background-music.sh +0 -0
  45. package/.claude/hooks/migrate-to-agentvibes.sh +0 -0
  46. package/.claude/hooks/optimize-background-music.sh +0 -0
  47. package/.claude/hooks/path-resolver.sh +0 -0
  48. package/.claude/hooks/personality-manager.sh +0 -0
  49. package/.claude/hooks/piper-download-voices.sh +39 -16
  50. package/.claude/hooks/piper-installer.sh +11 -6
  51. package/.claude/hooks/piper-multispeaker-registry.sh +0 -0
  52. package/.claude/hooks/piper-voice-manager.sh +6 -6
  53. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +3 -1
  54. package/.claude/hooks/play-tts-agentvibes-receiver.sh +1 -0
  55. package/.claude/hooks/play-tts-elevenlabs.sh +360 -0
  56. package/.claude/hooks/play-tts-enhanced.sh +0 -0
  57. package/.claude/hooks/play-tts-kokoro.sh +127 -0
  58. package/.claude/hooks/play-tts-macos.sh +0 -0
  59. package/.claude/hooks/play-tts-piper.sh +0 -0
  60. package/.claude/hooks/play-tts-soprano.sh +0 -0
  61. package/.claude/hooks/play-tts-ssh-remote.sh +9 -2
  62. package/.claude/hooks/play-tts-termux-ssh.sh +3 -1
  63. package/.claude/hooks/play-tts-windows-receiver.sh +0 -0
  64. package/.claude/hooks/play-tts.sh +78 -2
  65. package/.claude/hooks/prepare-release.sh +0 -0
  66. package/.claude/hooks/provider-commands.sh +71 -22
  67. package/.claude/hooks/provider-manager.sh +15 -7
  68. package/.claude/hooks/replay-target-audio.sh +0 -0
  69. package/.claude/hooks/requirements.txt +6 -6
  70. package/.claude/hooks/sentiment-manager.sh +0 -0
  71. package/.claude/hooks/session-start-tts.sh +0 -0
  72. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  73. package/.claude/hooks/speed-manager.sh +0 -0
  74. package/.claude/hooks/stop-tts.sh +0 -0
  75. package/.claude/hooks/termux-installer.sh +0 -0
  76. package/.claude/hooks/translate-manager.sh +0 -0
  77. package/.claude/hooks/translator.py +237 -237
  78. package/.claude/hooks/tts-queue-worker.sh +0 -0
  79. package/.claude/hooks/tts-queue.sh +0 -0
  80. package/.claude/hooks/verbosity-manager.sh +0 -0
  81. package/.claude/hooks/voice-manager.sh +0 -0
  82. package/.claude/hooks-windows/audio-cache-utils.ps1.user.bak +119 -0
  83. package/.claude/hooks-windows/kokoro-server.py +219 -0
  84. package/.claude/hooks-windows/kokoro-tts.py +107 -0
  85. package/.claude/hooks-windows/play-tts-kokoro.ps1 +191 -0
  86. package/.claude/hooks-windows/play-tts.ps1 +29 -1
  87. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  88. package/.claude/hooks-windows/soprano-gradio-synth.py.user.bak +153 -0
  89. package/.claude/piper-voices-dir.txt +1 -0
  90. package/.claude/verbosity.txt +1 -1
  91. package/.clawdbot/README.md +105 -105
  92. package/.mcp.json +6 -19
  93. package/README.md +12 -86
  94. package/RELEASE_NOTES.md +60 -0
  95. package/WINDOWS-SETUP.md +208 -208
  96. package/bin/agent-vibes +39 -39
  97. package/bin/agentvibes-voice-browser.js +0 -0
  98. package/bin/agentvibes.js +0 -0
  99. package/bin/mcp-server.js +121 -121
  100. package/bin/mcp-server.sh +0 -0
  101. package/bin/test-bmad-pr +78 -78
  102. package/mcp-server/QUICK_START.md +203 -203
  103. package/mcp-server/README.md +345 -345
  104. package/mcp-server/WINDOWS_SETUP.md +0 -0
  105. package/mcp-server/examples/claude_desktop_config.json +11 -11
  106. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  107. package/mcp-server/examples/custom_instructions.md +169 -169
  108. package/mcp-server/install-deps.js +0 -0
  109. package/mcp-server/server.py +1807 -1807
  110. package/mcp-server/test_server.py +0 -0
  111. package/package.json +4 -3
  112. package/src/cli/list-personalities.js +110 -110
  113. package/src/cli/list-voices.js +114 -114
  114. package/src/commands/bmad-voices.js +394 -394
  115. package/src/commands/install-mcp.js +3 -3
  116. package/src/console/app.js +25 -9
  117. package/src/console/audio-env.js +85 -1
  118. package/src/console/brand-colors.js +13 -13
  119. package/src/console/constants/personalities.js +44 -44
  120. package/src/console/navigation.js +4 -0
  121. package/src/console/tabs/agents-tab.js +12 -6
  122. package/src/console/tabs/help-tab.js +314 -314
  123. package/src/console/tabs/music-tab.js +7 -25
  124. package/src/console/tabs/readme-tab.js +272 -272
  125. package/src/console/tabs/setup-tab.js +1704 -120
  126. package/src/console/tabs/voices-tab.js +72 -88
  127. package/src/console/widgets/destroy-list.js +25 -25
  128. package/src/console/widgets/format-utils.js +14 -2
  129. package/src/console/widgets/help-bar.js +55 -0
  130. package/src/console/widgets/notice.js +55 -55
  131. package/src/console/widgets/reverb-picker.js +429 -41
  132. package/src/console/widgets/track-picker.js +60 -51
  133. package/src/i18n/de.js +2 -1
  134. package/src/i18n/en.js +1 -0
  135. package/src/i18n/es.js +2 -1
  136. package/src/i18n/fr.js +2 -1
  137. package/src/i18n/hi.js +2 -1
  138. package/src/i18n/ja.js +2 -1
  139. package/src/i18n/ko.js +2 -1
  140. package/src/i18n/pt.js +2 -1
  141. package/src/i18n/strings.js +9 -9
  142. package/src/i18n/zh-CN.js +2 -1
  143. package/src/installer/language-screen.js +31 -31
  144. package/src/installer/music-file-input.js +304 -304
  145. package/src/installer.js +95 -7
  146. package/src/services/config-service.js +264 -264
  147. package/src/services/language-service.js +47 -47
  148. package/src/services/provider-service.js +35 -0
  149. package/src/services/provider-voice-catalog.js +126 -0
  150. package/src/services/tts-engine-service.js +51 -2
  151. package/src/utils/audio-duration-validator.js +53 -10
  152. package/src/utils/audio-format-validator.js +277 -277
  153. package/src/utils/dependency-checker.js +469 -469
  154. package/src/utils/file-ownership-verifier.js +358 -358
  155. package/src/utils/music-file-validator.js +285 -285
  156. package/src/utils/preview-list-prompt.js +144 -136
  157. package/src/utils/provider-validator.js +70 -0
  158. package/src/utils/secure-music-storage.js +412 -412
  159. package/templates/agentvibes-receiver.sh +235 -231
  160. package/templates/audio/welcome-music.mp3 +0 -0
@@ -8,11 +8,11 @@
8
8
 
9
9
  import fs from 'node:fs';
10
10
  import path from 'node:path';
11
- import { spawn } from 'node:child_process';
12
11
  import { destroyList } from './destroy-list.js';
13
12
  import { BRAND_PINK } from '../brand-colors.js';
13
+ import { renderHelpBar, selectorTitle } from './help-bar.js';
14
14
  import { formatTrackName } from './format-utils.js';
15
- import { buildAudioEnv, detectMp3Player } from '../audio-env.js';
15
+ import { buildAudioEnv, spawnMp3Player } from '../audio-env.js';
16
16
 
17
17
  const IS_TEST = process.env.AGENTVIBES_TEST_MODE === 'true';
18
18
  let blessed;
@@ -22,7 +22,6 @@ if (!IS_TEST) {
22
22
  }
23
23
 
24
24
  const _modalTitle = (text) => ` {${BRAND_PINK}-fg}${text}{/${BRAND_PINK}-fg} `;
25
- const _hintLabel = '{#455a64-fg}[Space] Preview [Enter] Select [Esc] Cancel{/#455a64-fg}';
26
25
 
27
26
  /**
28
27
  * Open a small volume input modal (0–100).
@@ -172,16 +171,46 @@ export function openTrackPicker(screen, currentTrack, currentVolume, onSelect, o
172
171
  );
173
172
  const currentIdx = tracks.findIndex(t => t.file === currentTrack);
174
173
 
175
- const listHeight = Math.min(tracks.length + 6, Math.floor(screen.rows * 0.7));
176
- const list = blessed.list({
174
+ // Standardized chrome: bordered box titled "Music Track Selector", a pinned
175
+ // (non-scrolling) help bar at the top, and the track list filling the rest.
176
+ const TITLE = selectorTitle('Music Track');
177
+ const HELP = renderHelpBar([
178
+ { key: 'Space', label: 'preview' },
179
+ { key: 'Enter', label: 'select' },
180
+ { key: 'Esc', label: 'cancel' },
181
+ ]);
182
+
183
+ const boxHeight = Math.min(tracks.length + 5, Math.floor(screen.rows * 0.7));
184
+ const box = blessed.box({
177
185
  parent: screen,
178
186
  top: 'center',
179
187
  left: 'center',
180
188
  width: 54,
181
- height: listHeight,
189
+ height: boxHeight,
182
190
  border: { type: 'line' },
183
191
  tags: true,
184
- label: _modalTitle('Select Track'),
192
+ label: TITLE,
193
+ style: { border: { fg: COLORS.btnFocus } },
194
+ });
195
+ box.setFront();
196
+
197
+ blessed.text({
198
+ parent: box,
199
+ top: 0,
200
+ left: 1,
201
+ right: 1,
202
+ height: 1,
203
+ tags: true,
204
+ content: HELP,
205
+ });
206
+
207
+ const list = blessed.list({
208
+ parent: box,
209
+ top: 1,
210
+ left: 0,
211
+ right: 0,
212
+ bottom: 0,
213
+ tags: true,
185
214
  items,
186
215
  keys: true,
187
216
  vi: false,
@@ -189,50 +218,29 @@ export function openTrackPicker(screen, currentTrack, currentVolume, onSelect, o
189
218
  scrollable: true,
190
219
  scrollbar: { ch: '│', track: { bg: '#1e2a3a' }, style: { fg: COLORS.btnFocus } },
191
220
  style: {
192
- border: { fg: COLORS.btnFocus },
193
221
  selected: { bg: COLORS.btnFocus, fg: COLORS.btnFocusFg, bold: true },
194
222
  item: { fg: '#e3f2fd' },
195
223
  },
196
224
  });
197
225
 
198
- // Helper: update hint text in the bottom border label
199
- function _setHint(text) {
200
- list.setLabel({ text: _modalTitle('Select Track'), side: 'left' });
201
- // Use _ prefix convention for bottom border content (blessed doesn't have setFooter)
202
- list._label2 && list._label2.destroy();
203
- list._label2 = blessed.text({
204
- parent: list,
205
- bottom: -1,
206
- left: 1,
207
- width: 50,
208
- height: 1,
209
- tags: true,
210
- content: text,
211
- style: { fg: '#e3f2fd' },
212
- });
226
+ // Transient preview/error status shows in the title area; idle restores the title.
227
+ function _setStatus(text) {
228
+ box.setLabel(text || TITLE);
213
229
  screen.render();
214
230
  }
215
231
 
216
- _setHint(_hintLabel);
217
-
218
232
  if (currentIdx >= 0) list.select(currentIdx);
219
233
  list.focus();
220
234
  screen.render();
221
235
 
222
236
  // Preview playback state
223
237
  const _spawnEnv = buildAudioEnv();
224
- const _mp3Player = detectMp3Player(_spawnEnv);
225
238
  let _previewProc = null;
226
239
  let _previewTrackId = null;
227
240
 
228
241
  function _killPreview() {
229
242
  if (_previewProc) {
230
- const _isWin = process.platform === 'win32' && !process.env.WSL_DISTRO_NAME;
231
- if (_isWin) {
232
- try { _previewProc.kill(); } catch {}
233
- } else {
234
- try { process.kill(-_previewProc.pid, 'SIGTERM'); } catch {}
235
- }
243
+ _previewProc.kill();
236
244
  _previewProc = null;
237
245
  }
238
246
  _previewTrackId = null;
@@ -242,7 +250,7 @@ export function openTrackPicker(screen, currentTrack, currentVolume, onSelect, o
242
250
  // Toggle off if same track
243
251
  if (_previewTrackId === trackFile) {
244
252
  _killPreview();
245
- _setHint(_hintLabel);
253
+ _setStatus();
246
254
  return;
247
255
  }
248
256
 
@@ -252,31 +260,34 @@ export function openTrackPicker(screen, currentTrack, currentVolume, onSelect, o
252
260
  const safeBase = path.resolve(tracksDir);
253
261
  if (!trackPath.startsWith(safeBase + path.sep) && trackPath !== safeBase) return;
254
262
 
255
- if (!_mp3Player || !fs.existsSync(trackPath)) {
256
- _setHint('{red-fg}No MP3 player found or track missing{/red-fg}');
257
- setTimeout(() => {
258
- _setHint(_hintLabel);
259
- }, 3000);
263
+ if (!fs.existsSync(trackPath)) {
264
+ _setStatus(' {red-fg}Track file missing{/red-fg} ');
265
+ setTimeout(() => { _setStatus(); }, 3000);
260
266
  return;
261
267
  }
262
268
 
263
- _previewProc = spawn(_mp3Player.bin, _mp3Player.args(trackPath), {
264
- stdio: 'ignore', detached: true, env: _spawnEnv,
265
- });
269
+ const proc = spawnMp3Player(trackPath, _spawnEnv);
270
+ if (!proc) {
271
+ _setStatus(' {red-fg}No MP3 player found{/red-fg} ');
272
+ setTimeout(() => { _setStatus(); }, 3000);
273
+ return;
274
+ }
275
+
276
+ _previewProc = proc;
266
277
  _previewTrackId = trackFile;
267
278
 
268
279
  const label = tracks.find(t => t.file === trackFile)?.label ?? trackFile;
269
- _setHint(`{bright-cyan-fg}♪ Previewing: ${label} (Space to stop){/bright-cyan-fg}`);
280
+ _setStatus(` {bright-cyan-fg}♪ ${label} (Space to stop){/bright-cyan-fg} `);
270
281
 
271
- _previewProc.on('exit', () => {
282
+ proc.on('exit', () => {
272
283
  if (_previewTrackId === trackFile) {
273
284
  _previewTrackId = null;
274
285
  _previewProc = null;
275
- _setHint(_hintLabel);
286
+ _setStatus();
276
287
  }
277
288
  });
278
289
 
279
- _previewProc.on('error', () => {
290
+ proc.on('error', () => {
280
291
  _previewTrackId = null;
281
292
  _previewProc = null;
282
293
  });
@@ -284,12 +295,11 @@ export function openTrackPicker(screen, currentTrack, currentVolume, onSelect, o
284
295
 
285
296
  function _close(callback) {
286
297
  _killPreview();
287
- if (list._label2) list._label2.destroy();
288
298
  if (callback) {
289
299
  callback();
290
- destroyList(list, screen, onClose);
300
+ destroyList(box, screen, onClose);
291
301
  } else {
292
- destroyList(list, screen, onClose);
302
+ destroyList(box, screen, onClose);
293
303
  }
294
304
  }
295
305
 
@@ -304,15 +314,14 @@ export function openTrackPicker(screen, currentTrack, currentVolume, onSelect, o
304
314
  const selected = tracks[list.selected];
305
315
  if (!selected) return;
306
316
  _killPreview();
307
- if (list._label2) list._label2.destroy();
308
317
  if (options.skipVolume) {
309
- destroyList(list, screen, null);
318
+ destroyList(box, screen, null);
310
319
  setTimeout(() => {
311
320
  onSelect(selected.file);
312
321
  if (onClose) onClose();
313
322
  }, 0);
314
323
  } else {
315
- destroyList(list, screen, null);
324
+ destroyList(box, screen, null);
316
325
  openVolumeInput(screen, currentVolume ?? 20, (volume) => {
317
326
  onSelect(selected.file, volume);
318
327
  }, onClose);
package/src/i18n/de.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[Stimme wechseln]",
144
144
  voicesFavoriteBtn: "[★ Favorit]",
145
145
  voicesDownloadBtn: "[Stimme herunterladen]",
146
+ voicesInstallAllBtn: "[BMAD-Stimmen installieren]",
146
147
  voicesRowHintInstalled: "[Space] Vorschau [Enter] Auswählen [*] Favorit",
147
148
  voicesRowHintUninstalled: "[Enter] Herunterladen und installieren",
148
149
  musicRowHint: "[Space] Abspielen [Enter] Auswählen [*] Favorit",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(Keine README.md im aktuellen Verzeichnis gefunden)*",
201
202
  bmadFooterNobmad: "[Tab] Tab wechseln [Q] Beenden",
202
203
  bmadFooterBmad: "[↑↓/jk] Navigieren [Space] Vorschau [Enter] Konfigurieren [A] Auto-zuweisen [B] Stapel [X] Zurücksetzen [Q] Beenden",
203
- };
204
+ };
package/src/i18n/en.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[Switch Voice]",
144
144
  voicesFavoriteBtn: "[+ Thumbs Up]",
145
145
  voicesDownloadBtn: "[Download Voice]",
146
+ voicesInstallAllBtn: "[Install BMAD Voices]",
146
147
  voicesRowHintInstalled: "[Space] Preview [Enter] Select [+/*] Up [-] Down",
147
148
  voicesRowHintUninstalled: "[Enter] Download & Install",
148
149
  musicRowHint: "[Space] Play [Enter] Select [+/*] Favorite",
package/src/i18n/es.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[Cambiar Voz]",
144
144
  voicesFavoriteBtn: "[★ Favorito]",
145
145
  voicesDownloadBtn: "[Descargar Voz]",
146
+ voicesInstallAllBtn: "[Instalar Voces BMAD]",
146
147
  voicesRowHintInstalled: "[Space] Vista previa [Enter] Seleccionar [*] Favorito",
147
148
  voicesRowHintUninstalled: "[Enter] Descargar e instalar",
148
149
  musicRowHint: "[Space] Reproducir [Enter] Seleccionar [*] Favorito",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(No se encontró README.md en el directorio actual)*",
201
202
  bmadFooterNobmad: "[Tab] Cambiar Pestaña [Q] Salir",
202
203
  bmadFooterBmad: "[↑↓/jk] Navegar [Space] Previsualizar [Enter] Configurar [A] Auto-asignar [B] Masivo [X] Restablecer [Q] Salir",
203
- };
204
+ };
package/src/i18n/fr.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[Changer la voix]",
144
144
  voicesFavoriteBtn: "[★ Favori]",
145
145
  voicesDownloadBtn: "[Télécharger la voix]",
146
+ voicesInstallAllBtn: "[Installer les voix BMAD]",
146
147
  voicesRowHintInstalled: "[Space] Aperçu [Enter] Sélectionner [*] Favori",
147
148
  voicesRowHintUninstalled: "[Enter] Télécharger et installer",
148
149
  musicRowHint: "[Space] Lire [Enter] Sélectionner [*] Favori",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(Aucun README.md trouvé dans le répertoire actuel)*",
201
202
  bmadFooterNobmad: "[Tab] Changer d'onglet [Q] Quitter",
202
203
  bmadFooterBmad: "[↑↓/jk] Naviguer [Space] Aperçu [Enter] Configurer [A] Auto-assigner [B] Lot [X] Réinitialiser [Q] Quitter",
203
- };
204
+ };
package/src/i18n/hi.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[आवाज़ बदलें]",
144
144
  voicesFavoriteBtn: "[★ पसंदीदा]",
145
145
  voicesDownloadBtn: "[आवाज़ डाउनलोड]",
146
+ voicesInstallAllBtn: "[BMAD आवाज़ें इंस्टॉल करें]",
146
147
  voicesRowHintInstalled: "[Space] पूर्वावलोकन [Enter] चुनें [*] पसंदीदा",
147
148
  voicesRowHintUninstalled: "[Enter] डाउनलोड और इंस्टॉल करें",
148
149
  musicRowHint: "[Space] चलाएं [Enter] चुनें [*] पसंदीदा",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(वर्तमान निर्देशिका में README.md नहीं मिला)*",
201
202
  bmadFooterNobmad: "[Tab] टैब बदलें [Q] बाहर",
202
203
  bmadFooterBmad: "[↑↓/jk] नेविगेट [Space] प्रीव्यू [Enter] कॉन्फ़िगर [A] ऑटो-असाइन [B] बल्क [X] रीसेट [Q] बाहर",
203
- };
204
+ };
package/src/i18n/ja.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[音声切り替え]",
144
144
  voicesFavoriteBtn: "[★ お気に入り]",
145
145
  voicesDownloadBtn: "[音声ダウンロード]",
146
+ voicesInstallAllBtn: "[BMADボイスをインストール]",
146
147
  voicesRowHintInstalled: "[Space] プレビュー [Enter] 選択 [*] お気に入り",
147
148
  voicesRowHintUninstalled: "[Enter] ダウンロードしてインストール",
148
149
  musicRowHint: "[Space] 再生 [Enter] 選択 [*] お気に入り",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(現在のディレクトリにREADME.mdが見つかりません)*",
201
202
  bmadFooterNobmad: "[Tab] タブ切替 [Q] 終了",
202
203
  bmadFooterBmad: "[↑↓/jk] 移動 [Space] プレビュー [Enter] 設定 [A] 自動割当 [B] 一括 [X] リセット [Q] 終了",
203
- };
204
+ };
package/src/i18n/ko.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[음성 전환]",
144
144
  voicesFavoriteBtn: "[★ 즐겨찾기]",
145
145
  voicesDownloadBtn: "[음성 다운로드]",
146
+ voicesInstallAllBtn: "[BMAD 음성 설치]",
146
147
  voicesRowHintInstalled: "[Space] 미리보기 [Enter] 선택 [*] 즐겨찾기",
147
148
  voicesRowHintUninstalled: "[Enter] 다운로드 및 설치",
148
149
  musicRowHint: "[Space] 재생 [Enter] 선택 [*] 즐겨찾기",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(현재 디렉토리에서 README.md를 찾을 수 없습니다)*",
201
202
  bmadFooterNobmad: "[Tab] 탭 전환 [Q] 나가기",
202
203
  bmadFooterBmad: "[↑↓/jk] 탐색 [Space] 미리보기 [Enter] 설정 [A] 자동배정 [B] 일괄 [X] 초기화 [Q] 나가기",
203
- };
204
+ };
package/src/i18n/pt.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[Trocar Voz]",
144
144
  voicesFavoriteBtn: "[★ Favorito]",
145
145
  voicesDownloadBtn: "[Baixar Voz]",
146
+ voicesInstallAllBtn: "[Instalar Vozes BMAD]",
146
147
  voicesRowHintInstalled: "[Space] Visualizar [Enter] Selecionar [*] Favorito",
147
148
  voicesRowHintUninstalled: "[Enter] Baixar e instalar",
148
149
  musicRowHint: "[Space] Reproduzir [Enter] Selecionar [*] Favorito",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(Nenhum README.md encontrado no diretório atual)*",
201
202
  bmadFooterNobmad: "[Tab] Mudar Aba [Q] Sair",
202
203
  bmadFooterBmad: "[↑↓/jk] Navegar [Space] Visualizar [Enter] Configurar [A] Auto-atribuir [B] Lote [X] Redefinir [Q] Sair",
203
- };
204
+ };
@@ -42,13 +42,13 @@ export function t(lang, key) {
42
42
  * Each entry has: value (language code), name (display label for inquirer)
43
43
  */
44
44
  export const SUPPORTED_LANGUAGES = [
45
- { value: 'en', name: '🇺🇸 English' },
46
- { value: 'es', name: '🇪🇸 Español (Spanish)' },
47
- { value: 'fr', name: '🇫🇷 Français (French)' },
48
- { value: 'de', name: '🇩🇪 Deutsch (German)' },
49
- { value: 'pt', name: '🇧🇷 Português (Portuguese)' },
50
- { value: 'ja', name: '🇯🇵 日本語 (Japanese)' },
51
- { value: 'hi', name: '🇮🇳 हिन्दी (Hindi)' },
52
- { value: 'zh-CN', name: '🇨🇳 中文 (Chinese Simplified)' },
53
- { value: 'ko', name: '🇰🇷 한국어 (Korean)' },
45
+ { value: 'en', name: '[EN] English' },
46
+ { value: 'es', name: '[ES] Español (Spanish)' },
47
+ { value: 'fr', name: '[FR] Français (French)' },
48
+ { value: 'de', name: '[DE] Deutsch (German)' },
49
+ { value: 'pt', name: '[PT] Português (Portuguese)' },
50
+ { value: 'ja', name: '[JA] 日本語 (Japanese)' },
51
+ { value: 'hi', name: '[HI] हिन्दी (Hindi)' },
52
+ { value: 'zh-CN', name: '[ZH] 中文 (Chinese Simplified)' },
53
+ { value: 'ko', name: '[KO] 한국어 (Korean)' },
54
54
  ];
package/src/i18n/zh-CN.js CHANGED
@@ -143,6 +143,7 @@ export default {
143
143
  voicesSwitchBtn: "[切换语音]",
144
144
  voicesFavoriteBtn: "[★ 收藏]",
145
145
  voicesDownloadBtn: "[下载语音]",
146
+ voicesInstallAllBtn: "[安装BMAD语音]",
146
147
  voicesRowHintInstalled: "[Space] 预览 [Enter] 选择 [*] 收藏",
147
148
  voicesRowHintUninstalled: "[Enter] 下载并安装",
148
149
  musicRowHint: "[Space] 播放 [Enter] 选择 [*] 收藏",
@@ -200,4 +201,4 @@ export default {
200
201
  readmeNotFound: "*(当前目录中未找到README.md)*",
201
202
  bmadFooterNobmad: "[Tab] 切换标签 [Q] 退出",
202
203
  bmadFooterBmad: "[↑↓/jk] 导航 [Space] 预览 [Enter] 配置 [A] 自动分配 [B] 批量 [X] 重置 [Q] 退出",
203
- };
204
+ };
@@ -1,31 +1,31 @@
1
- /**
2
- * File: src/installer/language-screen.js
3
- *
4
- * Language selection screen for the AgentVibes installer TUI.
5
- * Presents a list of supported languages and returns the selected code.
6
- */
7
-
8
- import inquirer from 'inquirer';
9
- import { t, SUPPORTED_LANGUAGES } from '../i18n/strings.js';
10
-
11
- /**
12
- * Show the language selection screen and return the chosen language code.
13
- *
14
- * @param {string} [currentLang='en'] - Currently active language code (used as default)
15
- * @returns {Promise<string>} The selected language code (e.g. 'es', 'zh-CN')
16
- */
17
- export async function selectLanguage(currentLang = 'en') {
18
- const { lang } = await inquirer.prompt([{
19
- type: 'list',
20
- name: 'lang',
21
- message: '🌐 Select Language / Seleccionar Idioma / Choisir la langue / Sprache wählen / Selecionar Idioma / 言語を選択 / भाषा चुनें / 选择语言 / 언어 선택',
22
- default: currentLang,
23
- choices: SUPPORTED_LANGUAGES
24
- }]);
25
-
26
- console.clear();
27
- const chosenName = SUPPORTED_LANGUAGES.find(l => l.value === lang)?.name ?? lang;
28
- console.log(`\u2713 ${t(lang, 'languageApplied')}: ${chosenName}\n`);
29
-
30
- return lang;
31
- }
1
+ /**
2
+ * File: src/installer/language-screen.js
3
+ *
4
+ * Language selection screen for the AgentVibes installer TUI.
5
+ * Presents a list of supported languages and returns the selected code.
6
+ */
7
+
8
+ import inquirer from 'inquirer';
9
+ import { t, SUPPORTED_LANGUAGES } from '../i18n/strings.js';
10
+
11
+ /**
12
+ * Show the language selection screen and return the chosen language code.
13
+ *
14
+ * @param {string} [currentLang='en'] - Currently active language code (used as default)
15
+ * @returns {Promise<string>} The selected language code (e.g. 'es', 'zh-CN')
16
+ */
17
+ export async function selectLanguage(currentLang = 'en') {
18
+ const { lang } = await inquirer.prompt([{
19
+ type: 'list',
20
+ name: 'lang',
21
+ message: '🌐 Select Language / Seleccionar Idioma / Choisir la langue / Sprache wählen / Selecionar Idioma / 言語を選択 / भाषा चुनें / 选择语言 / 언어 선택',
22
+ default: currentLang,
23
+ choices: SUPPORTED_LANGUAGES
24
+ }]);
25
+
26
+ console.clear();
27
+ const chosenName = SUPPORTED_LANGUAGES.find(l => l.value === lang)?.name ?? lang;
28
+ console.log(`\u2713 ${t(lang, 'languageApplied')}: ${chosenName}\n`);
29
+
30
+ return lang;
31
+ }