agentvibes 5.11.2 → 5.12.0-alpha.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 (97) hide show
  1. package/.agentvibes/config.json +1 -15
  2. package/.claude/activation-instructions +54 -54
  3. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  4. package/.claude/commands/agent-vibes-rdp.md +24 -24
  5. package/.claude/config/audio-effects.cfg +5 -5
  6. package/.claude/config/background-music-enabled.txt +1 -1
  7. package/.claude/docs/TERMUX_SETUP.md +408 -408
  8. package/.claude/github-star-reminder.txt +1 -1
  9. package/.claude/hooks/audio-processor.sh +1 -1
  10. package/.claude/hooks/background-music-manager.sh +2 -1
  11. package/.claude/hooks/bmad-speak-enhanced.sh +37 -22
  12. package/.claude/hooks/bmad-speak.sh +26 -8
  13. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +1 -1
  14. package/.claude/hooks/play-tts-kokoro.sh +9 -0
  15. package/.claude/hooks/play-tts-piper.sh +13 -1
  16. package/.claude/hooks/play-tts-ssh-remote.sh +78 -5
  17. package/.claude/hooks/play-tts-termux-ssh.sh +1 -1
  18. package/.claude/hooks/play-tts.sh +85 -4
  19. package/.claude/hooks-windows/background-music-manager.ps1 +2 -1
  20. package/.claude/hooks-windows/play-tts-kokoro.ps1 +14 -0
  21. package/.claude/hooks-windows/play-tts.ps1 +163 -30
  22. package/.claude/hooks-windows/voice-manager-windows.ps1 +101 -1
  23. package/.clawdbot/README.md +105 -105
  24. package/LICENSE +190 -190
  25. package/RELEASE_NOTES.md +29 -0
  26. package/WINDOWS-SETUP.md +208 -208
  27. package/bin/agent-vibes +39 -39
  28. package/bin/mcp-server.js +121 -121
  29. package/bin/mcp-server.sh +6 -19
  30. package/bin/resolve-utterance.js +137 -0
  31. package/bin/test-bmad-pr +78 -78
  32. package/mcp-server/QUICK_START.md +203 -203
  33. package/mcp-server/README.md +345 -345
  34. package/mcp-server/examples/claude_desktop_config.json +11 -11
  35. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  36. package/mcp-server/examples/custom_instructions.md +169 -169
  37. package/mcp-server/pyproject.toml +52 -52
  38. package/mcp-server/requirements.txt +2 -2
  39. package/mcp-server/server.py +280 -99
  40. package/mcp-server/test_mcp_correctness.py +486 -0
  41. package/mcp-server/test_server.py +395 -395
  42. package/mcp-server/test_windows_script_parity.py +341 -336
  43. package/package.json +3 -2
  44. package/setup-windows.ps1 +867 -815
  45. package/src/cli/list-personalities.js +110 -110
  46. package/src/cli/list-voices.js +114 -114
  47. package/src/commands/bmad-voices.js +394 -394
  48. package/src/console/app.js +13 -2
  49. package/src/console/brand-colors.js +13 -13
  50. package/src/console/constants/personalities.js +44 -44
  51. package/src/console/tabs/agents-tab.js +82 -9
  52. package/src/console/tabs/help-tab.js +314 -314
  53. package/src/console/tabs/music-tab.js +7 -1
  54. package/src/console/tabs/readme-tab.js +272 -272
  55. package/src/console/tabs/settings-tab.js +29 -1
  56. package/src/console/tabs/setup-tab.js +4 -4
  57. package/src/console/widgets/destroy-list.js +25 -25
  58. package/src/console/widgets/notice.js +55 -55
  59. package/src/console/widgets/track-picker.js +3 -3
  60. package/src/i18n/de.js +0 -1
  61. package/src/i18n/en.js +0 -1
  62. package/src/i18n/es.js +0 -1
  63. package/src/i18n/fr.js +0 -1
  64. package/src/i18n/hi.js +0 -1
  65. package/src/i18n/ja.js +0 -1
  66. package/src/i18n/ko.js +0 -1
  67. package/src/i18n/pt.js +0 -1
  68. package/src/i18n/zh-CN.js +0 -1
  69. package/src/installer/language-screen.js +31 -31
  70. package/src/installer/music-file-input.js +304 -304
  71. package/src/installer.js +205 -15
  72. package/src/services/config-service.js +264 -264
  73. package/src/services/language-service.js +47 -47
  74. package/src/services/llm-provider-service.js +7 -7
  75. package/src/services/utterance-loader.js +280 -0
  76. package/src/services/utterance-resolver.js +526 -0
  77. package/src/utils/audio-format-validator.js +277 -277
  78. package/src/utils/dependency-checker.js +469 -469
  79. package/src/utils/file-ownership-verifier.js +358 -358
  80. package/src/utils/music-file-validator.js +285 -285
  81. package/src/utils/preview-list-prompt.js +144 -144
  82. package/src/utils/secure-music-storage.js +412 -412
  83. package/templates/agentvibes-receiver.sh +74 -12
  84. package/voice-assignments.json +8245 -0
  85. package/.agentvibes/install-manifest.json +0 -342
  86. package/.claude/config/background-music-position.txt +0 -27
  87. package/.claude/config/background-music-volume.txt +0 -1
  88. package/.claude/config/background-music.cfg +0 -1
  89. package/.claude/config/background-music.txt +0 -1
  90. package/.claude/config/language.txt +0 -1
  91. package/.claude/config/personality.txt +0 -1
  92. package/.claude/config/tts-speech-rate.txt +0 -1
  93. package/.claude/config/tts-verbosity.txt +0 -1
  94. package/.claude/hooks-windows/audio-cache-utils.ps1.user.bak +0 -119
  95. package/.claude/hooks-windows/soprano-gradio-synth.py.user.bak +0 -153
  96. package/.claude/piper-voices-dir.txt +0 -1
  97. package/.mcp.json +0 -22
