@drakulavich/kesha-voice-kit 1.19.0-beta.1 → 1.19.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 +17 -3
- package/SKILL.md +27 -3
- package/completions/kesha.bash +3 -2
- package/completions/kesha.fish +5 -0
- package/completions/kesha.zsh +8 -1
- package/docs/diagnostic-logs.md +93 -0
- package/man/kesha.1 +11 -1
- package/package.json +4 -5
- package/src/cli/dispatch.ts +22 -61
- package/src/cli/install.ts +54 -15
- package/src/cli/logs.ts +107 -0
- package/src/cli/main.ts +46 -1
- package/src/cli/say.ts +34 -0
- package/src/cli/support-bundle.ts +10 -1
- package/src/cli.ts +1 -0
- package/src/diagnostic-events.ts +14 -0
- package/src/diagnostic-log.ts +328 -0
- package/src/diagnostic-paths.ts +22 -0
- package/src/doctor.ts +86 -25
- package/src/engine.ts +11 -10
- package/src/fluid-kokoro-cache.ts +47 -0
- package/src/install-hint.ts +12 -0
- package/src/install-plan.ts +23 -13
- package/src/shell-artifacts.ts +2 -0
- package/src/status.ts +10 -16
- package/src/support-bundle.ts +47 -0
- package/src/synth.ts +2 -1
- package/src/transcribe.ts +5 -7
- package/scripts/postinstall.cjs +0 -25
package/README.md
CHANGED
|
@@ -96,10 +96,10 @@ Each segment gets a `speaker` integer (cluster ID, stable within one file). Linu
|
|
|
96
96
|
|
|
97
97
|
## Text-to-speech
|
|
98
98
|
|
|
99
|
-
Kesha speaks back via Kokoro-82M (English) and Vosk-TTS (Russian) — voice auto-picks from the text's language. On darwin-arm64, Kokoro uses FluidAudio CoreML instead of ONNX:
|
|
99
|
+
Kesha speaks back via Kokoro-82M (English) and Vosk-TTS (Russian) — voice auto-picks from the text's language. On darwin-arm64, Kokoro uses FluidAudio CoreML instead of ONNX; FluidAudio stores that CoreML cache at `~/.cache/fluidaudio/Models/kokoro`, outside Kesha's pinned model cache:
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
|
-
kesha install --tts #
|
|
102
|
+
kesha install --tts # TTS, opt-in; Darwin Kokoro uses FluidAudio cache
|
|
103
103
|
kesha say "Hello, world" > hello.wav
|
|
104
104
|
kesha say "Привет, мир" > privet.wav # auto-routes (Milena on darwin, ru-vosk-m02 elsewhere)
|
|
105
105
|
```
|
|
@@ -288,7 +288,7 @@ are missing.
|
|
|
288
288
|
| SpeechBrain ECAPA-TDNN | Audio language detection | ~86MB | [HuggingFace](https://huggingface.co/speechbrain/lang-id-voxlingua107-ecapa) |
|
|
289
289
|
| Apple NLLanguageRecognizer | Text language detection | built-in | macOS system framework |
|
|
290
290
|
| Silero VAD v5 (opt-in) | Voice activity detection | ~2.3MB | [snakers4/silero-vad](https://github.com/snakers4/silero-vad) |
|
|
291
|
-
| Kokoro-82M / Vosk-TTS (opt-in) | Text-to-speech | ~990MB | [FluidAudio Kokoro](https://github.com/FluidInference/FluidAudio) on darwin-arm64; ONNX Kokoro elsewhere · [Vosk-TTS](https://github.com/alphacep/vosk-tts) |
|
|
291
|
+
| Kokoro-82M / Vosk-TTS (opt-in) | Text-to-speech | ~990MB | [FluidAudio Kokoro](https://github.com/FluidInference/FluidAudio) on darwin-arm64 (FluidAudio cache, not Kesha-verified); ONNX Kokoro elsewhere · [Vosk-TTS](https://github.com/alphacep/vosk-tts) |
|
|
292
292
|
|
|
293
293
|
All models run through `kesha-engine` — a Rust binary using [FluidAudio](https://github.com/FluidInference/FluidAudio) (CoreML) on Apple Silicon and [ort](https://github.com/pykeio/ort) (ONNX Runtime) on other platforms.
|
|
294
294
|
|
|
@@ -321,9 +321,23 @@ Kesha can collect local diagnostics without downloading models or mutating cache
|
|
|
321
321
|
```bash
|
|
322
322
|
kesha doctor --json --redact
|
|
323
323
|
kesha support-bundle --output kesha-support.tar.gz
|
|
324
|
+
kesha support-bundle --include-logs --output kesha-support-with-logs.tar.gz
|
|
325
|
+
kesha logs status
|
|
326
|
+
kesha logs status --json
|
|
324
327
|
```
|
|
325
328
|
|
|
326
329
|
`support-bundle` creates a redacted `.tar.gz` archive for GitHub issues. It includes runtime, engine, cache, optional-component, Stats status, and known Kesha environment settings. It does not include audio, transcripts, model files, or the Stats database.
|
|
330
|
+
Diagnostic log contents are excluded by default; pass `--include-logs` to add a
|
|
331
|
+
bounded tail of Kesha's privacy-safe NDJSON diagnostic log.
|
|
332
|
+
|
|
333
|
+
`kesha logs` manages local, rotated diagnostic logs for troubleshooting. Logs
|
|
334
|
+
default to `retain-on-failure` and also support explicit `off` and `on` modes.
|
|
335
|
+
Use `kesha logs status --json` for a stable machine-readable status contract
|
|
336
|
+
covering the active path, mode, size, rotation settings, and rotated-file list.
|
|
337
|
+
They use content-free NDJSON events: command/stage names, versions, durations,
|
|
338
|
+
exit codes, and coarse audio metadata only. They must not store audio,
|
|
339
|
+
transcripts, input text, generated speech text, file names, full paths, raw
|
|
340
|
+
stdout/stderr, environment variables, tokens, or URLs. See [Diagnostic logs](docs/diagnostic-logs.md).
|
|
327
341
|
|
|
328
342
|
## Local Stats privacy and lifecycle
|
|
329
343
|
|
package/SKILL.md
CHANGED
|
@@ -25,6 +25,7 @@ Local voice toolkit: transcribe voice messages to text, synthesize speech, detec
|
|
|
25
25
|
- **Need to send a voice note (Telegram, WhatsApp, Signal, Discord)**: synthesize directly into messenger-native OGG/Opus with `kesha say --format ogg-opus --out reply.ogg "<text>"`. Default is mono 24 kHz @ 32 kbps - what Telegram `sendVoice` expects. No WAV redirect and no `ffmpeg` round-trip.
|
|
26
26
|
- **Need local file playback/debug output**: WAV is still available with `kesha say --out reply.wav "<text>"`, but do not use WAV for Telegram voice replies. Auto-routes by detected language (Kokoro-82M for English, Vosk-TTS for Russian). On darwin-arm64, English Kokoro uses FluidAudio CoreML instead of ONNX. For other languages and ~180 more voices use `--voice macos-*` on macOS (zero model download).
|
|
27
27
|
- **Need to detect what language a file is in** before choosing a pipeline: `kesha --json audio.ogg` returns both audio-based and text-based language detection with confidence scores.
|
|
28
|
+
- **Need to capture your own voice** for transcription or as a voice-note source: `kesha record --out clip.wav` records up to 120s (override with `--max-seconds`) of mono 16 kHz WAV from the default microphone. Pipe straight into `kesha --json clip.wav` to close the loop.
|
|
28
29
|
|
|
29
30
|
## OpenClaw plugin setup
|
|
30
31
|
|
|
@@ -150,9 +151,12 @@ Each `segment.speaker` is a number (cluster id, stable within one file). On Linu
|
|
|
150
151
|
- `kesha audio.ogg` — plain transcript on stdout
|
|
151
152
|
- `kesha --format transcript audio.ogg` — transcript + `[lang: ru, confidence: 0.99]` footer
|
|
152
153
|
- `kesha --json --timestamps audio.ogg` — JSON with timestamped `segments`
|
|
154
|
+
- `kesha --toon audio.ogg` — TOON (compact, LLM-friendly JSON encoding); preferred when piping multi-file results to an LLM/agent
|
|
153
155
|
- `kesha --verbose audio.ogg` — human-readable with language info
|
|
154
156
|
- `kesha --lang en audio.ogg` — warn if detected language differs (useful sanity check)
|
|
155
157
|
|
|
158
|
+
**Long audio:** files ≥ 120 s auto-engage Silero VAD chunking; force on with `--vad` or off with `--no-vad`. Short files use full-file ASR by default.
|
|
159
|
+
|
|
156
160
|
## TTS: synthesize speech
|
|
157
161
|
|
|
158
162
|
```bash
|
|
@@ -188,12 +192,25 @@ Format is also inferred from `--out` extension (`.ogg` / `.opus` / `.oga` → OG
|
|
|
188
192
|
|
|
189
193
|
## Install
|
|
190
194
|
|
|
195
|
+
**Humans use `kesha init` (guided). Agents and scripts use `kesha install` (deterministic).**
|
|
196
|
+
|
|
191
197
|
```bash
|
|
192
|
-
bun add -g @drakulavich/kesha-voice-kit # global CLI install
|
|
193
|
-
|
|
194
|
-
|
|
198
|
+
bun add -g @drakulavich/kesha-voice-kit # global CLI install (always first)
|
|
199
|
+
|
|
200
|
+
# For humans: interactive setup that prompts for backend / TTS / VAD / diarize
|
|
201
|
+
kesha init
|
|
202
|
+
|
|
203
|
+
# For agents and CI: explicit, scriptable install commands
|
|
204
|
+
kesha install # engine only (~350 MB)
|
|
205
|
+
kesha install --tts # + Kokoro + Vosk-TTS RU (~990 MB more)
|
|
206
|
+
kesha install --tts --vad # + Silero VAD (long-audio chunking)
|
|
207
|
+
kesha install --tts --vad --diarize # + speaker diarization (darwin-arm64 only)
|
|
195
208
|
```
|
|
196
209
|
|
|
210
|
+
Kesha's runtime error/warning messages adapt to the same split: when `kesha` is invoked from a TTY, hints suggest `kesha init`; when stderr is piped (CI logs, OpenClaw, agent subprocess), hints suggest the equivalent `kesha install [...flags]`. Both run the same install code under the hood — pick the one your caller is.
|
|
211
|
+
|
|
212
|
+
For pre-release builds: `bun add -g @drakulavich/kesha-voice-kit@beta` (current `beta` channel; `@latest` stays on the last stable release).
|
|
213
|
+
|
|
197
214
|
No system deps — English G2P is embedded (`misaki-rs`); Russian G2P is bundled inside Vosk-TTS. `macos-*` voices need no install either — they use voices already on the Mac.
|
|
198
215
|
|
|
199
216
|
## Supported languages
|
|
@@ -207,6 +224,13 @@ No system deps — English G2P is embedded (`misaki-rs`); Russian G2P is bundled
|
|
|
207
224
|
- ASR: ~19× faster than OpenAI Whisper on Apple Silicon (CoreML via FluidAudio), ~2.5× on CPU (ONNX via `ort`).
|
|
208
225
|
- TTS: sub-second latency for short utterances on Apple Silicon.
|
|
209
226
|
|
|
227
|
+
## Troubleshooting
|
|
228
|
+
|
|
229
|
+
- `kesha doctor` — collect support diagnostics without changing local state. Add `--json` for machine-readable output, `--redact` to scrub secrets and home paths before sharing.
|
|
230
|
+
- `kesha logs` — manage privacy-safe local diagnostic logs. Default mode is `retain-on-failure` (events buffered in memory, flushed to disk only when a command fails). `kesha logs mode on` captures every run, `kesha logs path` prints the NDJSON file, `kesha logs disable` turns it off entirely.
|
|
231
|
+
- `kesha support-bundle --output bundle.tar.gz` — produce a redacted `.tar.gz` for filing an issue. Add `--include-logs` to bundle a bounded tail of diagnostic logs.
|
|
232
|
+
- `kesha stats` — manage local anonymous performance stats (per-command latency percentiles). Actions: `enable | disable | status | week | errors | export | reset | vacuum | retention`. Stays on the machine.
|
|
233
|
+
|
|
210
234
|
## Why local
|
|
211
235
|
|
|
212
236
|
No API keys to manage. No per-minute billing. Voice data never leaves the machine — important for regulated industries, personal messaging, and anything that shouldn't be in a third-party log.
|
package/completions/kesha.bash
CHANGED
|
@@ -6,7 +6,7 @@ _kesha_completion() {
|
|
|
6
6
|
COMPREPLY=()
|
|
7
7
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
8
8
|
command="${COMP_WORDS[1]}"
|
|
9
|
-
commands="completions doctor init install manpage record say stats status support-bundle"
|
|
9
|
+
commands="completions doctor init install logs manpage record say stats status support-bundle"
|
|
10
10
|
|
|
11
11
|
if [[ "$COMP_CWORD" -eq 1 ]]; then
|
|
12
12
|
if [[ "$cur" == -* ]]; then
|
|
@@ -22,12 +22,13 @@ _kesha_completion() {
|
|
|
22
22
|
doctor) opts="--help -h --json --redact" ;;
|
|
23
23
|
init) opts="--help -h --coreml --onnx --no-cache --plan --yes --tts --vad --diarize" ;;
|
|
24
24
|
install) opts="--help -h --coreml --onnx --no-cache --plan --tts --vad --diarize" ;;
|
|
25
|
+
logs) opts="--help -h --json" ;;
|
|
25
26
|
manpage) opts="--help -h" ;;
|
|
26
27
|
record) opts="--help -h --out --max-seconds --debug" ;;
|
|
27
28
|
say) opts="--help -h --voice --lang --out --rate --list-voices --ssml --format --bitrate --sample-rate --no-expand-abbrev --verbose --debug" ;;
|
|
28
29
|
stats) opts="--help -h --format" ;;
|
|
29
30
|
status) opts="--help -h --disk" ;;
|
|
30
|
-
support-bundle) opts="--help -h --output" ;;
|
|
31
|
+
support-bundle) opts="--help -h --output --include-logs" ;;
|
|
31
32
|
*) opts="--help -h --version -v --json --toon --timestamps --speakers --include-errors --verbose --format --lang --debug --vad --no-vad" ;;
|
|
32
33
|
esac
|
|
33
34
|
|
package/completions/kesha.fish
CHANGED
|
@@ -4,6 +4,7 @@ complete -c kesha -n '__fish_use_subcommand' -a 'completions' -d 'Print shell co
|
|
|
4
4
|
complete -c kesha -n '__fish_use_subcommand' -a 'doctor' -d 'Collect support diagnostics without changing local state'
|
|
5
5
|
complete -c kesha -n '__fish_use_subcommand' -a 'init' -d 'Interactive setup guide for Kesha features'
|
|
6
6
|
complete -c kesha -n '__fish_use_subcommand' -a 'install' -d 'Download inference engine and models'
|
|
7
|
+
complete -c kesha -n '__fish_use_subcommand' -a 'logs' -d 'Manage local privacy-safe diagnostic logs'
|
|
7
8
|
complete -c kesha -n '__fish_use_subcommand' -a 'manpage' -d 'Print the kesha(1) manpage'
|
|
8
9
|
complete -c kesha -n '__fish_use_subcommand' -a 'record' -d 'Record microphone audio to a WAV file'
|
|
9
10
|
complete -c kesha -n '__fish_use_subcommand' -a 'say' -d 'Synthesize speech from text (TTS). Writes audio to stdout (or --out file). Defaults to WAV; use --format ogg-opus for messenger-ready voice notes.'
|
|
@@ -50,6 +51,9 @@ complete -c kesha -n '__fish_seen_subcommand_from install' -l plan -d 'Show down
|
|
|
50
51
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l tts -d 'Also install TTS models (Kokoro EN + Vosk-TTS RU, ~990MB)'
|
|
51
52
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l vad -d 'Also install Silero VAD (~2.3MB) for long-audio preprocessing'
|
|
52
53
|
complete -c kesha -n '__fish_seen_subcommand_from install' -l diarize -d 'Also install the Sortformer streaming-diarization model (~245MB, darwin-arm64 only — #199)'
|
|
54
|
+
complete -c kesha -n '__fish_seen_subcommand_from logs' -l help -d 'Show help'
|
|
55
|
+
complete -c kesha -n '__fish_seen_subcommand_from logs' -s h -d 'Show help'
|
|
56
|
+
complete -c kesha -n '__fish_seen_subcommand_from logs' -l json -d 'Output status as JSON'
|
|
53
57
|
complete -c kesha -n '__fish_seen_subcommand_from manpage' -l help -d 'Show help'
|
|
54
58
|
complete -c kesha -n '__fish_seen_subcommand_from manpage' -s h -d 'Show help'
|
|
55
59
|
complete -c kesha -n '__fish_seen_subcommand_from record' -l help -d 'Show help'
|
|
@@ -80,3 +84,4 @@ complete -c kesha -n '__fish_seen_subcommand_from status' -l disk -d 'Include re
|
|
|
80
84
|
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -l help -d 'Show help'
|
|
81
85
|
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -s h -d 'Show help'
|
|
82
86
|
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -l output -r -d 'Write archive to this .tar.gz path'
|
|
87
|
+
complete -c kesha -n '__fish_seen_subcommand_from support-bundle' -l include-logs -d 'Include a bounded tail of privacy-safe diagnostic logs'
|
package/completions/kesha.zsh
CHANGED
|
@@ -8,6 +8,7 @@ _kesha() {
|
|
|
8
8
|
'doctor:Collect support diagnostics without changing local state'
|
|
9
9
|
'init:Interactive setup guide for Kesha features'
|
|
10
10
|
'install:Download inference engine and models'
|
|
11
|
+
'logs:Manage local privacy-safe diagnostic logs'
|
|
11
12
|
'manpage:Print the kesha(1) manpage'
|
|
12
13
|
'record:Record microphone audio to a WAV file'
|
|
13
14
|
'say:Synthesize speech from text (TTS). Writes audio to stdout (or --out file). Defaults to WAV; use --format ogg-opus for messenger-ready voice notes.'
|
|
@@ -73,6 +74,11 @@ _kesha() {
|
|
|
73
74
|
'--vad[Also install Silero VAD (~2.3MB) for long-audio preprocessing]' \
|
|
74
75
|
'--diarize[Also install the Sortformer streaming-diarization model (~245MB, darwin-arm64 only — #199)]'
|
|
75
76
|
;;
|
|
77
|
+
logs)
|
|
78
|
+
_arguments '--help[Show help]' \
|
|
79
|
+
'-h[Show help]' \
|
|
80
|
+
'--json[Output status as JSON]'
|
|
81
|
+
;;
|
|
76
82
|
manpage)
|
|
77
83
|
_arguments '--help[Show help]' \
|
|
78
84
|
'-h[Show help]'
|
|
@@ -113,7 +119,8 @@ _kesha() {
|
|
|
113
119
|
support-bundle)
|
|
114
120
|
_arguments '--help[Show help]' \
|
|
115
121
|
'-h[Show help]' \
|
|
116
|
-
'--output=[Write archive to this .tar.gz path]:output:'
|
|
122
|
+
'--output=[Write archive to this .tar.gz path]:output:' \
|
|
123
|
+
'--include-logs[Include a bounded tail of privacy-safe diagnostic logs]'
|
|
117
124
|
;;
|
|
118
125
|
*)
|
|
119
126
|
_arguments '--help[Show help]' \
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Diagnostic Logs
|
|
2
|
+
|
|
3
|
+
Kesha diagnostic logs are local, rotated NDJSON event logs for install, engine,
|
|
4
|
+
and runtime troubleshooting. They are separate from Kesha Stats: Stats stores
|
|
5
|
+
aggregate timings in SQLite after explicit opt-in, while diagnostic logs keep a
|
|
6
|
+
small local ring buffer of structured events.
|
|
7
|
+
|
|
8
|
+
Diagnostic logs default to `retain-on-failure`: passing commands leave no log
|
|
9
|
+
file, while failed commands can preserve a small local trace for debugging.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
kesha logs status
|
|
13
|
+
kesha logs status --json
|
|
14
|
+
kesha logs enable
|
|
15
|
+
kesha logs disable
|
|
16
|
+
kesha logs mode retain-on-failure
|
|
17
|
+
kesha logs path
|
|
18
|
+
kesha logs reset
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Modes
|
|
22
|
+
|
|
23
|
+
Diagnostic logs follow a Playwright-style retention model:
|
|
24
|
+
|
|
25
|
+
- `off`: do not record diagnostic events.
|
|
26
|
+
- `on`: append events to the rotated local log immediately.
|
|
27
|
+
- `retain-on-failure`: buffer events for the current command and write them only
|
|
28
|
+
if the command fails. This is the default.
|
|
29
|
+
|
|
30
|
+
`kesha logs enable` is shorthand for `kesha logs mode on`; `kesha logs disable`
|
|
31
|
+
is shorthand for `kesha logs mode off`. `retain-on-failure` keeps passing runs
|
|
32
|
+
artifact-free while failed runs keep enough context to debug.
|
|
33
|
+
|
|
34
|
+
`kesha logs status --json` prints the same local status as a stable JSON object:
|
|
35
|
+
`dir`, `activePath`, `statePath`, `exists`, `activeSizeBytes`, `rotatedFiles`,
|
|
36
|
+
`totalSizeBytes`, `mode`, `maxBytes`, and `retain`.
|
|
37
|
+
|
|
38
|
+
## Privacy Contract
|
|
39
|
+
|
|
40
|
+
Diagnostic logs are content-free. Event payloads are built from an allowlist of
|
|
41
|
+
typed fields such as command name, app version, platform, backend, feature flags,
|
|
42
|
+
stage names, exit codes, duration numbers, and stable error codes.
|
|
43
|
+
|
|
44
|
+
When enabled, `kesha install`, `kesha <audio>`, and `kesha say` record command
|
|
45
|
+
lifecycle events such as `command.start`, `input.audio`, `input.missing`,
|
|
46
|
+
`engine.exit`, and `command.finish`. These events use only counts, booleans,
|
|
47
|
+
format extensions, duration milliseconds, and bucket labels. In the default
|
|
48
|
+
`retain-on-failure` mode, successful runs still leave no log file behind.
|
|
49
|
+
|
|
50
|
+
Diagnostic logs must not store:
|
|
51
|
+
|
|
52
|
+
- audio bytes
|
|
53
|
+
- transcripts
|
|
54
|
+
- input text or generated speech text
|
|
55
|
+
- file names, basenames, or full file paths
|
|
56
|
+
- raw stdout or stderr
|
|
57
|
+
- environment variables
|
|
58
|
+
- URLs, tokens, secrets, API keys, or cloud identifiers
|
|
59
|
+
- model files or model contents
|
|
60
|
+
|
|
61
|
+
For audio shape, logs should use coarse metadata such as extension, duration
|
|
62
|
+
bucket, size bucket, sample-rate bucket, or channel count. Do not log a path or
|
|
63
|
+
basename even when it looks harmless; names like `therapy-session.m4a` can be
|
|
64
|
+
private.
|
|
65
|
+
|
|
66
|
+
## Storage
|
|
67
|
+
|
|
68
|
+
Default paths:
|
|
69
|
+
|
|
70
|
+
- macOS: `~/Library/Logs/kesha/kesha.ndjson`
|
|
71
|
+
- Linux: `${XDG_STATE_HOME:-~/.local/state}/kesha/logs/kesha.ndjson`
|
|
72
|
+
- Windows: `%LOCALAPPDATA%\kesha\logs\kesha.ndjson`
|
|
73
|
+
|
|
74
|
+
Set `KESHA_LOG_DIR` to override the directory. The active file is
|
|
75
|
+
`kesha.ndjson`; rotated files are named `kesha.1.ndjson`, `kesha.2.ndjson`, and
|
|
76
|
+
so on.
|
|
77
|
+
|
|
78
|
+
The first implementation rotates at 10 MB and keeps 5 rotated files. `kesha logs
|
|
79
|
+
reset` deletes Kesha log files but preserves the selected mode.
|
|
80
|
+
|
|
81
|
+
## Support Bundles
|
|
82
|
+
|
|
83
|
+
`kesha support-bundle` does not include diagnostic log contents by default. Use
|
|
84
|
+
`kesha support-bundle --include-logs` to add a bounded tail of the active
|
|
85
|
+
already-sanitized NDJSON log when a support issue needs recent command events.
|
|
86
|
+
Recommended flow for a bug report:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
kesha logs status
|
|
90
|
+
kesha logs mode retain-on-failure
|
|
91
|
+
# reproduce the failure
|
|
92
|
+
kesha support-bundle --include-logs --output kesha-support-with-logs.tar.gz
|
|
93
|
+
```
|
package/man/kesha.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH KESHA 1 "May 2026" "kesha 1.19.0
|
|
1
|
+
.TH KESHA 1 "May 2026" "kesha 1.19.0" "User Commands"
|
|
2
2
|
.SH NAME
|
|
3
3
|
kesha \- open-source local voice toolkit
|
|
4
4
|
.SH SYNOPSIS
|
|
@@ -23,6 +23,9 @@ Interactive setup guide for Kesha features
|
|
|
23
23
|
.B install
|
|
24
24
|
Download inference engine and models
|
|
25
25
|
.TP
|
|
26
|
+
.B logs
|
|
27
|
+
Manage local privacy\-safe diagnostic logs
|
|
28
|
+
.TP
|
|
26
29
|
.B manpage
|
|
27
30
|
Print the kesha(1) manpage
|
|
28
31
|
.TP
|
|
@@ -129,6 +132,10 @@ Also install Silero VAD (~2.3MB) for long\-audio preprocessing
|
|
|
129
132
|
.TP
|
|
130
133
|
.B \-\-diarize
|
|
131
134
|
Also install the Sortformer streaming\-diarization model (~245MB, darwin\-arm64 only — #199)
|
|
135
|
+
.SS logs
|
|
136
|
+
.TP
|
|
137
|
+
.B \-\-json
|
|
138
|
+
Output status as JSON
|
|
132
139
|
.SS record
|
|
133
140
|
.TP
|
|
134
141
|
.B \-\-out
|
|
@@ -188,6 +195,9 @@ Include recursive cache disk usage
|
|
|
188
195
|
.TP
|
|
189
196
|
.B \-\-output
|
|
190
197
|
Write archive to this .tar.gz path
|
|
198
|
+
.TP
|
|
199
|
+
.B \-\-include\-logs
|
|
200
|
+
Include a bounded tail of privacy\-safe diagnostic logs
|
|
191
201
|
.SH FILES
|
|
192
202
|
.TP
|
|
193
203
|
.B completions/kesha.bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drakulavich/kesha-voice-kit",
|
|
3
|
-
"version": "1.19.0
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "Give your local tools a voice: fast STT in 25 languages (~19x faster than Whisper on Apple Silicon, ONNX CPU fallback), TTS via Kokoro/Vosk/macOS voices, VAD + 107-language detection. Rust engine, Bun CLI, OpenClaw skill.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"tsconfig.json",
|
|
20
20
|
"openclaw.plugin.json",
|
|
21
21
|
"openclaw-plugin.cjs",
|
|
22
|
+
"docs/diagnostic-logs.md",
|
|
22
23
|
"docs/product-positioning.md",
|
|
23
24
|
"SKILL.md",
|
|
24
|
-
"scripts/postinstall.cjs",
|
|
25
25
|
"LICENSE",
|
|
26
26
|
"NOTICES.md",
|
|
27
27
|
"README.md"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
]
|
|
33
33
|
},
|
|
34
34
|
"keshaEngine": {
|
|
35
|
-
"version": "1.19.0
|
|
35
|
+
"version": "1.19.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"test": "bun test",
|
|
@@ -49,8 +49,7 @@
|
|
|
49
49
|
"check": "bun run lint && bun run check:versions && bun run test:cli-fast",
|
|
50
50
|
"check:workflows": "bun .github/scripts/check-workflows.ts",
|
|
51
51
|
"check:release-manifest": "bun .github/scripts/release-manifest.mjs --check",
|
|
52
|
-
"check:versions": "bun .github/scripts/check-versions.ts"
|
|
53
|
-
"postinstall": "node scripts/postinstall.cjs"
|
|
52
|
+
"check:versions": "bun .github/scripts/check-versions.ts"
|
|
54
53
|
},
|
|
55
54
|
"keywords": [
|
|
56
55
|
"asr",
|
package/src/cli/dispatch.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runMain } from "citty";
|
|
1
|
+
import { runMain, type CommandDef } from "citty";
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { log } from "../log";
|
|
4
4
|
import { suggestCommand } from "../suggest-command";
|
|
@@ -6,6 +6,7 @@ import { completionsCommand } from "./completions";
|
|
|
6
6
|
import { doctorCommand } from "./doctor";
|
|
7
7
|
import { initCommand } from "./init";
|
|
8
8
|
import { installCommand } from "./install";
|
|
9
|
+
import { logsCommand } from "./logs";
|
|
9
10
|
import { manpageCommand } from "./manpage";
|
|
10
11
|
import { recordCommand } from "./record";
|
|
11
12
|
import { sayCommand } from "./say";
|
|
@@ -14,18 +15,23 @@ import { statusCommand } from "./status";
|
|
|
14
15
|
import { supportBundleCommand } from "./support-bundle";
|
|
15
16
|
import { mainCommand } from "./main";
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
// Single source of truth: keyed lookup also feeds the `did you mean` suggester.
|
|
19
|
+
// `CommandDef<any>` is intentional — citty's generic is invariant in the args
|
|
20
|
+
// shape, and each subcommand has its own arg schema; the value here is only
|
|
21
|
+
// passed back to `runMain`, which re-reads the schema from the def itself.
|
|
22
|
+
const SUBCOMMANDS: Record<string, CommandDef<any>> = {
|
|
23
|
+
doctor: doctorCommand,
|
|
24
|
+
init: initCommand,
|
|
25
|
+
install: installCommand,
|
|
26
|
+
logs: logsCommand,
|
|
27
|
+
status: statusCommand,
|
|
28
|
+
record: recordCommand,
|
|
29
|
+
say: sayCommand,
|
|
30
|
+
stats: statsCommand,
|
|
31
|
+
"support-bundle": supportBundleCommand,
|
|
32
|
+
completions: completionsCommand,
|
|
33
|
+
manpage: manpageCommand,
|
|
34
|
+
};
|
|
29
35
|
|
|
30
36
|
function isPathLike(arg: string): boolean {
|
|
31
37
|
return arg.includes(".") || arg.includes("/") || existsSync(arg);
|
|
@@ -34,53 +40,8 @@ function isPathLike(arg: string): boolean {
|
|
|
34
40
|
export async function runCli(rawArgs = process.argv.slice(2)): Promise<void> {
|
|
35
41
|
const [firstArg, ...restArgs] = rawArgs;
|
|
36
42
|
|
|
37
|
-
if (firstArg
|
|
38
|
-
await runMain(
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (firstArg === "init") {
|
|
43
|
-
await runMain(initCommand, { rawArgs: restArgs });
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (firstArg === "completions") {
|
|
48
|
-
await runMain(completionsCommand, { rawArgs: restArgs });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (firstArg === "install") {
|
|
53
|
-
await runMain(installCommand, { rawArgs: restArgs });
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (firstArg === "manpage") {
|
|
58
|
-
await runMain(manpageCommand, { rawArgs: restArgs });
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (firstArg === "status") {
|
|
63
|
-
await runMain(statusCommand, { rawArgs: restArgs });
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (firstArg === "record") {
|
|
68
|
-
await runMain(recordCommand, { rawArgs: restArgs });
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (firstArg === "say") {
|
|
73
|
-
await runMain(sayCommand, { rawArgs: restArgs });
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (firstArg === "stats") {
|
|
78
|
-
await runMain(statsCommand, { rawArgs: restArgs });
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (firstArg === "support-bundle") {
|
|
83
|
-
await runMain(supportBundleCommand, { rawArgs: restArgs });
|
|
43
|
+
if (firstArg && Object.hasOwn(SUBCOMMANDS, firstArg)) {
|
|
44
|
+
await runMain(SUBCOMMANDS[firstArg], { rawArgs: restArgs });
|
|
84
45
|
return;
|
|
85
46
|
}
|
|
86
47
|
|
|
@@ -88,7 +49,7 @@ export async function runCli(rawArgs = process.argv.slice(2)): Promise<void> {
|
|
|
88
49
|
// Extensionless existing files remain valid transcription inputs; missing
|
|
89
50
|
// bare tokens are more likely command typos and should not start the engine.
|
|
90
51
|
if (firstArg && !firstArg.startsWith("-") && !isPathLike(firstArg)) {
|
|
91
|
-
const suggestion = suggestCommand(firstArg, SUBCOMMANDS);
|
|
52
|
+
const suggestion = suggestCommand(firstArg, Object.keys(SUBCOMMANDS));
|
|
92
53
|
log.error(`unknown command '${firstArg}'`);
|
|
93
54
|
if (suggestion && suggestion !== firstArg) {
|
|
94
55
|
log.warn(`(Did you mean ${suggestion}?)`);
|
package/src/cli/install.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { renderInstallPlan } from "../install-plan";
|
|
|
5
5
|
import { maybeAskForStar } from "../star";
|
|
6
6
|
import { log } from "../log";
|
|
7
7
|
import { packageVersion } from "../package-info";
|
|
8
|
+
import { createDiagnosticLogSession, type DiagnosticLogSession } from "../diagnostic-log";
|
|
8
9
|
|
|
9
10
|
export interface InstallCommandArgs {
|
|
10
11
|
coreml: boolean;
|
|
@@ -46,6 +47,28 @@ function defaultBackendForPlatform(): string | undefined {
|
|
|
46
47
|
return undefined;
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
type InstallDiagnosticErrorKind = "validation_failed" | "install_failed";
|
|
51
|
+
|
|
52
|
+
function finishInstallDiagnostic(
|
|
53
|
+
diagnosticLog: DiagnosticLogSession | null,
|
|
54
|
+
startedAt: number,
|
|
55
|
+
status: "success" | "failed",
|
|
56
|
+
errorKind?: InstallDiagnosticErrorKind,
|
|
57
|
+
): void {
|
|
58
|
+
if (!diagnosticLog) return;
|
|
59
|
+
try {
|
|
60
|
+
diagnosticLog.event("command.finish", {
|
|
61
|
+
command: "install",
|
|
62
|
+
status,
|
|
63
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
64
|
+
...(errorKind ? { errorKind } : {}),
|
|
65
|
+
});
|
|
66
|
+
diagnosticLog.finish(status);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
log.debug(`install diagnostic log finish dropped: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
49
72
|
export async function performInstall(
|
|
50
73
|
noCache: boolean,
|
|
51
74
|
backend?: string,
|
|
@@ -58,26 +81,42 @@ export async function performInstall(
|
|
|
58
81
|
log.info(await renderInstallPlan({ noCache, backend, tts, vad, diarize }));
|
|
59
82
|
return;
|
|
60
83
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
const platformBackend = defaultBackendForPlatform();
|
|
69
|
-
if (backend && !process.env.KESHA_ENGINE_BIN && platformBackend && backend !== platformBackend) {
|
|
70
|
-
log.error(
|
|
71
|
-
`Requested backend "${backend}" is not available on this platform; ` +
|
|
72
|
-
`the release engine uses "${platformBackend}".`,
|
|
73
|
-
);
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
84
|
+
|
|
85
|
+
let diagnosticLog: DiagnosticLogSession | null = null;
|
|
86
|
+
let errorKind: InstallDiagnosticErrorKind = "install_failed";
|
|
87
|
+
const startedAt = performance.now();
|
|
76
88
|
try {
|
|
89
|
+
diagnosticLog = createDiagnosticLogSession();
|
|
90
|
+
diagnosticLog.event("command.start", {
|
|
91
|
+
command: "install",
|
|
92
|
+
backend: backend ?? "auto",
|
|
93
|
+
noCache,
|
|
94
|
+
tts,
|
|
95
|
+
vad,
|
|
96
|
+
diarize,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (diarize && !(process.platform === "darwin" && process.arch === "arm64")) {
|
|
100
|
+
errorKind = "validation_failed";
|
|
101
|
+
throw new Error(
|
|
102
|
+
"--diarize is currently darwin-arm64 only " +
|
|
103
|
+
"(see https://github.com/drakulavich/kesha-voice-kit/issues/199).",
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const platformBackend = defaultBackendForPlatform();
|
|
107
|
+
if (backend && !process.env.KESHA_ENGINE_BIN && platformBackend && backend !== platformBackend) {
|
|
108
|
+
errorKind = "validation_failed";
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Requested backend "${backend}" is not available on this platform; ` +
|
|
111
|
+
`the release engine uses "${platformBackend}".`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
77
114
|
await downloadEngine(noCache, backend, { tts, vad, diarize });
|
|
78
115
|
await maybeAskForStar(getEngineBinPath(), packageVersion, log);
|
|
116
|
+
finishInstallDiagnostic(diagnosticLog, startedAt, "success");
|
|
79
117
|
} catch (err: unknown) {
|
|
80
118
|
const message = err instanceof Error ? err.message : String(err);
|
|
119
|
+
finishInstallDiagnostic(diagnosticLog, startedAt, "failed", errorKind);
|
|
81
120
|
log.error(message);
|
|
82
121
|
process.exit(1);
|
|
83
122
|
}
|