agentvibes 5.6.0 → 5.6.2
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 +3 -38
- package/.claude/config/audio-effects.cfg +1 -1
- package/.claude/config/background-music-enabled.txt +1 -1
- package/.claude/config/background-music-position.txt +6 -6
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/play-tts-ssh-remote.sh +119 -42
- package/.claude/hooks/play-tts-windows-receiver.sh +31 -0
- package/.claude/hooks/stop.sh +2 -27
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
- package/.claude/hooks-windows/play-tts.ps1 +58 -8
- package/.claude/piper-voices-dir.txt +1 -1
- package/.clawdbot/skill/README.md +326 -0
- package/.mcp.json +17 -27
- package/README.md +15 -2
- package/RELEASE_NOTES.md +64 -0
- package/bin/agent-vibes +39 -39
- package/package.json +1 -1
- package/src/bmad-detector.js +71 -71
- 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/commands/install-mcp.js +476 -476
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +5 -1
- package/src/console/tabs/agents-tab.js +5 -5
- package/src/console/tabs/help-tab.js +314 -314
- package/src/console/tabs/readme-tab.js +272 -272
- package/src/console/tabs/setup-tab.js +32 -17
- package/src/console/tabs/voices-tab.js +2 -2
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/personality-picker.js +213 -213
- package/src/console/widgets/reverb-picker.js +97 -97
- package/src/console/widgets/track-picker.js +1 -1
- package/src/i18n/de.js +202 -202
- package/src/i18n/es.js +202 -202
- package/src/i18n/fr.js +202 -202
- package/src/i18n/hi.js +202 -202
- package/src/i18n/ja.js +202 -202
- package/src/i18n/ko.js +202 -202
- package/src/i18n/pt.js +202 -202
- package/src/i18n/strings.js +54 -54
- package/src/i18n/zh-CN.js +202 -202
- package/src/installer/language-screen.js +31 -31
- package/src/installer/music-file-input.js +304 -304
- package/src/services/agent-voice-store.js +420 -423
- package/src/services/config-service.js +264 -264
- package/src/services/language-service.js +47 -47
- package/src/services/llm-provider-service.js +11 -4
- package/src/services/navigation-service.js +34 -10
- package/src/services/provider-service.js +143 -143
- package/src/utils/audio-duration-validator.js +298 -298
- 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/list-formatter.js +194 -194
- package/src/utils/music-file-validator.js +285 -285
- package/src/utils/preview-list-prompt.js +136 -136
- package/src/utils/secure-music-storage.js +412 -412
- package/.agentvibes/LITE-MODE.md +0 -236
- package/.agentvibes/README.md +0 -136
- package/.agentvibes/backup/session-start-tts.sh.20251210_212814 +0 -141
- package/.agentvibes/backups/agents/analyst_20260204_144958.md +0 -78
- package/.agentvibes/backups/agents/architect_20260204_144958.md +0 -72
- package/.agentvibes/backups/agents/dev_20260204_144958.md +0 -74
- package/.agentvibes/backups/agents/pm_20260204_144958.md +0 -72
- package/.agentvibes/backups/agents/quick-flow-solo-dev_20260204_144958.md +0 -64
- package/.agentvibes/backups/agents/sm_20260204_144958.md +0 -87
- package/.agentvibes/backups/agents/tea_20260204_144958.md +0 -79
- package/.agentvibes/backups/agents/tech-writer_20260204_144958.md +0 -82
- package/.agentvibes/backups/agents/ux-designer_20260204_144958.md +0 -80
- package/.agentvibes/config/README-personality-defaults.md +0 -162
- package/.agentvibes/config/agentvibes.json +0 -1
- package/.agentvibes/config/mode.txt +0 -1
- package/.agentvibes/config/personality-voice-defaults.default.json +0 -21
- package/.agentvibes/config/save-audio.txt +0 -1
- package/.agentvibes/config/voice-metadata.json +0 -160
- package/.agentvibes/hooks/help.sh +0 -191
- package/.agentvibes/hooks/post-tool-use-lite.sh +0 -111
- package/.agentvibes/hooks/save-audio-manager.sh +0 -162
- package/.agentvibes/hooks/session-start-full-optimized.sh +0 -102
- package/.agentvibes/hooks/session-start-full.sh +0 -142
- package/.agentvibes/hooks/session-start-lite-v2.sh +0 -34
- package/.agentvibes/hooks/session-start-lite.sh +0 -29
- package/.agentvibes/hooks/stop-lite.sh +0 -115
- package/.agentvibes/hooks/switch-mode.sh +0 -215
- package/.agentvibes/output-styles/audio-summary.md +0 -30
- 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/hooks/post-response.sh +0 -41
- package/bin/ensure-soprano-running.sh +0 -43
|
@@ -17,7 +17,8 @@ export class NavigationService {
|
|
|
17
17
|
this._activeTab = TAB_ORDER.includes(initialTab) ? initialTab : 'settings';
|
|
18
18
|
this._switchCallbacks = [];
|
|
19
19
|
this._focusStack = [];
|
|
20
|
-
this.
|
|
20
|
+
this._modalDepth = 0;
|
|
21
|
+
this._modalCloseCallbacks = [];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
@@ -79,25 +80,48 @@ export class NavigationService {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
// ---------------------------------------------------------------------------
|
|
82
|
-
// Modal state
|
|
83
|
+
// Modal state
|
|
83
84
|
|
|
84
|
-
/** Returns true if
|
|
85
|
+
/** Returns true if one or more modals are currently open */
|
|
85
86
|
isModalOpen() {
|
|
86
|
-
return this.
|
|
87
|
+
return this._modalDepth > 0;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
/**
|
|
90
|
-
* Open a modal.
|
|
91
|
-
*
|
|
91
|
+
* Open a modal. Increments depth counter and registers an optional close
|
|
92
|
+
* callback so nav hotkeys can force-close all open modals.
|
|
93
|
+
* @param {Function|null} fn - Optional factory/callback invoked immediately
|
|
94
|
+
* @param {Function|null} closeFn - Optional callback to close this modal's UI
|
|
92
95
|
*/
|
|
93
|
-
openModal(fn) {
|
|
94
|
-
this.
|
|
96
|
+
openModal(fn, closeFn) {
|
|
97
|
+
this._modalDepth++;
|
|
98
|
+
this._modalCloseCallbacks.push(closeFn ?? null);
|
|
95
99
|
fn?.();
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Close the topmost modal, decrementing the depth counter.
|
|
104
|
+
* Safe to call when depth is already 0.
|
|
105
|
+
*/
|
|
99
106
|
closeModal() {
|
|
100
|
-
this.
|
|
107
|
+
if (this._modalDepth > 0) this._modalDepth--;
|
|
108
|
+
if (this._modalCloseCallbacks.length > 0) this._modalCloseCallbacks.pop();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Force-close all open modals by calling their registered close callbacks
|
|
113
|
+
* from innermost to outermost, then reset depth to 0.
|
|
114
|
+
* Used by nav hotkeys (S/V/M/…) to dismiss modals before switching tabs.
|
|
115
|
+
*/
|
|
116
|
+
forceCloseAll() {
|
|
117
|
+
const callbacks = [...this._modalCloseCallbacks].reverse();
|
|
118
|
+
this._modalDepth = 0;
|
|
119
|
+
this._modalCloseCallbacks = [];
|
|
120
|
+
for (const cb of callbacks) {
|
|
121
|
+
if (typeof cb === 'function') {
|
|
122
|
+
try { cb(); } catch {}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
|
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AgentVibes Provider Service
|
|
3
|
-
* Story 7.1: Provider & Voice Settings Group
|
|
4
|
-
*
|
|
5
|
-
* Detects installed TTS providers, reads/writes active provider and voice
|
|
6
|
-
* through ConfigService. Gracefully degrades when detection fails.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { execFileSync } from 'node:child_process';
|
|
10
|
-
import fs from 'node:fs';
|
|
11
|
-
import path from 'node:path';
|
|
12
|
-
import os from 'node:os';
|
|
13
|
-
|
|
14
|
-
export class ProviderService {
|
|
15
|
-
/**
|
|
16
|
-
* @param {import('./config-service.js').ConfigService} configService
|
|
17
|
-
*/
|
|
18
|
-
constructor(configService) {
|
|
19
|
-
this._config = configService;
|
|
20
|
-
this._installedProviders = null; // cached after first detection
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// Provider
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Returns the currently active TTS provider from config.
|
|
28
|
-
* Defaults to 'piper' if not configured.
|
|
29
|
-
* @returns {string}
|
|
30
|
-
*/
|
|
31
|
-
getActiveProvider() {
|
|
32
|
-
return this._config.getConfig().provider ?? 'piper';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Sets the active TTS provider in config AND syncs to .claude/tts-provider.txt
|
|
37
|
-
* so the shell hooks (play-tts.sh → provider-manager.sh) pick up the change.
|
|
38
|
-
* @param {string} provider
|
|
39
|
-
*/
|
|
40
|
-
setActiveProvider(provider) {
|
|
41
|
-
this._config.set('provider', provider);
|
|
42
|
-
this._config.setGlobal('provider', provider);
|
|
43
|
-
this._syncProviderFile(provider);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Write provider to .claude/tts-provider.txt so shell hooks stay in sync.
|
|
48
|
-
* Writes to projectRoot/.claude/tts-provider.txt if .claude/ exists there,
|
|
49
|
-
* otherwise falls back to ~/.claude/tts-provider.txt.
|
|
50
|
-
* @param {string} provider
|
|
51
|
-
*/
|
|
52
|
-
_syncProviderFile(provider) {
|
|
53
|
-
try {
|
|
54
|
-
const projectClaudeDir = path.resolve(this._config.getProjectRoot(), '.claude');
|
|
55
|
-
const targetDir = fs.existsSync(projectClaudeDir)
|
|
56
|
-
? projectClaudeDir
|
|
57
|
-
: path.resolve(os.homedir(), '.claude');
|
|
58
|
-
const targetFile = path.resolve(targetDir, 'tts-provider.txt');
|
|
59
|
-
// Verify resolved path stays within targetDir (path traversal guard)
|
|
60
|
-
if (!targetFile.startsWith(targetDir + path.sep) && targetFile !== targetDir) return;
|
|
61
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
62
|
-
fs.writeFileSync(targetFile, provider, 'utf8');
|
|
63
|
-
} catch {
|
|
64
|
-
// Non-fatal — config.json is the authoritative source
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Returns an array of installed/available TTS providers.
|
|
70
|
-
* Detection uses `which` binary check. Always returns at least ['piper']
|
|
71
|
-
* as graceful degradation (piper is the primary supported provider).
|
|
72
|
-
* @returns {string[]}
|
|
73
|
-
*/
|
|
74
|
-
getInstalledProviders() {
|
|
75
|
-
if (this._installedProviders) return this._installedProviders;
|
|
76
|
-
|
|
77
|
-
const providers = [];
|
|
78
|
-
|
|
79
|
-
if (this._isAvailable('piper')) providers.push('piper');
|
|
80
|
-
if (this._isAvailable('soprano')) providers.push('soprano');
|
|
81
|
-
|
|
82
|
-
// macOS Say (darwin only)
|
|
83
|
-
if (process.platform === 'darwin' && this._isAvailable('say')) {
|
|
84
|
-
providers.push('macos');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Graceful degradation: always return at least piper
|
|
88
|
-
if (providers.length === 0) providers.push('piper');
|
|
89
|
-
|
|
90
|
-
this._installedProviders = providers;
|
|
91
|
-
return providers;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
// Voice
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Returns the currently active voice ID from config.
|
|
99
|
-
* Falls back to first installed voice if not configured.
|
|
100
|
-
* @returns {string|null}
|
|
101
|
-
*/
|
|
102
|
-
getActiveVoiceId() {
|
|
103
|
-
const voice = this._config.getConfig().voice;
|
|
104
|
-
if (voice) return voice;
|
|
105
|
-
// Detect first installed voice instead of hardcoding a default that may not exist
|
|
106
|
-
const voicesDir = path.join(os.homedir(), '.claude', 'piper-voices');
|
|
107
|
-
try {
|
|
108
|
-
const models = fs.readdirSync(voicesDir).filter(f => f.endsWith('.onnx'));
|
|
109
|
-
if (models.length > 0) return models[0].replace(/\.onnx$/, '');
|
|
110
|
-
} catch { /* dir may not exist */ }
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Sets the active voice ID in config.
|
|
116
|
-
* Writes to both project (if exists) and global config for portability.
|
|
117
|
-
* @param {string} voiceId
|
|
118
|
-
*/
|
|
119
|
-
setActiveVoice(voiceId) {
|
|
120
|
-
this._config.set('voice', voiceId);
|
|
121
|
-
this._config.setGlobal('voice', voiceId);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// ---------------------------------------------------------------------------
|
|
125
|
-
// Private
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Check if a binary is available in PATH using `which`.
|
|
129
|
-
* Binary names are all hardcoded (not user input) — safe from injection.
|
|
130
|
-
* @param {string} binary - hardcoded binary name ('piper', 'soprano', 'say')
|
|
131
|
-
* @returns {boolean}
|
|
132
|
-
*/
|
|
133
|
-
_isAvailable(binary) {
|
|
134
|
-
try {
|
|
135
|
-
execFileSync('which', [binary], { stdio: 'ignore', timeout: 2000 });
|
|
136
|
-
return true;
|
|
137
|
-
} catch {
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export default ProviderService;
|
|
1
|
+
/**
|
|
2
|
+
* AgentVibes Provider Service
|
|
3
|
+
* Story 7.1: Provider & Voice Settings Group
|
|
4
|
+
*
|
|
5
|
+
* Detects installed TTS providers, reads/writes active provider and voice
|
|
6
|
+
* through ConfigService. Gracefully degrades when detection fails.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execFileSync } from 'node:child_process';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import os from 'node:os';
|
|
13
|
+
|
|
14
|
+
export class ProviderService {
|
|
15
|
+
/**
|
|
16
|
+
* @param {import('./config-service.js').ConfigService} configService
|
|
17
|
+
*/
|
|
18
|
+
constructor(configService) {
|
|
19
|
+
this._config = configService;
|
|
20
|
+
this._installedProviders = null; // cached after first detection
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Provider
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the currently active TTS provider from config.
|
|
28
|
+
* Defaults to 'piper' if not configured.
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
getActiveProvider() {
|
|
32
|
+
return this._config.getConfig().provider ?? 'piper';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sets the active TTS provider in config AND syncs to .claude/tts-provider.txt
|
|
37
|
+
* so the shell hooks (play-tts.sh → provider-manager.sh) pick up the change.
|
|
38
|
+
* @param {string} provider
|
|
39
|
+
*/
|
|
40
|
+
setActiveProvider(provider) {
|
|
41
|
+
this._config.set('provider', provider);
|
|
42
|
+
this._config.setGlobal('provider', provider);
|
|
43
|
+
this._syncProviderFile(provider);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Write provider to .claude/tts-provider.txt so shell hooks stay in sync.
|
|
48
|
+
* Writes to projectRoot/.claude/tts-provider.txt if .claude/ exists there,
|
|
49
|
+
* otherwise falls back to ~/.claude/tts-provider.txt.
|
|
50
|
+
* @param {string} provider
|
|
51
|
+
*/
|
|
52
|
+
_syncProviderFile(provider) {
|
|
53
|
+
try {
|
|
54
|
+
const projectClaudeDir = path.resolve(this._config.getProjectRoot(), '.claude');
|
|
55
|
+
const targetDir = fs.existsSync(projectClaudeDir)
|
|
56
|
+
? projectClaudeDir
|
|
57
|
+
: path.resolve(os.homedir(), '.claude');
|
|
58
|
+
const targetFile = path.resolve(targetDir, 'tts-provider.txt');
|
|
59
|
+
// Verify resolved path stays within targetDir (path traversal guard)
|
|
60
|
+
if (!targetFile.startsWith(targetDir + path.sep) && targetFile !== targetDir) return;
|
|
61
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
62
|
+
fs.writeFileSync(targetFile, provider, 'utf8');
|
|
63
|
+
} catch {
|
|
64
|
+
// Non-fatal — config.json is the authoritative source
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns an array of installed/available TTS providers.
|
|
70
|
+
* Detection uses `which` binary check. Always returns at least ['piper']
|
|
71
|
+
* as graceful degradation (piper is the primary supported provider).
|
|
72
|
+
* @returns {string[]}
|
|
73
|
+
*/
|
|
74
|
+
getInstalledProviders() {
|
|
75
|
+
if (this._installedProviders) return this._installedProviders;
|
|
76
|
+
|
|
77
|
+
const providers = [];
|
|
78
|
+
|
|
79
|
+
if (this._isAvailable('piper')) providers.push('piper');
|
|
80
|
+
if (this._isAvailable('soprano')) providers.push('soprano');
|
|
81
|
+
|
|
82
|
+
// macOS Say (darwin only)
|
|
83
|
+
if (process.platform === 'darwin' && this._isAvailable('say')) {
|
|
84
|
+
providers.push('macos');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Graceful degradation: always return at least piper
|
|
88
|
+
if (providers.length === 0) providers.push('piper');
|
|
89
|
+
|
|
90
|
+
this._installedProviders = providers;
|
|
91
|
+
return providers;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Voice
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns the currently active voice ID from config.
|
|
99
|
+
* Falls back to first installed voice if not configured.
|
|
100
|
+
* @returns {string|null}
|
|
101
|
+
*/
|
|
102
|
+
getActiveVoiceId() {
|
|
103
|
+
const voice = this._config.getConfig().voice;
|
|
104
|
+
if (voice) return voice;
|
|
105
|
+
// Detect first installed voice instead of hardcoding a default that may not exist
|
|
106
|
+
const voicesDir = path.join(os.homedir(), '.claude', 'piper-voices');
|
|
107
|
+
try {
|
|
108
|
+
const models = fs.readdirSync(voicesDir).filter(f => f.endsWith('.onnx'));
|
|
109
|
+
if (models.length > 0) return models[0].replace(/\.onnx$/, '');
|
|
110
|
+
} catch { /* dir may not exist */ }
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Sets the active voice ID in config.
|
|
116
|
+
* Writes to both project (if exists) and global config for portability.
|
|
117
|
+
* @param {string} voiceId
|
|
118
|
+
*/
|
|
119
|
+
setActiveVoice(voiceId) {
|
|
120
|
+
this._config.set('voice', voiceId);
|
|
121
|
+
this._config.setGlobal('voice', voiceId);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Private
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if a binary is available in PATH using `which`.
|
|
129
|
+
* Binary names are all hardcoded (not user input) — safe from injection.
|
|
130
|
+
* @param {string} binary - hardcoded binary name ('piper', 'soprano', 'say')
|
|
131
|
+
* @returns {boolean}
|
|
132
|
+
*/
|
|
133
|
+
_isAvailable(binary) {
|
|
134
|
+
try {
|
|
135
|
+
execFileSync('which', [binary], { stdio: 'ignore', timeout: 2000 });
|
|
136
|
+
return true;
|
|
137
|
+
} catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export default ProviderService;
|