/** * Voice-to-text capture control (ctrl+r / app.input.voiceTranscribe). * * Prefers a persistent `voicetools serve` daemon: the first press probes for * support and (if found) loads models once, showing a "warming up" spinner; * every later press reuses the already-warm daemon and jumps straight to * Listening. Binaries without `serve` support fall back to spawning * `voicetools transcribe` per press. Pressing the shortcut again while * listening (or while still warming up) cancels. */ import type { Container, TUI } from "@kolisachint/hoocode-tui"; /** The slice of the interactive mode the voice feature needs. */ export interface VoiceControllerDeps { ui: TUI; /** The status area below the chat; the voice panel mounts here. */ statusContainer: Container; /** Feed raw input (bracketed paste) to the prompt editor. */ sendEditorInput(data: string): void; showError(message: string): void; /** * Trailing-silence window (ms): how long a pause while speaking lasts before * the capture auto-stops. Resolved once by the caller (env `VOICETOOLS_SILENCE_MS` * → settings → default 800, clamped 300-10000) and used for both the binary * cutoff — passed to `voicetools serve` via `--silence-ms` (see * VoiceDaemon.spawn) — and the on-screen countdown, so the two stay in sync. * A longer window tolerates brief mid-sentence pauses without taxing every * dictation with dead air. */ silenceMs: number; } export declare class VoiceController { private readonly deps; /** In-flight legacy (`voicetools transcribe`) capture. */ private session; private daemon; /** Set when the binary rejected `serve`; future presses use the legacy path. */ private daemonUnsupported; /** True while the voicetools binary is being resolved/downloaded before a session starts. */ private starting; /** True while a capture is active (listening or transcribing). */ private active; /** The status panel while voice input is active. */ private panel; constructor(deps: VoiceControllerDeps); /** Toggle voice-to-text capture. */ toggle(): void; /** * Update the trailing-silence window live (e.g. from the settings selector). * The daemon's `--silence-ms` is fixed at spawn, so drop any idle warm daemon * and let the next capture respawn — that keeps the binary cutoff matched to * the countdown, which reads the same value. A drop is skipped while a capture * is active so the in-flight session keeps its own spawn-time value. */ setSilenceMs(ms: number): void; /** Stop any capture, shut down the daemon, and drop the panel. */ dispose(): void; /** * Build the (stable, reused-across-captures) handlers for the daemon. * * Every handler bails out once `active` is false: CANCEL is a soft * request (unlike the legacy path's `proc.kill()`, it doesn't sever the * pipe), so the daemon can still have a trailing PARTIAL/FINAL/DONE for the * just-cancelled capture in flight when the user presses cancel. Without * this guard that stale text would land in the editor after the panel had * already collapsed. * * v0.1.4 serve streams `PARTIAL ` (live preview, * never committed) and ends with a single `FINAL ` (the one * commit to the editor). `SEGMENT` is still handled for the legacy * transcribe path and any binary that streams committed chunks directly. */ private buildDaemonHandlers; /** Inject decoded text into the editor via bracketed paste (with a trailing space). */ private commitText; private beginDaemonCapture; private beginLegacyCapture; private resolveBin; /** Create (or reuse) the voice panel and mount it in the status container. */ private showPanel; private showWarming; /** Collapse the voice panel back to nothing (idle) and stop its animation. */ private resetUI; } //# sourceMappingURL=voice-controller.d.ts.map