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.
- package/.agentvibes/config.json +1 -15
- package/.claude/activation-instructions +54 -54
- package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
- package/.claude/commands/agent-vibes-rdp.md +24 -24
- package/.claude/config/audio-effects.cfg +5 -5
- package/.claude/config/background-music-enabled.txt +1 -1
- package/.claude/docs/TERMUX_SETUP.md +408 -408
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/audio-processor.sh +1 -1
- package/.claude/hooks/background-music-manager.sh +2 -1
- package/.claude/hooks/bmad-speak-enhanced.sh +37 -22
- package/.claude/hooks/bmad-speak.sh +26 -8
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +1 -1
- package/.claude/hooks/play-tts-kokoro.sh +9 -0
- package/.claude/hooks/play-tts-piper.sh +13 -1
- package/.claude/hooks/play-tts-ssh-remote.sh +78 -5
- package/.claude/hooks/play-tts-termux-ssh.sh +1 -1
- package/.claude/hooks/play-tts.sh +85 -4
- package/.claude/hooks-windows/background-music-manager.ps1 +2 -1
- package/.claude/hooks-windows/play-tts-kokoro.ps1 +14 -0
- package/.claude/hooks-windows/play-tts.ps1 +163 -30
- package/.claude/hooks-windows/voice-manager-windows.ps1 +101 -1
- package/.clawdbot/README.md +105 -105
- package/LICENSE +190 -190
- package/RELEASE_NOTES.md +29 -0
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +6 -19
- package/bin/resolve-utterance.js +137 -0
- package/bin/test-bmad-pr +78 -78
- package/mcp-server/QUICK_START.md +203 -203
- package/mcp-server/README.md +345 -345
- package/mcp-server/examples/claude_desktop_config.json +11 -11
- package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
- package/mcp-server/examples/custom_instructions.md +169 -169
- package/mcp-server/pyproject.toml +52 -52
- package/mcp-server/requirements.txt +2 -2
- package/mcp-server/server.py +280 -99
- package/mcp-server/test_mcp_correctness.py +486 -0
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +341 -336
- package/package.json +3 -2
- package/setup-windows.ps1 +867 -815
- package/src/cli/list-personalities.js +110 -110
- package/src/cli/list-voices.js +114 -114
- package/src/commands/bmad-voices.js +394 -394
- package/src/console/app.js +13 -2
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/tabs/agents-tab.js +82 -9
- package/src/console/tabs/help-tab.js +314 -314
- package/src/console/tabs/music-tab.js +7 -1
- package/src/console/tabs/readme-tab.js +272 -272
- package/src/console/tabs/settings-tab.js +29 -1
- package/src/console/tabs/setup-tab.js +4 -4
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/track-picker.js +3 -3
- package/src/i18n/de.js +0 -1
- package/src/i18n/en.js +0 -1
- package/src/i18n/es.js +0 -1
- package/src/i18n/fr.js +0 -1
- package/src/i18n/hi.js +0 -1
- package/src/i18n/ja.js +0 -1
- package/src/i18n/ko.js +0 -1
- package/src/i18n/pt.js +0 -1
- package/src/i18n/zh-CN.js +0 -1
- package/src/installer/language-screen.js +31 -31
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +205 -15
- package/src/services/config-service.js +264 -264
- package/src/services/language-service.js +47 -47
- package/src/services/llm-provider-service.js +7 -7
- package/src/services/utterance-loader.js +280 -0
- package/src/services/utterance-resolver.js +526 -0
- package/src/utils/audio-format-validator.js +277 -277
- package/src/utils/dependency-checker.js +469 -469
- package/src/utils/file-ownership-verifier.js +358 -358
- package/src/utils/music-file-validator.js +285 -285
- package/src/utils/preview-list-prompt.js +144 -144
- package/src/utils/secure-music-storage.js +412 -412
- package/templates/agentvibes-receiver.sh +74 -12
- package/voice-assignments.json +8245 -0
- package/.agentvibes/install-manifest.json +0 -342
- package/.claude/config/background-music-position.txt +0 -27
- package/.claude/config/background-music-volume.txt +0 -1
- package/.claude/config/background-music.cfg +0 -1
- package/.claude/config/background-music.txt +0 -1
- package/.claude/config/language.txt +0 -1
- package/.claude/config/personality.txt +0 -1
- package/.claude/config/tts-speech-rate.txt +0 -1
- package/.claude/config/tts-verbosity.txt +0 -1
- package/.claude/hooks-windows/audio-cache-utils.ps1.user.bak +0 -119
- package/.claude/hooks-windows/soprano-gradio-synth.py.user.bak +0 -153
- package/.claude/piper-voices-dir.txt +0 -1
- package/.mcp.json +0 -22
package/src/console/app.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1445
|
-
|
|
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
|
-
|
|
1452
|
-
|
|
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;
|