voicecc 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -7
- package/bin/voicecc.js +11 -14
- package/package.json +2 -3
- package/scripts/postinstall.js +32 -58
package/README.md
CHANGED
|
@@ -39,10 +39,3 @@ The voice loop runs locally with zero external API calls except to Claude:
|
|
|
39
39
|
6. **Narration**: Claude's response stripped of markdown and split into sentences
|
|
40
40
|
7. **Text-to-speech**: Kokoro-82M via mlx-audio on Apple Silicon GPU (~8x realtime)
|
|
41
41
|
8. **Speaker playback**: Audio output through VPIO at 24kHz with echo cancellation
|
|
42
|
-
|
|
43
|
-
## Troubleshooting
|
|
44
|
-
|
|
45
|
-
- **"sox not found"**: Install sox with `brew install sox`
|
|
46
|
-
- **"espeak not installed"**: Install espeak-ng with `brew install espeak-ng`
|
|
47
|
-
- **tts-server.py not ready**: Ensure the Python venv is set up correctly
|
|
48
|
-
- **Mic permission denied**: Grant microphone permissions to your terminal or IDE
|
package/bin/voicecc.js
CHANGED
|
@@ -3,31 +3,28 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* CLI entry point for the voicecc command.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* with
|
|
8
|
-
*
|
|
9
|
-
* Responsibilities:
|
|
10
|
-
* - Resolve the package root from this script's location
|
|
11
|
-
* - Spawn tsx with run.ts in the correct working directory
|
|
12
|
-
* - Forward signals (SIGINT, SIGTERM) so Ctrl+C stops the server cleanly
|
|
6
|
+
* Checks if first-run setup is needed (compile mic-vpio, Python venv, etc.)
|
|
7
|
+
* and runs it with visible output. Then spawns `tsx run.ts` for the dashboard.
|
|
13
8
|
*/
|
|
14
9
|
|
|
15
10
|
import { spawn } from "node:child_process";
|
|
16
11
|
import { dirname, join } from "node:path";
|
|
17
12
|
import { fileURLToPath } from "node:url";
|
|
18
13
|
|
|
19
|
-
// ============================================================================
|
|
20
|
-
// CONSTANTS
|
|
21
|
-
// ============================================================================
|
|
22
|
-
|
|
23
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
15
|
const PKG_ROOT = join(__dirname, "..");
|
|
25
16
|
const TSX_BIN = join(PKG_ROOT, "node_modules", ".bin", "tsx");
|
|
26
17
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
// Run setup if needed (first run or incomplete install)
|
|
19
|
+
process.chdir(PKG_ROOT);
|
|
20
|
+
const { needsSetup, runSetup } = await import("../scripts/postinstall.js");
|
|
21
|
+
|
|
22
|
+
if (needsSetup()) {
|
|
23
|
+
console.log("[voicecc] Running first-time setup...\n");
|
|
24
|
+
runSetup();
|
|
25
|
+
}
|
|
30
26
|
|
|
27
|
+
// Start the dashboard
|
|
31
28
|
const child = spawn(TSX_BIN, ["run.ts"], {
|
|
32
29
|
cwd: PKG_ROOT,
|
|
33
30
|
stdio: "inherit",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voicecc",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Voice mode plugin for Claude Code -- hands-free interaction via local STT/TTS/VAD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
"start": "tsx run.ts",
|
|
11
11
|
"dev:dashboard": "cd dashboard && npx vite",
|
|
12
12
|
"build:dashboard": "cd dashboard && npx vite build",
|
|
13
|
-
"prepublishOnly": "npm run build:dashboard"
|
|
14
|
-
"postinstall": "node scripts/postinstall.js"
|
|
13
|
+
"prepublishOnly": "npm run build:dashboard"
|
|
15
14
|
},
|
|
16
15
|
"files": [
|
|
17
16
|
"bin/",
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Setup script for voicecc.
|
|
3
3
|
*
|
|
4
4
|
* Compiles the mic-vpio Swift binary (macOS VPIO echo cancellation),
|
|
5
5
|
* checks for required system dependencies (espeak-ng), then sets up
|
|
6
6
|
* the Python virtual environment and installs TTS dependencies.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* - Compile the mic-vpio Swift binary for echo-cancelled audio I/O
|
|
10
|
-
* - Verify espeak-ng is installed
|
|
11
|
-
* - Create Python venv in sidecar/.venv (if not already present)
|
|
12
|
-
* - Install Python TTS packages (mlx-audio, misaki, etc.)
|
|
13
|
-
* - Download spaCy English model
|
|
8
|
+
* Called from bin/voicecc.js on first run (or when setup is incomplete).
|
|
14
9
|
*/
|
|
15
10
|
|
|
16
11
|
import { execSync } from "child_process";
|
|
@@ -24,6 +19,7 @@ import { join } from "path";
|
|
|
24
19
|
const VENV_DIR = join("sidecar", ".venv");
|
|
25
20
|
const PIP = join(VENV_DIR, "bin", "pip");
|
|
26
21
|
const PYTHON = join(VENV_DIR, "bin", "python3");
|
|
22
|
+
const MIC_VPIO = join("sidecar", "mic-vpio");
|
|
27
23
|
|
|
28
24
|
const PYTHON_PACKAGES = [
|
|
29
25
|
"mlx-audio",
|
|
@@ -34,10 +30,24 @@ const PYTHON_PACKAGES = [
|
|
|
34
30
|
];
|
|
35
31
|
|
|
36
32
|
// ============================================================================
|
|
37
|
-
//
|
|
33
|
+
// PUBLIC API
|
|
38
34
|
// ============================================================================
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Returns true if any setup step is incomplete.
|
|
38
|
+
*/
|
|
39
|
+
export function needsSetup() {
|
|
40
|
+
return (
|
|
41
|
+
!existsSync(MIC_VPIO) ||
|
|
42
|
+
!existsSync(PYTHON) ||
|
|
43
|
+
!existsSync(join("dashboard", "dist", "index.html"))
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Run all setup steps. Shows progress to stdout.
|
|
49
|
+
*/
|
|
50
|
+
export function runSetup() {
|
|
41
51
|
installClaudeMd();
|
|
42
52
|
buildDashboard();
|
|
43
53
|
compileMicVpio();
|
|
@@ -48,21 +58,20 @@ function main() {
|
|
|
48
58
|
|
|
49
59
|
console.log("");
|
|
50
60
|
console.log("========================================");
|
|
51
|
-
console.log("
|
|
61
|
+
console.log(" VOICECC SETUP COMPLETE ");
|
|
52
62
|
console.log("========================================");
|
|
53
63
|
console.log("");
|
|
54
|
-
console.log(" Run 'voicecc' in terminal to start the server!");
|
|
55
|
-
console.log("");
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
// ============================================================================
|
|
59
67
|
// HELPER FUNCTIONS
|
|
60
68
|
// ============================================================================
|
|
61
69
|
|
|
62
|
-
/**
|
|
63
|
-
* Build the dashboard frontend via Vite.
|
|
64
|
-
*/
|
|
65
70
|
function buildDashboard() {
|
|
71
|
+
if (existsSync(join("dashboard", "dist", "index.html"))) {
|
|
72
|
+
console.log("Dashboard already built, skipping.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
66
75
|
console.log("Building dashboard...");
|
|
67
76
|
try {
|
|
68
77
|
run("cd dashboard && npx vite build");
|
|
@@ -74,16 +83,11 @@ function buildDashboard() {
|
|
|
74
83
|
console.log("Dashboard built successfully");
|
|
75
84
|
}
|
|
76
85
|
|
|
77
|
-
/**
|
|
78
|
-
* Copy the project CLAUDE.md from init/ to the project root.
|
|
79
|
-
* Overwrites any existing CLAUDE.md to keep it in sync with the repo.
|
|
80
|
-
*/
|
|
81
86
|
function installClaudeMd() {
|
|
82
87
|
const src = join("init", "CLAUDE.md");
|
|
83
88
|
const dest = "CLAUDE.md";
|
|
84
89
|
|
|
85
90
|
if (!existsSync(src)) {
|
|
86
|
-
console.warn("init/CLAUDE.md not found, skipping.");
|
|
87
91
|
return;
|
|
88
92
|
}
|
|
89
93
|
|
|
@@ -91,13 +95,13 @@ function installClaudeMd() {
|
|
|
91
95
|
console.log("Installed CLAUDE.md to project root.");
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
/**
|
|
95
|
-
* Compile the mic-vpio Swift binary for macOS VPIO echo cancellation.
|
|
96
|
-
* Skips compilation if the binary already exists and is newer than the source.
|
|
97
|
-
*/
|
|
98
98
|
function compileMicVpio() {
|
|
99
|
+
if (existsSync(MIC_VPIO)) {
|
|
100
|
+
console.log("mic-vpio already compiled, skipping.");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
const source = join("sidecar", "mic-vpio.swift");
|
|
100
|
-
const binary = join("sidecar", "mic-vpio");
|
|
101
105
|
|
|
102
106
|
if (process.platform !== "darwin") {
|
|
103
107
|
console.error("\n[voicecc] ERROR: macOS is required.");
|
|
@@ -114,7 +118,7 @@ function compileMicVpio() {
|
|
|
114
118
|
|
|
115
119
|
console.log("Compiling mic-vpio (VPIO echo cancellation)...");
|
|
116
120
|
try {
|
|
117
|
-
run(`swiftc -O -o ${
|
|
121
|
+
run(`swiftc -O -o ${MIC_VPIO} ${source} -framework AudioToolbox -framework CoreAudio`);
|
|
118
122
|
} catch (err) {
|
|
119
123
|
console.error("\n[voicecc] ERROR: Failed to compile mic-vpio.swift.");
|
|
120
124
|
console.error(" Make sure Xcode Command Line Tools are installed: xcode-select --install\n");
|
|
@@ -123,10 +127,6 @@ function compileMicVpio() {
|
|
|
123
127
|
console.log("mic-vpio compiled successfully");
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
/**
|
|
127
|
-
* Check that required system binaries are available.
|
|
128
|
-
* Exits with a clear error message if any are missing.
|
|
129
|
-
*/
|
|
130
130
|
function checkSystemDeps() {
|
|
131
131
|
const missing = [];
|
|
132
132
|
|
|
@@ -135,16 +135,13 @@ function checkSystemDeps() {
|
|
|
135
135
|
if (missing.length > 0) {
|
|
136
136
|
console.error(`\n[voicecc] ERROR: Missing system dependencies: ${missing.join(", ")}`);
|
|
137
137
|
console.error(` Install with: brew install ${missing.join(" ")}`);
|
|
138
|
-
console.error(` Then re-run:
|
|
138
|
+
console.error(` Then re-run: voicecc\n`);
|
|
139
139
|
process.exit(1);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
console.log("System dependencies OK (espeak-ng)");
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
/**
|
|
146
|
-
* Create the Python virtual environment if it doesn't exist.
|
|
147
|
-
*/
|
|
148
145
|
function setupPythonVenv() {
|
|
149
146
|
if (existsSync(PIP)) {
|
|
150
147
|
console.log(`Python venv already exists at ${VENV_DIR}`);
|
|
@@ -167,9 +164,6 @@ function setupPythonVenv() {
|
|
|
167
164
|
}
|
|
168
165
|
}
|
|
169
166
|
|
|
170
|
-
/**
|
|
171
|
-
* Install Python TTS packages into the venv.
|
|
172
|
-
*/
|
|
173
167
|
function installPythonPackages() {
|
|
174
168
|
console.log("Installing Python TTS packages...");
|
|
175
169
|
try {
|
|
@@ -178,14 +172,11 @@ function installPythonPackages() {
|
|
|
178
172
|
console.error("\n[voicecc] ERROR: Failed to install Python TTS packages.");
|
|
179
173
|
console.error(" This may be due to missing build tools or incompatible Python version.");
|
|
180
174
|
console.error(" Required packages: " + PYTHON_PACKAGES.join(", "));
|
|
181
|
-
console.error(" Try deleting sidecar/.venv and re-running:
|
|
175
|
+
console.error(" Try deleting sidecar/.venv and re-running: voicecc\n");
|
|
182
176
|
process.exit(1);
|
|
183
177
|
}
|
|
184
178
|
}
|
|
185
179
|
|
|
186
|
-
/**
|
|
187
|
-
* Download the spaCy English language model.
|
|
188
|
-
*/
|
|
189
180
|
function downloadSpacyModel() {
|
|
190
181
|
console.log("Downloading spaCy English model...");
|
|
191
182
|
try {
|
|
@@ -197,12 +188,6 @@ function downloadSpacyModel() {
|
|
|
197
188
|
}
|
|
198
189
|
}
|
|
199
190
|
|
|
200
|
-
/**
|
|
201
|
-
* Check if a command exists on the system PATH.
|
|
202
|
-
*
|
|
203
|
-
* @param {string} cmd - Command name to check
|
|
204
|
-
* @returns {boolean} True if the command exists
|
|
205
|
-
*/
|
|
206
191
|
function commandExists(cmd) {
|
|
207
192
|
try {
|
|
208
193
|
execSync(`which ${cmd}`, { stdio: "ignore" });
|
|
@@ -212,17 +197,6 @@ function commandExists(cmd) {
|
|
|
212
197
|
}
|
|
213
198
|
}
|
|
214
199
|
|
|
215
|
-
/**
|
|
216
|
-
* Run a shell command with inherited stdio (output visible to user).
|
|
217
|
-
*
|
|
218
|
-
* @param {string} cmd - Shell command to execute
|
|
219
|
-
*/
|
|
220
200
|
function run(cmd) {
|
|
221
201
|
execSync(cmd, { stdio: "inherit" });
|
|
222
202
|
}
|
|
223
|
-
|
|
224
|
-
// ============================================================================
|
|
225
|
-
// ENTRY POINT
|
|
226
|
-
// ============================================================================
|
|
227
|
-
|
|
228
|
-
main();
|