voicecc 1.1.8 → 1.1.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/bin/voicecc.js CHANGED
@@ -297,12 +297,33 @@ function stopDaemon() {
297
297
  const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
298
298
  console.log(`Stopping VoiceCC (PID ${pid})...`);
299
299
 
300
+ // Kill the entire process group (negative PID) so child processes
301
+ // like cloudflared and tsx's Node subprocess are also terminated.
300
302
  try {
301
- process.kill(pid, "SIGTERM");
303
+ process.kill(-pid, "SIGTERM");
302
304
  } catch {
303
- // Already dead
305
+ // Fall back to killing just the main PID
306
+ try { process.kill(pid, "SIGTERM"); } catch { /* already dead */ }
304
307
  }
305
308
 
309
+ // Wait for the process to actually die (up to 5 seconds)
310
+ const deadline = Date.now() + 5000;
311
+ while (Date.now() < deadline) {
312
+ try {
313
+ process.kill(pid, 0);
314
+ } catch {
315
+ break; // Process is gone
316
+ }
317
+ // Busy-wait in small increments
318
+ const waitUntil = Date.now() + 100;
319
+ while (Date.now() < waitUntil) { /* spin */ }
320
+ }
321
+
322
+ // Force kill if still alive
323
+ try {
324
+ process.kill(-pid, "SIGKILL");
325
+ } catch { /* already dead */ }
326
+
306
327
  // Clean up
307
328
  try { unlinkSync(PID_FILE); } catch { /* ignore */ }
308
329
  try { unlinkSync(STATUS_FILE); } catch { /* ignore */ }
@@ -479,10 +500,20 @@ function startDaemon() {
479
500
  ensureNonRootUser();
480
501
  chownPkgRoot();
481
502
  console.log(`Dropping root privileges, running as '${VOICECC_USER}'...`);
482
- child = spawn("su", ["-", VOICECC_USER, "-c", `cd ${PKG_ROOT} && ${TSX_BIN} server/index.ts`], {
503
+
504
+ // Resolve uid/gid for the voicecc user so we can drop privileges
505
+ // via spawn options instead of `su`, which can leak stdio and
506
+ // cause PID tracking issues.
507
+ const uid = parseInt(execSync(`id -u ${VOICECC_USER}`, { encoding: "utf-8" }).trim(), 10);
508
+ const gid = parseInt(execSync(`id -g ${VOICECC_USER}`, { encoding: "utf-8" }).trim(), 10);
509
+
510
+ child = spawn(TSX_BIN, ["server/index.ts"], {
483
511
  cwd: PKG_ROOT,
484
512
  detached: true,
485
513
  stdio: ["ignore", logFd, logFd],
514
+ uid,
515
+ gid,
516
+ env: { ...process.env, HOME: `/home/${VOICECC_USER}`, USER: VOICECC_USER, VOICECC_DIR },
486
517
  });
487
518
  } else {
488
519
  child = spawn(TSX_BIN, ["server/index.ts"], {
@@ -543,6 +574,16 @@ if (isRunning()) {
543
574
  // Start the daemon
544
575
  startDaemon();
545
576
 
546
- // Wait briefly for server to write status.json, then show info
547
- await new Promise((resolve) => setTimeout(resolve, 3000));
577
+ // Poll for status.json until the server is ready
578
+ const tunnelEnabled = readFileSync(ENV_PATH, "utf-8").includes("TUNNEL_ENABLED=true");
579
+ const MAX_WAIT_MS = tunnelEnabled ? 30000 : 10000;
580
+ const POLL_INTERVAL_MS = 500;
581
+ const startTime = Date.now();
582
+
583
+ while (Date.now() - startTime < MAX_WAIT_MS) {
584
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
585
+ const status = readStatus();
586
+ if (status && (!tunnelEnabled || status.tunnelUrl)) break;
587
+ }
588
+
548
589
  showInfo();