klaudio 0.12.3 → 0.12.6

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/cli.js CHANGED
@@ -4,6 +4,7 @@
4
4
  if (process.argv[2] === "play") {
5
5
  const { handlePlayCommand } = await import("../src/player.js");
6
6
  await handlePlayCommand(process.argv.slice(3));
7
+ // Hard exit: skip native module destructors (onnxruntime crashes during cleanup)
7
8
  process.exit(0);
8
9
  }
9
10
 
@@ -28,6 +29,7 @@ if (process.argv[2] === "say") {
28
29
  const { speak } = await import("../src/tts.js");
29
30
  await speak(text, { voice });
30
31
  }
32
+ // Hard exit: skip native module destructors (onnxruntime crashes during cleanup)
31
33
  process.exit(0);
32
34
  }
33
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klaudio",
3
- "version": "0.12.3",
3
+ "version": "0.12.6",
4
4
  "description": "Add sound effects to your coding sessions — play sounds when tasks complete, notifications arrive, and more",
5
5
  "type": "module",
6
6
  "bin": {
package/src/player.js CHANGED
@@ -467,10 +467,19 @@ export async function handlePlayCommand(args) {
467
467
  const project = hookData.cwd ? hookData.cwd.replace(/\\/g, "/").split("/").pop() : null;
468
468
  const spoken = project ? `${project}: ${summary}` : summary;
469
469
  await soundPromise;
470
- const { speak } = await import("./tts.js");
471
470
  const voice = args.find((a) => a.startsWith("--voice="))?.slice(8)
472
471
  || args[args.indexOf("--voice") + 1];
473
- await speak(spoken, { voice });
472
+ // Spawn a detached child process for TTS so the hook can exit immediately
473
+ const { spawn } = await import("node:child_process");
474
+ const child = spawn(process.execPath, [
475
+ "--input-type=module",
476
+ "-e",
477
+ `import{speak}from"${import.meta.resolve("./tts.js")}";await speak(${JSON.stringify(spoken)},{voice:${JSON.stringify(voice || undefined)}});`,
478
+ ], {
479
+ detached: true,
480
+ stdio: "ignore",
481
+ });
482
+ child.unref();
474
483
  } else {
475
484
  await soundPromise;
476
485
  }
package/src/tts.js CHANGED
@@ -317,10 +317,9 @@ async function speakPiper(text, onProgress) {
317
317
 
318
318
  function speakMacOS(text) {
319
319
  return new Promise((resolve) => {
320
- // Try Samantha (high quality US English), fall back to default
321
- execFile("say", ["-v", "Samantha", text], { timeout: 15000 }, (err) => {
320
+ execFile("say", ["-v", "Samantha", text], { timeout: 30000 }, (err) => {
322
321
  if (err) {
323
- execFile("say", [text], { timeout: 15000 }, () => resolve());
322
+ execFile("say", [text], { timeout: 30000 }, () => resolve());
324
323
  } else {
325
324
  resolve();
326
325
  }
@@ -374,13 +373,7 @@ export async function speak(text, options = {}) {
374
373
  ? { voice: null, onProgress: options } // backwards compat: speak(text, onProgress)
375
374
  : options;
376
375
 
377
- // macOS: use built-in `say` (skip Kokoro — native onnxruntime module
378
- // can abort the process with a C++ exception before JS can catch it)
379
- if (platform() === "darwin") {
380
- return speakMacOS(text);
381
- }
382
-
383
- // Try Kokoro (best quality, works on Linux/Windows)
376
+ // Try Kokoro (best quality)
384
377
  if (await isKokoroAvailable()) {
385
378
  try {
386
379
  await speakKokoro(text, voice);
@@ -390,8 +383,11 @@ export async function speak(text, options = {}) {
390
383
  }
391
384
  }
392
385
 
393
- // Fallback: Piper
394
- return speakPiper(text, onProgress);
386
+ // Fallback: Piper (Linux/Windows), then macOS say
387
+ if (platform() !== "darwin") {
388
+ return speakPiper(text, onProgress);
389
+ }
390
+ return speakMacOS(text);
395
391
  } finally {
396
392
  speaking = false;
397
393
  await releaseTTSLock();