voicecc 1.1.6 → 1.1.7

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.
Files changed (2) hide show
  1. package/bin/voicecc.js +52 -9
  2. package/package.json +1 -1
package/bin/voicecc.js CHANGED
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { spawn, execSync } from "node:child_process";
12
- import { copyFileSync, existsSync } from "node:fs";
12
+ import { copyFileSync, existsSync, chownSync, mkdirSync } from "node:fs";
13
13
  import { writeFile, readFile } from "node:fs/promises";
14
14
  import { createInterface } from "node:readline";
15
15
  import { randomBytes } from "node:crypto";
@@ -168,6 +168,33 @@ async function runSetupWizard() {
168
168
  console.log("");
169
169
  }
170
170
 
171
+ // ============================================================================
172
+ // ROOT PRIVILEGE DROP
173
+ // ============================================================================
174
+
175
+ const VOICECC_USER = "voicecc";
176
+
177
+ /**
178
+ * Ensure a non-root user exists for running the server.
179
+ * Creates the user if it doesn't exist (Linux only).
180
+ */
181
+ function ensureNonRootUser() {
182
+ try {
183
+ execSync(`id ${VOICECC_USER}`, { stdio: "ignore" });
184
+ } catch {
185
+ console.log(`Creating '${VOICECC_USER}' user...`);
186
+ execSync(`useradd -r -m -s /bin/bash ${VOICECC_USER}`, { stdio: "inherit" });
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Give the voicecc user ownership of the package directory so it can
192
+ * read config, write .env, etc.
193
+ */
194
+ function chownPkgRoot() {
195
+ execSync(`chown -R ${VOICECC_USER}:${VOICECC_USER} ${PKG_ROOT}`, { stdio: "inherit" });
196
+ }
197
+
171
198
  // ============================================================================
172
199
  // MAIN ENTRYPOINT
173
200
  // ============================================================================
@@ -183,13 +210,29 @@ if (!existsSync(ENV_PATH)) {
183
210
  await runSetupWizard();
184
211
  }
185
212
 
186
- // Start the dashboard
187
- const child = spawn(TSX_BIN, ["server/index.ts"], {
188
- cwd: PKG_ROOT,
189
- stdio: "inherit",
190
- });
213
+ // If running as root, re-exec as a non-root user
214
+ const isRoot = process.getuid && process.getuid() === 0;
215
+ if (isRoot) {
216
+ ensureNonRootUser();
217
+ chownPkgRoot();
191
218
 
192
- process.on("SIGINT", () => child.kill("SIGINT"));
193
- process.on("SIGTERM", () => child.kill("SIGTERM"));
219
+ console.log(`Dropping root privileges, running as '${VOICECC_USER}'...`);
220
+ const child = spawn("su", ["-", VOICECC_USER, "-c", `cd ${PKG_ROOT} && ${TSX_BIN} server/index.ts`], {
221
+ cwd: PKG_ROOT,
222
+ stdio: "inherit",
223
+ });
224
+
225
+ process.on("SIGINT", () => child.kill("SIGINT"));
226
+ process.on("SIGTERM", () => child.kill("SIGTERM"));
227
+ child.on("exit", (code) => process.exit(code ?? 1));
228
+ } else {
229
+ // Start the dashboard directly
230
+ const child = spawn(TSX_BIN, ["server/index.ts"], {
231
+ cwd: PKG_ROOT,
232
+ stdio: "inherit",
233
+ });
194
234
 
195
- child.on("exit", (code) => process.exit(code ?? 1));
235
+ process.on("SIGINT", () => child.kill("SIGINT"));
236
+ process.on("SIGTERM", () => child.kill("SIGTERM"));
237
+ child.on("exit", (code) => process.exit(code ?? 1));
238
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "voicecc",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "description": "Voice mode plugin for Claude Code -- hands-free interaction via ElevenLabs STT/TTS and VAD",
5
5
  "type": "module",
6
6
  "bin": {