claude-voice 1.3.8 → 1.3.10
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/dist/terminal/input-injector.d.ts.map +1 -1
- package/dist/terminal/input-injector.js +37 -0
- package/dist/terminal/input-injector.js.map +1 -1
- package/dist/utils/audio.d.ts.map +1 -1
- package/dist/utils/audio.js +31 -10
- package/dist/utils/audio.js.map +1 -1
- package/package.json +5 -2
- package/scripts/postinstall.js +386 -315
- package/sounds/ping.wav +0 -0
- package/sounds/pop.wav +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-injector.d.ts","sourceRoot":"","sources":["../../src/terminal/input-injector.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IAEzC;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAcD;;;GAGG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAuB;gBAE3B,OAAO,GAAE,oBAAyB;IAS9C;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B1D;;OAEG;YACW,cAAc;IAO5B;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAK,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9E;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB1C,OAAO,CAAC,mBAAmB;IAkC3B;;OAEG;YACW,SAAS;
|
|
1
|
+
{"version":3,"file":"input-injector.d.ts","sourceRoot":"","sources":["../../src/terminal/input-injector.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IAEzC;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAcD;;;GAGG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAuB;gBAE3B,OAAO,GAAE,oBAAyB;IAS9C;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B1D;;OAEG;YACW,cAAc;IAO5B;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAK,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9E;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB1C,OAAO,CAAC,mBAAmB;IAkC3B;;OAEG;YACW,SAAS;IAoEvB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,UAAU;IAwClB,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,MAAM,CAAC,YAAY,IAAI,OAAO;IAI9B;;OAEG;IACH,MAAM,CAAC,cAAc,IAAI,UAAU,GAAG,OAAO,GAAG,SAAS;CAa1D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlE"}
|
|
@@ -150,6 +150,43 @@ end tell`;
|
|
|
150
150
|
.replace(/`/g, '\\`')
|
|
151
151
|
.replace(/\$/g, '\\$');
|
|
152
152
|
try {
|
|
153
|
+
// First, try to find and activate a terminal window
|
|
154
|
+
// Common terminal names: gnome-terminal, konsole, xfce4-terminal, xterm, etc.
|
|
155
|
+
const terminalPatterns = [
|
|
156
|
+
'gnome-terminal',
|
|
157
|
+
'konsole',
|
|
158
|
+
'xfce4-terminal',
|
|
159
|
+
'xterm',
|
|
160
|
+
'terminator',
|
|
161
|
+
'alacritty',
|
|
162
|
+
'kitty',
|
|
163
|
+
'tilix',
|
|
164
|
+
'Terminal', // Generic
|
|
165
|
+
];
|
|
166
|
+
let activated = false;
|
|
167
|
+
for (const pattern of terminalPatterns) {
|
|
168
|
+
try {
|
|
169
|
+
// Search for terminal window and activate it
|
|
170
|
+
await execAsync(`xdotool search --name "${pattern}" windowactivate --sync 2>/dev/null`);
|
|
171
|
+
activated = true;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Try next pattern
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (!activated) {
|
|
180
|
+
// Fallback: try to get any focused window (user may have terminal focused)
|
|
181
|
+
try {
|
|
182
|
+
await execAsync('xdotool getactivewindow');
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
throw new Error('No terminal window found. Please focus your terminal window.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Small delay to ensure window is activated
|
|
189
|
+
await this.delay(100);
|
|
153
190
|
// Type the text using xdotool
|
|
154
191
|
await execAsync(`xdotool type --clearmodifiers "${escapedText}"`);
|
|
155
192
|
// Press Enter if requested
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-injector.js","sourceRoot":"","sources":["../../src/terminal/input-injector.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"input-injector.js","sourceRoot":"","sources":["../../src/terminal/input-injector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../src/utils/audio.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../src/utils/audio.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAqBpD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAqBjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAarE;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,IAAI,GACnB,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,SAAU,EAAE,SAAS,SAAQ,GAAG,MAAM,CAE/E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQrD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,IAAI,CA2BN"}
|
package/dist/utils/audio.js
CHANGED
|
@@ -45,25 +45,46 @@ exports.saveToWav = saveToWav;
|
|
|
45
45
|
const child_process_1 = require("child_process");
|
|
46
46
|
const fs = __importStar(require("fs"));
|
|
47
47
|
const os = __importStar(require("os"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
48
49
|
const platform_1 = require("../platform");
|
|
50
|
+
/**
|
|
51
|
+
* Get the path to bundled sound files
|
|
52
|
+
*/
|
|
53
|
+
function getBundledSoundPath(soundName) {
|
|
54
|
+
// Sound files are in sounds/ directory relative to package root
|
|
55
|
+
// From dist/utils/audio.js -> ../../sounds/
|
|
56
|
+
const soundsDir = path.join(__dirname, '..', '..', 'sounds');
|
|
57
|
+
const soundFile = path.join(soundsDir, `${soundName.toLowerCase()}.wav`);
|
|
58
|
+
if (fs.existsSync(soundFile)) {
|
|
59
|
+
return soundFile;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
49
63
|
/**
|
|
50
64
|
* Play a system sound (cross-platform)
|
|
51
65
|
* @param soundName - Name of the sound (e.g., 'Ping', 'Pop' on macOS)
|
|
52
66
|
*/
|
|
53
67
|
function playSound(soundName) {
|
|
54
68
|
const caps = (0, platform_1.getPlatformCapabilities)();
|
|
69
|
+
const bundledSound = getBundledSoundPath(soundName);
|
|
55
70
|
if (caps.platform === 'darwin') {
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
// macOS: Try system sound first, then bundled
|
|
72
|
+
const systemSound = `/System/Library/Sounds/${soundName}.aiff`;
|
|
73
|
+
if (fs.existsSync(systemSound)) {
|
|
74
|
+
(0, child_process_1.spawn)('afplay', [systemSound], { stdio: 'ignore' });
|
|
75
|
+
}
|
|
76
|
+
else if (bundledSound) {
|
|
77
|
+
(0, child_process_1.spawn)('afplay', [bundledSound], { stdio: 'ignore' });
|
|
78
|
+
}
|
|
58
79
|
}
|
|
59
|
-
else if (caps.platform === 'linux'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
else if (caps.platform === 'linux') {
|
|
81
|
+
// Linux: Use bundled WAV files (works with all audio players)
|
|
82
|
+
if (bundledSound && caps.audioPlayer) {
|
|
83
|
+
(0, child_process_1.spawn)(caps.audioPlayer, [bundledSound], { stdio: 'ignore' });
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Fallback: terminal bell
|
|
87
|
+
process.stdout.write('\x07');
|
|
67
88
|
}
|
|
68
89
|
}
|
|
69
90
|
}
|
package/dist/utils/audio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/utils/audio.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/utils/audio.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-voice",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.10",
|
|
4
4
|
"description": "Voice interface extension for Claude Code - TTS, STT, and wake word detection",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -47,7 +47,9 @@
|
|
|
47
47
|
"node-global-key-listener": "^0.3.0",
|
|
48
48
|
"openai": "^4.20.0",
|
|
49
49
|
"ora": "^5.4.1",
|
|
50
|
-
"sherpa-onnx-node": "^1.12.20"
|
|
50
|
+
"sherpa-onnx-node": "^1.12.20",
|
|
51
|
+
"tar": "^7.5.2",
|
|
52
|
+
"unbzip2-stream": "^1.4.3"
|
|
51
53
|
},
|
|
52
54
|
"optionalDependencies": {
|
|
53
55
|
"@picovoice/porcupine-node": "^3.0.6",
|
|
@@ -86,6 +88,7 @@
|
|
|
86
88
|
"plugin/**/*",
|
|
87
89
|
"models/.gitkeep",
|
|
88
90
|
"python/**/*",
|
|
91
|
+
"sounds/**/*",
|
|
89
92
|
"README.md",
|
|
90
93
|
"LICENSE"
|
|
91
94
|
]
|
package/scripts/postinstall.js
CHANGED
|
@@ -8,13 +8,16 @@
|
|
|
8
8
|
* 3. Install Piper TTS and download default voice
|
|
9
9
|
* 4. Download whisper-tiny STT model
|
|
10
10
|
* 5. Download keyword spotting model for wake word
|
|
11
|
-
* 6.
|
|
11
|
+
* 6. Check platform-specific audio tools
|
|
12
12
|
* 7. Finalize setup and show next steps
|
|
13
|
+
*
|
|
14
|
+
* Uses pure Node.js for downloads (no curl/bzip2 system dependencies)
|
|
13
15
|
*/
|
|
14
16
|
|
|
15
17
|
const fs = require('fs');
|
|
16
18
|
const path = require('path');
|
|
17
19
|
const os = require('os');
|
|
20
|
+
const https = require('https');
|
|
18
21
|
const { execSync } = require('child_process');
|
|
19
22
|
const { installHooks } = require('./install-hooks');
|
|
20
23
|
const { installPlugin } = require('./install-plugin');
|
|
@@ -37,367 +40,435 @@ function checkCommand(cmd) {
|
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!fs.existsSync(CONFIG_FILE)) {
|
|
55
|
-
if (fs.existsSync(DEFAULT_CONFIG)) {
|
|
56
|
-
fs.copyFileSync(DEFAULT_CONFIG, CONFIG_FILE);
|
|
57
|
-
console.log(' [✓] Created default configuration');
|
|
43
|
+
/**
|
|
44
|
+
* Download and extract a .tar.bz2 file using pure Node.js
|
|
45
|
+
* No system dependencies required (bzip2, curl, etc.)
|
|
46
|
+
*/
|
|
47
|
+
async function downloadAndExtract(url, destDir, expectedFolder, label) {
|
|
48
|
+
// Lazy load dependencies (only available after npm install)
|
|
49
|
+
let tar, unbzip2;
|
|
50
|
+
try {
|
|
51
|
+
tar = require('tar');
|
|
52
|
+
unbzip2 = require('unbzip2-stream');
|
|
53
|
+
} catch (err) {
|
|
54
|
+
// Fallback to curl/tar if packages not available yet
|
|
55
|
+
console.log(` Using system tools for ${label}...`);
|
|
56
|
+
return downloadAndExtractFallback(url, destDir, expectedFolder, label);
|
|
58
57
|
}
|
|
59
|
-
} else {
|
|
60
|
-
console.log(' [✓] Configuration file exists');
|
|
61
|
-
}
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
config.stt = config.stt || {};
|
|
74
|
-
config.stt.provider = 'sherpa-onnx';
|
|
75
|
-
config.stt.sherpaOnnx = config.stt.sherpaOnnx || {};
|
|
76
|
-
config.stt.sherpaOnnx.model = 'whisper-tiny';
|
|
77
|
-
|
|
78
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
79
|
-
console.log(' [✓] Configured: Piper TTS + Whisper STT');
|
|
80
|
-
} catch (err) {
|
|
81
|
-
console.log(' [!] Could not update config:', err.message);
|
|
82
|
-
}
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const makeRequest = (requestUrl) => {
|
|
61
|
+
https.get(requestUrl, (response) => {
|
|
62
|
+
// Handle redirects (GitHub releases use them)
|
|
63
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
64
|
+
const redirectUrl = response.headers.location;
|
|
65
|
+
console.log(` Redirecting...`);
|
|
66
|
+
makeRequest(redirectUrl);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
83
69
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.log(' [✓] Hooks installed');
|
|
89
|
-
console.log(' [✓] Settings file:', settingsFile);
|
|
90
|
-
} catch (err) {
|
|
91
|
-
console.log(' [!] Could not install hooks:', err.message);
|
|
92
|
-
}
|
|
70
|
+
if (response.statusCode !== 200) {
|
|
71
|
+
reject(new Error(`HTTP ${response.statusCode}`));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
93
74
|
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
75
|
+
// Get total size for progress
|
|
76
|
+
const totalSize = parseInt(response.headers['content-length'], 10);
|
|
77
|
+
let downloaded = 0;
|
|
78
|
+
let lastPercent = 0;
|
|
79
|
+
|
|
80
|
+
response.on('data', (chunk) => {
|
|
81
|
+
downloaded += chunk.length;
|
|
82
|
+
if (totalSize) {
|
|
83
|
+
const percent = Math.floor((downloaded / totalSize) * 100);
|
|
84
|
+
if (percent >= lastPercent + 10) {
|
|
85
|
+
process.stdout.write(`\r Downloading: ${percent}%`);
|
|
86
|
+
lastPercent = percent;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Pipe: HTTP response -> unbzip2 -> tar extract
|
|
92
|
+
response
|
|
93
|
+
.pipe(unbzip2())
|
|
94
|
+
.pipe(tar.extract({ cwd: destDir }))
|
|
95
|
+
.on('finish', () => {
|
|
96
|
+
console.log(`\r Downloading: 100%`);
|
|
97
|
+
const extractedPath = path.join(destDir, expectedFolder);
|
|
98
|
+
if (fs.existsSync(extractedPath)) {
|
|
99
|
+
resolve();
|
|
100
|
+
} else {
|
|
101
|
+
reject(new Error('Extraction failed - folder not found'));
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.on('error', (err) => {
|
|
105
|
+
reject(new Error(`Extraction error: ${err.message}`));
|
|
106
|
+
});
|
|
107
|
+
}).on('error', (err) => {
|
|
108
|
+
reject(new Error(`Download error: ${err.message}`));
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
makeRequest(url);
|
|
113
|
+
});
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const voiceId = 'en_US-joe-medium';
|
|
110
|
-
const onnxPath = path.join(VOICES_DIR, `${voiceId}.onnx`);
|
|
111
|
-
const jsonPath = path.join(VOICES_DIR, `${voiceId}.onnx.json`);
|
|
112
|
-
|
|
113
|
-
if (fs.existsSync(onnxPath) && fs.existsSync(jsonPath)) {
|
|
114
|
-
console.log(` [✓] Voice already installed: ${voiceId}`);
|
|
115
|
-
} else {
|
|
116
|
-
// Create voices directory
|
|
117
|
-
if (!fs.existsSync(VOICES_DIR)) {
|
|
118
|
-
fs.mkdirSync(VOICES_DIR, { recursive: true });
|
|
119
|
-
}
|
|
116
|
+
/**
|
|
117
|
+
* Fallback: Use curl and tar if Node.js packages not available
|
|
118
|
+
*/
|
|
119
|
+
async function downloadAndExtractFallback(url, destDir, expectedFolder, label) {
|
|
120
|
+
const archivePath = path.join(destDir, `${label}.tar.bz2`);
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const quality = parts[2];
|
|
127
|
-
const baseUrl = 'https://huggingface.co/rhasspy/piper-voices/resolve/main';
|
|
128
|
-
const voicePath = `${lang}/${langCode}/${voiceName}/${quality}`;
|
|
129
|
-
const onnxUrl = `${baseUrl}/${voicePath}/${voiceId}.onnx`;
|
|
130
|
-
const jsonUrl = `${baseUrl}/${voicePath}/${voiceId}.onnx.json`;
|
|
131
|
-
|
|
132
|
-
console.log(` Voice: Joe (US English)`);
|
|
133
|
-
console.log(` [1/2] Downloading voice model (~50MB)...`);
|
|
134
|
-
execSync(`curl -L --progress-bar -o "${onnxPath}" "${onnxUrl}"`, { stdio: 'inherit' });
|
|
135
|
-
|
|
136
|
-
console.log(` [2/2] Downloading voice config...`);
|
|
137
|
-
execSync(`curl -sL -o "${jsonPath}" "${jsonUrl}"`, { stdio: 'inherit' });
|
|
138
|
-
|
|
139
|
-
console.log(` [✓] Voice installed: ${voiceId}`);
|
|
140
|
-
}
|
|
122
|
+
try {
|
|
123
|
+
execSync(`curl -L --progress-bar -o "${archivePath}" "${url}"`, {
|
|
124
|
+
stdio: 'inherit',
|
|
125
|
+
cwd: destDir
|
|
126
|
+
});
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!fs.existsSync(PIPER_BIN)) {
|
|
148
|
-
// Find Python 3.9-3.13
|
|
149
|
-
const pythonCandidates = [
|
|
150
|
-
'/opt/homebrew/bin/python3.12', '/opt/homebrew/bin/python3.11', '/opt/homebrew/bin/python3',
|
|
151
|
-
'/usr/local/bin/python3.12', '/usr/local/bin/python3.11', '/usr/local/bin/python3',
|
|
152
|
-
'/usr/bin/python3.12', '/usr/bin/python3.11', '/usr/bin/python3.10', '/usr/bin/python3.9', '/usr/bin/python3',
|
|
153
|
-
'python3.12', 'python3.11', 'python3.10', 'python3'
|
|
154
|
-
];
|
|
155
|
-
|
|
156
|
-
let python = null;
|
|
157
|
-
for (const py of pythonCandidates) {
|
|
158
|
-
try {
|
|
159
|
-
const version = execSync(`${py} --version 2>&1`, { encoding: 'utf-8' });
|
|
160
|
-
const match = version.match(/Python 3\.(\d+)/);
|
|
161
|
-
if (match) {
|
|
162
|
-
const minor = parseInt(match[1], 10);
|
|
163
|
-
if (minor >= 9 && minor <= 13) {
|
|
164
|
-
python = py;
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
} catch {}
|
|
169
|
-
}
|
|
128
|
+
execSync(`tar -xjf "${archivePath}"`, {
|
|
129
|
+
stdio: 'inherit',
|
|
130
|
+
cwd: destDir
|
|
131
|
+
});
|
|
170
132
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
console.log(' [2/3] Creating Python virtual environment...');
|
|
177
|
-
execSync(`${python} -m venv "${PIPER_VENV}"`, { stdio: 'pipe' });
|
|
178
|
-
console.log(' [3/3] Installing piper-tts package...');
|
|
179
|
-
const pip = path.join(PIPER_VENV, 'bin', 'pip');
|
|
180
|
-
execSync(`"${pip}" install --quiet piper-tts`, { stdio: 'pipe' });
|
|
181
|
-
console.log(' [✓] Piper TTS installed successfully');
|
|
182
|
-
} else {
|
|
183
|
-
const installCmd = os.platform() === 'darwin'
|
|
184
|
-
? 'brew install python@3.12'
|
|
185
|
-
: 'sudo apt install python3.12 python3.12-venv';
|
|
186
|
-
console.log(` [!] Python 3.9-3.13 not found. Install with: ${installCmd}`);
|
|
133
|
+
fs.unlinkSync(archivePath);
|
|
134
|
+
|
|
135
|
+
const extractedPath = path.join(destDir, expectedFolder);
|
|
136
|
+
if (!fs.existsSync(extractedPath)) {
|
|
137
|
+
throw new Error('Extraction failed');
|
|
187
138
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
139
|
+
} catch (err) {
|
|
140
|
+
throw new Error(`Fallback download failed: ${err.message}`);
|
|
190
141
|
}
|
|
191
|
-
} catch (err) {
|
|
192
|
-
console.log(' [!] Could not install Piper voice:', err.message);
|
|
193
|
-
console.log(' Run manually: claude-voice voice download en_US-joe-medium');
|
|
194
142
|
}
|
|
195
143
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
} else {
|
|
209
|
-
// Create models directory
|
|
210
|
-
if (!fs.existsSync(MODELS_DIR)) {
|
|
211
|
-
fs.mkdirSync(MODELS_DIR, { recursive: true });
|
|
212
|
-
}
|
|
144
|
+
/**
|
|
145
|
+
* Download a file using Node.js https (for simple files like .onnx)
|
|
146
|
+
*/
|
|
147
|
+
async function downloadFile(url, destPath, label) {
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
const makeRequest = (requestUrl) => {
|
|
150
|
+
https.get(requestUrl, (response) => {
|
|
151
|
+
// Handle redirects
|
|
152
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
153
|
+
makeRequest(response.headers.location);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
213
156
|
|
|
214
|
-
|
|
157
|
+
if (response.statusCode !== 200) {
|
|
158
|
+
reject(new Error(`HTTP ${response.statusCode}`));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
215
161
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
stdio: 'inherit',
|
|
220
|
-
cwd: MODELS_DIR
|
|
221
|
-
});
|
|
162
|
+
const totalSize = parseInt(response.headers['content-length'], 10);
|
|
163
|
+
let downloaded = 0;
|
|
164
|
+
let lastPercent = 0;
|
|
222
165
|
|
|
223
|
-
|
|
166
|
+
const fileStream = fs.createWriteStream(destPath);
|
|
224
167
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
168
|
+
response.on('data', (chunk) => {
|
|
169
|
+
downloaded += chunk.length;
|
|
170
|
+
if (totalSize) {
|
|
171
|
+
const percent = Math.floor((downloaded / totalSize) * 100);
|
|
172
|
+
if (percent >= lastPercent + 10) {
|
|
173
|
+
process.stdout.write(`\r ${label}: ${percent}%`);
|
|
174
|
+
lastPercent = percent;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
230
178
|
|
|
231
|
-
|
|
232
|
-
stdio: 'inherit',
|
|
233
|
-
cwd: MODELS_DIR
|
|
234
|
-
});
|
|
179
|
+
response.pipe(fileStream);
|
|
235
180
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
181
|
+
fileStream.on('finish', () => {
|
|
182
|
+
console.log(`\r ${label}: 100%`);
|
|
183
|
+
fileStream.close();
|
|
184
|
+
resolve();
|
|
185
|
+
});
|
|
240
186
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
187
|
+
fileStream.on('error', (err) => {
|
|
188
|
+
fs.unlink(destPath, () => {});
|
|
189
|
+
reject(err);
|
|
190
|
+
});
|
|
191
|
+
}).on('error', reject);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
makeRequest(url);
|
|
195
|
+
});
|
|
249
196
|
}
|
|
250
197
|
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
console.log('
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
console.log(` [✓] Model already installed: ${kwsModelId}`);
|
|
198
|
+
// Main async setup function
|
|
199
|
+
async function runSetup() {
|
|
200
|
+
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
|
201
|
+
console.log('║ Claude Voice Extension - Auto Setup ║');
|
|
202
|
+
console.log('╚════════════════════════════════════════════════════════════╝\n');
|
|
203
|
+
|
|
204
|
+
// 1. Create config directory
|
|
205
|
+
console.log('Step 1/7: Setting up configuration...');
|
|
206
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
207
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
208
|
+
console.log(' [✓] Created config directory');
|
|
263
209
|
} else {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
210
|
+
console.log(' [✓] Config directory exists');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// 2. Copy default config if none exists
|
|
214
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
215
|
+
if (fs.existsSync(DEFAULT_CONFIG)) {
|
|
216
|
+
fs.copyFileSync(DEFAULT_CONFIG, CONFIG_FILE);
|
|
217
|
+
console.log(' [✓] Created default configuration');
|
|
267
218
|
}
|
|
219
|
+
} else {
|
|
220
|
+
console.log(' [✓] Configuration file exists');
|
|
221
|
+
}
|
|
268
222
|
|
|
269
|
-
|
|
223
|
+
// 3. Configure with sensible defaults
|
|
224
|
+
try {
|
|
225
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
|
226
|
+
config.tts = config.tts || {};
|
|
227
|
+
config.tts.provider = 'piper';
|
|
228
|
+
config.tts.piper = { voice: 'en_US-joe-medium', speaker: 0 };
|
|
229
|
+
config.stt = config.stt || {};
|
|
230
|
+
config.stt.provider = 'sherpa-onnx';
|
|
231
|
+
config.stt.sherpaOnnx = config.stt.sherpaOnnx || {};
|
|
232
|
+
config.stt.sherpaOnnx.model = 'whisper-tiny';
|
|
233
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
234
|
+
console.log(' [✓] Configured: Piper TTS + Whisper STT');
|
|
235
|
+
} catch (err) {
|
|
236
|
+
console.log(' [!] Could not update config:', err.message);
|
|
237
|
+
}
|
|
270
238
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
239
|
+
// 4. Install Claude Code hooks
|
|
240
|
+
console.log('\nStep 2/7: Installing Claude Code hooks...');
|
|
241
|
+
try {
|
|
242
|
+
const settingsFile = installHooks(HOOKS_DIR);
|
|
243
|
+
console.log(' [✓] Hooks installed');
|
|
244
|
+
console.log(' [✓] Settings file:', settingsFile);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
console.log(' [!] Could not install hooks:', err.message);
|
|
247
|
+
}
|
|
277
248
|
|
|
278
|
-
|
|
249
|
+
// 5. Install Claude Code plugin (skill)
|
|
250
|
+
console.log('\nStep 3/7: Installing Claude Code plugin...');
|
|
251
|
+
try {
|
|
252
|
+
const pluginPath = installPlugin(path.join(__dirname, '..'));
|
|
253
|
+
console.log(' [✓] Plugin installed');
|
|
254
|
+
console.log(' [✓] Plugin path:', pluginPath);
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.log(' [!] Could not install plugin:', err.message);
|
|
257
|
+
}
|
|
279
258
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
259
|
+
// 6. Install Piper TTS and download default voice
|
|
260
|
+
console.log('\nStep 4/7: Installing Piper TTS engine...');
|
|
261
|
+
console.log(' (First-time install may take 1-2 minutes)\n');
|
|
262
|
+
try {
|
|
263
|
+
const voiceId = 'en_US-joe-medium';
|
|
264
|
+
const onnxPath = path.join(VOICES_DIR, `${voiceId}.onnx`);
|
|
265
|
+
const jsonPath = path.join(VOICES_DIR, `${voiceId}.onnx.json`);
|
|
285
266
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
267
|
+
if (fs.existsSync(onnxPath) && fs.existsSync(jsonPath)) {
|
|
268
|
+
console.log(` [✓] Voice already installed: ${voiceId}`);
|
|
269
|
+
} else {
|
|
270
|
+
if (!fs.existsSync(VOICES_DIR)) {
|
|
271
|
+
fs.mkdirSync(VOICES_DIR, { recursive: true });
|
|
272
|
+
}
|
|
290
273
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
274
|
+
const parts = voiceId.split('-');
|
|
275
|
+
const langCode = parts[0];
|
|
276
|
+
const lang = langCode.split('_')[0];
|
|
277
|
+
const voiceName = parts[1];
|
|
278
|
+
const quality = parts[2];
|
|
279
|
+
const baseUrl = 'https://huggingface.co/rhasspy/piper-voices/resolve/main';
|
|
280
|
+
const voicePath = `${lang}/${langCode}/${voiceName}/${quality}`;
|
|
281
|
+
const onnxUrl = `${baseUrl}/${voicePath}/${voiceId}.onnx`;
|
|
282
|
+
const jsonUrl = `${baseUrl}/${voicePath}/${voiceId}.onnx.json`;
|
|
283
|
+
|
|
284
|
+
console.log(` Voice: Joe (US English)`);
|
|
285
|
+
await downloadFile(onnxUrl, onnxPath, 'Downloading voice model (~50MB)');
|
|
286
|
+
await downloadFile(jsonUrl, jsonPath, 'Downloading voice config');
|
|
287
|
+
console.log(` [✓] Voice installed: ${voiceId}`);
|
|
294
288
|
}
|
|
295
289
|
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
290
|
+
// Install Piper TTS via pip if needed
|
|
291
|
+
const PIPER_DIR = path.join(CONFIG_DIR, 'piper');
|
|
292
|
+
const PIPER_VENV = path.join(PIPER_DIR, 'venv');
|
|
293
|
+
const PIPER_BIN = path.join(PIPER_VENV, 'bin', 'piper');
|
|
294
|
+
|
|
295
|
+
if (!fs.existsSync(PIPER_BIN)) {
|
|
296
|
+
const pythonCandidates = [
|
|
297
|
+
'/opt/homebrew/bin/python3.12', '/opt/homebrew/bin/python3.11', '/opt/homebrew/bin/python3',
|
|
298
|
+
'/usr/local/bin/python3.12', '/usr/local/bin/python3.11', '/usr/local/bin/python3',
|
|
299
|
+
'/usr/bin/python3.12', '/usr/bin/python3.11', '/usr/bin/python3.10', '/usr/bin/python3.9', '/usr/bin/python3',
|
|
300
|
+
'python3.12', 'python3.11', 'python3.10', 'python3'
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
let python = null;
|
|
304
|
+
for (const py of pythonCandidates) {
|
|
305
|
+
try {
|
|
306
|
+
const version = execSync(`${py} --version 2>&1`, { encoding: 'utf-8' });
|
|
307
|
+
const match = version.match(/Python 3\.(\d+)/);
|
|
308
|
+
if (match) {
|
|
309
|
+
const minor = parseInt(match[1], 10);
|
|
310
|
+
if (minor >= 9 && minor <= 13) {
|
|
311
|
+
python = py;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} catch {}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (python) {
|
|
319
|
+
console.log(` [1/3] Found Python: ${python}`);
|
|
320
|
+
if (!fs.existsSync(PIPER_DIR)) {
|
|
321
|
+
fs.mkdirSync(PIPER_DIR, { recursive: true });
|
|
322
|
+
}
|
|
323
|
+
console.log(' [2/3] Creating Python virtual environment...');
|
|
324
|
+
execSync(`${python} -m venv "${PIPER_VENV}"`, { stdio: 'pipe' });
|
|
325
|
+
console.log(' [3/3] Installing piper-tts package...');
|
|
326
|
+
const pip = path.join(PIPER_VENV, 'bin', 'pip');
|
|
327
|
+
execSync(`"${pip}" install --quiet piper-tts`, { stdio: 'pipe' });
|
|
328
|
+
console.log(' [✓] Piper TTS installed successfully');
|
|
329
|
+
} else {
|
|
330
|
+
const installCmd = platform === 'darwin'
|
|
331
|
+
? 'brew install python@3.12'
|
|
332
|
+
: 'sudo apt install python3.12 python3.12-venv';
|
|
333
|
+
console.log(` [!] Python 3.9-3.13 not found. Install with: ${installCmd}`);
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
console.log(' [✓] Piper TTS already installed');
|
|
337
|
+
}
|
|
338
|
+
} catch (err) {
|
|
339
|
+
console.log(' [!] Could not install Piper voice:', err.message);
|
|
340
|
+
console.log(' Run manually: claude-voice voice download en_US-joe-medium');
|
|
299
341
|
}
|
|
300
|
-
} catch (err) {
|
|
301
|
-
console.log(' [!] Could not download wake word model:', err.message);
|
|
302
|
-
console.log(' On Linux, install bzip2: sudo apt install bzip2');
|
|
303
|
-
console.log(' Then run: claude-voice model download kws-zipformer-gigaspeech');
|
|
304
|
-
}
|
|
305
342
|
|
|
306
|
-
//
|
|
307
|
-
console.log('\nStep
|
|
343
|
+
// 7. Download whisper-tiny STT model
|
|
344
|
+
console.log('\nStep 5/7: Downloading Whisper STT model...');
|
|
345
|
+
console.log(' (This may take 2-3 minutes depending on connection)\n');
|
|
346
|
+
try {
|
|
347
|
+
const modelId = 'whisper-tiny';
|
|
348
|
+
const modelFolder = 'sherpa-onnx-whisper-tiny';
|
|
349
|
+
const modelUrl = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-whisper-tiny.tar.bz2';
|
|
350
|
+
const modelPath = path.join(MODELS_DIR, modelFolder);
|
|
308
351
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
352
|
+
if (fs.existsSync(modelPath)) {
|
|
353
|
+
console.log(` [✓] Model already installed: ${modelId}`);
|
|
354
|
+
} else {
|
|
355
|
+
if (!fs.existsSync(MODELS_DIR)) {
|
|
356
|
+
fs.mkdirSync(MODELS_DIR, { recursive: true });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
console.log(` Model: Whisper Tiny (75MB)`);
|
|
360
|
+
await downloadAndExtract(modelUrl, MODELS_DIR, modelFolder, modelId);
|
|
361
|
+
console.log(` [✓] Model installed: ${modelId}`);
|
|
362
|
+
}
|
|
363
|
+
} catch (err) {
|
|
364
|
+
console.log(' [!] Could not download STT model:', err.message);
|
|
365
|
+
console.log(' Run manually: claude-voice model download whisper-tiny');
|
|
316
366
|
}
|
|
317
|
-
}
|
|
318
367
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
console.log(' [!] Could not install sox automatically');
|
|
331
|
-
console.log(' Run manually: brew install sox');
|
|
332
|
-
}
|
|
368
|
+
// 8. Download Sherpa-ONNX keyword spotting model for wake word
|
|
369
|
+
console.log('\nStep 6/7: Downloading Sherpa-ONNX Wake Word model...');
|
|
370
|
+
console.log(' (Sherpa-ONNX keyword spotting - ~19MB)\n');
|
|
371
|
+
try {
|
|
372
|
+
const kwsModelId = 'kws-zipformer-gigaspeech';
|
|
373
|
+
const kwsModelFolder = 'sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01';
|
|
374
|
+
const kwsModelUrl = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/kws-models/sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01.tar.bz2';
|
|
375
|
+
const kwsModelPath = path.join(MODELS_DIR, kwsModelFolder);
|
|
376
|
+
|
|
377
|
+
if (fs.existsSync(kwsModelPath)) {
|
|
378
|
+
console.log(` [✓] Model already installed: ${kwsModelId}`);
|
|
333
379
|
} else {
|
|
334
|
-
|
|
380
|
+
if (!fs.existsSync(MODELS_DIR)) {
|
|
381
|
+
fs.mkdirSync(MODELS_DIR, { recursive: true });
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
console.log(` Model: Keyword Spotter English (19MB)`);
|
|
385
|
+
await downloadAndExtract(kwsModelUrl, MODELS_DIR, kwsModelFolder, kwsModelId);
|
|
386
|
+
console.log(` [✓] Model installed: ${kwsModelId}`);
|
|
335
387
|
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// Linux - check all required tools
|
|
340
|
-
console.log(' Checking Linux dependencies...\n');
|
|
341
|
-
|
|
342
|
-
// Check sox for audio capture
|
|
343
|
-
if (checkCommand('rec')) {
|
|
344
|
-
console.log(' [✓] sox installed');
|
|
345
|
-
} else {
|
|
346
|
-
console.log(' [!] sox not found');
|
|
347
|
-
console.log(' Install: sudo apt install sox');
|
|
388
|
+
} catch (err) {
|
|
389
|
+
console.log(' [!] Could not download wake word model:', err.message);
|
|
390
|
+
console.log(' Run manually: claude-voice model download kws-zipformer-gigaspeech');
|
|
348
391
|
}
|
|
349
392
|
|
|
350
|
-
// Check
|
|
351
|
-
|
|
352
|
-
console.log(' [✓] alsa-utils installed (arecord)');
|
|
353
|
-
} else {
|
|
354
|
-
console.log(' [!] alsa-utils not found');
|
|
355
|
-
console.log(' Install: sudo apt install alsa-utils');
|
|
356
|
-
}
|
|
393
|
+
// 9. Check platform-specific audio tools
|
|
394
|
+
console.log('\nStep 7/7: Checking audio tools...');
|
|
357
395
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
396
|
+
if (platform === 'darwin') {
|
|
397
|
+
if (checkCommand('rec')) {
|
|
398
|
+
console.log(' [✓] sox installed');
|
|
399
|
+
} else {
|
|
400
|
+
if (checkCommand('brew')) {
|
|
401
|
+
try {
|
|
402
|
+
console.log(' Installing sox via Homebrew...');
|
|
403
|
+
execSync('brew install sox', { stdio: 'inherit', timeout: 120000 });
|
|
404
|
+
console.log(' [✓] sox installed via Homebrew');
|
|
405
|
+
} catch (err) {
|
|
406
|
+
console.log(' [!] Could not install sox automatically');
|
|
407
|
+
console.log(' Run manually: brew install sox');
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
console.log(' [!] sox not found. Install with: brew install sox');
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
console.log(' [✓] Audio playback: afplay (native)');
|
|
414
|
+
} else if (platform === 'linux') {
|
|
415
|
+
console.log(' Checking Linux dependencies...\n');
|
|
365
416
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
417
|
+
if (checkCommand('arecord')) {
|
|
418
|
+
console.log(' [✓] alsa-utils installed (arecord)');
|
|
419
|
+
} else {
|
|
420
|
+
console.log(' [!] alsa-utils not found');
|
|
421
|
+
console.log(' Install: sudo apt install alsa-utils');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (checkCommand('aplay') || checkCommand('paplay') || checkCommand('ffplay')) {
|
|
425
|
+
console.log(' [✓] Audio playback available');
|
|
426
|
+
} else {
|
|
427
|
+
console.log(' [!] No audio player found');
|
|
428
|
+
console.log(' Install: sudo apt install alsa-utils');
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (checkCommand('xdotool')) {
|
|
432
|
+
console.log(' [✓] xdotool installed (terminal injection)');
|
|
433
|
+
} else {
|
|
434
|
+
console.log(' [!] xdotool not found (required for voice commands)');
|
|
435
|
+
console.log(' Install: sudo apt install xdotool');
|
|
436
|
+
}
|
|
372
437
|
}
|
|
373
|
-
}
|
|
374
438
|
|
|
375
|
-
// 10. Show platform info and completion
|
|
376
|
-
console.log('\nFinalizing setup...');
|
|
377
|
-
console.log(` Platform: ${platform}`);
|
|
439
|
+
// 10. Show platform info and completion
|
|
440
|
+
console.log('\nFinalizing setup...');
|
|
441
|
+
console.log(` Platform: ${platform}`);
|
|
378
442
|
|
|
379
|
-
if (platform === 'darwin') {
|
|
380
|
-
|
|
381
|
-
} else if (platform === 'linux') {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
443
|
+
if (platform === 'darwin') {
|
|
444
|
+
console.log(' [✓] macOS: All features supported');
|
|
445
|
+
} else if (platform === 'linux') {
|
|
446
|
+
const missingDeps = [];
|
|
447
|
+
if (!checkCommand('arecord')) missingDeps.push('alsa-utils');
|
|
448
|
+
if (!checkCommand('xdotool')) missingDeps.push('xdotool');
|
|
385
449
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
450
|
+
if (missingDeps.length === 0) {
|
|
451
|
+
console.log(' [✓] Linux: All features supported');
|
|
452
|
+
} else {
|
|
453
|
+
console.log(' [!] Linux: Missing dependencies: ' + missingDeps.join(', '));
|
|
454
|
+
}
|
|
390
455
|
}
|
|
456
|
+
|
|
457
|
+
// 11. Show next steps
|
|
458
|
+
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
|
459
|
+
console.log('║ Setup Complete! ║');
|
|
460
|
+
console.log('╚════════════════════════════════════════════════════════════╝\n');
|
|
461
|
+
console.log(' The extension will auto-start when you launch Claude Code.');
|
|
462
|
+
console.log(' TTS, STT, and Wake Word are ready to use!\n');
|
|
463
|
+
console.log(' Say "Jarvis" to start speaking a command.\n');
|
|
464
|
+
console.log(' Commands:');
|
|
465
|
+
console.log(' - Run "claude-voice setup" to customize settings');
|
|
466
|
+
console.log(' - Run "claude-voice doctor" to diagnose issues');
|
|
467
|
+
console.log(' - Run "claude-voice status" to check status\n');
|
|
391
468
|
}
|
|
392
469
|
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
console.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
console.log(' TTS, STT, and Wake Word are ready to use!\n');
|
|
399
|
-
console.log(' Say "Jarvis" to start speaking a command.\n');
|
|
400
|
-
console.log(' Commands:');
|
|
401
|
-
console.log(' - Run "claude-voice setup" to customize settings');
|
|
402
|
-
console.log(' - Run "claude-voice doctor" to diagnose issues');
|
|
403
|
-
console.log(' - Run "claude-voice status" to check status\n');
|
|
470
|
+
// Run setup
|
|
471
|
+
runSetup().catch((err) => {
|
|
472
|
+
console.error('Setup failed:', err.message);
|
|
473
|
+
process.exit(1);
|
|
474
|
+
});
|
package/sounds/ping.wav
ADDED
|
Binary file
|
package/sounds/pop.wav
ADDED
|
Binary file
|