agentvibes 4.2.0 → 4.4.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/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config.json +12 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/tracks/README.md +52 -52
- 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/verbosity.md +89 -89
- 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/agentvibes.json +1 -0
- package/.claude/config/audio-effects.cfg +2 -2
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-volume.txt +1 -0
- package/.claude/config/intro-text.txt +1 -0
- package/.claude/config/piper-speech-rate.txt +4 -0
- package/.claude/config/piper-target-speech-rate.txt +1 -0
- package/.claude/config/reverb-level.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +4 -0
- package/.claude/config/tts-target-speech-rate.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 +246 -246
- package/.claude/hooks/audio-processor.sh +433 -433
- package/.claude/hooks/background-music-manager.sh +404 -404
- package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
- package/.claude/hooks/bmad-speak.sh +269 -269
- package/.claude/hooks/bmad-tts-injector.sh +568 -568
- package/.claude/hooks/bmad-voice-manager.sh +928 -928
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
- package/.claude/hooks/clawdbot-receiver.sh +107 -107
- package/.claude/hooks/clean-audio-cache.sh +22 -22
- package/.claude/hooks/cleanup-cache.sh +106 -106
- package/.claude/hooks/configure-rdp-mode.sh +137 -137
- package/.claude/hooks/download-extra-voices.sh +244 -244
- package/.claude/hooks/effects-manager.sh +268 -268
- package/.claude/hooks/github-star-reminder.sh +154 -154
- package/.claude/hooks/language-manager.sh +362 -362
- package/.claude/hooks/learn-manager.sh +492 -492
- package/.claude/hooks/macos-voice-manager.sh +205 -205
- package/.claude/hooks/migrate-background-music.sh +125 -125
- package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
- package/.claude/hooks/optimize-background-music.sh +87 -87
- package/.claude/hooks/path-resolver.sh +60 -60
- package/.claude/hooks/personality-manager.sh +448 -448
- package/.claude/hooks/piper-download-voices.sh +225 -225
- package/.claude/hooks/piper-installer.sh +292 -292
- package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
- package/.claude/hooks/piper-voice-manager.sh +24 -3
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
- package/.claude/hooks/play-tts-enhanced.sh +105 -105
- package/.claude/hooks/play-tts-macos.sh +368 -368
- package/.claude/hooks/play-tts-piper.sh +679 -679
- package/.claude/hooks/play-tts-soprano.sh +356 -356
- package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
- package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
- package/.claude/hooks/play-tts.sh +301 -301
- package/.claude/hooks/prepare-release.sh +54 -54
- package/.claude/hooks/provider-commands.sh +617 -617
- package/.claude/hooks/provider-manager.sh +399 -399
- package/.claude/hooks/replay-target-audio.sh +95 -95
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +201 -201
- package/.claude/hooks/session-start-tts.sh +81 -81
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +291 -291
- package/.claude/hooks/stop-tts.sh +84 -84
- package/.claude/hooks/termux-installer.sh +261 -261
- package/.claude/hooks/translate-manager.sh +341 -341
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +145 -145
- package/.claude/hooks/tts-queue.sh +165 -165
- package/.claude/hooks/verbosity-manager.sh +178 -178
- package/.claude/hooks/voice-manager.sh +548 -548
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
- package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
- package/.claude/hooks-windows/effects-manager.ps1 +294 -0
- package/.claude/hooks-windows/language-manager.ps1 +193 -0
- package/.claude/hooks-windows/learn-manager.ps1 +241 -0
- package/.claude/hooks-windows/personality-manager.ps1 +266 -0
- package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
- package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
- package/.claude/hooks-windows/play-tts.ps1 +344 -266
- package/.claude/hooks-windows/provider-manager.ps1 +29 -10
- package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -0
- package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
- package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
- 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/settings.json +15 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +241 -241
- package/.mcp.json +12 -0
- package/CLAUDE.md +170 -170
- package/README.md +2029 -2007
- package/RELEASE_NOTES.md +1310 -1203
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/agentvibes-voice-browser.js +1840 -1840
- package/bin/agentvibes.js +48 -2
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +206 -206
- 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 +1465 -1453
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +336 -0
- package/package.json +110 -110
- package/setup-windows.ps1 +815 -815
- 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/app.js +824 -824
- package/src/console/audio-env.js +20 -1
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/footer-config.js +50 -50
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +62 -62
- package/src/console/tabs/agents-tab.js +1684 -1516
- package/src/console/tabs/help-tab.js +261 -261
- package/src/console/tabs/install-tab.js +1007 -991
- package/src/console/tabs/music-tab.js +22 -8
- package/src/console/tabs/placeholder-tab.js +53 -53
- package/src/console/tabs/readme-tab.js +267 -267
- package/src/console/tabs/receiver-tab.js +1472 -1212
- package/src/console/tabs/settings-tab.js +208 -84
- package/src/console/tabs/voices-tab.js +100 -21
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/format-utils.js +89 -89
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/personality-picker.js +185 -185
- package/src/console/widgets/reverb-picker.js +94 -94
- package/src/console/widgets/track-picker.js +285 -285
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +5895 -5829
- package/src/services/agent-voice-store.js +423 -423
- package/src/services/config-service.js +264 -264
- package/src/services/navigation-service.js +123 -123
- package/src/services/provider-service.js +143 -132
- package/src/services/verbosity-service.js +157 -157
- 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 -466
- 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/provider-validator.js +96 -12
- package/src/utils/secure-music-storage.js +412 -412
- package/templates/agentvibes-receiver.sh +482 -482
- package/templates/audio/welcome-music.mp3 +0 -0
- package/voice-assignments.json +8244 -8244
- package/.claude/config/background-music-position.txt +0 -1
package/src/bmad-detector.js
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import yaml from 'js-yaml';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Detect BMAD installation and version
|
|
7
|
-
* @param {string} targetDir - Directory to check
|
|
8
|
-
* @returns {Promise<Object>} Detection result with version info
|
|
9
|
-
*/
|
|
10
|
-
export async function detectBMAD(targetDir) {
|
|
11
|
-
// Check v6 first (newer version) - support both .bmad and bmad paths
|
|
12
|
-
// Try .bmad (standard path with dot prefix) first
|
|
13
|
-
let v6Manifest = path.join(targetDir, '.bmad/_cfg/manifest.yaml');
|
|
14
|
-
let bmadPath = '.bmad';
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
await fs.access(v6Manifest);
|
|
18
|
-
} catch {
|
|
19
|
-
// Try bmad (alternative path without dot prefix)
|
|
20
|
-
v6Manifest = path.join(targetDir, 'bmad/_cfg/manifest.yaml');
|
|
21
|
-
bmadPath = 'bmad';
|
|
22
|
-
try {
|
|
23
|
-
await fs.access(v6Manifest);
|
|
24
|
-
} catch {
|
|
25
|
-
// Neither path found, continue to v4 check
|
|
26
|
-
bmadPath = null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (bmadPath) {
|
|
31
|
-
try {
|
|
32
|
-
const manifestContent = await fs.readFile(v6Manifest, 'utf8');
|
|
33
|
-
const manifest = yaml.load(manifestContent);
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
version: 6,
|
|
37
|
-
detailedVersion: manifest.installation?.version || '6.0.0-alpha.x',
|
|
38
|
-
manifestPath: v6Manifest,
|
|
39
|
-
configPath: path.join(targetDir, bmadPath, 'core/config.yaml'),
|
|
40
|
-
bmadPath: path.join(targetDir, bmadPath),
|
|
41
|
-
installed: true
|
|
42
|
-
};
|
|
43
|
-
} catch {}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Check v4 (legacy)
|
|
47
|
-
const v4Manifest = path.join(targetDir, '.bmad-core/install-manifest.yaml');
|
|
48
|
-
try {
|
|
49
|
-
await fs.access(v4Manifest);
|
|
50
|
-
return {
|
|
51
|
-
version: 4,
|
|
52
|
-
detailedVersion: '4.x',
|
|
53
|
-
manifestPath: v4Manifest,
|
|
54
|
-
configPath: path.join(targetDir, '.bmad-core/config.yaml'),
|
|
55
|
-
bmadPath: path.join(targetDir, '.bmad-core'),
|
|
56
|
-
installed: true
|
|
57
|
-
};
|
|
58
|
-
} catch {}
|
|
59
|
-
|
|
60
|
-
// Not installed
|
|
61
|
-
return { version: null, installed: false };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Get BMAD configuration file path for detected version
|
|
66
|
-
* @param {Object} detection - Result from detectBMAD()
|
|
67
|
-
* @returns {string|null} Path to config.yaml or null
|
|
68
|
-
*/
|
|
69
|
-
export function getBMADConfigPath(detection) {
|
|
70
|
-
return detection.installed ? detection.configPath : null;
|
|
71
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detect BMAD installation and version
|
|
7
|
+
* @param {string} targetDir - Directory to check
|
|
8
|
+
* @returns {Promise<Object>} Detection result with version info
|
|
9
|
+
*/
|
|
10
|
+
export async function detectBMAD(targetDir) {
|
|
11
|
+
// Check v6 first (newer version) - support both .bmad and bmad paths
|
|
12
|
+
// Try .bmad (standard path with dot prefix) first
|
|
13
|
+
let v6Manifest = path.join(targetDir, '.bmad/_cfg/manifest.yaml');
|
|
14
|
+
let bmadPath = '.bmad';
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
await fs.access(v6Manifest);
|
|
18
|
+
} catch {
|
|
19
|
+
// Try bmad (alternative path without dot prefix)
|
|
20
|
+
v6Manifest = path.join(targetDir, 'bmad/_cfg/manifest.yaml');
|
|
21
|
+
bmadPath = 'bmad';
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(v6Manifest);
|
|
24
|
+
} catch {
|
|
25
|
+
// Neither path found, continue to v4 check
|
|
26
|
+
bmadPath = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (bmadPath) {
|
|
31
|
+
try {
|
|
32
|
+
const manifestContent = await fs.readFile(v6Manifest, 'utf8');
|
|
33
|
+
const manifest = yaml.load(manifestContent);
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
version: 6,
|
|
37
|
+
detailedVersion: manifest.installation?.version || '6.0.0-alpha.x',
|
|
38
|
+
manifestPath: v6Manifest,
|
|
39
|
+
configPath: path.join(targetDir, bmadPath, 'core/config.yaml'),
|
|
40
|
+
bmadPath: path.join(targetDir, bmadPath),
|
|
41
|
+
installed: true
|
|
42
|
+
};
|
|
43
|
+
} catch {}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check v4 (legacy)
|
|
47
|
+
const v4Manifest = path.join(targetDir, '.bmad-core/install-manifest.yaml');
|
|
48
|
+
try {
|
|
49
|
+
await fs.access(v4Manifest);
|
|
50
|
+
return {
|
|
51
|
+
version: 4,
|
|
52
|
+
detailedVersion: '4.x',
|
|
53
|
+
manifestPath: v4Manifest,
|
|
54
|
+
configPath: path.join(targetDir, '.bmad-core/config.yaml'),
|
|
55
|
+
bmadPath: path.join(targetDir, '.bmad-core'),
|
|
56
|
+
installed: true
|
|
57
|
+
};
|
|
58
|
+
} catch {}
|
|
59
|
+
|
|
60
|
+
// Not installed
|
|
61
|
+
return { version: null, installed: false };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get BMAD configuration file path for detected version
|
|
66
|
+
* @param {Object} detection - Result from detectBMAD()
|
|
67
|
+
* @returns {string|null} Path to config.yaml or null
|
|
68
|
+
*/
|
|
69
|
+
export function getBMADConfigPath(detection) {
|
|
70
|
+
return detection.installed ? detection.configPath : null;
|
|
71
|
+
}
|
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Personality List Display - Beautiful multi-column personality listing
|
|
4
|
-
* Called by personality-manager.sh to display personalities with boxen formatting
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { formatPersonalitiesList } from '../utils/list-formatter.js';
|
|
8
|
-
import fs from 'fs';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import os from 'os';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Get personality description from markdown file
|
|
14
|
-
*/
|
|
15
|
-
function getPersonalityDescription(filePath) {
|
|
16
|
-
try {
|
|
17
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
18
|
-
|
|
19
|
-
// Try to extract description from frontmatter or first paragraph
|
|
20
|
-
const descMatch = content.match(/description:\s*(.+)/i);
|
|
21
|
-
if (descMatch) {
|
|
22
|
-
return descMatch[1].trim();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Try to get first line after frontmatter
|
|
26
|
-
const lines = content.split('\n');
|
|
27
|
-
let inFrontmatter = false;
|
|
28
|
-
let frontmatterCount = 0;
|
|
29
|
-
|
|
30
|
-
for (const line of lines) {
|
|
31
|
-
if (line.trim() === '---') {
|
|
32
|
-
frontmatterCount++;
|
|
33
|
-
inFrontmatter = frontmatterCount === 1;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!inFrontmatter && frontmatterCount >= 2 && line.trim()) {
|
|
38
|
-
// First non-empty line after frontmatter
|
|
39
|
-
return line.trim().replace(/^#+\s*/, '').substring(0, 50);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return '';
|
|
44
|
-
} catch (error) {
|
|
45
|
-
return '';
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get all personalities from directory
|
|
51
|
-
*/
|
|
52
|
-
function getPersonalities(personalitiesDir, currentPersonality) {
|
|
53
|
-
const personalities = [];
|
|
54
|
-
|
|
55
|
-
if (!fs.existsSync(personalitiesDir)) {
|
|
56
|
-
return personalities;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const files = fs.readdirSync(personalitiesDir);
|
|
60
|
-
for (const file of files) {
|
|
61
|
-
if (file.endsWith('.md')) {
|
|
62
|
-
const name = path.basename(file, '.md');
|
|
63
|
-
const filePath = path.join(personalitiesDir, file);
|
|
64
|
-
const description = getPersonalityDescription(filePath);
|
|
65
|
-
|
|
66
|
-
personalities.push({
|
|
67
|
-
name,
|
|
68
|
-
description,
|
|
69
|
-
current: name === currentPersonality
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Add special 'random' option
|
|
75
|
-
personalities.push({
|
|
76
|
-
name: 'random',
|
|
77
|
-
description: 'Picks randomly each time',
|
|
78
|
-
current: currentPersonality === 'random'
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
return personalities.sort((a, b) => {
|
|
82
|
-
// Keep 'random' at the end
|
|
83
|
-
if (a.name === 'random') return 1;
|
|
84
|
-
if (b.name === 'random') return -1;
|
|
85
|
-
return a.name.localeCompare(b.name);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Main function
|
|
91
|
-
*/
|
|
92
|
-
function main() {
|
|
93
|
-
const args = process.argv.slice(2);
|
|
94
|
-
|
|
95
|
-
// Parse arguments
|
|
96
|
-
const personalitiesDir = args[0] || path.join(os.homedir(), '.claude', 'personalities');
|
|
97
|
-
const currentPersonality = args[1] || 'normal';
|
|
98
|
-
|
|
99
|
-
const personalities = getPersonalities(personalitiesDir, currentPersonality);
|
|
100
|
-
|
|
101
|
-
// Display with boxen
|
|
102
|
-
const output = formatPersonalitiesList(personalities, {
|
|
103
|
-
columns: 2,
|
|
104
|
-
showUsage: true
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
console.log(output);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Personality List Display - Beautiful multi-column personality listing
|
|
4
|
+
* Called by personality-manager.sh to display personalities with boxen formatting
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { formatPersonalitiesList } from '../utils/list-formatter.js';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get personality description from markdown file
|
|
14
|
+
*/
|
|
15
|
+
function getPersonalityDescription(filePath) {
|
|
16
|
+
try {
|
|
17
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
18
|
+
|
|
19
|
+
// Try to extract description from frontmatter or first paragraph
|
|
20
|
+
const descMatch = content.match(/description:\s*(.+)/i);
|
|
21
|
+
if (descMatch) {
|
|
22
|
+
return descMatch[1].trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Try to get first line after frontmatter
|
|
26
|
+
const lines = content.split('\n');
|
|
27
|
+
let inFrontmatter = false;
|
|
28
|
+
let frontmatterCount = 0;
|
|
29
|
+
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
if (line.trim() === '---') {
|
|
32
|
+
frontmatterCount++;
|
|
33
|
+
inFrontmatter = frontmatterCount === 1;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!inFrontmatter && frontmatterCount >= 2 && line.trim()) {
|
|
38
|
+
// First non-empty line after frontmatter
|
|
39
|
+
return line.trim().replace(/^#+\s*/, '').substring(0, 50);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return '';
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get all personalities from directory
|
|
51
|
+
*/
|
|
52
|
+
function getPersonalities(personalitiesDir, currentPersonality) {
|
|
53
|
+
const personalities = [];
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(personalitiesDir)) {
|
|
56
|
+
return personalities;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const files = fs.readdirSync(personalitiesDir);
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
if (file.endsWith('.md')) {
|
|
62
|
+
const name = path.basename(file, '.md');
|
|
63
|
+
const filePath = path.join(personalitiesDir, file);
|
|
64
|
+
const description = getPersonalityDescription(filePath);
|
|
65
|
+
|
|
66
|
+
personalities.push({
|
|
67
|
+
name,
|
|
68
|
+
description,
|
|
69
|
+
current: name === currentPersonality
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add special 'random' option
|
|
75
|
+
personalities.push({
|
|
76
|
+
name: 'random',
|
|
77
|
+
description: 'Picks randomly each time',
|
|
78
|
+
current: currentPersonality === 'random'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return personalities.sort((a, b) => {
|
|
82
|
+
// Keep 'random' at the end
|
|
83
|
+
if (a.name === 'random') return 1;
|
|
84
|
+
if (b.name === 'random') return -1;
|
|
85
|
+
return a.name.localeCompare(b.name);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Main function
|
|
91
|
+
*/
|
|
92
|
+
function main() {
|
|
93
|
+
const args = process.argv.slice(2);
|
|
94
|
+
|
|
95
|
+
// Parse arguments
|
|
96
|
+
const personalitiesDir = args[0] || path.join(os.homedir(), '.claude', 'personalities');
|
|
97
|
+
const currentPersonality = args[1] || 'normal';
|
|
98
|
+
|
|
99
|
+
const personalities = getPersonalities(personalitiesDir, currentPersonality);
|
|
100
|
+
|
|
101
|
+
// Display with boxen
|
|
102
|
+
const output = formatPersonalitiesList(personalities, {
|
|
103
|
+
columns: 2,
|
|
104
|
+
showUsage: true
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
console.log(output);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
main();
|
package/src/cli/list-voices.js
CHANGED
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Voice List Display - Beautiful multi-column voice listing
|
|
4
|
-
* Called by voice-manager.sh to display voices with boxen formatting
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { formatVoicesList } from '../utils/list-formatter.js';
|
|
8
|
-
import fs from 'fs';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import { execFileSync } from 'child_process';
|
|
11
|
-
import os from 'os';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Get Piper voices from voice directory
|
|
15
|
-
*/
|
|
16
|
-
function getPiperVoices(voiceDir, currentVoice) {
|
|
17
|
-
const voices = [];
|
|
18
|
-
|
|
19
|
-
if (!fs.existsSync(voiceDir)) {
|
|
20
|
-
return voices;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const files = fs.readdirSync(voiceDir);
|
|
24
|
-
for (const file of files) {
|
|
25
|
-
if (file.endsWith('.onnx')) {
|
|
26
|
-
const voiceName = path.basename(file, '.onnx');
|
|
27
|
-
voices.push({
|
|
28
|
-
name: voiceName,
|
|
29
|
-
lang: extractLanguage(voiceName),
|
|
30
|
-
current: voiceName === currentVoice
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return voices.sort((a, b) => a.name.localeCompare(b.name));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get macOS voices using say -v ?
|
|
40
|
-
*/
|
|
41
|
-
function getMacOSVoices(currentVoice) {
|
|
42
|
-
const voices = [];
|
|
43
|
-
|
|
44
|
-
if (os.platform() !== 'darwin') {
|
|
45
|
-
return voices;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const output = execFileSync('say', ['-v', '?'], { encoding: 'utf8' }); // NOSONAR - Safe: checking macOS say voices from system PATH
|
|
50
|
-
const lines = output.split('\n');
|
|
51
|
-
|
|
52
|
-
for (const line of lines) {
|
|
53
|
-
if (!line.trim()) continue;
|
|
54
|
-
|
|
55
|
-
const parts = line.trim().split(/\s+/);
|
|
56
|
-
if (parts.length >= 2) {
|
|
57
|
-
const voiceName = parts[0];
|
|
58
|
-
const lang = parts[1];
|
|
59
|
-
|
|
60
|
-
voices.push({
|
|
61
|
-
name: voiceName,
|
|
62
|
-
lang,
|
|
63
|
-
current: voiceName === currentVoice
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
} catch (error) {
|
|
68
|
-
// say command failed
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return voices;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Extract language code from voice name
|
|
76
|
-
*/
|
|
77
|
-
function extractLanguage(voiceName) {
|
|
78
|
-
const match = voiceName.match(/^([a-z]{2}_[A-Z]{2})/);
|
|
79
|
-
return match ? match[1] : '';
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Main function
|
|
84
|
-
*/
|
|
85
|
-
function main() {
|
|
86
|
-
const args = process.argv.slice(2);
|
|
87
|
-
|
|
88
|
-
// Parse arguments
|
|
89
|
-
const provider = args[0] || 'piper';
|
|
90
|
-
const currentVoice = args[1] || '';
|
|
91
|
-
const voiceDir = args[2] || '';
|
|
92
|
-
|
|
93
|
-
let voices = [];
|
|
94
|
-
let providerName = 'Piper TTS';
|
|
95
|
-
|
|
96
|
-
if (provider === 'piper') {
|
|
97
|
-
voices = getPiperVoices(voiceDir, currentVoice);
|
|
98
|
-
providerName = 'Piper TTS';
|
|
99
|
-
} else if (provider === 'macos') {
|
|
100
|
-
voices = getMacOSVoices(currentVoice);
|
|
101
|
-
providerName = 'macOS TTS';
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Display with boxen
|
|
105
|
-
const output = formatVoicesList(voices, {
|
|
106
|
-
provider: providerName,
|
|
107
|
-
columns: 2,
|
|
108
|
-
showUsage: true
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
console.log(output);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Voice List Display - Beautiful multi-column voice listing
|
|
4
|
+
* Called by voice-manager.sh to display voices with boxen formatting
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { formatVoicesList } from '../utils/list-formatter.js';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { execFileSync } from 'child_process';
|
|
11
|
+
import os from 'os';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get Piper voices from voice directory
|
|
15
|
+
*/
|
|
16
|
+
function getPiperVoices(voiceDir, currentVoice) {
|
|
17
|
+
const voices = [];
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(voiceDir)) {
|
|
20
|
+
return voices;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const files = fs.readdirSync(voiceDir);
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
if (file.endsWith('.onnx')) {
|
|
26
|
+
const voiceName = path.basename(file, '.onnx');
|
|
27
|
+
voices.push({
|
|
28
|
+
name: voiceName,
|
|
29
|
+
lang: extractLanguage(voiceName),
|
|
30
|
+
current: voiceName === currentVoice
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return voices.sort((a, b) => a.name.localeCompare(b.name));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get macOS voices using say -v ?
|
|
40
|
+
*/
|
|
41
|
+
function getMacOSVoices(currentVoice) {
|
|
42
|
+
const voices = [];
|
|
43
|
+
|
|
44
|
+
if (os.platform() !== 'darwin') {
|
|
45
|
+
return voices;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const output = execFileSync('say', ['-v', '?'], { encoding: 'utf8' }); // NOSONAR - Safe: checking macOS say voices from system PATH
|
|
50
|
+
const lines = output.split('\n');
|
|
51
|
+
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
if (!line.trim()) continue;
|
|
54
|
+
|
|
55
|
+
const parts = line.trim().split(/\s+/);
|
|
56
|
+
if (parts.length >= 2) {
|
|
57
|
+
const voiceName = parts[0];
|
|
58
|
+
const lang = parts[1];
|
|
59
|
+
|
|
60
|
+
voices.push({
|
|
61
|
+
name: voiceName,
|
|
62
|
+
lang,
|
|
63
|
+
current: voiceName === currentVoice
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// say command failed
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return voices;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extract language code from voice name
|
|
76
|
+
*/
|
|
77
|
+
function extractLanguage(voiceName) {
|
|
78
|
+
const match = voiceName.match(/^([a-z]{2}_[A-Z]{2})/);
|
|
79
|
+
return match ? match[1] : '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Main function
|
|
84
|
+
*/
|
|
85
|
+
function main() {
|
|
86
|
+
const args = process.argv.slice(2);
|
|
87
|
+
|
|
88
|
+
// Parse arguments
|
|
89
|
+
const provider = args[0] || 'piper';
|
|
90
|
+
const currentVoice = args[1] || '';
|
|
91
|
+
const voiceDir = args[2] || '';
|
|
92
|
+
|
|
93
|
+
let voices = [];
|
|
94
|
+
let providerName = 'Piper TTS';
|
|
95
|
+
|
|
96
|
+
if (provider === 'piper') {
|
|
97
|
+
voices = getPiperVoices(voiceDir, currentVoice);
|
|
98
|
+
providerName = 'Piper TTS';
|
|
99
|
+
} else if (provider === 'macos') {
|
|
100
|
+
voices = getMacOSVoices(currentVoice);
|
|
101
|
+
providerName = 'macOS TTS';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Display with boxen
|
|
105
|
+
const output = formatVoicesList(voices, {
|
|
106
|
+
provider: providerName,
|
|
107
|
+
columns: 2,
|
|
108
|
+
showUsage: true
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
console.log(output);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
main();
|