agentvibes 5.7.1 → 5.7.3
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/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://github.com/paulpreibisch/AgentVibes/actions/workflows/publish.yml)
|
|
12
12
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
13
13
|
|
|
14
|
-
**Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v5.7.
|
|
14
|
+
**Author**: Paul Preibisch ([@997Fire](https://x.com/997Fire)) | **Version**: v5.7.3
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "agentvibes",
|
|
4
|
-
"version": "5.7.
|
|
4
|
+
"version": "5.7.3",
|
|
5
5
|
"description": "Now your AI Agents can finally talk back! Professional TTS voice for Claude Code, Claude Desktop (via MCP), and Clawdbot with multi-provider support.",
|
|
6
6
|
"homepage": "https://agentvibes.org",
|
|
7
7
|
"keywords": [
|
package/src/console/audio-env.js
CHANGED
|
@@ -109,6 +109,29 @@ function _detect(players, env) {
|
|
|
109
109
|
return null;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Detect the first LLM configured with remote transport in
|
|
114
|
+
* ~/.agentvibes/transport-config.json.
|
|
115
|
+
*
|
|
116
|
+
* Returns the LLM key (e.g. "claude-code") whose `mode` is "remote", or
|
|
117
|
+
* null if no such entry exists or the file is absent/invalid.
|
|
118
|
+
* Used by TUI voice-preview functions to route audio through the correct
|
|
119
|
+
* SSH transport rather than playing locally.
|
|
120
|
+
*
|
|
121
|
+
* @returns {string|null}
|
|
122
|
+
*/
|
|
123
|
+
export function detectRemoteLlm() {
|
|
124
|
+
const cfgPath = path.join(os.homedir(), '.agentvibes', 'transport-config.json');
|
|
125
|
+
if (!fs.existsSync(cfgPath)) return null;
|
|
126
|
+
try {
|
|
127
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
|
|
128
|
+
for (const [llm, opts] of Object.entries(cfg)) {
|
|
129
|
+
if (opts && opts.mode === 'remote') return llm;
|
|
130
|
+
}
|
|
131
|
+
} catch {}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
112
135
|
/**
|
|
113
136
|
* Detect the best available MP3 player.
|
|
114
137
|
* On Windows, falls back to ffplay/mpv if installed, otherwise null.
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
PIPER_VOICES_DIR, SAMPLE_PHRASES,
|
|
19
19
|
parseMultiSpeaker, scanInstalledVoices, getVoiceMeta, genderIconTag,
|
|
20
20
|
} from './voices-tab.js';
|
|
21
|
-
import { buildAudioEnv, detectWavPlayer } from '../audio-env.js';
|
|
21
|
+
import { buildAudioEnv, detectWavPlayer, detectRemoteLlm } from '../audio-env.js';
|
|
22
22
|
import { destroyList } from '../widgets/destroy-list.js';
|
|
23
23
|
import { BRAND_PINK } from '../brand-colors.js';
|
|
24
24
|
import { t } from '../../i18n/strings.js';
|
|
@@ -1031,64 +1031,35 @@ ${_tl('bmadDesc')}
|
|
|
1031
1031
|
if (_previewVoiceId === voiceId) { _killVP(); vpPreviewLine.setContent(''); screen.render(); return; }
|
|
1032
1032
|
_killVP();
|
|
1033
1033
|
|
|
1034
|
-
const _isWin = process.platform === 'win32' && !process.env.WSL_DISTRO_NAME;
|
|
1035
|
-
|
|
1036
|
-
const _ms = parseMultiSpeaker(voiceId);
|
|
1037
|
-
const voicePath = path.resolve(PIPER_VOICES_DIR, _ms.model + '.onnx');
|
|
1038
|
-
const safeBase = path.resolve(PIPER_VOICES_DIR);
|
|
1039
|
-
if (!voicePath.startsWith(safeBase + path.sep) && voicePath !== safeBase) return;
|
|
1040
|
-
|
|
1041
|
-
const tempWav = _secureTempWav('vp');
|
|
1042
1034
|
const phrase = SAMPLE_PHRASES[Math.floor(Math.random() * SAMPLE_PHRASES.length)];
|
|
1035
|
+
const playTtsScript = path.join(_projectRoot, '.claude', 'hooks', 'play-tts.sh');
|
|
1036
|
+
if (!fs.existsSync(playTtsScript)) return;
|
|
1043
1037
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
if (
|
|
1047
|
-
const _lad = process.env.LOCALAPPDATA ||
|
|
1048
|
-
(process.env.USERPROFILE ? path.join(process.env.USERPROFILE, 'AppData', 'Local') : null);
|
|
1049
|
-
if (_lad) {
|
|
1050
|
-
const _ep = path.join(_lad, 'Programs', 'Piper', 'piper.exe');
|
|
1051
|
-
if (fs.existsSync(_ep)) _piperBin = _ep;
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1038
|
+
const remoteLlm = detectRemoteLlm();
|
|
1039
|
+
const args = [playTtsScript, phrase, voiceId];
|
|
1040
|
+
if (remoteLlm) args.push('--llm', remoteLlm);
|
|
1054
1041
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
stdio: ['pipe', 'ignore', 'ignore'],
|
|
1059
|
-
detached: !_isWin,
|
|
1060
|
-
windowsHide: true,
|
|
1042
|
+
_previewProc = spawn('bash', args, {
|
|
1043
|
+
stdio: 'ignore',
|
|
1044
|
+
detached: true,
|
|
1061
1045
|
env: _spawnEnv,
|
|
1046
|
+
cwd: _projectRoot,
|
|
1062
1047
|
});
|
|
1063
|
-
piper.stdin.write(phrase + '\n');
|
|
1064
|
-
piper.stdin.end();
|
|
1065
|
-
_previewProc = piper;
|
|
1066
1048
|
_previewVoiceId = voiceId;
|
|
1067
1049
|
|
|
1068
1050
|
if (!_vpClosed) {
|
|
1069
|
-
vpPreviewLine.setContent(`{bright-cyan-fg}♪
|
|
1051
|
+
vpPreviewLine.setContent(`{bright-cyan-fg}♪ Playing: ${voiceId}...{/bright-cyan-fg}`);
|
|
1070
1052
|
screen.render();
|
|
1071
1053
|
}
|
|
1072
1054
|
|
|
1073
|
-
|
|
1074
|
-
if (_previewVoiceId
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
stdio: 'ignore',
|
|
1080
|
-
detached: !_isWin,
|
|
1081
|
-
windowsHide: true,
|
|
1082
|
-
env: _spawnEnv,
|
|
1083
|
-
});
|
|
1084
|
-
_previewProc = pp;
|
|
1085
|
-
if (!_vpClosed) { vpPreviewLine.setContent(`{bright-cyan-fg}♪ Playing: ${voiceId}{/bright-cyan-fg}`); screen.render(); }
|
|
1086
|
-
pp.on('exit', () => {
|
|
1087
|
-
if (_previewVoiceId === voiceId) { _previewVoiceId = null; _previewProc = null; if (!_vpClosed) { vpPreviewLine.setContent(''); screen.render(); } }
|
|
1088
|
-
try { fs.unlinkSync(tempWav); } catch {}
|
|
1089
|
-
});
|
|
1055
|
+
_previewProc.on('exit', () => {
|
|
1056
|
+
if (_previewVoiceId === voiceId) {
|
|
1057
|
+
_previewVoiceId = null;
|
|
1058
|
+
_previewProc = null;
|
|
1059
|
+
if (!_vpClosed) { vpPreviewLine.setContent(''); screen.render(); }
|
|
1060
|
+
}
|
|
1090
1061
|
});
|
|
1091
|
-
|
|
1062
|
+
_previewProc.on('error', () => { _previewProc = null; _previewVoiceId = null; });
|
|
1092
1063
|
}
|
|
1093
1064
|
|
|
1094
1065
|
vpList.key(['enter'], () => {
|
|
@@ -1220,8 +1191,10 @@ ${_tl('bmadDesc')}
|
|
|
1220
1191
|
const _spawnEnv = buildAudioEnv();
|
|
1221
1192
|
const scriptDir = path.join(_projectRoot, '.claude', 'hooks');
|
|
1222
1193
|
const plainScript = path.join(scriptDir, 'play-tts.sh');
|
|
1194
|
+
const remoteLlm = detectRemoteLlm();
|
|
1223
1195
|
const args = [plainScript, phrase];
|
|
1224
1196
|
if (voiceId) args.push(voiceId);
|
|
1197
|
+
if (remoteLlm) args.push('--llm', remoteLlm);
|
|
1225
1198
|
|
|
1226
1199
|
const proc = spawn('bash', args, {
|
|
1227
1200
|
stdio: ['ignore', 'ignore', 'ignore'],
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
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';
|
|
27
|
-
import { buildAudioEnv, detectWavPlayer } from '../audio-env.js';
|
|
27
|
+
import { buildAudioEnv, detectWavPlayer, detectRemoteLlm } from '../audio-env.js';
|
|
28
28
|
import { destroyList } from '../widgets/destroy-list.js';
|
|
29
29
|
import { openReverbPicker } from '../widgets/reverb-picker.js';
|
|
30
30
|
import { openPersonalityPicker } from '../widgets/personality-picker.js';
|
|
@@ -633,61 +633,35 @@ export function createSettingsTab(screen, services) {
|
|
|
633
633
|
if (_previewVoiceId === voiceId) { _killVP(); vpPreviewLine.setContent(''); _refreshVP(); return; }
|
|
634
634
|
_killVP();
|
|
635
635
|
|
|
636
|
-
const _ms = parseMultiSpeaker(voiceId);
|
|
637
|
-
const voicePath = path.resolve(PIPER_VOICES_DIR, _ms.model + '.onnx');
|
|
638
|
-
const safeBase = path.resolve(PIPER_VOICES_DIR);
|
|
639
|
-
if (!voicePath.startsWith(safeBase + path.sep) && voicePath !== safeBase) return;
|
|
640
|
-
|
|
641
|
-
const tempWav = _secureTempWav('vp');
|
|
642
636
|
const phrase = SAMPLE_PHRASES[Math.floor(Math.random() * SAMPLE_PHRASES.length)];
|
|
637
|
+
const playTtsScript = path.join(_projectRoot, '.claude', 'hooks', 'play-tts.sh');
|
|
638
|
+
if (!fs.existsSync(playTtsScript)) return;
|
|
643
639
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
(process.env.USERPROFILE ? path.join(process.env.USERPROFILE, 'AppData', 'Local') : null);
|
|
648
|
-
if (_lad) {
|
|
649
|
-
const _ep = path.join(_lad, 'Programs', 'Piper', 'piper.exe');
|
|
650
|
-
if (fs.existsSync(_ep)) _piperBin = _ep;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
640
|
+
const remoteLlm = detectRemoteLlm();
|
|
641
|
+
const args = [playTtsScript, phrase, voiceId];
|
|
642
|
+
if (remoteLlm) args.push('--llm', remoteLlm);
|
|
653
643
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
stdio: ['pipe', 'ignore', 'ignore'],
|
|
658
|
-
detached: !_isWin,
|
|
659
|
-
windowsHide: true,
|
|
644
|
+
_previewProc = spawn('bash', args, {
|
|
645
|
+
stdio: 'ignore',
|
|
646
|
+
detached: true,
|
|
660
647
|
env: _spawnEnv,
|
|
648
|
+
cwd: _projectRoot,
|
|
661
649
|
});
|
|
662
|
-
piper.stdin.write(phrase + '\n');
|
|
663
|
-
piper.stdin.end();
|
|
664
|
-
_previewProc = piper;
|
|
665
650
|
_previewVoiceId = voiceId;
|
|
666
651
|
|
|
667
652
|
if (!_vpClosed) {
|
|
668
|
-
vpPreviewLine.setContent(`{cyan-fg}♪
|
|
653
|
+
vpPreviewLine.setContent(`{cyan-fg}♪ Playing: ${voiceId}...{/cyan-fg}`);
|
|
669
654
|
_refreshVP();
|
|
670
655
|
}
|
|
671
656
|
|
|
672
|
-
|
|
673
|
-
if (_previewVoiceId
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
stdio: 'ignore',
|
|
679
|
-
detached: !_isWin,
|
|
680
|
-
windowsHide: true,
|
|
681
|
-
env: _spawnEnv,
|
|
682
|
-
});
|
|
683
|
-
_previewProc = pp;
|
|
684
|
-
if (!_vpClosed) { vpPreviewLine.setContent(`{cyan-fg}♪ Playing: ${voiceId}{/cyan-fg}`); screen.render(); }
|
|
685
|
-
pp.on('exit', () => {
|
|
686
|
-
if (_previewVoiceId === voiceId) { _previewVoiceId = null; _previewProc = null; if (!_vpClosed) { vpPreviewLine.setContent(''); _refreshVP(); } }
|
|
687
|
-
try { fs.unlinkSync(tempWav); } catch {}
|
|
688
|
-
});
|
|
657
|
+
_previewProc.on('exit', () => {
|
|
658
|
+
if (_previewVoiceId === voiceId) {
|
|
659
|
+
_previewVoiceId = null;
|
|
660
|
+
_previewProc = null;
|
|
661
|
+
if (!_vpClosed) { vpPreviewLine.setContent(''); _refreshVP(); }
|
|
662
|
+
}
|
|
689
663
|
});
|
|
690
|
-
|
|
664
|
+
_previewProc.on('error', () => { _previewProc = null; _previewVoiceId = null; });
|
|
691
665
|
}
|
|
692
666
|
|
|
693
667
|
vpList.key(['enter'], () => {
|
|
@@ -10,7 +10,7 @@ import fs from 'node:fs';
|
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import { spawn } from 'node:child_process';
|
|
12
12
|
import { destroyList } from './destroy-list.js';
|
|
13
|
-
import { buildAudioEnv } from '../audio-env.js';
|
|
13
|
+
import { buildAudioEnv, detectRemoteLlm } from '../audio-env.js';
|
|
14
14
|
import { BRAND_PINK } from '../brand-colors.js';
|
|
15
15
|
import { PERSONALITY_EMOJIS, PERSONALITIES } from '../constants/personalities.js';
|
|
16
16
|
|
|
@@ -138,7 +138,10 @@ export function openPersonalityPicker(screen, currentPersonality, onSelect, onCl
|
|
|
138
138
|
});
|
|
139
139
|
} else {
|
|
140
140
|
const ttsScript = path.join(process.cwd(), '.claude', 'hooks', 'play-tts.sh');
|
|
141
|
-
|
|
141
|
+
const remoteLlm = detectRemoteLlm();
|
|
142
|
+
const ttsArgs = [ttsScript, phrase];
|
|
143
|
+
if (remoteLlm) ttsArgs.push('--llm', remoteLlm);
|
|
144
|
+
_pickerTtsProc = spawn('bash', ttsArgs, {
|
|
142
145
|
stdio: 'ignore',
|
|
143
146
|
detached: true,
|
|
144
147
|
env: _env,
|