agentvibes 3.3.0 → 3.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.
- package/.claude/config/audio-effects.cfg +1 -1
- package/.claude/config/background-music-position.txt +1 -26
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/audio-cache-utils.sh +0 -0
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +0 -0
- package/.claude/hooks/play-tts-soprano.sh +320 -0
- package/.claude/hooks/play-tts.sh +6 -0
- package/.claude/hooks/provider-manager.sh +17 -0
- package/.claude/hooks/soprano-gradio-synth.py +139 -0
- package/.claude/piper-voices-dir.txt +1 -1
- package/.mcp.json +6 -28
- package/README.md +19 -15
- package/RELEASE_NOTES.md +199 -1
- package/package.json +1 -1
- package/src/installer.js +339 -47
- 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/tts-speech-rate.txt +0 -1
- package/.claude/config/tts-verbosity.txt +0 -1
- package/.claude/hooks/bmad-party-manager.sh +0 -225
- package/.claude/hooks/stop.sh +0 -38
package/src/installer.js
CHANGED
|
@@ -99,6 +99,85 @@ function detectAndNotifyTermux() {
|
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Check if PulseAudio tunnel is active
|
|
104
|
+
* @returns {boolean} True if PULSE_SERVER points to a TCP connection
|
|
105
|
+
*/
|
|
106
|
+
function hasPulseAudioTunnel() {
|
|
107
|
+
return process.env.PULSE_SERVER &&
|
|
108
|
+
process.env.PULSE_SERVER.toLowerCase().startsWith('tcp:');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Detect system capabilities for smart provider recommendations
|
|
113
|
+
* @returns {Promise<Object>} System info including GPU, memory, platform
|
|
114
|
+
*/
|
|
115
|
+
async function detectSystemCapabilities() {
|
|
116
|
+
const isMacOS = process.platform === 'darwin';
|
|
117
|
+
const isAndroid = isTermux();
|
|
118
|
+
let hasGPU = false;
|
|
119
|
+
let totalRAM = 0;
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
// Detect NVIDIA GPU
|
|
123
|
+
try {
|
|
124
|
+
execSync('nvidia-smi --query-gpu=name --format=csv,noheader', {
|
|
125
|
+
stdio: 'pipe',
|
|
126
|
+
timeout: 5000 // 5 second timeout
|
|
127
|
+
});
|
|
128
|
+
hasGPU = true;
|
|
129
|
+
} catch (e) {
|
|
130
|
+
// No NVIDIA GPU or timeout
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Detect total RAM (in MB)
|
|
134
|
+
if (isMacOS) {
|
|
135
|
+
const output = execSync('sysctl hw.memsize', {
|
|
136
|
+
encoding: 'utf8',
|
|
137
|
+
timeout: 3000 // 3 second timeout
|
|
138
|
+
});
|
|
139
|
+
const parts = output.split(':');
|
|
140
|
+
if (parts.length < 2) {
|
|
141
|
+
throw new Error('Unexpected sysctl output format');
|
|
142
|
+
}
|
|
143
|
+
const bytes = parseInt(parts[1].trim(), 10);
|
|
144
|
+
if (isNaN(bytes)) {
|
|
145
|
+
throw new Error('Failed to parse memory size');
|
|
146
|
+
}
|
|
147
|
+
totalRAM = Math.floor(bytes / (1024 * 1024));
|
|
148
|
+
} else {
|
|
149
|
+
const output = execSync('cat /proc/meminfo | grep MemTotal', {
|
|
150
|
+
encoding: 'utf8',
|
|
151
|
+
timeout: 3000 // 3 second timeout
|
|
152
|
+
});
|
|
153
|
+
const parts = output.split(':');
|
|
154
|
+
if (parts.length < 2) {
|
|
155
|
+
throw new Error('Unexpected meminfo output format');
|
|
156
|
+
}
|
|
157
|
+
const memParts = parts[1].trim().split(' ');
|
|
158
|
+
if (memParts.length < 1) {
|
|
159
|
+
throw new Error('Unexpected meminfo value format');
|
|
160
|
+
}
|
|
161
|
+
const kb = parseInt(memParts[0], 10);
|
|
162
|
+
if (isNaN(kb)) {
|
|
163
|
+
throw new Error('Failed to parse memory size');
|
|
164
|
+
}
|
|
165
|
+
totalRAM = Math.floor(kb / 1024);
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
// Fallback: assume 4GB if detection fails
|
|
169
|
+
totalRAM = 4096;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
hasGPU,
|
|
174
|
+
lowMemory: totalRAM < 4096,
|
|
175
|
+
totalRAM,
|
|
176
|
+
isMacOS,
|
|
177
|
+
isAndroid
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
102
181
|
/**
|
|
103
182
|
* Detect environment type for smart installation defaults
|
|
104
183
|
* @returns {string} - 'DESKTOP', 'PHONE', or 'VOICELESS'
|
|
@@ -109,18 +188,24 @@ function detectEnvironment() {
|
|
|
109
188
|
return 'PHONE';
|
|
110
189
|
}
|
|
111
190
|
|
|
112
|
-
// Check for audio devices
|
|
191
|
+
// Check for audio devices (local hardware)
|
|
113
192
|
const hasAudio = checkAudioDevices();
|
|
114
193
|
|
|
194
|
+
// Check if PulseAudio tunnel is active (e.g., tcp:hostname:port)
|
|
195
|
+
// This provides working audio over SSH connections
|
|
196
|
+
const hasTunnel = hasPulseAudioTunnel();
|
|
197
|
+
|
|
115
198
|
// Check if in SSH session
|
|
116
199
|
const isSSH = process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY;
|
|
117
200
|
|
|
118
|
-
// Voiceless: No audio
|
|
119
|
-
|
|
201
|
+
// Voiceless: No audio devices AND no PulseAudio tunnel
|
|
202
|
+
// (SSH status doesn't matter - what matters is whether audio works)
|
|
203
|
+
if (!hasAudio && !hasTunnel) {
|
|
120
204
|
return 'VOICELESS';
|
|
121
205
|
}
|
|
122
206
|
|
|
123
|
-
// Desktop: Has audio
|
|
207
|
+
// Desktop: Has working audio (local devices OR PulseAudio tunnel)
|
|
208
|
+
// This includes SSH sessions with PulseAudio tunnels
|
|
124
209
|
return 'DESKTOP';
|
|
125
210
|
}
|
|
126
211
|
|
|
@@ -475,6 +560,9 @@ async function collectConfiguration(options = {}) {
|
|
|
475
560
|
const pageOffset = options.pageOffset || 0;
|
|
476
561
|
const totalPages = options.totalPages || sectionPages;
|
|
477
562
|
|
|
563
|
+
// Cache system capabilities to avoid duplicate detection
|
|
564
|
+
let systemInfoCache = null;
|
|
565
|
+
|
|
478
566
|
console.clear();
|
|
479
567
|
console.log(chalk.cyan.bold('\n⚙️ Configuration Setup\n'));
|
|
480
568
|
console.log(chalk.white('Please configure your AgentVibes installation.\n'));
|
|
@@ -536,24 +624,76 @@ async function collectConfiguration(options = {}) {
|
|
|
536
624
|
}
|
|
537
625
|
));
|
|
538
626
|
}
|
|
539
|
-
// Desktop:
|
|
627
|
+
// Desktop: Smart provider selection with system detection
|
|
540
628
|
else {
|
|
629
|
+
// Detect system capabilities for smart recommendations (cached to avoid duplicate calls)
|
|
630
|
+
if (!systemInfoCache) {
|
|
631
|
+
systemInfoCache = await detectSystemCapabilities();
|
|
632
|
+
}
|
|
633
|
+
const systemInfo = systemInfoCache;
|
|
634
|
+
|
|
635
|
+
// Detect audio method (local devices vs PulseAudio tunnel)
|
|
636
|
+
const hasLocalAudio = checkAudioDevices();
|
|
637
|
+
const hasTunnel = hasPulseAudioTunnel();
|
|
638
|
+
|
|
639
|
+
// Context-aware header message
|
|
640
|
+
let audioHeader = '';
|
|
641
|
+
let audioSubtext = '';
|
|
642
|
+
if (hasLocalAudio && hasTunnel) {
|
|
643
|
+
audioHeader = chalk.green.bold('🔊 Audio Output Detected!\n\n');
|
|
644
|
+
audioSubtext = chalk.white('Local speakers + PulseAudio tunnel detected. Choose your TTS engine:\n\n');
|
|
645
|
+
} else if (hasTunnel) {
|
|
646
|
+
audioHeader = chalk.blue.bold('🌐 PulseAudio Tunnel Detected!\n\n');
|
|
647
|
+
audioSubtext = chalk.white('Audio will play through your PulseAudio tunnel. Choose your TTS engine:\n\n');
|
|
648
|
+
} else {
|
|
649
|
+
audioHeader = chalk.green.bold('🔊 Audio Output Detected!\n\n');
|
|
650
|
+
audioSubtext = chalk.white('Your system has speakers. Choose your TTS engine:\n\n');
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Build recommendation message
|
|
654
|
+
let recommendation = '';
|
|
655
|
+
if (systemInfo.hasGPU && !systemInfo.isMacOS) {
|
|
656
|
+
recommendation = chalk.yellow('💡 Recommendation: Soprano\n') +
|
|
657
|
+
chalk.gray(' Your GPU will run Soprano 2000x faster than CPU!\n') +
|
|
658
|
+
chalk.gray(' Perfect for high-volume TTS or real-time applications.\n\n');
|
|
659
|
+
} else if (systemInfo.lowMemory && !systemInfo.isMacOS) {
|
|
660
|
+
const ramGB = systemInfo.totalRAM / 1024;
|
|
661
|
+
const ramDisplay = ramGB < 1
|
|
662
|
+
? `${systemInfo.totalRAM}MB`
|
|
663
|
+
: `${Math.floor(ramGB)}GB`;
|
|
664
|
+
recommendation = chalk.yellow('💡 Recommendation: Soprano\n') +
|
|
665
|
+
chalk.gray(` Your system has limited RAM (${ramDisplay}).\n`) +
|
|
666
|
+
chalk.gray(' Soprano uses <1GB vs Piper\'s 2-3GB.\n\n');
|
|
667
|
+
} else if (systemInfo.isMacOS) {
|
|
668
|
+
recommendation = chalk.yellow('💡 Recommendation: macOS Say\n') +
|
|
669
|
+
chalk.gray(' Built-in, zero setup, 100+ voices included.\n') +
|
|
670
|
+
chalk.gray(' Best choice for macOS users.\n\n');
|
|
671
|
+
} else {
|
|
672
|
+
recommendation = chalk.yellow('💡 Recommendation: Piper\n') +
|
|
673
|
+
chalk.gray(' Most versatile: 50+ voices, 18+ languages.\n') +
|
|
674
|
+
chalk.gray(' Great for multi-language projects and variety.\n\n');
|
|
675
|
+
}
|
|
676
|
+
|
|
541
677
|
console.log(boxen(
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
chalk.
|
|
546
|
-
chalk.
|
|
547
|
-
chalk.gray(' •
|
|
678
|
+
audioHeader +
|
|
679
|
+
audioSubtext +
|
|
680
|
+
recommendation +
|
|
681
|
+
chalk.white('Available Providers:\n\n') +
|
|
682
|
+
(systemInfo.isMacOS ? chalk.yellow('🍎 macOS Say\n') +
|
|
683
|
+
chalk.gray(' • Built-in, zero setup, 100+ voices\n\n') : '') +
|
|
684
|
+
chalk.magenta('⚡ Soprano TTS\n') +
|
|
685
|
+
chalk.gray(' • Ultra-fast: 20x CPU, 2000x GPU\n') +
|
|
686
|
+
chalk.gray(' • 1 premium English voice\n') +
|
|
687
|
+
chalk.gray(' • <1GB memory footprint\n\n') +
|
|
548
688
|
chalk.green('🆓 Piper TTS\n') +
|
|
689
|
+
chalk.gray(' • 50+ voices, 18+ languages\n') +
|
|
549
690
|
chalk.gray(' • Free & offline\n') +
|
|
550
|
-
chalk.gray(' • 50+ Hugging Face AI voices\n') +
|
|
551
691
|
chalk.gray(' • Human-like speech quality'),
|
|
552
692
|
{
|
|
553
693
|
padding: 1,
|
|
554
694
|
margin: { top: 0, bottom: 0, left: 0, right: 0 },
|
|
555
695
|
borderStyle: 'round',
|
|
556
|
-
borderColor: '
|
|
696
|
+
borderColor: 'green',
|
|
557
697
|
width: 80
|
|
558
698
|
}
|
|
559
699
|
));
|
|
@@ -565,41 +705,98 @@ async function collectConfiguration(options = {}) {
|
|
|
565
705
|
// VOICELESS SERVER: Prioritize remote audio options
|
|
566
706
|
if (environment === 'VOICELESS') {
|
|
567
707
|
providerChoices.push({
|
|
568
|
-
name: chalk.green('📱
|
|
569
|
-
value: 'termux-ssh'
|
|
708
|
+
name: chalk.green('📱 AgentVibes Receiver (Text → SSH → Device)') + chalk.yellow(' (Recommended)'),
|
|
709
|
+
value: 'termux-ssh',
|
|
710
|
+
short: 'SSH-Remote'
|
|
570
711
|
});
|
|
571
712
|
providerChoices.push({
|
|
572
|
-
name: chalk.blue('🔊
|
|
573
|
-
value: 'ssh-pulseaudio'
|
|
713
|
+
name: chalk.blue('🔊 PulseAudio Tunnel (Audio → TCP → Speakers)'),
|
|
714
|
+
value: 'ssh-pulseaudio',
|
|
715
|
+
short: 'PulseAudio'
|
|
574
716
|
});
|
|
575
717
|
providerChoices.push({
|
|
576
|
-
name: chalk.gray('🔇
|
|
577
|
-
value: 'silent'
|
|
718
|
+
name: chalk.gray('🔇 Silent Mode (No TTS)'),
|
|
719
|
+
value: 'silent',
|
|
720
|
+
short: 'Silent'
|
|
578
721
|
});
|
|
579
722
|
}
|
|
580
723
|
// PHONE/TERMUX: Receiver mode or local playback
|
|
581
724
|
else if (environment === 'PHONE') {
|
|
582
725
|
providerChoices.push({
|
|
583
|
-
name: chalk.green('
|
|
584
|
-
value: 'piper-receiver'
|
|
726
|
+
name: chalk.green('📱 Receiver Mode (Remote Server → This Phone)') + chalk.yellow(' (Recommended)'),
|
|
727
|
+
value: 'piper-receiver',
|
|
728
|
+
short: 'Receiver'
|
|
585
729
|
});
|
|
586
730
|
providerChoices.push({
|
|
587
|
-
name: chalk.blue('
|
|
588
|
-
value: 'piper'
|
|
731
|
+
name: chalk.blue('🔊 Local Playback (This Device Only)'),
|
|
732
|
+
value: 'piper',
|
|
733
|
+
short: 'Local'
|
|
589
734
|
});
|
|
590
735
|
}
|
|
591
|
-
// DESKTOP:
|
|
736
|
+
// DESKTOP: Smart provider ordering
|
|
592
737
|
else {
|
|
593
|
-
|
|
738
|
+
// Reuse cached system info from earlier detection
|
|
739
|
+
const systemInfo = systemInfoCache || await detectSystemCapabilities();
|
|
740
|
+
|
|
741
|
+
// Smart ordering based on system capabilities
|
|
742
|
+
if (systemInfo.hasGPU && !systemInfo.isMacOS) {
|
|
743
|
+
// GPU detected: Soprano first
|
|
744
|
+
providerChoices.push({
|
|
745
|
+
name: chalk.magenta('⚡ Soprano TTS') + chalk.yellow(' (Recommended for your GPU)') +
|
|
746
|
+
chalk.gray(' - 2000x real-time'),
|
|
747
|
+
value: 'soprano',
|
|
748
|
+
short: 'Soprano'
|
|
749
|
+
});
|
|
750
|
+
providerChoices.push({
|
|
751
|
+
name: chalk.green('🆓 Piper TTS') + chalk.gray(' - 50+ voices, 18+ languages'),
|
|
752
|
+
value: 'piper',
|
|
753
|
+
short: 'Piper'
|
|
754
|
+
});
|
|
755
|
+
} else if (systemInfo.lowMemory && !systemInfo.isMacOS) {
|
|
756
|
+
// Low memory: Soprano first
|
|
594
757
|
providerChoices.push({
|
|
595
|
-
name: chalk.yellow('
|
|
596
|
-
|
|
758
|
+
name: chalk.magenta('⚡ Soprano TTS') + chalk.yellow(' (Best for low memory)') +
|
|
759
|
+
chalk.gray(' - <1GB'),
|
|
760
|
+
value: 'soprano',
|
|
761
|
+
short: 'Soprano'
|
|
762
|
+
});
|
|
763
|
+
providerChoices.push({
|
|
764
|
+
name: chalk.green('🆓 Piper TTS') + chalk.gray(' - 50+ voices (uses 2-3GB RAM)'),
|
|
765
|
+
value: 'piper',
|
|
766
|
+
short: 'Piper'
|
|
767
|
+
});
|
|
768
|
+
} else if (systemInfo.isMacOS) {
|
|
769
|
+
// macOS: System voice first
|
|
770
|
+
providerChoices.push({
|
|
771
|
+
name: chalk.yellow('🍎 macOS Say') + chalk.yellow(' (Recommended)') +
|
|
772
|
+
chalk.gray(' - Zero setup, 100+ built-in voices'),
|
|
773
|
+
value: 'macos',
|
|
774
|
+
short: 'macOS Say'
|
|
775
|
+
});
|
|
776
|
+
providerChoices.push({
|
|
777
|
+
name: chalk.magenta('⚡ Soprano TTS') + chalk.gray(' - Ultra-fast, 1 premium voice'),
|
|
778
|
+
value: 'soprano',
|
|
779
|
+
short: 'Soprano'
|
|
780
|
+
});
|
|
781
|
+
providerChoices.push({
|
|
782
|
+
name: chalk.green('🆓 Piper TTS') + chalk.gray(' - 50+ voices, 18+ languages'),
|
|
783
|
+
value: 'piper',
|
|
784
|
+
short: 'Piper'
|
|
785
|
+
});
|
|
786
|
+
} else {
|
|
787
|
+
// Standard: Piper first (most versatile)
|
|
788
|
+
providerChoices.push({
|
|
789
|
+
name: chalk.green('🆓 Piper TTS') + chalk.yellow(' (Recommended)') +
|
|
790
|
+
chalk.gray(' - 50+ voices, versatile'),
|
|
791
|
+
value: 'piper',
|
|
792
|
+
short: 'Piper'
|
|
793
|
+
});
|
|
794
|
+
providerChoices.push({
|
|
795
|
+
name: chalk.magenta('⚡ Soprano TTS') + chalk.gray(' - Ultra-fast, 1 premium voice'),
|
|
796
|
+
value: 'soprano',
|
|
797
|
+
short: 'Soprano'
|
|
597
798
|
});
|
|
598
799
|
}
|
|
599
|
-
providerChoices.push({
|
|
600
|
-
name: chalk.green('🆓 Piper TTS (Free, Offline)'),
|
|
601
|
-
value: 'piper'
|
|
602
|
-
});
|
|
603
800
|
}
|
|
604
801
|
|
|
605
802
|
providerChoices.push(new inquirer.Separator());
|
|
@@ -677,8 +874,8 @@ async function collectConfiguration(options = {}) {
|
|
|
677
874
|
}
|
|
678
875
|
}
|
|
679
876
|
|
|
680
|
-
// If
|
|
681
|
-
if (config.provider === 'termux-ssh' || config.provider === 'ssh-
|
|
877
|
+
// If SSH-Remote selected, show setup guide (NOT PulseAudio!)
|
|
878
|
+
if (config.provider === 'termux-ssh' || config.provider === 'ssh-remote') {
|
|
682
879
|
console.log('\n' + boxen(
|
|
683
880
|
chalk.cyan.bold('📱 AgentVibes Receiver Setup\n\n') +
|
|
684
881
|
chalk.white('What is Receiver Mode?\n') +
|
|
@@ -745,12 +942,63 @@ async function collectConfiguration(options = {}) {
|
|
|
745
942
|
}
|
|
746
943
|
}
|
|
747
944
|
|
|
945
|
+
// If PulseAudio selected, show different setup (BUG FIX!)
|
|
946
|
+
if (config.provider === 'ssh-pulseaudio' || config.provider === 'pulseaudio') {
|
|
947
|
+
console.log('\n' + boxen(
|
|
948
|
+
chalk.blue.bold('🔊 PulseAudio Tunnel Setup\n\n') +
|
|
949
|
+
chalk.white('What is PulseAudio Tunnel?\n') +
|
|
950
|
+
chalk.gray('Server generates audio and streams it via TCP to your speakers.\n\n') +
|
|
951
|
+
chalk.white('How it Works:\n') +
|
|
952
|
+
chalk.gray('1. Server: Generates TTS audio (Piper/Soprano/macOS Say)\n') +
|
|
953
|
+
chalk.gray('2. Server: Streams AUDIO via TCP tunnel (port 14713)\n') +
|
|
954
|
+
chalk.gray('3. Your device: PulseAudio receives and plays audio\n\n') +
|
|
955
|
+
chalk.white('Requirements:\n') +
|
|
956
|
+
chalk.yellow('⚠️ PulseAudio must be installed on BOTH devices\n') +
|
|
957
|
+
chalk.yellow('⚠️ SSH tunnel or network route to port 14713\n\n') +
|
|
958
|
+
chalk.white('Manual Setup Required:\n') +
|
|
959
|
+
chalk.gray('On Server:\n') +
|
|
960
|
+
chalk.white(' export PULSE_SERVER=tcp:localhost:14713\n') +
|
|
961
|
+
chalk.white(' (Add to ~/.bashrc for persistence)\n\n') +
|
|
962
|
+
chalk.gray('On Your Local Machine:\n') +
|
|
963
|
+
chalk.white(' ssh -R 14713:localhost:4713 your-server\n\n') +
|
|
964
|
+
chalk.cyan('📖 Full guide: ') + chalk.blue('docs/remote-audio-setup.md\n\n') +
|
|
965
|
+
chalk.yellow('💡 Tip: ') + chalk.gray('PulseAudio works best on local networks.\n') +
|
|
966
|
+
chalk.gray(' For mobile/remote, consider SSH-Remote instead.'),
|
|
967
|
+
{
|
|
968
|
+
padding: 1,
|
|
969
|
+
margin: { top: 0, bottom: 0, left: 0, right: 0 },
|
|
970
|
+
borderStyle: 'round',
|
|
971
|
+
borderColor: 'blue',
|
|
972
|
+
width: 80
|
|
973
|
+
}
|
|
974
|
+
));
|
|
975
|
+
console.log('');
|
|
976
|
+
}
|
|
977
|
+
|
|
748
978
|
} else if (currentPage === 2) {
|
|
749
979
|
// Page 3: Voice Selection
|
|
980
|
+
// Provider-aware voice selection introduction
|
|
981
|
+
let voiceIntroMessage = '';
|
|
982
|
+
if (config.provider === 'soprano') {
|
|
983
|
+
voiceIntroMessage = chalk.white('Soprano Voice Configuration\n\n') +
|
|
984
|
+
chalk.gray('Soprano has a single premium neural voice.\n') +
|
|
985
|
+
chalk.gray('Voice details and specifications shown below.');
|
|
986
|
+
} else if (config.provider === 'piper') {
|
|
987
|
+
voiceIntroMessage = chalk.white('Choose a default voice for your AgentVibes.\n\n') +
|
|
988
|
+
chalk.gray('Piper offers 50+ voices in 18+ languages.\n') +
|
|
989
|
+
chalk.gray('You can change this anytime with: ') + chalk.cyan('/agent-vibes:voice switch <name>');
|
|
990
|
+
} else if (config.provider === 'macos') {
|
|
991
|
+
voiceIntroMessage = chalk.white('Choose a default voice for your AgentVibes.\n\n') +
|
|
992
|
+
chalk.gray('macOS includes 100+ built-in voices.\n') +
|
|
993
|
+
chalk.gray('You can change this anytime with: ') + chalk.cyan('/agent-vibes:voice switch <name>');
|
|
994
|
+
} else {
|
|
995
|
+
voiceIntroMessage = chalk.white('Choose a default voice for your AgentVibes.\n\n') +
|
|
996
|
+
chalk.gray('This will be used when no specific voice is configured.\n') +
|
|
997
|
+
chalk.gray('You can change this anytime with: ') + chalk.cyan('/agent-vibes:voice switch <name>');
|
|
998
|
+
}
|
|
999
|
+
|
|
750
1000
|
console.log(boxen(
|
|
751
|
-
|
|
752
|
-
chalk.gray('This will be used when no specific voice is configured.\n') +
|
|
753
|
-
chalk.gray('You can change this anytime with: ') + chalk.cyan('/agent-vibes:voice switch <name>'),
|
|
1001
|
+
voiceIntroMessage,
|
|
754
1002
|
{
|
|
755
1003
|
padding: 1,
|
|
756
1004
|
margin: { top: 0, bottom: 0, left: 0, right: 0 },
|
|
@@ -840,6 +1088,36 @@ async function collectConfiguration(options = {}) {
|
|
|
840
1088
|
continue;
|
|
841
1089
|
}
|
|
842
1090
|
|
|
1091
|
+
} else if (config.provider === 'soprano') {
|
|
1092
|
+
// Soprano TTS - single voice model
|
|
1093
|
+
console.log(boxen(
|
|
1094
|
+
chalk.magenta.bold('⚡ Soprano TTS Voice\n\n') +
|
|
1095
|
+
chalk.white('Soprano is a single-speaker neural TTS model.\n\n') +
|
|
1096
|
+
chalk.cyan('Voice Details:\n') +
|
|
1097
|
+
chalk.gray(' • Model: ') + chalk.white('Soprano-1.1-80M\n') +
|
|
1098
|
+
chalk.gray(' • Language: ') + chalk.white('English (en_US)\n') +
|
|
1099
|
+
chalk.gray(' • Gender: ') + chalk.white('Female\n') +
|
|
1100
|
+
chalk.gray(' • Quality: ') + chalk.white('Premium neural voice\n') +
|
|
1101
|
+
chalk.gray(' • Speed: ') + chalk.white('20x CPU, 2000x GPU (if available)\n\n') +
|
|
1102
|
+
chalk.yellow('💡 ') + chalk.white('Only one voice available - automatically selected.\n') +
|
|
1103
|
+
chalk.gray(' For multiple voices, consider switching to Piper (50+ voices).'),
|
|
1104
|
+
{
|
|
1105
|
+
padding: 1,
|
|
1106
|
+
margin: { top: 0, bottom: 0, left: 0, right: 0 },
|
|
1107
|
+
borderStyle: 'round',
|
|
1108
|
+
borderColor: 'magenta',
|
|
1109
|
+
width: 80
|
|
1110
|
+
}
|
|
1111
|
+
));
|
|
1112
|
+
|
|
1113
|
+
// Auto-set the single Soprano voice
|
|
1114
|
+
config.defaultVoice = 'soprano-default';
|
|
1115
|
+
console.log(chalk.green('\n✓ Voice: Soprano-1.1-80M (auto-selected)\n'));
|
|
1116
|
+
|
|
1117
|
+
// Auto-advance to next page
|
|
1118
|
+
currentPage++;
|
|
1119
|
+
continue;
|
|
1120
|
+
|
|
843
1121
|
} else if (config.provider === 'termux-ssh' || config.provider === 'ssh-pulseaudio') {
|
|
844
1122
|
// Termux SSH - voices are managed on Android device
|
|
845
1123
|
console.log(boxen(
|
|
@@ -1242,18 +1520,19 @@ function showWelcome() {
|
|
|
1242
1520
|
* Shown during install and update commands
|
|
1243
1521
|
*/
|
|
1244
1522
|
function getReleaseInfoBoxen() {
|
|
1245
|
-
return chalk.cyan.bold('📦 AgentVibes v3.
|
|
1523
|
+
return chalk.cyan.bold('📦 AgentVibes v3.4.0 - Soprano TTS & Security Hardening\n\n') +
|
|
1246
1524
|
chalk.green.bold('🎙️ WHAT\'S NEW:\n\n') +
|
|
1247
|
-
chalk.cyan('AgentVibes v3.
|
|
1248
|
-
chalk.cyan('
|
|
1249
|
-
chalk.cyan('
|
|
1250
|
-
chalk.cyan('
|
|
1525
|
+
chalk.cyan('AgentVibes v3.4.0 introduces Soprano TTS - an 80M parameter neural provider with 20x CPU\n') +
|
|
1526
|
+
chalk.cyan('and 2000x GPU acceleration - plus comprehensive security hardening (timeouts, bounds checking,\n') +
|
|
1527
|
+
chalk.cyan('NaN validation) and intelligent environment detection that recognizes PulseAudio tunnels as\n') +
|
|
1528
|
+
chalk.cyan('working audio for remote scenarios. Enhanced installer provides GPU-based recommendations.\n\n') +
|
|
1529
|
+
chalk.yellow('🙏 Special thanks to community member @nathanchase for contributing Soprano TTS!\n\n') +
|
|
1251
1530
|
chalk.green.bold('✨ KEY HIGHLIGHTS:\n\n') +
|
|
1252
|
-
chalk.gray('
|
|
1253
|
-
chalk.gray('
|
|
1254
|
-
chalk.gray('
|
|
1255
|
-
chalk.gray('
|
|
1256
|
-
chalk.gray('
|
|
1531
|
+
chalk.gray(' ⚡ Soprano TTS Provider - Ultra-fast neural TTS with GPU acceleration (thanks @nathanchase!)\n') +
|
|
1532
|
+
chalk.gray(' 🛡️ Security Hardening - 9.5/10 score with timeouts and comprehensive validation\n') +
|
|
1533
|
+
chalk.gray(' 🌐 Environment Intelligence - PulseAudio tunnel auto-detection for SSH scenarios\n') +
|
|
1534
|
+
chalk.gray(' 🎯 Smart Recommendations - GPU/RAM-based provider suggestions\n') +
|
|
1535
|
+
chalk.gray(' 🧪 260/260 Tests Passing - Complete test coverage with fixed edge cases\n\n') +
|
|
1257
1536
|
chalk.gray('📖 Full Release Notes: RELEASE_NOTES.md\n') +
|
|
1258
1537
|
chalk.gray('🌐 Website: https://agentvibes.org\n') +
|
|
1259
1538
|
chalk.gray('📦 Repository: https://github.com/paulpreibisch/AgentVibes\n\n') +
|
|
@@ -1572,6 +1851,12 @@ async function promptProviderSelection(options) {
|
|
|
1572
1851
|
value: 'piper',
|
|
1573
1852
|
});
|
|
1574
1853
|
|
|
1854
|
+
// Soprano TTS (all platforms)
|
|
1855
|
+
choices.push({
|
|
1856
|
+
name: chalk.magenta('⚡ Soprano TTS (Ultra-Fast)') + chalk.gray(' - 1 premium voice, 20x faster, <1GB memory'),
|
|
1857
|
+
value: 'soprano',
|
|
1858
|
+
});
|
|
1859
|
+
|
|
1575
1860
|
// Termux SSH (all platforms)
|
|
1576
1861
|
choices.push({
|
|
1577
1862
|
name: chalk.blue('📱 Termux SSH (Android)') + chalk.gray(' - Only choose if your project is on a remote server and you want audio sent to your Android device. See: github.com/paulpreibisch/AgentVibes/blob/master/.claude/docs/TERMUX_SETUP.md'),
|
|
@@ -3351,7 +3636,14 @@ async function install(options = {}) {
|
|
|
3351
3636
|
const preInstallPages = [];
|
|
3352
3637
|
|
|
3353
3638
|
// Page 1: Configuration Summary
|
|
3354
|
-
const providerLabels = {
|
|
3639
|
+
const providerLabels = {
|
|
3640
|
+
piper: 'Piper TTS',
|
|
3641
|
+
macos: 'macOS Say',
|
|
3642
|
+
soprano: 'Soprano TTS',
|
|
3643
|
+
'termux-ssh': 'Termux SSH (Android)',
|
|
3644
|
+
'ssh-pulseaudio': 'PulseAudio Tunnel',
|
|
3645
|
+
pulseaudio: 'PulseAudio Tunnel'
|
|
3646
|
+
};
|
|
3355
3647
|
const reverbLabels = {
|
|
3356
3648
|
off: 'Off',
|
|
3357
3649
|
light: 'Light',
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.30
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
enabled
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
enabled
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.3
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
high
|