@@ -899,8 +899,19 @@ export class AgentVibesConsole {
899
899
  // Private: Global keyboard handlers
900
900
 
901
901
  _registerHandlers() {
902
- // Q or Ctrl+C → clean exit (no zombie processes)
903
- this.screen.key(['q', 'Q', 'C-c'], () => {
902
+ // Q or Ctrl+C → clean exit (no zombie processes).
903
+ // Guarded by isModalOpen(): blessed fires screen-level key handlers
904
+ // before focused-element handlers, so without this guard 'q' here would
905
+ // always win over a picker/modal's own Esc/q close binding — e.g. typing
906
+ // 'q' to jump to a voice named "Quinn" would kill the whole TUI instead
907
+ // of just being handled by the picker. Ctrl+C always force-quits (it's
908
+ // the universal "get me out" signal and has no in-modal meaning).
909
+ this.screen.key(['q', 'Q', 'C-c'], (ch, key) => {
910
+ const isCtrlC = key?.ctrl && key?.name === 'c';
911
+ if (!isCtrlC && this.navigationService?.isModalOpen()) {
912
+ // Let the focused modal/picker's own key handler deal with it.
913
+ return;
914
+ }
904
915
  this.screen.destroy();
905
916
  process.exit(0);
906
917
  });
@@ -1,13 +1,13 @@
1
- /**
2
- * AgentVibes TUI — Brand Color Constants
3
- *
4
- * Single source of truth for the two primary brand colors.
5
- * Change BRAND_PINK or BRAND_BLUE here to update every modal title,
6
- * button, and the "Vibes" logotype across the entire TUI.
7
- */
8
-
9
- /** Magenta-pink used for modal titles and the "Vibes" logotype. */
10
- export const BRAND_PINK = '#f06292'; // Light magenta — Pink 300
11
-
12
- /** Indigo blue used for default button backgrounds and primary accents. */
13
- export const BRAND_BLUE = '#3949ab';
1
+ /**
2
+ * AgentVibes TUI — Brand Color Constants
3
+ *
4
+ * Single source of truth for the two primary brand colors.
5
+ * Change BRAND_PINK or BRAND_BLUE here to update every modal title,
6
+ * button, and the "Vibes" logotype across the entire TUI.
7
+ */
8
+
9
+ /** Magenta-pink used for modal titles and the "Vibes" logotype. */
10
+ export const BRAND_PINK = '#f06292'; // Light magenta — Pink 300
11
+
12
+ /** Indigo blue used for default button backgrounds and primary accents. */
13
+ export const BRAND_BLUE = '#3949ab';
@@ -1,44 +1,44 @@
1
- /**
2
- * AgentVibes — Canonical personality constants.
3
- *
4
- * Single source of truth for personality names and their associated emoji
5
- * glyphs. All TUI modules (settings-tab, agents-tab, personality-picker …)
6
- * import from here; src/installer.js maintains its own copy because it
7
- * predates the TUI and uses a different module-load path.
8
- *
9
- * Exported:
10
- * PERSONALITY_EMOJIS — Map of personality name → emoji string
11
- * PERSONALITIES — Ordered array of personality names (canonical order
12
- * used for picker lists)
13
- */
14
-
15
- export const PERSONALITY_EMOJIS = Object.freeze({
16
- angry: '😠',
17
- annoying: '😤',
18
- crass: '🤬',
19
- dramatic: '🎭',
20
- 'dry-humor': '😐',
21
- flirty: '😘',
22
- funny: '😂',
23
- grandpa: '👴',
24
- millennial: '🙄',
25
- moody: '😒',
26
- none: '😊',
27
- normal: '😊',
28
- pirate: '⚓',
29
- poetic: '📜',
30
- professional: '👔',
31
- rapper: '🎤',
32
- robot: '🤖',
33
- sarcastic: '😏',
34
- sassy: '💁',
35
- 'surfer-dude':'🏄',
36
- zen: '🧘',
37
- });
38
-
39
- export const PERSONALITIES = Object.freeze([
40
- 'none', 'angry', 'annoying', 'crass', 'dramatic', 'dry-humor',
41
- 'flirty', 'funny', 'grandpa', 'millennial', 'moody', 'normal',
42
- 'pirate', 'poetic', 'professional', 'rapper', 'robot', 'sarcastic',
43
- 'sassy', 'surfer-dude', 'zen',
44
- ]);
1
+ /**
2
+ * AgentVibes — Canonical personality constants.
3
+ *
4
+ * Single source of truth for personality names and their associated emoji
5
+ * glyphs. All TUI modules (settings-tab, agents-tab, personality-picker …)
6
+ * import from here; src/installer.js maintains its own copy because it
7
+ * predates the TUI and uses a different module-load path.
8
+ *
9
+ * Exported:
10
+ * PERSONALITY_EMOJIS — Map of personality name → emoji string
11
+ * PERSONALITIES — Ordered array of personality names (canonical order
12
+ * used for picker lists)
13
+ */
14
+
15
+ export const PERSONALITY_EMOJIS = Object.freeze({
16
+ angry: '😠',
17
+ annoying: '😤',
18
+ crass: '🤬',
19
+ dramatic: '🎭',
20
+ 'dry-humor': '😐',
21
+ flirty: '😘',
22
+ funny: '😂',
23
+ grandpa: '👴',
24
+ millennial: '🙄',
25
+ moody: '😒',
26
+ none: '😊',
27
+ normal: '😊',
28
+ pirate: '⚓',
29
+ poetic: '📜',
30
+ professional: '👔',
31
+ rapper: '🎤',
32
+ robot: '🤖',
33
+ sarcastic: '😏',
34
+ sassy: '💁',
35
+ 'surfer-dude':'🏄',
36
+ zen: '🧘',
37
+ });
38
+
39
+ export const PERSONALITIES = Object.freeze([
40
+ 'none', 'angry', 'annoying', 'crass', 'dramatic', 'dry-humor',
41
+ 'flirty', 'funny', 'grandpa', 'millennial', 'moody', 'normal',
42
+ 'pirate', 'poetic', 'professional', 'rapper', 'robot', 'sarcastic',
43
+ 'sassy', 'surfer-dude', 'zen',
44
+ ]);
@@ -176,6 +176,33 @@ function createTestStub() {
176
176
  /**
177
177
  * Create the Agents tab component.
178
178
  */
179
+ // Module-level so the process 'exit'/'SIGINT' handlers are registered EXACTLY
180
+ // once per process, no matter how many times createAgentsTab() is called (the
181
+ // test suite creates many). Registering them per-call leaked listeners
182
+ // (MaxListenersExceededWarning) and left stale SIGINT handlers that each called
183
+ // process.exit(). Each tab adds its patched-files map here; the single handler
184
+ // restores every registered map.
185
+ const _allPatchedConfigMaps = new Set();
186
+ let _patchHandlersRegistered = false;
187
+ function _restoreAllRegisteredPatchedConfigMaps() {
188
+ for (const map of _allPatchedConfigMaps) {
189
+ for (const filePath of [...map.keys()]) {
190
+ const original = map.get(filePath);
191
+ try {
192
+ if (original !== null) fs.writeFileSync(filePath, original);
193
+ else fs.unlinkSync(filePath);
194
+ } catch { /* best-effort restore */ }
195
+ map.delete(filePath);
196
+ }
197
+ }
198
+ }
199
+ function _ensurePatchExitHandlers() {
200
+ if (_patchHandlersRegistered) return;
201
+ _patchHandlersRegistered = true;
202
+ process.on('exit', _restoreAllRegisteredPatchedConfigMaps);
203
+ process.on('SIGINT', () => { _restoreAllRegisteredPatchedConfigMaps(); process.exit(130); });
204
+ }
205
+
179
206
  export function createAgentsTab(screen, services) {
180
207
  if (IS_TEST) return createTestStub();
181
208
 
@@ -208,6 +235,37 @@ ${_tl('bmadDesc')}
208
235
  // Capture cwd once at construction (L1 fix)
209
236
  const _projectRoot = process.cwd();
210
237
 
238
+ // Story 8.3 fix: Windows agent-preview temp-patches config files (personality.txt,
239
+ // reverb-level.txt) to apply per-agent settings during a preview. Track every
240
+ // patched file + its pre-patch content here so ALL of them can be restored —
241
+ // not just on normal preview completion, but also on abnormal exit (Ctrl+C,
242
+ // crash, or quitting mid-preview). Non-Destructive Configuration Rule: a
243
+ // preview must never permanently mutate the user's config.
244
+ const _patchedConfigFiles = new Map(); // filePath -> original content (string) | null (file did not exist)
245
+
246
+ /** Record a file's pre-patch content the first time it's touched (idempotent). */
247
+ function _trackPatchedConfigFile(filePath, originalContent) {
248
+ if (!_patchedConfigFiles.has(filePath)) _patchedConfigFiles.set(filePath, originalContent);
249
+ }
250
+
251
+ /** Restore a single tracked file to its pre-patch state (or remove it if it didn't exist before). */
252
+ function _restorePatchedConfigFile(filePath) {
253
+ if (!_patchedConfigFiles.has(filePath)) return;
254
+ const original = _patchedConfigFiles.get(filePath);
255
+ try {
256
+ if (original !== null) fs.writeFileSync(filePath, original);
257
+ else fs.unlinkSync(filePath);
258
+ } catch { /* best-effort restore */ }
259
+ _patchedConfigFiles.delete(filePath);
260
+ }
261
+
262
+ // Abnormal-exit safety net: if the process dies mid-preview (Ctrl+C, crash,
263
+ // or the TUI quitting before the preview process's own 'exit' handler runs),
264
+ // still restore any temp-patched config files. Registered once per process
265
+ // via a module-level registry (see top of file) to avoid listener leaks.
266
+ _allPatchedConfigMaps.add(_patchedConfigFiles);
267
+ _ensurePatchExitHandlers();
268
+
211
269
  let _bmadDetected = false;
212
270
  let _agents = [];
213
271
  let _playingProcess = null;
@@ -1425,10 +1483,14 @@ ${_tl('bmadDesc')}
1425
1483
  }
1426
1484
 
1427
1485
  try {
1428
- if (profile.personality && profile.personality !== 'none')
1486
+ if (profile.personality && profile.personality !== 'none') {
1487
+ _trackPatchedConfigFile(personalityFile, origPersonality);
1429
1488
  fs.writeFileSync(personalityFile, profile.personality);
1430
- if (profile.reverbPreset)
1489
+ }
1490
+ if (profile.reverbPreset) {
1491
+ _trackPatchedConfigFile(reverbFile, origReverb);
1431
1492
  fs.writeFileSync(reverbFile, profile.reverbPreset);
1493
+ }
1432
1494
  } catch { /* degrade gracefully */ }
1433
1495
 
1434
1496
  const voiceId = profile.voice || '';
@@ -1440,16 +1502,21 @@ ${_tl('bmadDesc')}
1440
1502
  });
1441
1503
  _playingProcess = proc;
1442
1504
 
1505
+ // Restore BOTH temp-patched files (personality + reverb) — transactional:
1506
+ // whichever files were actually patched above get restored/unlinked here.
1507
+ // Also covered by the module-level process 'exit'/SIGINT handlers if the
1508
+ // process dies before this fires (see the module-level exit/SIGINT handler).
1443
1509
  function _restore() {
1444
- try {
1445
- if (origPersonality !== null) fs.writeFileSync(personalityFile, origPersonality);
1446
- else try { fs.unlinkSync(personalityFile); } catch {}
1447
- if (origReverb !== null) fs.writeFileSync(reverbFile, origReverb);
1448
- } catch {}
1510
+ _restorePatchedConfigFile(personalityFile);
1511
+ _restorePatchedConfigFile(reverbFile);
1449
1512
  }
1450
1513
 
1451
- proc.on('exit', () => { if (gen === _playGeneration) { _playingProcess = null; _stopSpinner(); } _restore(); if (onComplete) onComplete(); });
1452
- proc.on('error', () => { if (gen === _playGeneration) { _playingProcess = null; _stopSpinner(); } _restore(); if (onComplete) onComplete(); });
1514
+ // Gate restore + onComplete behind the generation check too: a superseded
1515
+ // preview's late exit must NOT restore config (it would clobber the newer
1516
+ // preview's in-flight patch and fire onComplete out of order). The current
1517
+ // generation's process — or the module-level exit/SIGINT handler — restores.
1518
+ proc.on('exit', () => { if (gen === _playGeneration) { _playingProcess = null; _stopSpinner(); _restore(); if (onComplete) onComplete(); } });
1519
+ proc.on('error', () => { if (gen === _playGeneration) { _playingProcess = null; _stopSpinner(); _restore(); if (onComplete) onComplete(); } });
1453
1520
  }
1454
1521
 
1455
1522
  // -------------------------------------------------------------------------
@@ -1627,9 +1694,15 @@ ${_tl('bmadDesc')}
1627
1694
  function _closeMenu(callback) {
1628
1695
  if (_menuClosed) return;
1629
1696
  _menuClosed = true;
1697
+ navigationService?.closeModal();
1630
1698
  destroyList(menuList, screen, callback);
1631
1699
  }
1632
1700
 
1701
+ // Register as an open modal so the global 'q' quit guard (app.js) blocks
1702
+ // quit while this menu is up — otherwise 'q' falls through and exits the
1703
+ // whole TUI instead of closing the menu.
1704
+ navigationService?.openModal(null, () => _closeMenu(() => { agentList.focus(); screen.render(); }));
1705
+
1633
1706
  menuList.key(['enter'], () => {
1634
1707
  const action = BULK_ACTIONS[menuList.selected];
1635
1708
  if (!action) return;