@drakulavich/kesha-voice-kit 1.31.0 → 2.1.0
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 +4 -4
- package/SKILL.md +1 -1
- package/docs/product-positioning.md +3 -3
- package/model-plan.json +14 -14
- package/package.json +21 -7
- package/src/cache-layout.ts +78 -8
- package/src/cli/init.ts +10 -11
- package/src/cli/install.ts +7 -5
- package/src/cli/main.ts +2 -14
- package/src/cli/support-bundle.ts +2 -1
- package/src/doctor.ts +3 -9
- package/src/engine/events.ts +6 -1
- package/src/engine/spawn.ts +114 -0
- package/src/engine-health.ts +25 -56
- package/src/engine-install.ts +333 -142
- package/src/engine-targets.ts +53 -5
- package/src/engine.ts +79 -121
- package/src/install-plan.ts +20 -41
- package/src/kokoro-ane.ts +1 -1
- package/src/language-routing.ts +14 -0
- package/src/lib.ts +95 -66
- package/src/mcp/tools.ts +5 -11
- package/src/package-info.ts +28 -2
- package/src/path-errnos.ts +11 -0
- package/src/process-tree.ts +13 -11
- package/src/progress.ts +30 -13
- package/src/semver.mjs +7 -10
- package/src/status.ts +5 -16
- package/src/support-bundle.ts +72 -8
- package/src/synth.ts +38 -86
- package/src/transcribe.ts +9 -4
package/src/engine-health.ts
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { existsSync } from "fs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
getDescribe,
|
|
5
|
-
getEngineBinPath,
|
|
6
|
-
spawnEngineProcess,
|
|
7
|
-
type EngineCapabilities,
|
|
8
|
-
} from "./engine";
|
|
2
|
+
import { ENGINE_PROBE_TIMEOUT_MS, getDescribe, getEngineBinPath, type EngineCapabilities } from "./engine";
|
|
9
3
|
import { describeToCapabilities } from "./engine/describe";
|
|
10
4
|
import { KeshaError } from "./engine/events";
|
|
11
|
-
import {
|
|
5
|
+
import { runEngineProcess } from "./engine/spawn";
|
|
12
6
|
|
|
13
7
|
export type ExecutableHealth =
|
|
14
8
|
| { status: "ok" }
|
|
15
9
|
| { status: "missing" }
|
|
16
10
|
| { status: "unusable"; detail: string };
|
|
17
11
|
|
|
18
|
-
const PROBE_TIMEOUT_MS = 15_000;
|
|
19
|
-
|
|
20
12
|
/**
|
|
21
13
|
* Proves a downloaded binary actually executes — existence is not health (#770).
|
|
22
14
|
*
|
|
@@ -28,39 +20,32 @@ const PROBE_TIMEOUT_MS = 15_000;
|
|
|
28
20
|
* The timeout guards against a binary that starts but never exits; macOS Gatekeeper can take
|
|
29
21
|
* several seconds to scan a freshly written binary on its first run, so it is generous.
|
|
30
22
|
*/
|
|
23
|
+
/** Message plus hint, not the rendered error: a caller wrapping it would otherwise nest a second code line. */
|
|
24
|
+
function spawnFailureDetail(err: unknown): string {
|
|
25
|
+
if (!(err instanceof Error)) return String(err);
|
|
26
|
+
return err instanceof KeshaError && err.hint ? `${err.message}; ${err.hint}` : err.message;
|
|
27
|
+
}
|
|
28
|
+
|
|
31
29
|
export async function probeExecutable(
|
|
32
30
|
binPath: string,
|
|
33
31
|
args: string[] = [],
|
|
34
32
|
): Promise<ExecutableHealth> {
|
|
35
33
|
if (!existsSync(binPath)) return { status: "missing" };
|
|
36
34
|
|
|
37
|
-
let
|
|
35
|
+
let run: Awaited<ReturnType<typeof runEngineProcess>>;
|
|
38
36
|
try {
|
|
39
|
-
|
|
37
|
+
run = await runEngineProcess(binPath, args, {
|
|
38
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
39
|
+
signal: AbortSignal.timeout(ENGINE_PROBE_TIMEOUT_MS),
|
|
40
|
+
});
|
|
40
41
|
} catch (err) {
|
|
41
|
-
return { status: "unusable", detail:
|
|
42
|
-
}
|
|
43
|
-
const tree = registerProcessTree(proc);
|
|
44
|
-
|
|
45
|
-
let timedOut = false;
|
|
46
|
-
let forceKillTimer: Timer | undefined;
|
|
47
|
-
const timer = setTimeout(() => {
|
|
48
|
-
timedOut = true;
|
|
49
|
-
tree.terminate();
|
|
50
|
-
forceKillTimer = tree.forceKillAfterGrace();
|
|
51
|
-
}, PROBE_TIMEOUT_MS);
|
|
52
|
-
try {
|
|
53
|
-
await proc.exited;
|
|
54
|
-
} finally {
|
|
55
|
-
clearTimeout(timer);
|
|
56
|
-
tree.dispose();
|
|
57
|
-
if (!timedOut && forceKillTimer) clearTimeout(forceKillTimer);
|
|
42
|
+
return { status: "unusable", detail: spawnFailureDetail(err) };
|
|
58
43
|
}
|
|
59
44
|
|
|
60
|
-
if (
|
|
61
|
-
return { status: "unusable", detail: `no exit within ${
|
|
45
|
+
if (run.aborted) {
|
|
46
|
+
return { status: "unusable", detail: `no exit within ${ENGINE_PROBE_TIMEOUT_MS / 1000}s` };
|
|
62
47
|
}
|
|
63
|
-
if (
|
|
48
|
+
if (run.signalCode) return { status: "unusable", detail: `killed by ${run.signalCode}` };
|
|
64
49
|
return { status: "ok" };
|
|
65
50
|
}
|
|
66
51
|
|
|
@@ -73,36 +58,20 @@ export async function probeExecutable(
|
|
|
73
58
|
*/
|
|
74
59
|
export async function readExecutableVersion(
|
|
75
60
|
binPath: string,
|
|
76
|
-
timeoutMs =
|
|
61
|
+
timeoutMs = ENGINE_PROBE_TIMEOUT_MS,
|
|
77
62
|
): Promise<string | null> {
|
|
78
63
|
if (!existsSync(binPath)) return null;
|
|
79
64
|
|
|
80
|
-
let
|
|
65
|
+
let stdout: string;
|
|
81
66
|
try {
|
|
82
|
-
|
|
67
|
+
({ stdout } = await runEngineProcess(binPath, ["--version"], {
|
|
68
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
69
|
+
readStdout: (stream) => new Response(stream).text(),
|
|
70
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
71
|
+
}));
|
|
83
72
|
} catch {
|
|
84
73
|
return null;
|
|
85
74
|
}
|
|
86
|
-
const tree = registerProcessTree(proc);
|
|
87
|
-
|
|
88
|
-
let timedOut = false;
|
|
89
|
-
let forceKillTimer: Timer | undefined;
|
|
90
|
-
const timer = setTimeout(() => {
|
|
91
|
-
timedOut = true;
|
|
92
|
-
tree.terminate();
|
|
93
|
-
forceKillTimer = tree.forceKillAfterGrace();
|
|
94
|
-
}, timeoutMs);
|
|
95
|
-
let stdout: string;
|
|
96
|
-
try {
|
|
97
|
-
[stdout] = await Promise.all([
|
|
98
|
-
new Response(proc.stdout as ReadableStream<Uint8Array>).text(),
|
|
99
|
-
proc.exited,
|
|
100
|
-
]);
|
|
101
|
-
} finally {
|
|
102
|
-
clearTimeout(timer);
|
|
103
|
-
tree.dispose();
|
|
104
|
-
if (!timedOut && forceKillTimer) clearTimeout(forceKillTimer);
|
|
105
|
-
}
|
|
106
75
|
return /(\d+\.\d+\.\d+[0-9A-Za-z.+-]*)/.exec(stdout)?.[1] ?? null;
|
|
107
76
|
}
|
|
108
77
|
|
|
@@ -132,7 +101,7 @@ const MUTE_DETAIL = "reports no capabilities";
|
|
|
132
101
|
* that could not be made to answer (`unusable`), not one that answered nothing (`mute`).
|
|
133
102
|
*/
|
|
134
103
|
export async function engineFunctionalHealth(
|
|
135
|
-
timeoutMs =
|
|
104
|
+
timeoutMs = ENGINE_PROBE_TIMEOUT_MS,
|
|
136
105
|
): Promise<EngineFunctionalHealth> {
|
|
137
106
|
const controller = new AbortController();
|
|
138
107
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|