agentvibes 5.0.0 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/audio/tracks/Drifting Down the Hall.mp3 +0 -0
- package/.claude/audio/tracks/Late Night Hip Hop Groove.mp3 +0 -0
- package/.claude/audio/tracks/Midnight Charleston Stomp.mp3 +0 -0
- package/.claude/config/audio-effects.cfg +1 -1
- package/.claude/hooks/play-tts.sh +10 -3
- package/.claude/hooks-windows/play-tts.ps1 +8 -1
- package/README.md +22 -2
- package/RELEASE_NOTES.md +76 -0
- package/package.json +1 -1
- package/src/console/tabs/agents-tab.js +65 -62
- package/src/console/tabs/music-tab.js +49 -19
- package/src/console/tabs/settings-tab.js +39 -37
- package/src/console/tabs/setup-tab.js +346 -86
- package/src/console/tabs/voices-tab.js +152 -29
- package/src/console/widgets/format-utils.js +92 -89
- package/src/console/widgets/track-picker.js +325 -322
- package/src/installer.js +8 -8
- package/src/services/llm-provider-service.js +79 -0
|
@@ -20,7 +20,7 @@ import os from 'node:os';
|
|
|
20
20
|
import crypto from 'node:crypto';
|
|
21
21
|
import { spawn } from 'node:child_process';
|
|
22
22
|
import {
|
|
23
|
-
scanInstalledVoices, getVoiceMeta, PIPER_VOICES_DIR, SAMPLE_PHRASES, parseMultiSpeaker,
|
|
23
|
+
scanInstalledVoices, getVoiceMeta, genderIconTag, PIPER_VOICES_DIR, SAMPLE_PHRASES, parseMultiSpeaker,
|
|
24
24
|
} from './voices-tab.js';
|
|
25
25
|
import { LanguageService } from '../../services/language-service.js';
|
|
26
26
|
import { SUPPORTED_LANGUAGES, t } from '../../i18n/strings.js';
|
|
@@ -525,7 +525,6 @@ export function createSettingsTab(screen, services) {
|
|
|
525
525
|
navigationService?.openModal();
|
|
526
526
|
|
|
527
527
|
let _allVoices = [];
|
|
528
|
-
let _filterText = '';
|
|
529
528
|
let _previewProc = null;
|
|
530
529
|
let _previewVoiceId = null;
|
|
531
530
|
let _vpClosed = false;
|
|
@@ -567,26 +566,16 @@ export function createSettingsTab(screen, services) {
|
|
|
567
566
|
});
|
|
568
567
|
vpModal.setFront();
|
|
569
568
|
|
|
569
|
+
const COL_N = 30;
|
|
570
|
+
const COL_G = 4;
|
|
570
571
|
blessed.text({
|
|
571
|
-
parent: vpModal, top: 1, left:
|
|
572
|
-
content: '
|
|
573
|
-
});
|
|
574
|
-
const vpSearch = blessed.textbox({
|
|
575
|
-
parent: vpModal, top: 1, left: 11, width: 40, height: 1,
|
|
576
|
-
inputOnFocus: true, keys: true,
|
|
577
|
-
style: { fg: COLORS.valueFg, bg: 'blue', focus: { bg: 'cyan' } },
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
const COL_N = 28;
|
|
581
|
-
const COL_G = 10;
|
|
582
|
-
blessed.text({
|
|
583
|
-
parent: vpModal, top: 2, left: 6, tags: true,
|
|
584
|
-
content: `{cyan-fg}${'Name'.padEnd(COL_N)}${'Gender'.padEnd(COL_G)}Provider{/cyan-fg}`,
|
|
572
|
+
parent: vpModal, top: 1, left: 6, tags: true,
|
|
573
|
+
content: `{cyan-fg}${'Name'.padEnd(COL_N)}{/cyan-fg}{magenta-fg}♀{/magenta-fg}/{bright-cyan-fg}♂{/bright-cyan-fg} {cyan-fg}Provider{/cyan-fg}`,
|
|
585
574
|
style: { bg: COLORS.contentBg },
|
|
586
575
|
});
|
|
587
576
|
|
|
588
577
|
const vpList = blessed.list({
|
|
589
|
-
parent: vpModal, top:
|
|
578
|
+
parent: vpModal, top: 2, left: 2, right: 2, bottom: 5,
|
|
590
579
|
keys: true, vi: true, mouse: true,
|
|
591
580
|
border: { type: 'line' },
|
|
592
581
|
scrollbar: { ch: '|', style: { fg: 'cyan' } },
|
|
@@ -606,16 +595,10 @@ export function createSettingsTab(screen, services) {
|
|
|
606
595
|
|
|
607
596
|
blessed.text({
|
|
608
597
|
parent: vpModal, bottom: 2, left: 2, right: 2, tags: true,
|
|
609
|
-
content: '{white-fg}[
|
|
598
|
+
content: '{white-fg}[↑↓] Nav [PgUp/PgDn] Page [Home/End] [a-z] Jump [Enter] Select [Space] Preview [Esc] Cancel{/white-fg}',
|
|
610
599
|
style: { bg: COLORS.contentBg },
|
|
611
600
|
});
|
|
612
601
|
|
|
613
|
-
function _getFiltered() {
|
|
614
|
-
if (!_filterText) return _allVoices;
|
|
615
|
-
const f = _filterText.toLowerCase();
|
|
616
|
-
return _allVoices.filter(v => v.toLowerCase().includes(f));
|
|
617
|
-
}
|
|
618
|
-
|
|
619
602
|
function _buildItems(voices) {
|
|
620
603
|
const currentVoice = providerService?.getActiveVoiceId() ?? '';
|
|
621
604
|
return voices.map(v => {
|
|
@@ -626,7 +609,8 @@ export function createSettingsTab(screen, services) {
|
|
|
626
609
|
const name = meta.displayName.length > COL_N
|
|
627
610
|
? meta.displayName.slice(0, COL_N - 1) + '…'
|
|
628
611
|
: meta.displayName.padEnd(COL_N);
|
|
629
|
-
|
|
612
|
+
// genderIconTag has invisible color tags — pad with literal spaces (1 visible char + 3 spaces = 4)
|
|
613
|
+
return ` ${dot} ${name}${genderIconTag(meta.gender)} ${meta.provider}`;
|
|
630
614
|
});
|
|
631
615
|
}
|
|
632
616
|
|
|
@@ -635,8 +619,10 @@ export function createSettingsTab(screen, services) {
|
|
|
635
619
|
const savedIdx = vpList.selected ?? 0;
|
|
636
620
|
const savedScroll = vpList.childBase ?? 0;
|
|
637
621
|
_allVoices = scanInstalledVoices();
|
|
638
|
-
|
|
639
|
-
|
|
622
|
+
// Sort by display name so the first-letter quick jump is intuitive
|
|
623
|
+
_allVoices.sort((a, b) => getVoiceMeta(a).displayName.localeCompare(
|
|
624
|
+
getVoiceMeta(b).displayName, undefined, { sensitivity: 'base' }));
|
|
625
|
+
const items = _buildItems(_allVoices);
|
|
640
626
|
vpList.setItems(items.length > 0 ? items : [' (no voices found)']);
|
|
641
627
|
vpList.select(Math.min(savedIdx, items.length - 1));
|
|
642
628
|
vpList.childBase = Math.min(savedScroll, Math.max(0, items.length - (vpList.height - 2)));
|
|
@@ -704,14 +690,8 @@ export function createSettingsTab(screen, services) {
|
|
|
704
690
|
piper.on('error', () => { _previewProc = null; _previewVoiceId = null; });
|
|
705
691
|
}
|
|
706
692
|
|
|
707
|
-
vpSearch.on('keypress', () => {
|
|
708
|
-
setTimeout(() => { _filterText = vpSearch.getValue().trim(); _refreshVP(); }, 0);
|
|
709
|
-
});
|
|
710
|
-
vpSearch.key(['escape'], () => { vpList.focus(); screen.render(); });
|
|
711
|
-
vpList.key(['/'], () => { vpSearch.clearValue(); vpSearch.focus(); screen.render(); });
|
|
712
693
|
vpList.key(['enter'], () => {
|
|
713
|
-
const
|
|
714
|
-
const sel = filtered[vpList.selected];
|
|
694
|
+
const sel = _allVoices[vpList.selected];
|
|
715
695
|
if (sel) {
|
|
716
696
|
if (providerService) providerService.setActiveVoice(sel);
|
|
717
697
|
else configService.set('voice', sel);
|
|
@@ -719,15 +699,37 @@ export function createSettingsTab(screen, services) {
|
|
|
719
699
|
_closeVP();
|
|
720
700
|
});
|
|
721
701
|
vpList.key(['space'], () => {
|
|
722
|
-
const
|
|
723
|
-
const sel = filtered[vpList.selected];
|
|
702
|
+
const sel = _allVoices[vpList.selected];
|
|
724
703
|
if (sel) _previewVoice(sel);
|
|
725
704
|
});
|
|
726
705
|
vpList.key(['escape', 'q'], _closeVP);
|
|
727
706
|
|
|
707
|
+
// PageUp / PageDown / Home / End navigation
|
|
708
|
+
const _pageSize = () => Math.max(1, (vpList.height ?? 10) - 2);
|
|
709
|
+
vpList.key(['pageup'], () => { vpList.up(_pageSize()); screen.render(); });
|
|
710
|
+
vpList.key(['pagedown'], () => { vpList.down(_pageSize()); screen.render(); });
|
|
711
|
+
vpList.key(['home'], () => { vpList.select(0); screen.render(); });
|
|
712
|
+
vpList.key(['end'], () => { vpList.select(Math.max(0, _allVoices.length - 1)); screen.render(); });
|
|
713
|
+
|
|
714
|
+
// First-letter quick jump: typing 'a' jumps to the first voice starting
|
|
715
|
+
// with A. Block keys reserved by the list widget (vi nav, cancel) so
|
|
716
|
+
// they don't get swallowed: q (cancel), j/k/g/h/l (vi navigation).
|
|
717
|
+
const _vpJumpBlocked = new Set(['j', 'k', 'g', 'h', 'l', 'q']);
|
|
718
|
+
vpList.on('keypress', (ch, key) => {
|
|
719
|
+
if (!ch || key?.ctrl || key?.meta) return;
|
|
720
|
+
if (!/^[a-zA-Z]$/.test(ch)) return;
|
|
721
|
+
const target = ch.toLowerCase();
|
|
722
|
+
if (_vpJumpBlocked.has(target)) return;
|
|
723
|
+
const idx = _allVoices.findIndex(v => {
|
|
724
|
+
const name = getVoiceMeta(v).displayName.toLowerCase();
|
|
725
|
+
return name.startsWith(target);
|
|
726
|
+
});
|
|
727
|
+
if (idx >= 0) { vpList.select(idx); screen.render(); }
|
|
728
|
+
});
|
|
729
|
+
|
|
728
730
|
_refreshVP();
|
|
729
731
|
const currentVoice = providerService?.getActiveVoiceId() ?? '';
|
|
730
|
-
const activeIdx =
|
|
732
|
+
const activeIdx = _allVoices.indexOf(currentVoice);
|
|
731
733
|
if (activeIdx >= 0) vpList.select(activeIdx);
|
|
732
734
|
vpList.focus();
|
|
733
735
|
screen.render();
|