@drakulavich/kesha-voice-kit 1.24.6 → 1.25.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 +14 -5
- package/completions/kesha.bash +1 -1
- package/completions/kesha.fish +3 -2
- package/completions/kesha.zsh +4 -3
- package/docs/product-positioning.md +16 -7
- package/man/kesha.1 +5 -2
- package/model-plan.json +43 -0
- package/package.json +10 -8
- package/src/cli/action-result.ts +18 -0
- package/src/cli/command-session.ts +86 -0
- package/src/cli/context.ts +108 -0
- package/src/cli/dispatch.ts +36 -99
- package/src/cli/init.ts +2 -2
- package/src/cli/install.ts +18 -6
- package/src/cli/logs.ts +93 -67
- package/src/cli/main.ts +235 -210
- package/src/cli/record.ts +23 -2
- package/src/cli/say.ts +145 -96
- package/src/cli/stats.ts +96 -77
- package/src/cli/status.ts +15 -2
- package/src/cli.ts +3 -1
- package/src/engine.ts +41 -11
- package/src/error-codes.ts +1 -0
- package/src/install-plan.ts +125 -140
- package/src/mcp/tools.ts +10 -3
- package/src/mcp/voices.ts +12 -7
- package/src/shell-artifacts.ts +2 -2
- package/src/status.ts +110 -47
- package/src/synth.ts +2 -4
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
- **Transcribe locally** — [25 languages](docs/languages.md#speech-to-text-25), up to ~19x faster than Whisper on Apple Silicon, ~2.5x on CPU
|
|
17
17
|
- **Speak back** — text-to-speech in [9 languages](docs/languages.md#text-to-speech)
|
|
18
18
|
- **Plug into agents** — ship voice workflows as CLI commands, an MCP server, an <a href="docs/openclaw.md">OpenClaw</a> skill, or a <a href="docs/hermes.md">Hermes</a> agent
|
|
19
|
-
- **Small Rust engine** — single ~
|
|
19
|
+
- **Small Rust engine** — single ~60MB binary, no ffmpeg, no Python, no native Node addons
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
22
|
<img src="https://github.com/drakulavich/kesha-voice-kit/raw/main/demo.gif" alt="kesha demo — English + Russian transcription with automatic language detection" width="800">
|
|
@@ -24,16 +24,21 @@
|
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
|
27
|
-
Runtime: **[Bun](https://bun.sh)** >= 1.3.0 · Platforms: macOS arm64, Linux x64
|
|
27
|
+
Runtime: **[Bun](https://bun.sh)** >= 1.3.0 · Platforms: macOS arm64, Linux x64. Windows x64 is currently blocked at install ([#216](https://github.com/drakulavich/kesha-voice-kit/issues/216)).
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
# 1. Install Bun (skip if you have it) — Linux & macOS:
|
|
31
31
|
curl -fsSL https://bun.sh/install | bash # or: brew install oven-sh/bun/bun
|
|
32
32
|
# Windows: powershell -c "irm bun.sh/install.ps1 | iex"
|
|
33
|
+
# if `bun --version` fails, reload PATH: exec $SHELL -l
|
|
33
34
|
|
|
34
35
|
# 2. Install Kesha:
|
|
35
36
|
bun add -g @drakulavich/kesha-voice-kit
|
|
36
|
-
kesha
|
|
37
|
+
kesha --version # confirms `kesha` resolved on PATH
|
|
38
|
+
kesha install --plan # preview exact download/disk sizes first — downloads nothing
|
|
39
|
+
kesha install # ~2.5 GB (engine + speech-to-text models), explicit — never automatic.
|
|
40
|
+
# No progress bar during the model step; can take several minutes.
|
|
41
|
+
# Prefer a guided wizard? `kesha init` walks through the same choices interactively.
|
|
37
42
|
|
|
38
43
|
# 3. Transcribe:
|
|
39
44
|
kesha audio.ogg # transcript to stdout
|
|
@@ -51,6 +56,8 @@ kesha --format json audio.ogg # full JSON with lang fields
|
|
|
51
56
|
kesha --json --timestamps audio.ogg # JSON with timestamped segments
|
|
52
57
|
kesha --toon audio.ogg # compact LLM-friendly TOON
|
|
53
58
|
kesha status # show installed backend info
|
|
59
|
+
kesha status --disk # + recursive cache disk usage
|
|
60
|
+
kesha status --json # machine-readable, for scripts
|
|
54
61
|
```
|
|
55
62
|
|
|
56
63
|
Multiple files get `head`-style headers; stdout is the transcript, stderr is errors — pipe-friendly:
|
|
@@ -64,6 +71,7 @@ $ kesha freedom.ogg tahiti.ogg
|
|
|
64
71
|
Таити, Таити! Не были мы ни в какой Таити! Нас и тут неплохо кормят.
|
|
65
72
|
```
|
|
66
73
|
|
|
74
|
+
- **Record from the mic (macOS):** `kesha record --out hello.wav` writes microphone audio to a WAV file (`kesha hello.wav` transcribes it). macOS prompts for microphone access on first use — grant it under System Settings → Privacy & Security → Microphone if it was denied. On Linux/Windows or headless boxes, pass any existing audio file straight to `kesha` instead.
|
|
67
75
|
- **Long / silence-heavy audio:** install VAD (`kesha install --vad`); Kesha auto-uses it past 120 s. Without VAD, long audio falls back to fixed ASR chunks. See [docs/vad.md](docs/vad.md).
|
|
68
76
|
- **Speaker diarization** (darwin-arm64): `kesha install --diarize`, then `kesha --json --vad --speakers meeting.m4a` stamps each segment with a `speaker` id. Linux/Windows return a clear "darwin-arm64 only" error ([#199](https://github.com/drakulavich/kesha-voice-kit/issues/199)).
|
|
69
77
|
|
|
@@ -72,7 +80,8 @@ $ kesha freedom.ogg tahiti.ogg
|
|
|
72
80
|
Kesha speaks back in [9 languages](docs/languages.md#text-to-speech), auto-picking the voice from the text's language. Override with `--lang <code>` or `--voice <id>`.
|
|
73
81
|
|
|
74
82
|
```bash
|
|
75
|
-
kesha install --tts #
|
|
83
|
+
kesha install --tts # English voices; sizes differ per platform — preview: kesha install --plan
|
|
84
|
+
kesha install --tts en ru # + Russian (+~890 MB, Vosk)
|
|
76
85
|
kesha say "Hello, world" > hello.wav
|
|
77
86
|
kesha say "Привет, мир" > privet.wav # auto-routes by language
|
|
78
87
|
kesha say --voice ru-vosk-m02 "Голос в текст." > ru.wav
|
|
@@ -117,7 +126,7 @@ All of these install the Bun CLI wrapper; engine + models still download explici
|
|
|
117
126
|
- **MCP server** — `kesha mcp` exposes transcribe/synthesize/list tools to any MCP client (Claude, Cursor, Codex, Gemini). Setup: [docs/mcp.md](docs/mcp.md).
|
|
118
127
|
- **OpenClaw** — give your LLM agent ears. Install & config: [docs/openclaw.md](docs/openclaw.md).
|
|
119
128
|
- **Hermes Agent** — local STT/TTS through Hermes command providers. Setup: [docs/hermes.md](docs/hermes.md).
|
|
120
|
-
- **Raycast** (macOS) —
|
|
129
|
+
- **Raycast** (macOS) — offline microphone dictation from the launcher: *Dictate to Clipboard* records with a live signal meter, auto-stops on silence, transcribes locally, and copies the text. [Install from the Raycast Store](https://www.raycast.com/drakulavich/kesha-voice-kit) · source: [`raycast/`](raycast/).
|
|
121
130
|
- **Programmatic API** — `@drakulavich/kesha-voice-kit/core` for use inside a Bun program. See [docs/api.md](docs/api.md).
|
|
122
131
|
|
|
123
132
|
## More
|
package/completions/kesha.bash
CHANGED
|
@@ -28,7 +28,7 @@ _kesha_completion() {
|
|
|
28
28
|
record) opts="--help -h --out --max-seconds --debug" ;;
|
|
29
29
|
say) opts="--help -h --voice --lang --out --rate --list-voices --ssml --format --bitrate --sample-rate --no-expand-abbrev --verbose --debug" ;;
|
|
30
30
|
stats) opts="--help -h --format" ;;
|
|
31
|
-
status) opts="--help -h --disk" ;;
|
|
31
|
+
status) opts="--help -h --disk --json" ;;
|
|
32
32
|
support-bundle) opts="--help -h --output --include-logs" ;;
|
|
33
33
|
*) opts="--help -h --version -v --json --toon --timestamps --speakers --include-errors --verbose --format --lang --debug --vad --no-vad --quiet --no-color" ;;
|
|
34
34
|
esac
|
package/completions/kesha.fish
CHANGED
|
@@ -42,7 +42,7 @@ complete -c kesha -n '__fish_seen_subcommand_from init' -l onnx -d 'Preselect ON
|
|
|
42
42
|
complete -c kesha -n '__fish_seen_subcommand_from init' -l no-cache -d 'Re-download even if cached'
|
|
43
43
|
complete -c kesha -n '__fish_seen_subcommand_from init' -l plan -d 'Show the selected install plan without downloading'
|
|
44
44
|
complete -c kesha -n '__fish_seen_subcommand_from init' -l yes -d 'Accept defaults and run without prompts'
|
|
45
|
-
complete -c kesha -n '__fish_seen_subcommand_from init' -l tts -d 'Preselect TTS models (
|
|
45
|
+
complete -c kesha -n '__fish_seen_subcommand_from init' -l tts -d 'Preselect TTS models (English; more languages via kesha install --tts <langs>)'
|
|
46
46
|
complete -c kesha -n '__fish_seen_subcommand_from init' -l vad -d 'Preselect Silero VAD (~2.3MB) for long-audio preprocessing'
|
|
47
47
|
complete -c kesha -n '__fish_seen_subcommand_from init' -l diarize -d 'Preselect Sortformer speaker diarization (~245MB, darwin-arm64 only)'
|
|
48
48
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l help -d 'Show help'
|
|
@@ -51,7 +51,7 @@ complete -c kesha -n '__fish_seen_subcommand_from install' -l coreml -d 'Force C
|
|
|
51
51
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l onnx -d 'Force ONNX backend'
|
|
52
52
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l no-cache -d 'Re-download even if cached'
|
|
53
53
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l plan -d 'Show download, disk, and warm-up plan without changing local state'
|
|
54
|
-
complete -c kesha -n '__fish_seen_subcommand_from install' -l tts -d 'Also install TTS models (
|
|
54
|
+
complete -c kesha -n '__fish_seen_subcommand_from install' -l tts -d 'Also install TTS models (English only; add codes for more, e.g. --tts en ru (preview sizes: kesha install --plan))'
|
|
55
55
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l vad -d 'Also install Silero VAD (~2.3MB) for long-audio preprocessing'
|
|
56
56
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l diarize -d 'Also install the Sortformer streaming-diarization model (~245MB, darwin-arm64 only — #199)'
|
|
57
57
|
complete -c kesha -n '__fish_seen_subcommand_from logs' -l help -d 'Show help'
|
|
@@ -86,6 +86,7 @@ complete -c kesha -n '__fish_seen_subcommand_from stats' -l format -r -d 'Export
|
|
|
86
86
|
complete -c kesha -n '__fish_seen_subcommand_from status' -l help -d 'Show help'
|
|
87
87
|
complete -c kesha -n '__fish_seen_subcommand_from status' -s h -d 'Show help'
|
|
88
88
|
complete -c kesha -n '__fish_seen_subcommand_from status' -l disk -d 'Include recursive cache disk usage'
|
|
89
|
+
complete -c kesha -n '__fish_seen_subcommand_from status' -l json -d 'Output status as JSON'
|
|
89
90
|
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -l help -d 'Show help'
|
|
90
91
|
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -s h -d 'Show help'
|
|
91
92
|
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -l output -r -d 'Write archive to this .tar.gz path'
|
package/completions/kesha.zsh
CHANGED
|
@@ -62,7 +62,7 @@ _kesha() {
|
|
|
62
62
|
'--no-cache[Re-download even if cached]' \
|
|
63
63
|
'--plan[Show the selected install plan without downloading]' \
|
|
64
64
|
'--yes[Accept defaults and run without prompts]' \
|
|
65
|
-
'--tts[Preselect TTS models (
|
|
65
|
+
'--tts[Preselect TTS models (English; more languages via kesha install --tts <langs>)]' \
|
|
66
66
|
'--vad[Preselect Silero VAD (~2.3MB) for long-audio preprocessing]' \
|
|
67
67
|
'--diarize[Preselect Sortformer speaker diarization (~245MB, darwin-arm64 only)]'
|
|
68
68
|
;;
|
|
@@ -73,7 +73,7 @@ _kesha() {
|
|
|
73
73
|
'--onnx[Force ONNX backend]' \
|
|
74
74
|
'--no-cache[Re-download even if cached]' \
|
|
75
75
|
'--plan[Show download, disk, and warm-up plan without changing local state]' \
|
|
76
|
-
'--tts[Also install TTS models (
|
|
76
|
+
'--tts[Also install TTS models (English only; add codes for more, e.g. --tts en ru (preview sizes: kesha install --plan))]' \
|
|
77
77
|
'--vad[Also install Silero VAD (~2.3MB) for long-audio preprocessing]' \
|
|
78
78
|
'--diarize[Also install the Sortformer streaming-diarization model (~245MB, darwin-arm64 only — #199)]'
|
|
79
79
|
;;
|
|
@@ -121,7 +121,8 @@ _kesha() {
|
|
|
121
121
|
status)
|
|
122
122
|
_arguments '--help[Show help]' \
|
|
123
123
|
'-h[Show help]' \
|
|
124
|
-
'--disk[Include recursive cache disk usage]'
|
|
124
|
+
'--disk[Include recursive cache disk usage]' \
|
|
125
|
+
'--json[Output status as JSON]'
|
|
125
126
|
;;
|
|
126
127
|
support-bundle)
|
|
127
128
|
_arguments '--help[Show help]' \
|
|
@@ -60,19 +60,28 @@ The product promise is not "one model for every audio problem." The promise is a
|
|
|
60
60
|
|
|
61
61
|
| Capability | macOS arm64 | macOS x64 | Linux x64 | Windows x64 | Nix path |
|
|
62
62
|
|---|---|---|---|---|---|
|
|
63
|
-
| STT | Supported, CoreML path | Not shipped | Supported, ONNX CPU path |
|
|
64
|
-
| Audio language detection | Supported | Not shipped | Supported |
|
|
65
|
-
| VAD | Supported with `kesha install --vad` | Not shipped | Supported with `kesha install --vad` |
|
|
66
|
-
| TTS: English Kokoro | Supported, FluidAudio/CoreML in release builds | Not shipped | Supported, ONNX path |
|
|
67
|
-
| TTS: Russian Vosk-TTS | Supported | Not shipped | Supported |
|
|
63
|
+
| STT | Supported, CoreML path | Not shipped | Supported, ONNX CPU path | Blocked at install (#216) | `aarch64-darwin`, `x86_64-linux` |
|
|
64
|
+
| Audio language detection | Supported | Not shipped | Supported | Blocked at install (#216) | Supported where the flake builds |
|
|
65
|
+
| VAD | Supported with `kesha install --vad` | Not shipped | Supported with `kesha install --vad` | Blocked at install (#216) | Supported where the engine path includes VAD assets |
|
|
66
|
+
| TTS: English Kokoro | Supported, FluidAudio/CoreML in release builds | Not shipped | Supported, ONNX path | Blocked at install (#216) | Supported except where noted in `docs/nix-install.md` |
|
|
67
|
+
| TTS: Russian Vosk-TTS | Supported | Not shipped | Supported | Blocked at install (#216) | Supported except where noted in `docs/nix-install.md` |
|
|
68
68
|
| macOS system voices | Supported | Not shipped | Not applicable | Not applicable | Supported on `aarch64-darwin` |
|
|
69
69
|
| Speaker diarization | Preview, darwin-arm64 only | Not supported | Not supported | Not supported | Not wired into the Nix build yet |
|
|
70
70
|
| Raycast extension | Supported | Not shipped | Not applicable | Not applicable | Not applicable |
|
|
71
|
-
| OpenClaw integration | Supported through CLI route | Not shipped | Supported through CLI route |
|
|
72
|
-
| Hermes Agent integration | Supported through command providers | Not shipped | Supported through command providers |
|
|
71
|
+
| OpenClaw integration | Supported through CLI route | Not shipped | Supported through CLI route | Blocked at install (#216) | Use the installed `kesha` command from the chosen path |
|
|
72
|
+
| Hermes Agent integration | Supported through command providers | Not shipped | Supported through command providers | Blocked at install (#216) | Use the installed `kesha` command from the chosen path |
|
|
73
73
|
|
|
74
74
|
`macOS x64` means Intel Macs. Kesha does not currently publish a `darwin-x64` engine binary, so Intel Macs are intentionally marked as not shipped rather than implied to use the ONNX fallback.
|
|
75
75
|
|
|
76
|
+
`Windows x64` shows "Blocked at install" because the CLI's install step
|
|
77
|
+
refuses to run on Windows, not because no binary exists — `build-engine.yml`
|
|
78
|
+
builds and publishes `kesha-engine-windows-x64.exe` with every release. The
|
|
79
|
+
Vosk-TTS native dependency trips MSVC at link time, so the CLI blocks the
|
|
80
|
+
install client-side rather than shipping a broken engine. See
|
|
81
|
+
[issue #216](https://github.com/drakulavich/kesha-voice-kit/issues/216) for
|
|
82
|
+
the underlying failure and the v1.4.x workaround; the toolkit is unusable on
|
|
83
|
+
Windows until that lands.
|
|
84
|
+
|
|
76
85
|
## When to choose something else
|
|
77
86
|
|
|
78
87
|
Use a hosted transcription provider when you need managed uptime, centralized audit logs, team permissions, or no local model cache. Use a streaming ASR stack when partial transcripts during a live call matter more than local-first batch reliability. Use a domain-specific ASR model when medical, legal, or noisy industrial audio quality is the primary requirement.
|
package/man/kesha.1
CHANGED
|
@@ -112,7 +112,7 @@ Show the selected install plan without downloading
|
|
|
112
112
|
Accept defaults and run without prompts
|
|
113
113
|
.TP
|
|
114
114
|
.B \-\-tts
|
|
115
|
-
Preselect TTS models (
|
|
115
|
+
Preselect TTS models (English; more languages via kesha install \-\-tts <langs>)
|
|
116
116
|
.TP
|
|
117
117
|
.B \-\-vad
|
|
118
118
|
Preselect Silero VAD (~2.3MB) for long\-audio preprocessing
|
|
@@ -134,7 +134,7 @@ Re\-download even if cached
|
|
|
134
134
|
Show download, disk, and warm\-up plan without changing local state
|
|
135
135
|
.TP
|
|
136
136
|
.B \-\-tts
|
|
137
|
-
Also install TTS models (
|
|
137
|
+
Also install TTS models (English only; add codes for more, e.g. \-\-tts en ru (preview sizes: kesha install \-\-plan))
|
|
138
138
|
.TP
|
|
139
139
|
.B \-\-vad
|
|
140
140
|
Also install Silero VAD (~2.3MB) for long\-audio preprocessing
|
|
@@ -200,6 +200,9 @@ Export format: json | csv
|
|
|
200
200
|
.TP
|
|
201
201
|
.B \-\-disk
|
|
202
202
|
Include recursive cache disk usage
|
|
203
|
+
.TP
|
|
204
|
+
.B \-\-json
|
|
205
|
+
Output status as JSON
|
|
203
206
|
.SS support-bundle
|
|
204
207
|
.TP
|
|
205
208
|
.B \-\-output
|
package/model-plan.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"asr": [
|
|
3
|
+
{ "relPath": "models/parakeet-tdt-v3/encoder-model.onnx", "sizeBytes": 41770866 },
|
|
4
|
+
{ "relPath": "models/parakeet-tdt-v3/encoder-model.onnx.data", "sizeBytes": 2435420160 },
|
|
5
|
+
{ "relPath": "models/parakeet-tdt-v3/decoder_joint-model.onnx", "sizeBytes": 72520893 },
|
|
6
|
+
{ "relPath": "models/parakeet-tdt-v3/nemo128.onnx", "sizeBytes": 139764 },
|
|
7
|
+
{ "relPath": "models/parakeet-tdt-v3/vocab.txt", "sizeBytes": 93939 }
|
|
8
|
+
],
|
|
9
|
+
"langId": [
|
|
10
|
+
{ "relPath": "models/lang-id-ecapa/lang-id-ecapa.onnx", "sizeBytes": 759814 },
|
|
11
|
+
{ "relPath": "models/lang-id-ecapa/lang-id-ecapa.onnx.data", "sizeBytes": 85327872 },
|
|
12
|
+
{ "relPath": "models/lang-id-ecapa/labels.json", "sizeBytes": 646 }
|
|
13
|
+
],
|
|
14
|
+
"vad": [
|
|
15
|
+
{ "relPath": "models/silero-vad/silero_vad.onnx", "sizeBytes": 2327524 }
|
|
16
|
+
],
|
|
17
|
+
"g2pCharsiu": [
|
|
18
|
+
{ "relPath": "models/g2p/byt5-tiny/encoder_model.onnx", "sizeBytes": 12478704 },
|
|
19
|
+
{ "relPath": "models/g2p/byt5-tiny/decoder_model.onnx", "sizeBytes": 11983268 },
|
|
20
|
+
{ "relPath": "models/g2p/byt5-tiny/decoder_with_past_model.onnx", "sizeBytes": 5427260 }
|
|
21
|
+
],
|
|
22
|
+
"kokoroGraph": { "relPath": "models/kokoro-82m/model.onnx", "sizeBytes": 325532387 },
|
|
23
|
+
"kokoroVoices": {
|
|
24
|
+
"en": { "relPath": "models/kokoro-82m/voices/am_michael.bin", "sizeBytes": 522240 },
|
|
25
|
+
"es": { "relPath": "models/kokoro-82m/voices/em_alex.bin", "sizeBytes": 522240 },
|
|
26
|
+
"fr": { "relPath": "models/kokoro-82m/voices/ff_siwis.bin", "sizeBytes": 522240 },
|
|
27
|
+
"it": { "relPath": "models/kokoro-82m/voices/im_nicola.bin", "sizeBytes": 522240 },
|
|
28
|
+
"pt": { "relPath": "models/kokoro-82m/voices/pm_alex.bin", "sizeBytes": 522240 }
|
|
29
|
+
},
|
|
30
|
+
"voskRu": [
|
|
31
|
+
{ "relPath": "models/vosk-ru/model.onnx", "sizeBytes": 179314533 },
|
|
32
|
+
{ "relPath": "models/vosk-ru/dictionary", "sizeBytes": 101431118 },
|
|
33
|
+
{ "relPath": "models/vosk-ru/config.json", "sizeBytes": 1518 },
|
|
34
|
+
{ "relPath": "models/vosk-ru/bert/model.onnx", "sizeBytes": 654361598 },
|
|
35
|
+
{ "relPath": "models/vosk-ru/bert/vocab.txt", "sizeBytes": 1780720 }
|
|
36
|
+
],
|
|
37
|
+
"diarize": [
|
|
38
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Manifest.json", "sizeBytes": 617 },
|
|
39
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/model.mlmodel", "sizeBytes": 7080357 },
|
|
40
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/weights/0-weight.bin", "sizeBytes": 5930400 },
|
|
41
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/weights/1-weight.bin", "sizeBytes": 232161600 }
|
|
42
|
+
]
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drakulavich/kesha-voice-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Give your tools a voice — speech to text and back, 25 languages, up to ~19× faster than Whisper. On your machine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"completions/",
|
|
16
16
|
"man/",
|
|
17
17
|
"src/",
|
|
18
|
+
"model-plan.json",
|
|
18
19
|
"package.json",
|
|
19
20
|
"tsconfig.json",
|
|
20
21
|
"openclaw.plugin.json",
|
|
@@ -38,14 +39,14 @@
|
|
|
38
39
|
}
|
|
39
40
|
},
|
|
40
41
|
"keshaEngine": {
|
|
41
|
-
"version": "1.24.
|
|
42
|
+
"version": "1.24.7"
|
|
42
43
|
},
|
|
43
44
|
"scripts": {
|
|
44
|
-
"test": "bun test",
|
|
45
|
-
"test:watch": "bun test --watch",
|
|
46
|
-
"test:unit": "bun test tests/unit/",
|
|
47
|
-
"test:cli-fast": "bun test tests/unit/ tests/integration/cli-contracts.test.ts tests/integration/e2e-cli.test.ts tests/integration/say.test.ts",
|
|
48
|
-
"test:integration": "bun test tests/integration/",
|
|
45
|
+
"test": "bun test --timeout 30000",
|
|
46
|
+
"test:watch": "bun test --timeout 30000 --watch",
|
|
47
|
+
"test:unit": "bun test --timeout 30000 tests/unit/",
|
|
48
|
+
"test:cli-fast": "bun test --timeout 30000 tests/unit/ tests/integration/cli-contracts.test.ts tests/integration/e2e-cli.test.ts tests/integration/say.test.ts",
|
|
49
|
+
"test:integration": "bun test --timeout 30000 tests/integration/",
|
|
49
50
|
"coverage:ts": "bun run test:cli-fast --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage/ts",
|
|
50
51
|
"coverage:check:ts": "bun .github/scripts/check-coverage.ts --preset=ts --lcov=coverage/ts/lcov.info --summary=coverage/ts/summary.md",
|
|
51
52
|
"coverage:rust": "mkdir -p coverage/rust && cd rust && cargo llvm-cov nextest --features tts --lcov --output-path ../coverage/rust/lcov.info",
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
"lint": "bunx tsc --noEmit",
|
|
55
56
|
"check": "bun run lint && bun run check:versions && bun run test:cli-fast",
|
|
56
57
|
"check:workflows": "bun .github/scripts/check-workflows.ts",
|
|
58
|
+
"check:specs": "bunx @fission-ai/openspec@1.4.1 validate --specs --strict",
|
|
57
59
|
"check:release-manifest": "bun .github/scripts/release-manifest.mjs --check",
|
|
58
60
|
"check:versions": "bun .github/scripts/check-versions.ts"
|
|
59
61
|
},
|
|
@@ -91,7 +93,7 @@
|
|
|
91
93
|
"dependencies": {
|
|
92
94
|
"@clack/prompts": "^1.5.0",
|
|
93
95
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
94
|
-
"@toon-format/toon": "^
|
|
96
|
+
"@toon-format/toon": "^4.1.0",
|
|
95
97
|
"citty": "^0.2.2",
|
|
96
98
|
"fastest-levenshtein": "^1.0.16",
|
|
97
99
|
"picocolors": "^1.1.1",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { log } from "../log";
|
|
2
|
+
|
|
3
|
+
export type ActionMessage = { level: "success" | "info" | "warn"; text: string };
|
|
4
|
+
|
|
5
|
+
export type ActionResult =
|
|
6
|
+
| { ok: true; messages: ActionMessage[]; stdout?: string }
|
|
7
|
+
| { ok: false; error: string; hint?: string };
|
|
8
|
+
|
|
9
|
+
/** Renders an action's messages, writing `stdout` verbatim; a rejected action exits 2. */
|
|
10
|
+
export function emitActionResult(result: ActionResult): void {
|
|
11
|
+
if (!result.ok) {
|
|
12
|
+
log.error(result.error);
|
|
13
|
+
if (result.hint) log.warn(result.hint);
|
|
14
|
+
process.exit(2);
|
|
15
|
+
}
|
|
16
|
+
for (const message of result.messages) log[message.level](message.text);
|
|
17
|
+
if (result.stdout !== undefined) process.stdout.write(result.stdout);
|
|
18
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createDiagnosticLogSession } from "../diagnostic-log";
|
|
2
|
+
import type {
|
|
3
|
+
DiagnosticLogFields,
|
|
4
|
+
DiagnosticLogSession,
|
|
5
|
+
DiagnosticSessionStatus,
|
|
6
|
+
} from "../diagnostic-log";
|
|
7
|
+
import { errorMessage } from "../error-utils";
|
|
8
|
+
import { log } from "../log";
|
|
9
|
+
import { createStatsRecorder } from "../stats";
|
|
10
|
+
import type { StatsCommandName, StatsRecorder } from "../stats";
|
|
11
|
+
|
|
12
|
+
export interface CommandSession {
|
|
13
|
+
readonly stats: StatsRecorder;
|
|
14
|
+
readonly diagnosticLog: DiagnosticLogSession;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CommandOutcome {
|
|
18
|
+
status: DiagnosticSessionStatus;
|
|
19
|
+
itemCount: number;
|
|
20
|
+
/** Merged into the `command.finish` event alongside `command` and `status`. */
|
|
21
|
+
finishFields?: DiagnosticLogFields;
|
|
22
|
+
/** Exit code the caller should terminate with; omitted means "don't exit". */
|
|
23
|
+
exitCode?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface CommandSessionFactories {
|
|
27
|
+
createStats: (command: StatsCommandName) => StatsRecorder;
|
|
28
|
+
createDiagnosticLog: () => DiagnosticLogSession;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const defaultFactories: CommandSessionFactories = {
|
|
32
|
+
createStats: createStatsRecorder,
|
|
33
|
+
createDiagnosticLog: createDiagnosticLogSession,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Runs one CLI command's body between `command.start` / `command.finish`, closing both recorders exactly once; `body` reports failure by returning a {@link CommandOutcome}, never by exiting. */
|
|
37
|
+
export async function runCommandSession(
|
|
38
|
+
command: StatsCommandName,
|
|
39
|
+
startFields: DiagnosticLogFields,
|
|
40
|
+
body: (session: CommandSession) => Promise<CommandOutcome>,
|
|
41
|
+
factories: CommandSessionFactories = defaultFactories,
|
|
42
|
+
): Promise<CommandOutcome> {
|
|
43
|
+
const session: CommandSession = {
|
|
44
|
+
stats: factories.createStats(command),
|
|
45
|
+
diagnosticLog: factories.createDiagnosticLog(),
|
|
46
|
+
};
|
|
47
|
+
session.diagnosticLog.event("command.start", { command, ...startFields });
|
|
48
|
+
|
|
49
|
+
let outcome: CommandOutcome;
|
|
50
|
+
try {
|
|
51
|
+
outcome = await body(session);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
closeSessionQuietly(session, command, { status: "failed", itemCount: 0 });
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// A flush error must not displace a failure the command already has to report (Greptile P1/P2 on #607).
|
|
58
|
+
if (outcome.status === "failed") {
|
|
59
|
+
closeSessionQuietly(session, command, outcome);
|
|
60
|
+
} else {
|
|
61
|
+
closeSession(session, command, outcome);
|
|
62
|
+
}
|
|
63
|
+
return outcome;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function closeSessionQuietly(
|
|
67
|
+
session: CommandSession,
|
|
68
|
+
command: StatsCommandName,
|
|
69
|
+
outcome: CommandOutcome,
|
|
70
|
+
): void {
|
|
71
|
+
try {
|
|
72
|
+
closeSession(session, command, outcome);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
log.debug(`command session cleanup failed: ${errorMessage(err)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function closeSession(session: CommandSession, command: StatsCommandName, outcome: CommandOutcome): void {
|
|
79
|
+
session.diagnosticLog.event("command.finish", {
|
|
80
|
+
command,
|
|
81
|
+
status: outcome.status,
|
|
82
|
+
...outcome.finishFields,
|
|
83
|
+
});
|
|
84
|
+
session.stats.finish(outcome.status, outcome.itemCount);
|
|
85
|
+
session.diagnosticLog.finish(outcome.status);
|
|
86
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { log, setColorEnabled } from "../log";
|
|
2
|
+
|
|
3
|
+
/** The global flags resolved before citty, so every command sees the same decision. */
|
|
4
|
+
export interface CliContext {
|
|
5
|
+
quiet: boolean;
|
|
6
|
+
disableColor: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ResolvedCliContext extends CliContext {
|
|
10
|
+
/** `rawArgs` with the global flag tokens removed, ready to hand to citty. */
|
|
11
|
+
rawArgs: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Falsey grammar shared by --no-color, --quiet, and CI. Mirrors KESHA_DEBUG so
|
|
15
|
+
// `CI=false`/`CI=0` and `--no-color=false` opt back in.
|
|
16
|
+
const FALSEY_VALUES = new Set(["", "0", "false", "no", "off"]);
|
|
17
|
+
function isFalsey(v: string): boolean {
|
|
18
|
+
return FALSEY_VALUES.has(v.trim().toLowerCase());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** True when NO_COLOR came from the user's environment, so re-enabling colors must not clear it. */
|
|
22
|
+
export const USER_FORCED_NO_COLOR =
|
|
23
|
+
process.env.NO_COLOR !== undefined && !isFalsey(process.env.NO_COLOR);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Strip a boolean global flag out of rawArgs so citty never sees it. Matches
|
|
27
|
+
* any of `names` bare (sets the flag) and the `--name=<value>` form for the
|
|
28
|
+
* long names (`<falsey>` explicitly turns the flag back off).
|
|
29
|
+
*/
|
|
30
|
+
function stripBooleanFlag(
|
|
31
|
+
rawArgs: string[],
|
|
32
|
+
names: string[],
|
|
33
|
+
): { value: boolean; rawArgs: string[] } {
|
|
34
|
+
const valuedPrefixes = names.filter((n) => n.startsWith("--")).map((n) => `${n}=`);
|
|
35
|
+
let value = false;
|
|
36
|
+
const cleaned: string[] = [];
|
|
37
|
+
for (const arg of rawArgs) {
|
|
38
|
+
if (names.includes(arg)) {
|
|
39
|
+
value = true;
|
|
40
|
+
} else if (valuedPrefixes.some((prefix) => arg.startsWith(prefix))) {
|
|
41
|
+
value = !isFalsey(arg.slice(arg.indexOf("=") + 1));
|
|
42
|
+
} else {
|
|
43
|
+
cleaned.push(arg);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { value, rawArgs: cleaned };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Decide whether ANSI colors should be disabled (#531) and return rawArgs with
|
|
51
|
+
* any `--no-color[=value]` token stripped so citty never sees it.
|
|
52
|
+
*
|
|
53
|
+
* Colors are disabled when `--no-color` (bare) or `--no-color=<truthy>` is
|
|
54
|
+
* passed, or when the environment looks like CI (`CI` set to a non-falsey value
|
|
55
|
+
* — GitHub Actions, GitLab, CircleCI, … export `CI=true`). `--no-color=false`
|
|
56
|
+
* and `CI=false`/`CI=0` explicitly opt back in.
|
|
57
|
+
*/
|
|
58
|
+
export function resolveColorMode(
|
|
59
|
+
rawArgs: string[],
|
|
60
|
+
env: { CI?: string } = process.env as { CI?: string },
|
|
61
|
+
): { disableColor: boolean; rawArgs: string[] } {
|
|
62
|
+
const { value, rawArgs: cleaned } = stripBooleanFlag(rawArgs, ["--no-color"]);
|
|
63
|
+
const ci = env.CI !== undefined && !isFalsey(env.CI);
|
|
64
|
+
return { disableColor: value || ci, rawArgs: cleaned };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Detect `--quiet`/`-q` (and `--quiet=<value>`) and return rawArgs with the
|
|
69
|
+
* token stripped (#526). Resolved before citty — like `--no-color` — so quiet
|
|
70
|
+
* is global: it works for every command, not just the transcribe path, and a
|
|
71
|
+
* subcommand that doesn't declare it never sees the flag.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveQuietMode(rawArgs: string[]): { quiet: boolean; rawArgs: string[] } {
|
|
74
|
+
const { value, rawArgs: cleaned } = stripBooleanFlag(rawArgs, ["--quiet", "-q"]);
|
|
75
|
+
return { quiet: value, rawArgs: cleaned };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Resolves every pre-citty global flag into one value, with the tokens stripped from rawArgs. */
|
|
79
|
+
export function resolveCliContext(
|
|
80
|
+
rawArgs: string[],
|
|
81
|
+
env: { CI?: string } = process.env as { CI?: string },
|
|
82
|
+
): ResolvedCliContext {
|
|
83
|
+
const color = resolveColorMode(rawArgs, env);
|
|
84
|
+
const quiet = resolveQuietMode(color.rawArgs);
|
|
85
|
+
return { quiet: quiet.quiet, disableColor: color.disableColor, rawArgs: quiet.rawArgs };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Sync NO_COLOR with the resolved color decision so engine subprocesses inherit
|
|
90
|
+
* the right value. Separated from setColorEnabled so it can be tested without
|
|
91
|
+
* picocolors side-effects.
|
|
92
|
+
*
|
|
93
|
+
* Never clears a NO_COLOR the user exported before this process started.
|
|
94
|
+
*/
|
|
95
|
+
export function applyColorEnv(disableColor: boolean): void {
|
|
96
|
+
if (disableColor) {
|
|
97
|
+
process.env.NO_COLOR = "1";
|
|
98
|
+
} else if (!USER_FORCED_NO_COLOR) {
|
|
99
|
+
delete process.env.NO_COLOR;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Applies the context to the process-wide output sinks, writing every value so an earlier in-process run (unit tests, `kesha mcp`) can't leak its settings into a later one. */
|
|
104
|
+
export function applyCliContext(context: CliContext): void {
|
|
105
|
+
setColorEnabled(!context.disableColor);
|
|
106
|
+
applyColorEnv(context.disableColor);
|
|
107
|
+
log.quietEnabled = context.quiet;
|
|
108
|
+
}
|