agentvibes 5.3.0 → 5.5.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/LITE-MODE.md +236 -0
- package/.agentvibes/README.md +136 -0
- package/.agentvibes/backup/session-start-tts.sh.20251210_212814 +141 -0
- package/.agentvibes/backups/agents/analyst_20260204_144958.md +78 -0
- package/.agentvibes/backups/agents/architect_20260204_144958.md +72 -0
- package/.agentvibes/backups/agents/dev_20260204_144958.md +74 -0
- package/.agentvibes/backups/agents/pm_20260204_144958.md +72 -0
- package/.agentvibes/backups/agents/quick-flow-solo-dev_20260204_144958.md +64 -0
- package/.agentvibes/backups/agents/sm_20260204_144958.md +87 -0
- package/.agentvibes/backups/agents/tea_20260204_144958.md +79 -0
- package/.agentvibes/backups/agents/tech-writer_20260204_144958.md +82 -0
- package/.agentvibes/backups/agents/ux-designer_20260204_144958.md +80 -0
- package/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config/README-personality-defaults.md +162 -0
- package/.agentvibes/config/mode.txt +1 -0
- package/.agentvibes/config/personality-voice-defaults.default.json +21 -0
- package/.agentvibes/config/save-audio.txt +1 -0
- package/.agentvibes/config/voice-metadata.json +160 -0
- package/.agentvibes/config.json +24 -15
- package/.agentvibes/hooks/help.sh +191 -0
- package/.agentvibes/hooks/post-tool-use-lite.sh +111 -0
- package/.agentvibes/hooks/save-audio-manager.sh +162 -0
- package/.agentvibes/hooks/session-start-full-optimized.sh +102 -0
- package/.agentvibes/hooks/session-start-full.sh +142 -0
- package/.agentvibes/hooks/session-start-lite-v2.sh +34 -0
- package/.agentvibes/hooks/session-start-lite.sh +29 -0
- package/.agentvibes/hooks/stop-lite.sh +115 -0
- package/.agentvibes/hooks/switch-mode.sh +215 -0
- package/.agentvibes/output-styles/audio-summary.md +30 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/voice-samples/piper/alan.wav +0 -0
- package/.claude/audio/voice-samples/piper/amy.wav +0 -0
- package/.claude/audio/voice-samples/piper/charlotte.wav +0 -0
- package/.claude/audio/voice-samples/piper/joe.wav +0 -0
- package/.claude/audio/voice-samples/piper/john.wav +0 -0
- package/.claude/audio/voice-samples/piper/katherine.wav +0 -0
- package/.claude/audio/voice-samples/piper/kristin.wav +0 -0
- package/.claude/audio/voice-samples/piper/linda.wav +0 -0
- package/.claude/audio/voice-samples/piper/marcus.wav +0 -0
- package/.claude/audio/voice-samples/piper/ryan.wav +0 -0
- package/.claude/commands/agent-vibes/add.md +21 -21
- package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
- package/.claude/commands/agent-vibes/agent.md +79 -79
- package/.claude/commands/agent-vibes/background-music.md +111 -111
- package/.claude/commands/agent-vibes/bmad.md +198 -198
- package/.claude/commands/agent-vibes/clean.md +18 -18
- package/.claude/commands/agent-vibes/cleanup.md +18 -18
- package/.claude/commands/agent-vibes/commands.json +145 -145
- package/.claude/commands/agent-vibes/effects.md +97 -97
- package/.claude/commands/agent-vibes/get.md +9 -9
- package/.claude/commands/agent-vibes/hide.md +91 -91
- package/.claude/commands/agent-vibes/language.md +23 -23
- package/.claude/commands/agent-vibes/learn.md +67 -67
- package/.claude/commands/agent-vibes/list.md +13 -13
- package/.claude/commands/agent-vibes/mute.md +37 -37
- package/.claude/commands/agent-vibes/preview.md +17 -17
- package/.claude/commands/agent-vibes/provider.md +68 -68
- package/.claude/commands/agent-vibes/replay-target.md +14 -14
- package/.claude/commands/agent-vibes/sample.md +12 -12
- package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
- package/.claude/commands/agent-vibes/set-pretext.md +65 -65
- package/.claude/commands/agent-vibes/set-speed.md +41 -41
- package/.claude/commands/agent-vibes/show.md +84 -84
- package/.claude/commands/agent-vibes/switch.md +87 -87
- package/.claude/commands/agent-vibes/target-voice.md +26 -26
- package/.claude/commands/agent-vibes/target.md +30 -30
- package/.claude/commands/agent-vibes/translate.md +68 -68
- package/.claude/commands/agent-vibes/unmute.md +45 -45
- package/.claude/commands/agent-vibes/whoami.md +7 -7
- 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 +16 -11
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-position.txt +27 -0
- package/.claude/config/background-music-volume.txt +1 -1
- package/.claude/config/background-music.cfg +1 -0
- package/.claude/config/background-music.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +1 -4
- package/.claude/config/tts-verbosity.txt +1 -0
- package/.claude/docs/TERMUX_SETUP.md +408 -408
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/README-TTS-QUEUE.md +135 -135
- package/.claude/hooks/audio-cache-utils.sh +0 -0
- package/.claude/hooks/audio-processor.sh +60 -14
- package/.claude/hooks/background-music-manager.sh +0 -0
- package/.claude/hooks/bmad-party-manager.sh +225 -0
- package/.claude/hooks/bmad-party-speak.sh +0 -0
- package/.claude/hooks/bmad-speak-enhanced.sh +0 -0
- package/.claude/hooks/bmad-speak.sh +12 -15
- package/.claude/hooks/bmad-tts-injector.sh +0 -0
- package/.claude/hooks/bmad-voice-manager.sh +0 -0
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +25 -23
- package/.claude/hooks/clawdbot-receiver.sh +4 -28
- package/.claude/hooks/clean-audio-cache.sh +0 -0
- package/.claude/hooks/cleanup-cache.sh +0 -0
- package/.claude/hooks/configure-rdp-mode.sh +0 -0
- package/.claude/hooks/download-extra-voices.sh +0 -0
- package/.claude/hooks/effects-manager.sh +0 -0
- package/.claude/hooks/github-star-reminder.sh +0 -0
- package/.claude/hooks/language-manager.sh +0 -0
- package/.claude/hooks/learn-manager.sh +0 -0
- package/.claude/hooks/macos-voice-manager.sh +0 -0
- package/.claude/hooks/migrate-background-music.sh +0 -0
- package/.claude/hooks/migrate-to-agentvibes.sh +0 -0
- package/.claude/hooks/optimize-background-music.sh +0 -0
- package/.claude/hooks/personality-manager.sh +0 -0
- package/.claude/hooks/piper-download-voices.sh +0 -0
- package/.claude/hooks/piper-installer.sh +1 -1
- package/.claude/hooks/piper-multispeaker-registry.sh +0 -0
- package/.claude/hooks/piper-voice-manager.sh +0 -0
- package/.claude/hooks/play-tts-enhanced.sh +0 -0
- package/.claude/hooks/play-tts-macos.sh +6 -12
- package/.claude/hooks/play-tts-piper.sh +52 -81
- package/.claude/hooks/play-tts-soprano.sh +9 -43
- package/.claude/hooks/play-tts-ssh-remote.sh +43 -215
- package/.claude/hooks/play-tts-termux-ssh.sh +0 -0
- package/.claude/hooks/play-tts.sh +41 -20
- package/.claude/hooks/post-response.sh +41 -0
- package/.claude/hooks/prepare-release.sh +0 -0
- package/.claude/hooks/provider-commands.sh +0 -0
- package/.claude/hooks/provider-manager.sh +0 -0
- package/.claude/hooks/replay-target-audio.sh +0 -0
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +0 -0
- package/.claude/hooks/session-start-tts.sh +56 -39
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +0 -0
- package/.claude/hooks/stop.sh +63 -0
- package/.claude/hooks/termux-installer.sh +0 -0
- package/.claude/hooks/translate-manager.sh +0 -0
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +0 -0
- package/.claude/hooks/tts-queue.sh +0 -0
- package/.claude/hooks/verbosity-manager.sh +0 -0
- package/.claude/hooks/voice-manager.sh +26 -4
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/bmad-party-speak.ps1 +278 -278
- package/.claude/hooks-windows/bmad-speak.ps1 +264 -264
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -53
- package/.claude/hooks-windows/effects-manager.ps1 +294 -294
- package/.claude/hooks-windows/language-manager.ps1 +193 -193
- package/.claude/hooks-windows/learn-manager.ps1 +241 -241
- package/.claude/hooks-windows/personality-manager.ps1 +266 -266
- package/.claude/hooks-windows/play-tts-soprano.ps1 +5 -5
- package/.claude/hooks-windows/play-tts-termux-ssh.ps1 +138 -138
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +178 -0
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts.ps1 +265 -507
- package/.claude/hooks-windows/provider-manager.ps1 +158 -192
- package/.claude/hooks-windows/session-start-tts.ps1 +55 -46
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -166
- package/.claude/hooks-windows/voice-manager-windows.ps1 +176 -260
- package/.claude/output-styles/agent-vibes.md +202 -202
- package/.claude/personalities/angry.md +14 -14
- package/.claude/personalities/annoying.md +14 -14
- package/.claude/personalities/crass.md +14 -14
- package/.claude/personalities/dramatic.md +14 -14
- package/.claude/personalities/dry-humor.md +50 -50
- package/.claude/personalities/flirty.md +20 -20
- package/.claude/personalities/funny.md +14 -14
- package/.claude/personalities/grandpa.md +32 -32
- package/.claude/personalities/millennial.md +14 -14
- package/.claude/personalities/moody.md +14 -14
- package/.claude/personalities/normal.md +16 -16
- package/.claude/personalities/pirate.md +14 -14
- package/.claude/personalities/poetic.md +14 -14
- package/.claude/personalities/professional.md +14 -14
- package/.claude/personalities/rapper.md +55 -55
- package/.claude/personalities/robot.md +14 -14
- package/.claude/personalities/sarcastic.md +38 -38
- package/.claude/personalities/sassy.md +14 -14
- package/.claude/personalities/surfer-dude.md +14 -14
- package/.claude/personalities/zen.md +14 -14
- package/.claude/piper-voices-dir.txt +1 -0
- package/.claude/settings.json +25 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +149 -145
- package/.mcp.json +30 -11
- package/CLAUDE.md +170 -215
- package/README.md +207 -521
- package/RELEASE_NOTES.md +1172 -1976
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +0 -0
- package/bin/agentvibes-voice-browser.js +64 -1289
- package/bin/agentvibes.js +28 -0
- package/bin/ensure-soprano-running.sh +43 -0
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +0 -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/WINDOWS_SETUP.md +260 -260
- package/mcp-server/docs/troubleshooting-audio.md +313 -313
- 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/install-deps.js +130 -130
- package/mcp-server/pyproject.toml +52 -52
- package/mcp-server/requirements.txt +2 -2
- package/mcp-server/server.py +1467 -1578
- package/mcp-server/test_server.py +395 -395
- package/package.json +1 -3
- package/setup-windows.ps1 +815 -815
- package/src/console/tabs/music-tab.js +5 -2
- package/src/console/tabs/voices-tab.js +71 -37
- package/src/installer.js +52 -5
- package/src/services/llm-provider-service.js +1 -1
- package/templates/agentvibes-receiver.sh +158 -483
- package/templates/audio/welcome-music.mp3 +0 -0
- package/.agentvibes/bmad-voice-map.json +0 -104
- package/.agentvibes/copilot-sessions.log +0 -4
- package/.claude/config/audio-effects-bmad.cfg +0 -50
- package/.claude/config/intro-text.txt +0 -1
- package/.claude/config/personality.txt +0 -1
- package/.claude/config/piper-speech-rate.txt +0 -4
- package/.claude/config/piper-target-speech-rate.txt +0 -1
- package/.claude/config/reverb-level.txt +0 -1
- package/.claude/config/tts-target-speech-rate.txt +0 -1
- package/voice-assignments.json +0 -8245
- /package/{.claude → .agentvibes}/config/agentvibes.json +0 -0
|
@@ -185,12 +185,15 @@ export function scanTracks() {
|
|
|
185
185
|
const tracksDir = _getTracksDir();
|
|
186
186
|
try {
|
|
187
187
|
const files = fs.readdirSync(tracksDir);
|
|
188
|
+
const mp3s = files.filter(f => /\.mp3$/i.test(f));
|
|
189
|
+
// If the directory exists but has no mp3s (e.g. empty npm package dir),
|
|
190
|
+
// fall back to the static catalog so bundled tracks always show.
|
|
191
|
+
if (mp3s.length === 0) return BUILT_IN_TRACK_CATALOG.map(t => ({ ...t, isBuiltIn: true }));
|
|
188
192
|
const builtInIds = new Set(BUILT_IN_TRACK_CATALOG.map(t => t.id));
|
|
189
193
|
// Sort by the alphabetic part of the label (skip leading emoji/symbols)
|
|
190
194
|
// so the order reflects the track NAME, not the emoji codepoint.
|
|
191
195
|
const _sortKey = (s) => s.replace(/^[^a-zA-Z]+/, '');
|
|
192
|
-
return
|
|
193
|
-
.filter(f => /\.mp3$/i.test(f))
|
|
196
|
+
return mp3s
|
|
194
197
|
.map(f => ({ id: f, label: formatTrackLabel(f), isBuiltIn: builtInIds.has(f) }))
|
|
195
198
|
.sort((a, b) => _sortKey(a.label).localeCompare(_sortKey(b.label), undefined, { sensitivity: 'base' }));
|
|
196
199
|
} catch {
|
|
@@ -133,6 +133,10 @@ function loadCatalog() {
|
|
|
133
133
|
// Build lookup map for O(1) access by voiceId
|
|
134
134
|
_catalogMap = new Map();
|
|
135
135
|
for (const c of _catalogEntries) _catalogMap.set(c.voiceId, c);
|
|
136
|
+
|
|
137
|
+
// Patch libritts_r onnx.json files so their speaker IDs become friendly names.
|
|
138
|
+
// Must run after catalog loads so the name mapping is available.
|
|
139
|
+
patchLibriTTSSpeakerNames();
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
/**
|
|
@@ -142,45 +146,48 @@ function loadCatalog() {
|
|
|
142
146
|
* Safe to call multiple times — skips if already patched.
|
|
143
147
|
*/
|
|
144
148
|
function patchLibriTTSSpeakerNames() {
|
|
149
|
+
// Load catalog once for all models
|
|
150
|
+
const catalogPath = path.resolve(__dirname, '..', '..', '..', 'voice-assignments.json');
|
|
151
|
+
if (!fs.existsSync(catalogPath)) return;
|
|
152
|
+
let speakers;
|
|
145
153
|
try {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
154
|
+
speakers = JSON.parse(fs.readFileSync(catalogPath, 'utf8')).libritts_speakers ?? {};
|
|
155
|
+
} catch { return; }
|
|
156
|
+
|
|
157
|
+
// Models to patch and how to detect unpatched keys:
|
|
158
|
+
// libritts-high → raw keys are p-prefixed corpus IDs (p3922, p8699, …)
|
|
159
|
+
// libritts_r-* → raw keys are plain numeric corpus IDs (3922, 8699, …)
|
|
160
|
+
const MODELS = [
|
|
161
|
+
{ file: 'en_US-libritts-high.onnx.json', notPatched: (k) => /^p\d+$/.test(k) },
|
|
162
|
+
{ file: 'en_US-libritts_r-medium.onnx.json', notPatched: (k) => /^\d+$/.test(k) },
|
|
163
|
+
{ file: 'en_US-libritts_r-high.onnx.json', notPatched: (k) => /^\d+$/.test(k) },
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for (const { file, notPatched } of MODELS) {
|
|
167
|
+
try {
|
|
168
|
+
const jsonPath = path.join(PIPER_VOICES_DIR, file);
|
|
169
|
+
if (!fs.existsSync(jsonPath)) continue;
|
|
170
|
+
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
171
|
+
if (!data.speaker_id_map || data.num_speakers <= 1) continue;
|
|
160
172
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const friendly = speakers[idx]?.voice_name;
|
|
171
|
-
if (friendly) {
|
|
172
|
-
newMap[friendly] = parseInt(idx, 10);
|
|
173
|
-
} else {
|
|
174
|
-
newMap[pname] = parseInt(idx, 10);
|
|
173
|
+
const names = Object.keys(data.speaker_id_map);
|
|
174
|
+
// Skip if already patched (first key is a friendly name, not a raw corpus ID)
|
|
175
|
+
if (names.length === 0 || !notPatched(names[0])) continue;
|
|
176
|
+
|
|
177
|
+
// Values are 0-based sequential indices into the model — use as catalog key
|
|
178
|
+
const newMap = {};
|
|
179
|
+
for (const [rawKey, idx] of Object.entries(data.speaker_id_map)) {
|
|
180
|
+
const friendly = speakers[String(idx)]?.voice_name;
|
|
181
|
+
newMap[friendly ?? rawKey] = idx;
|
|
175
182
|
}
|
|
176
|
-
}
|
|
177
183
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
data.speaker_id_map = newMap;
|
|
185
|
+
// Verify file ownership before writing (security: CLAUDE.md)
|
|
186
|
+
const stat = fs.statSync(jsonPath);
|
|
187
|
+
if (typeof process.getuid === 'function' && stat.uid !== process.getuid()) continue;
|
|
188
|
+
fs.writeFileSync(jsonPath, JSON.stringify(data, null, 2), 'utf8');
|
|
189
|
+
} catch { /* non-fatal — skip this model */ }
|
|
190
|
+
}
|
|
184
191
|
}
|
|
185
192
|
|
|
186
193
|
// Column widths for the multi-column voice list
|
|
@@ -417,9 +424,9 @@ export function parseMultiSpeaker(voiceId) {
|
|
|
417
424
|
try {
|
|
418
425
|
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
419
426
|
let speakerId = data.speaker_id_map?.[speakerName] ?? null;
|
|
420
|
-
// Fallback: if the .onnx.json still has raw
|
|
427
|
+
// Fallback: if the .onnx.json still has raw corpus IDs (not yet patched),
|
|
421
428
|
// look up the numeric speaker ID from voice-assignments.json catalog.
|
|
422
|
-
if (speakerId == null && model === 'en_US-libritts-high') {
|
|
429
|
+
if (speakerId == null && (model === 'en_US-libritts-high' || /^en_US-libritts_r-/.test(model))) {
|
|
423
430
|
try {
|
|
424
431
|
const catalogPath = path.resolve(__dirname, '..', '..', '..', 'voice-assignments.json');
|
|
425
432
|
const catalog = JSON.parse(fs.readFileSync(catalogPath, 'utf8'));
|
|
@@ -443,6 +450,9 @@ export function parseMultiSpeaker(voiceId) {
|
|
|
443
450
|
* @returns {string[]}
|
|
444
451
|
*/
|
|
445
452
|
export function scanInstalledVoices() {
|
|
453
|
+
// Ensure catalog is loaded and libritts_r onnx.json files are patched
|
|
454
|
+
// before we read their speaker_id_map keys (otherwise we get raw corpus IDs).
|
|
455
|
+
loadCatalog();
|
|
446
456
|
try {
|
|
447
457
|
const files = fs.readdirSync(PIPER_VOICES_DIR);
|
|
448
458
|
const onnxFiles = files
|
|
@@ -588,6 +598,30 @@ export function getVoiceMeta(voiceId) {
|
|
|
588
598
|
_metaCache.set(voiceId, result);
|
|
589
599
|
return result;
|
|
590
600
|
}
|
|
601
|
+
// libritts_r variants share speaker names with libritts-high after patching
|
|
602
|
+
if (/^en_US-libritts_r-/.test(ms.model)) {
|
|
603
|
+
// After patching: speakerName is a friendly name — look up in libritts-high catalog
|
|
604
|
+
const highCat = _catalogMap.get(`en_US-libritts-high${MS_SEP}${ms.speakerName}`);
|
|
605
|
+
if (highCat) {
|
|
606
|
+
const result = { displayName: highCat.displayName, gender: highCat.gender, provider: `Piper (${ms.model})` };
|
|
607
|
+
_metaCache.set(voiceId, result);
|
|
608
|
+
return result;
|
|
609
|
+
}
|
|
610
|
+
// Before patching: speakerName is a raw numeric corpus ID — resolve via onnx.json value
|
|
611
|
+
if (/^\d+$/.test(ms.speakerName)) {
|
|
612
|
+
try {
|
|
613
|
+
const jsonPath = path.join(PIPER_VOICES_DIR, ms.model + '.onnx.json');
|
|
614
|
+
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
615
|
+
const seqIdx = data.speaker_id_map?.[ms.speakerName];
|
|
616
|
+
if (seqIdx != null && _catalogEntries[seqIdx]) {
|
|
617
|
+
const cat = _catalogEntries[seqIdx];
|
|
618
|
+
const result = { displayName: cat.displayName, gender: cat.gender, provider: `Piper (${ms.model})` };
|
|
619
|
+
_metaCache.set(voiceId, result);
|
|
620
|
+
return result;
|
|
621
|
+
}
|
|
622
|
+
} catch { /* fall through */ }
|
|
623
|
+
}
|
|
624
|
+
}
|
|
591
625
|
// Fallback for speakers not in the catalog (e.g. 16Speakers model)
|
|
592
626
|
const displayName = uniquifyVoiceName(ms.speakerName.replace(/_/g, ' '));
|
|
593
627
|
const result = {
|
package/src/installer.js
CHANGED
|
@@ -132,6 +132,36 @@ function isNativeWindows() {
|
|
|
132
132
|
return process.platform === 'win32' && !process.env.WSL_DISTRO_NAME;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Wrap an ora spinner with safe fallbacks for all methods.
|
|
137
|
+
* Ensures compatibility across platforms (Windows, WSL, macOS, Linux) and ora versions.
|
|
138
|
+
* @param {Object} spinner - An ora spinner instance (or any spinner-like object)
|
|
139
|
+
* @returns {Object} A spinner proxy with guaranteed methods
|
|
140
|
+
*/
|
|
141
|
+
function createRobustSpinner(spinner) {
|
|
142
|
+
const safe = (method, fallback) => (...args) => {
|
|
143
|
+
if (typeof spinner[method] === 'function') {
|
|
144
|
+
try { spinner[method](...args); } catch { fallback?.(...args); }
|
|
145
|
+
} else {
|
|
146
|
+
fallback?.(...args);
|
|
147
|
+
}
|
|
148
|
+
return proxy;
|
|
149
|
+
};
|
|
150
|
+
const proxy = {
|
|
151
|
+
start: safe('start'),
|
|
152
|
+
stop: safe('stop'),
|
|
153
|
+
succeed: safe('succeed', (t) => { if (t) process.stdout.write(`✓ ${t}\n`); }),
|
|
154
|
+
fail: safe('fail', (t) => { if (t) process.stderr.write(`✗ ${t}\n`); }),
|
|
155
|
+
warn: safe('warn', (t) => { if (t) process.stdout.write(`⚠ ${t}\n`); }),
|
|
156
|
+
info: safe('info', (t) => { if (t) process.stdout.write(`ℹ ${t}\n`); }),
|
|
157
|
+
stopAndPersist: safe('stopAndPersist'),
|
|
158
|
+
get text() { return spinner.text ?? ''; },
|
|
159
|
+
set text(t) { try { spinner.text = t; } catch { /* non-TTY */ } },
|
|
160
|
+
get isSpinning(){ return spinner.isSpinning ?? false; },
|
|
161
|
+
};
|
|
162
|
+
return proxy;
|
|
163
|
+
}
|
|
164
|
+
|
|
135
165
|
/**
|
|
136
166
|
* Get the Piper provider name (always 'piper' on all platforms)
|
|
137
167
|
* @returns {string} The piper provider identifier
|
|
@@ -3219,6 +3249,7 @@ async function handleTermuxSshConfiguration() {
|
|
|
3219
3249
|
* @returns {Promise<{count: number, boxen: string}>} Number of files copied and boxen content
|
|
3220
3250
|
*/
|
|
3221
3251
|
async function copyCommandFiles(targetDir, spinner) {
|
|
3252
|
+
spinner = createRobustSpinner(spinner);
|
|
3222
3253
|
spinner.start('Installing /agent-vibes slash commands...');
|
|
3223
3254
|
const srcCommandsDir = path.join(__dirname, '..', '.claude', 'commands', 'agent-vibes');
|
|
3224
3255
|
const commandsDir = path.join(targetDir, '.claude', 'commands');
|
|
@@ -3432,6 +3463,7 @@ function buildHookInstallationBoxen(installedFiles, failedFiles) {
|
|
|
3432
3463
|
* @returns {Promise<{count: number, boxen: string|null}>} Number of files copied and boxen content
|
|
3433
3464
|
*/
|
|
3434
3465
|
async function copyHookFiles(targetDir, spinner) {
|
|
3466
|
+
spinner = createRobustSpinner(spinner);
|
|
3435
3467
|
spinner.start('Installing TTS helper scripts...');
|
|
3436
3468
|
const hooksSubdir = isNativeWindows() ? 'hooks-windows' : 'hooks';
|
|
3437
3469
|
const srcHooksDir = path.join(__dirname, '..', '.claude', hooksSubdir);
|
|
@@ -3486,6 +3518,7 @@ async function copyHookFiles(targetDir, spinner) {
|
|
|
3486
3518
|
* @returns {Promise<{count: number, boxen: string|null}>} Number of files copied and boxen content
|
|
3487
3519
|
*/
|
|
3488
3520
|
async function copyPersonalityFiles(targetDir, spinner) {
|
|
3521
|
+
spinner = createRobustSpinner(spinner);
|
|
3489
3522
|
spinner.start('Installing personality templates...');
|
|
3490
3523
|
const srcPersonalitiesDir = path.join(__dirname, '..', '.claude', 'personalities');
|
|
3491
3524
|
const destPersonalitiesDir = path.join(targetDir, '.claude', 'personalities');
|
|
@@ -3568,6 +3601,7 @@ async function copyPersonalityFiles(targetDir, spinner) {
|
|
|
3568
3601
|
* @returns {Promise<number>} Number of files copied
|
|
3569
3602
|
*/
|
|
3570
3603
|
async function copyPluginFiles(targetDir, spinner) {
|
|
3604
|
+
spinner = createRobustSpinner(spinner);
|
|
3571
3605
|
spinner.start('Installing BMAD plugin files...');
|
|
3572
3606
|
const srcPluginsDir = path.join(__dirname, '..', '.claude', 'plugins');
|
|
3573
3607
|
const destPluginsDir = path.join(targetDir, '.claude', 'plugins');
|
|
@@ -3602,6 +3636,7 @@ async function copyPluginFiles(targetDir, spinner) {
|
|
|
3602
3636
|
* @returns {Promise<number>} Number of files copied
|
|
3603
3637
|
*/
|
|
3604
3638
|
async function copyBmadConfigFiles(targetDir, spinner) {
|
|
3639
|
+
spinner = createRobustSpinner(spinner);
|
|
3605
3640
|
spinner.start('Installing BMAD config files...');
|
|
3606
3641
|
const srcBmadDir = path.join(__dirname, '..', '.agentvibes', 'bmad');
|
|
3607
3642
|
const destBmadDir = path.join(targetDir, '.agentvibes', 'bmad');
|
|
@@ -3634,6 +3669,7 @@ async function copyBmadConfigFiles(targetDir, spinner) {
|
|
|
3634
3669
|
* @returns {Promise<{count: number, boxen: string}>} Number of files copied and boxen content
|
|
3635
3670
|
*/
|
|
3636
3671
|
async function copyBackgroundMusicFiles(targetDir, spinner) {
|
|
3672
|
+
spinner = createRobustSpinner(spinner);
|
|
3637
3673
|
spinner.start('Installing background music tracks...');
|
|
3638
3674
|
const srcBackgroundsDir = path.join(__dirname, '..', '.claude', 'audio', 'tracks');
|
|
3639
3675
|
const destBackgroundsDir = path.join(targetDir, '.claude', 'audio', 'tracks');
|
|
@@ -3756,6 +3792,7 @@ async function copyBackgroundMusicFiles(targetDir, spinner) {
|
|
|
3756
3792
|
* @returns {Promise<number>} Number of files copied
|
|
3757
3793
|
*/
|
|
3758
3794
|
async function copyConfigFiles(targetDir, spinner) {
|
|
3795
|
+
spinner = createRobustSpinner(spinner);
|
|
3759
3796
|
spinner.start('Installing configuration files...');
|
|
3760
3797
|
const srcConfigDir = path.join(__dirname, '..', '.claude', 'config');
|
|
3761
3798
|
const destConfigDir = path.join(targetDir, '.claude', 'config');
|
|
@@ -3818,6 +3855,7 @@ async function copyConfigFiles(targetDir, spinner) {
|
|
|
3818
3855
|
* @param {Object} spinner - Ora spinner instance
|
|
3819
3856
|
*/
|
|
3820
3857
|
async function copyCodexFiles(targetDir, spinner) {
|
|
3858
|
+
spinner = createRobustSpinner(spinner);
|
|
3821
3859
|
spinner.start('Installing Codex integration files...');
|
|
3822
3860
|
const srcCodexDir = path.join(__dirname, '..', '.codex');
|
|
3823
3861
|
const destCodexDir = path.join(targetDir, '.codex');
|
|
@@ -3871,6 +3909,7 @@ async function copyCodexFiles(targetDir, spinner) {
|
|
|
3871
3909
|
* @param {Object} spinner - Ora spinner instance
|
|
3872
3910
|
*/
|
|
3873
3911
|
async function configureSessionStartHook(targetDir, spinner) {
|
|
3912
|
+
spinner = createRobustSpinner(spinner);
|
|
3874
3913
|
spinner.start('Configuring AgentVibes hook for automatic TTS...');
|
|
3875
3914
|
const claudeDir = path.join(targetDir, '.claude');
|
|
3876
3915
|
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
@@ -3926,6 +3965,7 @@ async function configureSessionStartHook(targetDir, spinner) {
|
|
|
3926
3965
|
* @param {Object} spinner - Ora spinner instance
|
|
3927
3966
|
*/
|
|
3928
3967
|
async function configurePartyModeHook(targetDir, spinner, homeDirOverride) {
|
|
3968
|
+
spinner = createRobustSpinner(spinner);
|
|
3929
3969
|
spinner.start('Configuring BMAD party mode TTS hook...');
|
|
3930
3970
|
const homeDir = homeDirOverride || os.homedir();
|
|
3931
3971
|
const globalClaudeDir = path.join(homeDir, '.claude');
|
|
@@ -4215,7 +4255,7 @@ async function checkAndInstallPiperWindows(targetDir, options) {
|
|
|
4215
4255
|
}
|
|
4216
4256
|
const piperDir = path.join(localAppData, 'Programs', 'Piper');
|
|
4217
4257
|
const piperExe = path.join(piperDir, 'piper.exe');
|
|
4218
|
-
const spinner = ora();
|
|
4258
|
+
const spinner = createRobustSpinner(ora());
|
|
4219
4259
|
|
|
4220
4260
|
if (fsSync.existsSync(piperExe)) {
|
|
4221
4261
|
console.log(chalk.green('✓ Piper TTS is already installed at ' + piperDir + '\n'));
|
|
@@ -4844,7 +4884,14 @@ async function updatePersonalityFiles(targetDir, srcPersonalitiesDir) {
|
|
|
4844
4884
|
* @returns {Object} Mock spinner object
|
|
4845
4885
|
*/
|
|
4846
4886
|
function createSilentSpinner() {
|
|
4847
|
-
const s = {
|
|
4887
|
+
const s = {
|
|
4888
|
+
start: () => s, succeed: () => s, info: () => s,
|
|
4889
|
+
fail: () => s, warn: () => s, stop: () => s,
|
|
4890
|
+
stopAndPersist: () => s,
|
|
4891
|
+
get text() { return ''; },
|
|
4892
|
+
set text(_) {},
|
|
4893
|
+
get isSpinning() { return false; },
|
|
4894
|
+
};
|
|
4848
4895
|
return s;
|
|
4849
4896
|
}
|
|
4850
4897
|
|
|
@@ -5025,7 +5072,7 @@ function displayUpdateSummary(results) {
|
|
|
5025
5072
|
* @param {Object} options - Update options
|
|
5026
5073
|
*/
|
|
5027
5074
|
async function updateAgentVibes(targetDir, options) {
|
|
5028
|
-
const spinner = ora('Updating AgentVibes...').start();
|
|
5075
|
+
const spinner = createRobustSpinner(ora('Updating AgentVibes...').start());
|
|
5029
5076
|
|
|
5030
5077
|
try {
|
|
5031
5078
|
// Perform all update operations
|
|
@@ -5145,7 +5192,7 @@ async function install(options = {}) {
|
|
|
5145
5192
|
const silentSpinner = createSilentSpinner();
|
|
5146
5193
|
|
|
5147
5194
|
console.log('');
|
|
5148
|
-
const spinner = ora('Installing AgentVibes...').start();
|
|
5195
|
+
const spinner = createRobustSpinner(ora('Installing AgentVibes...').start());
|
|
5149
5196
|
|
|
5150
5197
|
try {
|
|
5151
5198
|
// Create .claude directory structure
|
|
@@ -5599,7 +5646,7 @@ program
|
|
|
5599
5646
|
console.log(chalk.gray('✓ Auto-confirmed (--yes flag)\n'));
|
|
5600
5647
|
}
|
|
5601
5648
|
|
|
5602
|
-
const spinner = ora('Uninstalling AgentVibes...').start();
|
|
5649
|
+
const spinner = createRobustSpinner(ora('Uninstalling AgentVibes...').start());
|
|
5603
5650
|
|
|
5604
5651
|
try {
|
|
5605
5652
|
let removedCount = 0;
|
|
@@ -198,7 +198,7 @@ export async function installClaudeMcp(targetDir) {
|
|
|
198
198
|
|
|
199
199
|
try {
|
|
200
200
|
// Copy hooks, commands, config, personality, plugin, bmad config files
|
|
201
|
-
const silentSpinner = { start: () => {}, succeed: () => {}, fail: () => {} };
|
|
201
|
+
const silentSpinner = { start: () => {}, stop: () => {}, succeed: () => {}, fail: () => {}, warn: () => {}, info: () => {}, stopAndPersist: () => {}, get text() { return ''; }, set text(_) {}, get isSpinning() { return false; } };
|
|
202
202
|
const installer = await import('../installer.js');
|
|
203
203
|
await installer.copyHookFiles(targetDir, silentSpinner);
|
|
204
204
|
await installer.copyCommandFiles(targetDir, silentSpinner);
|