compact-agent 1.5.0 → 1.7.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/dist/accessibility.d.ts +50 -0
- package/dist/accessibility.js +0 -0
- package/dist/accessibility.js.map +1 -0
- package/dist/audio.d.ts +50 -0
- package/dist/audio.js +382 -0
- package/dist/audio.js.map +1 -0
- package/dist/config.js +48 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +473 -5
- package/dist/index.js.map +1 -1
- package/dist/query.js +116 -3
- package/dist/query.js.map +1 -1
- package/dist/status.d.ts +49 -0
- package/dist/status.js +82 -0
- package/dist/status.js.map +1 -0
- package/dist/theme.d.ts +3 -0
- package/dist/theme.js +51 -29
- package/dist/theme.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.js.map +1 -1
- package/dist/voice.d.ts +79 -0
- package/dist/voice.js +351 -0
- package/dist/voice.js.map +1 -0
- package/package.json +10 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen-reader-friendly output transformations.
|
|
3
|
+
*
|
|
4
|
+
* When accessibility.screenReader is enabled, all terminal output passes
|
|
5
|
+
* through `applyScreenReader()` first. This:
|
|
6
|
+
* - strips ANSI escape codes (NVDA/JAWS/VoiceOver read them literally)
|
|
7
|
+
* - replaces decorative emoji + unicode glyphs with their word meaning
|
|
8
|
+
* ("✓" → "done", "→" → "to", "•" → "bullet", etc.)
|
|
9
|
+
* - normalizes whitespace so the reader doesn't pause mid-sentence on
|
|
10
|
+
* box-drawing characters
|
|
11
|
+
*
|
|
12
|
+
* Also exports utilities for blind-friendly UX:
|
|
13
|
+
* - `summarize()` — heuristic short-summary of a long response, so the
|
|
14
|
+
* reader can ask "give me the gist" instead of listening to 800 words
|
|
15
|
+
* - `isLikelyDestructive(toolName, args)` — used by the destructive-action
|
|
16
|
+
* verbal-confirm path in query.ts
|
|
17
|
+
* - `countWords()` — quick word count for the long-response threshold
|
|
18
|
+
*/
|
|
19
|
+
import type { CrowcoderConfig } from './types.js';
|
|
20
|
+
export declare function stripAnsi(s: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Replace decorative symbols + emoji with spoken-language equivalents.
|
|
23
|
+
*/
|
|
24
|
+
export declare function symbolsToWords(s: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Full screen-reader transform: ANSI off, symbols → words, then a final
|
|
27
|
+
* pass that drops any remaining lone control character.
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyScreenReader(s: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Conditional transform: only runs when screenReader is enabled, otherwise
|
|
32
|
+
* returns the input unchanged. Use this as the standard sink for any
|
|
33
|
+
* terminal output (console.log replacements, status lines, etc.).
|
|
34
|
+
*/
|
|
35
|
+
export declare function screenReaderFilter(s: string, config: CrowcoderConfig): string;
|
|
36
|
+
export declare function countWords(s: string): number;
|
|
37
|
+
/**
|
|
38
|
+
* Cheap, no-LLM summary: take the first sentence of each paragraph (up to
|
|
39
|
+
* 3 paragraphs) and return as a single paragraph. Good enough to answer
|
|
40
|
+
* "give me the gist" for a blind user without burning another API call.
|
|
41
|
+
*
|
|
42
|
+
* If the response is shorter than the threshold, returns it unchanged.
|
|
43
|
+
*/
|
|
44
|
+
export declare function summarize(text: string, thresholdWords?: number, maxSentences?: number): string;
|
|
45
|
+
export declare function isLikelyDestructive(toolName: string, args: unknown): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Build a one-sentence "I am about to X" announcement for the destructive
|
|
48
|
+
* confirmation prompt. Kept terse — TTS time is user time.
|
|
49
|
+
*/
|
|
50
|
+
export declare function describeDestructive(toolName: string, args: unknown): string;
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessibility.js","sourceRoot":"","sources":["../src/accessibility.ts"],"names":[],"mappings":"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"}
|
package/dist/audio.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect ffmpeg on the user's PATH. Result is cached; call resetFfmpegCache()
|
|
3
|
+
* if you want to re-probe (e.g. after the user installs ffmpeg mid-session).
|
|
4
|
+
*/
|
|
5
|
+
export declare function isFfmpegAvailable(): Promise<boolean>;
|
|
6
|
+
export declare function resetFfmpegCache(): void;
|
|
7
|
+
export declare function setFfmpegPath(p: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Record from the default mic for up to `maxSeconds`, return WAV-encoded
|
|
10
|
+
* bytes. ffmpeg encodes to 16kHz mono PCM-16 (Whisper's preferred format).
|
|
11
|
+
*
|
|
12
|
+
* Returns null on failure — including ffmpeg missing or mic unavailable.
|
|
13
|
+
* Caller usually wraps with `dictateOnce()` which handles the UX.
|
|
14
|
+
*/
|
|
15
|
+
export declare function recordAudio(maxSeconds: number): Promise<Buffer | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Pipe an audio buffer (MP3 from ElevenLabs, or WAV from us) through ffplay
|
|
18
|
+
* if available, falling back to ffmpeg with the platform's default audio
|
|
19
|
+
* output. Honors an AbortSignal so a Ctrl+C or new-message arrival can cut
|
|
20
|
+
* playback immediately.
|
|
21
|
+
*
|
|
22
|
+
* Returns true if playback completed without error, false otherwise.
|
|
23
|
+
*/
|
|
24
|
+
export declare function playAudioBuffer(buf: Buffer, signal?: AbortSignal): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Generate + play a short tone for state transitions. Uses ffmpeg's `sine`
|
|
27
|
+
* filter, so no asset files needed. Plays via ffplay when available so it
|
|
28
|
+
* doesn't fight the main TTS pipeline.
|
|
29
|
+
*
|
|
30
|
+
* Frequencies / durations are tuned to be brief (under 250ms) and pleasant
|
|
31
|
+
* (no harsh upper harmonics).
|
|
32
|
+
*/
|
|
33
|
+
export type AudioCue = 'ready' | 'recording-start' | 'recording-stop' | 'processing' | 'done' | 'error';
|
|
34
|
+
/**
|
|
35
|
+
* Play a named audio cue. Best-effort; returns true on apparent success.
|
|
36
|
+
* Failures are silent — a missing beep should never break the REPL.
|
|
37
|
+
*/
|
|
38
|
+
export declare function audioCue(name: AudioCue): Promise<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Start a recording subprocess and return a controller. The caller calls
|
|
41
|
+
* `stop()` to finalize and receive the audio buffer (or null on error).
|
|
42
|
+
*
|
|
43
|
+
* Used by the F1 push-to-talk hotkey: keydown → startRecording, keyup →
|
|
44
|
+
* controller.stop(). The maxSeconds cap is a safety net for stuck keys.
|
|
45
|
+
*/
|
|
46
|
+
export interface RecordController {
|
|
47
|
+
stop: () => Promise<Buffer | null>;
|
|
48
|
+
abort: () => void;
|
|
49
|
+
}
|
|
50
|
+
export declare function startRecording(maxSeconds?: number): Promise<RecordController | null>;
|
package/dist/audio.js
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio I/O via ffmpeg subprocess.
|
|
3
|
+
*
|
|
4
|
+
* We deliberately don't depend on native node modules (`speaker`, `mic`, etc.)
|
|
5
|
+
* because they need rebuilding per Node version and are flaky across Windows /
|
|
6
|
+
* macOS / Linux. ffmpeg is a single statically-linked binary the user can
|
|
7
|
+
* install once and forget.
|
|
8
|
+
*
|
|
9
|
+
* All exports degrade to a no-op (or null) when ffmpeg is missing — callers
|
|
10
|
+
* should treat ffmpeg-absence as "voice features off", not as an error.
|
|
11
|
+
*
|
|
12
|
+
* Five named audio cues:
|
|
13
|
+
* - 'ready' short rising chirp (REPL ready for input)
|
|
14
|
+
* - 'recording-start' two-tone tick (mic opened)
|
|
15
|
+
* - 'recording-stop' single low tick (mic closed)
|
|
16
|
+
* - 'processing' sustained mid tone (TTS/STT in flight)
|
|
17
|
+
* - 'done' short falling chirp (operation succeeded)
|
|
18
|
+
* - 'error' low buzz (operation failed)
|
|
19
|
+
*
|
|
20
|
+
* Cues are generated on-the-fly by ffmpeg's `sine` filter so we don't have to
|
|
21
|
+
* ship binary asset files in the npm tarball.
|
|
22
|
+
*/
|
|
23
|
+
import { spawn } from 'node:child_process';
|
|
24
|
+
import { Readable } from 'node:stream';
|
|
25
|
+
// ── Detection ─────────────────────────────────────────────
|
|
26
|
+
let ffmpegCheckCache = null;
|
|
27
|
+
let ffmpegPathCache = 'ffmpeg';
|
|
28
|
+
/**
|
|
29
|
+
* Detect ffmpeg on the user's PATH. Result is cached; call resetFfmpegCache()
|
|
30
|
+
* if you want to re-probe (e.g. after the user installs ffmpeg mid-session).
|
|
31
|
+
*/
|
|
32
|
+
export async function isFfmpegAvailable() {
|
|
33
|
+
if (ffmpegCheckCache !== null)
|
|
34
|
+
return ffmpegCheckCache;
|
|
35
|
+
ffmpegCheckCache = await new Promise((resolve) => {
|
|
36
|
+
const child = spawn(ffmpegPathCache, ['-version'], { stdio: 'ignore' });
|
|
37
|
+
child.on('error', () => resolve(false));
|
|
38
|
+
child.on('close', (code) => resolve(code === 0));
|
|
39
|
+
});
|
|
40
|
+
return ffmpegCheckCache;
|
|
41
|
+
}
|
|
42
|
+
export function resetFfmpegCache() {
|
|
43
|
+
ffmpegCheckCache = null;
|
|
44
|
+
}
|
|
45
|
+
export function setFfmpegPath(p) {
|
|
46
|
+
ffmpegPathCache = p;
|
|
47
|
+
ffmpegCheckCache = null;
|
|
48
|
+
}
|
|
49
|
+
// ── Platform-specific mic input args ──────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* Build the `-f <driver> -i <device>` arguments for capturing from the
|
|
52
|
+
* default mic on each OS.
|
|
53
|
+
*
|
|
54
|
+
* Windows : -f dshow -i audio="<first input device>"
|
|
55
|
+
* We can't enumerate without listing — but ffmpeg's "default"
|
|
56
|
+
* alias works on most systems via dshow. If it doesn't, the user
|
|
57
|
+
* can override via env var COMPACT_AGENT_AUDIO_INPUT.
|
|
58
|
+
* macOS : -f avfoundation -i ":0" (":0" = default audio input)
|
|
59
|
+
* Linux : -f pulse -i default (PulseAudio default sink)
|
|
60
|
+
*
|
|
61
|
+
* Env override: COMPACT_AGENT_AUDIO_INPUT="-f dshow -i audio=\"My Mic\""
|
|
62
|
+
* (raw argv, split by spaces — anything in quotes preserved)
|
|
63
|
+
*/
|
|
64
|
+
function getMicInputArgs() {
|
|
65
|
+
const override = process.env.COMPACT_AGENT_AUDIO_INPUT;
|
|
66
|
+
if (override) {
|
|
67
|
+
// Quote-aware split so `audio="My Mic"` survives as one token
|
|
68
|
+
return tokenize(override);
|
|
69
|
+
}
|
|
70
|
+
switch (process.platform) {
|
|
71
|
+
case 'win32':
|
|
72
|
+
return ['-f', 'dshow', '-i', 'audio=default'];
|
|
73
|
+
case 'darwin':
|
|
74
|
+
return ['-f', 'avfoundation', '-i', ':0'];
|
|
75
|
+
default:
|
|
76
|
+
return ['-f', 'pulse', '-i', 'default'];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function tokenize(s) {
|
|
80
|
+
const out = [];
|
|
81
|
+
let buf = '';
|
|
82
|
+
let inQuote = false;
|
|
83
|
+
for (const ch of s) {
|
|
84
|
+
if (ch === '"') {
|
|
85
|
+
inQuote = !inQuote;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (ch === ' ' && !inQuote) {
|
|
89
|
+
if (buf) {
|
|
90
|
+
out.push(buf);
|
|
91
|
+
buf = '';
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
buf += ch;
|
|
96
|
+
}
|
|
97
|
+
if (buf)
|
|
98
|
+
out.push(buf);
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
// ── Recording ─────────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Record from the default mic for up to `maxSeconds`, return WAV-encoded
|
|
104
|
+
* bytes. ffmpeg encodes to 16kHz mono PCM-16 (Whisper's preferred format).
|
|
105
|
+
*
|
|
106
|
+
* Returns null on failure — including ffmpeg missing or mic unavailable.
|
|
107
|
+
* Caller usually wraps with `dictateOnce()` which handles the UX.
|
|
108
|
+
*/
|
|
109
|
+
export async function recordAudio(maxSeconds) {
|
|
110
|
+
if (!(await isFfmpegAvailable()))
|
|
111
|
+
return null;
|
|
112
|
+
return new Promise((resolve) => {
|
|
113
|
+
const args = [
|
|
114
|
+
...getMicInputArgs(),
|
|
115
|
+
'-t', String(Math.max(1, Math.min(300, maxSeconds))),
|
|
116
|
+
'-ac', '1', // mono
|
|
117
|
+
'-ar', '16000', // 16 kHz (Whisper)
|
|
118
|
+
'-f', 'wav',
|
|
119
|
+
'-loglevel', 'error',
|
|
120
|
+
'pipe:1', // write WAV to stdout
|
|
121
|
+
];
|
|
122
|
+
const child = spawn(ffmpegPathCache, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
123
|
+
const chunks = [];
|
|
124
|
+
let errBuf = '';
|
|
125
|
+
child.stdout.on('data', (c) => chunks.push(c));
|
|
126
|
+
child.stderr.on('data', (c) => { errBuf += c.toString(); });
|
|
127
|
+
child.on('error', () => resolve(null));
|
|
128
|
+
child.on('close', (code) => {
|
|
129
|
+
if (code !== 0 && chunks.length === 0) {
|
|
130
|
+
if (process.env.COMPACT_AGENT_AUDIO_DEBUG) {
|
|
131
|
+
// eslint-disable-next-line no-console
|
|
132
|
+
console.error('[audio] record failed:', errBuf.slice(0, 400));
|
|
133
|
+
}
|
|
134
|
+
resolve(null);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
resolve(Buffer.concat(chunks));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// ── Playback ──────────────────────────────────────────────
|
|
142
|
+
/**
|
|
143
|
+
* Pipe an audio buffer (MP3 from ElevenLabs, or WAV from us) through ffplay
|
|
144
|
+
* if available, falling back to ffmpeg with the platform's default audio
|
|
145
|
+
* output. Honors an AbortSignal so a Ctrl+C or new-message arrival can cut
|
|
146
|
+
* playback immediately.
|
|
147
|
+
*
|
|
148
|
+
* Returns true if playback completed without error, false otherwise.
|
|
149
|
+
*/
|
|
150
|
+
export async function playAudioBuffer(buf, signal) {
|
|
151
|
+
if (!(await isFfmpegAvailable()))
|
|
152
|
+
return false;
|
|
153
|
+
if (!buf || buf.length === 0)
|
|
154
|
+
return false;
|
|
155
|
+
if (signal?.aborted)
|
|
156
|
+
return false;
|
|
157
|
+
// Try ffplay first (smaller, dedicated to playback). If it's not on PATH
|
|
158
|
+
// we'll fall back to `ffmpeg -f <platform-audio-out>`.
|
|
159
|
+
const ffplayOk = await tryFfplay(buf, signal);
|
|
160
|
+
if (ffplayOk)
|
|
161
|
+
return true;
|
|
162
|
+
return await tryFfmpegPlay(buf, signal);
|
|
163
|
+
}
|
|
164
|
+
async function tryFfplay(buf, signal) {
|
|
165
|
+
return new Promise((resolve) => {
|
|
166
|
+
const args = ['-nodisp', '-autoexit', '-loglevel', 'error', '-i', 'pipe:0'];
|
|
167
|
+
let child;
|
|
168
|
+
try {
|
|
169
|
+
child = spawn('ffplay', args, { stdio: ['pipe', 'ignore', 'pipe'] });
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
resolve(false);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
let resolved = false;
|
|
176
|
+
const onAbort = () => {
|
|
177
|
+
if (!resolved) {
|
|
178
|
+
resolved = true;
|
|
179
|
+
try {
|
|
180
|
+
child.kill('SIGTERM');
|
|
181
|
+
}
|
|
182
|
+
catch { /* noop */ }
|
|
183
|
+
resolve(false);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
if (signal)
|
|
187
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
188
|
+
child.on('error', () => { if (!resolved) {
|
|
189
|
+
resolved = true;
|
|
190
|
+
resolve(false);
|
|
191
|
+
} });
|
|
192
|
+
child.on('close', (code) => {
|
|
193
|
+
if (signal)
|
|
194
|
+
signal.removeEventListener('abort', onAbort);
|
|
195
|
+
if (!resolved) {
|
|
196
|
+
resolved = true;
|
|
197
|
+
resolve(code === 0);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
// Stream the buffer into stdin
|
|
201
|
+
const stream = Readable.from([buf]);
|
|
202
|
+
stream.pipe(child.stdin).on('error', () => { });
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function getPlayOutputArgs() {
|
|
206
|
+
switch (process.platform) {
|
|
207
|
+
case 'win32':
|
|
208
|
+
// DirectSound is the most universally-available output on Windows
|
|
209
|
+
return ['-f', 'dshow']; // Unfortunately dshow is input-only; use sdl2 if linked
|
|
210
|
+
case 'darwin':
|
|
211
|
+
return ['-f', 'audiotoolbox'];
|
|
212
|
+
default:
|
|
213
|
+
return ['-f', 'pulse'];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function tryFfmpegPlay(buf, signal) {
|
|
217
|
+
return new Promise((resolve) => {
|
|
218
|
+
// ffmpeg-as-player: decode from stdin and route to platform audio out.
|
|
219
|
+
// This is a fallback, ffplay is the preferred path. We try sdl2 first
|
|
220
|
+
// (works on all platforms if ffmpeg was built with --enable-sdl2), then
|
|
221
|
+
// a platform-specific output module.
|
|
222
|
+
const args = [
|
|
223
|
+
'-loglevel', 'error',
|
|
224
|
+
'-i', 'pipe:0',
|
|
225
|
+
'-f', 'sdl', '-',
|
|
226
|
+
];
|
|
227
|
+
let child;
|
|
228
|
+
try {
|
|
229
|
+
child = spawn(ffmpegPathCache, args, { stdio: ['pipe', 'ignore', 'ignore'] });
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
resolve(false);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
let resolved = false;
|
|
236
|
+
const onAbort = () => {
|
|
237
|
+
if (!resolved) {
|
|
238
|
+
resolved = true;
|
|
239
|
+
try {
|
|
240
|
+
child.kill('SIGTERM');
|
|
241
|
+
}
|
|
242
|
+
catch { /* noop */ }
|
|
243
|
+
resolve(false);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
if (signal)
|
|
247
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
248
|
+
child.on('error', () => { if (!resolved) {
|
|
249
|
+
resolved = true;
|
|
250
|
+
resolve(false);
|
|
251
|
+
} });
|
|
252
|
+
child.on('close', (code) => {
|
|
253
|
+
if (signal)
|
|
254
|
+
signal.removeEventListener('abort', onAbort);
|
|
255
|
+
if (!resolved) {
|
|
256
|
+
resolved = true;
|
|
257
|
+
resolve(code === 0);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
const stream = Readable.from([buf]);
|
|
261
|
+
stream.pipe(child.stdin).on('error', () => { });
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const CUE_TONES = {
|
|
265
|
+
'ready': { freqHz: 880, durationSec: 0.08, follow: { freqHz: 1320, durationSec: 0.08 } },
|
|
266
|
+
'recording-start': { freqHz: 660, durationSec: 0.07, follow: { freqHz: 880, durationSec: 0.07 } },
|
|
267
|
+
'recording-stop': { freqHz: 440, durationSec: 0.10 },
|
|
268
|
+
'processing': { freqHz: 660, durationSec: 0.18 },
|
|
269
|
+
'done': { freqHz: 1320, durationSec: 0.08, follow: { freqHz: 880, durationSec: 0.08 } },
|
|
270
|
+
'error': { freqHz: 220, durationSec: 0.22 },
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Play a named audio cue. Best-effort; returns true on apparent success.
|
|
274
|
+
* Failures are silent — a missing beep should never break the REPL.
|
|
275
|
+
*/
|
|
276
|
+
export async function audioCue(name) {
|
|
277
|
+
if (!(await isFfmpegAvailable()))
|
|
278
|
+
return false;
|
|
279
|
+
const spec = CUE_TONES[name];
|
|
280
|
+
if (!spec)
|
|
281
|
+
return false;
|
|
282
|
+
const buf = await generateTone(spec);
|
|
283
|
+
if (!buf)
|
|
284
|
+
return false;
|
|
285
|
+
return await playAudioBuffer(buf);
|
|
286
|
+
}
|
|
287
|
+
async function generateTone(spec) {
|
|
288
|
+
// We compose a single ffmpeg pipeline using anullsrc + sine + concat. Easier:
|
|
289
|
+
// synthesize each tone to a WAV stream, concatenate buffers.
|
|
290
|
+
const part1 = await synthSine(spec.freqHz, spec.durationSec);
|
|
291
|
+
if (!part1)
|
|
292
|
+
return null;
|
|
293
|
+
if (!spec.follow)
|
|
294
|
+
return part1;
|
|
295
|
+
const part2 = await synthSine(spec.follow.freqHz, spec.follow.durationSec);
|
|
296
|
+
if (!part2)
|
|
297
|
+
return part1;
|
|
298
|
+
// Simple concat: both WAV bodies; ffplay handles back-to-back WAV headers
|
|
299
|
+
// OK in practice, but to be safe we just emit two short tones as separate
|
|
300
|
+
// playback calls if needed. Here we just concatenate the raw buffers; ffplay
|
|
301
|
+
// ignores the second header.
|
|
302
|
+
return Buffer.concat([part1, part2]);
|
|
303
|
+
}
|
|
304
|
+
function synthSine(freq, durationSec) {
|
|
305
|
+
return new Promise((resolve) => {
|
|
306
|
+
const args = [
|
|
307
|
+
'-f', 'lavfi',
|
|
308
|
+
'-i', `sine=frequency=${freq}:duration=${durationSec}`,
|
|
309
|
+
'-ac', '1',
|
|
310
|
+
'-ar', '22050',
|
|
311
|
+
'-f', 'wav',
|
|
312
|
+
'-loglevel', 'error',
|
|
313
|
+
'pipe:1',
|
|
314
|
+
];
|
|
315
|
+
const child = spawn(ffmpegPathCache, args, { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
316
|
+
const chunks = [];
|
|
317
|
+
child.stdout.on('data', (c) => chunks.push(c));
|
|
318
|
+
child.on('error', () => resolve(null));
|
|
319
|
+
child.on('close', (code) => resolve(code === 0 ? Buffer.concat(chunks) : null));
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
export async function startRecording(maxSeconds = 60) {
|
|
323
|
+
if (!(await isFfmpegAvailable()))
|
|
324
|
+
return null;
|
|
325
|
+
const args = [
|
|
326
|
+
...getMicInputArgs(),
|
|
327
|
+
'-t', String(Math.max(1, Math.min(300, maxSeconds))),
|
|
328
|
+
'-ac', '1',
|
|
329
|
+
'-ar', '16000',
|
|
330
|
+
'-f', 'wav',
|
|
331
|
+
'-loglevel', 'error',
|
|
332
|
+
'pipe:1',
|
|
333
|
+
];
|
|
334
|
+
const child = spawn(ffmpegPathCache, args, { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
335
|
+
const chunks = [];
|
|
336
|
+
child.stdout.on('data', (c) => chunks.push(c));
|
|
337
|
+
// Drain stderr to avoid back-pressure
|
|
338
|
+
child.stderr.on('data', () => { });
|
|
339
|
+
let resolved = false;
|
|
340
|
+
let finalResolve = null;
|
|
341
|
+
const donePromise = new Promise((resolve) => { finalResolve = resolve; });
|
|
342
|
+
child.on('close', () => {
|
|
343
|
+
if (!resolved && finalResolve) {
|
|
344
|
+
resolved = true;
|
|
345
|
+
finalResolve(chunks.length > 0 ? Buffer.concat(chunks) : null);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
child.on('error', () => {
|
|
349
|
+
if (!resolved && finalResolve) {
|
|
350
|
+
resolved = true;
|
|
351
|
+
finalResolve(null);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
return {
|
|
355
|
+
stop: async () => {
|
|
356
|
+
// ffmpeg flushes a clean WAV when it gets 'q' on stdin
|
|
357
|
+
try {
|
|
358
|
+
child.stdin.write('q');
|
|
359
|
+
}
|
|
360
|
+
catch { /* noop */ }
|
|
361
|
+
try {
|
|
362
|
+
child.stdin.end();
|
|
363
|
+
}
|
|
364
|
+
catch { /* noop */ }
|
|
365
|
+
// Safety: if it doesn't exit within 1500ms, SIGTERM it
|
|
366
|
+
const killer = setTimeout(() => { try {
|
|
367
|
+
child.kill('SIGTERM');
|
|
368
|
+
}
|
|
369
|
+
catch { /* noop */ } }, 1500);
|
|
370
|
+
const buf = await donePromise;
|
|
371
|
+
clearTimeout(killer);
|
|
372
|
+
return buf;
|
|
373
|
+
},
|
|
374
|
+
abort: () => {
|
|
375
|
+
try {
|
|
376
|
+
child.kill('SIGTERM');
|
|
377
|
+
}
|
|
378
|
+
catch { /* noop */ }
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,6DAA6D;AAC7D,IAAI,gBAAgB,GAAmB,IAAI,CAAC;AAC5C,IAAI,eAAe,GAAW,QAAQ,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,gBAAgB,KAAK,IAAI;QAAE,OAAO,gBAAgB,CAAC;IACvD,gBAAgB,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IACH,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,gBAAgB,GAAG,IAAI,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,eAAe,GAAG,CAAC,CAAC;IACpB,gBAAgB,GAAG,IAAI,CAAC;AAC1B,CAAC;AAED,6DAA6D;AAC7D;;;;;;;;;;;;;GAaG;AACH,SAAS,eAAe;IACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACvD,IAAI,QAAQ,EAAE,CAAC;QACb,8DAA8D;QAC9D,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,OAAO;YACV,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;QAChD,KAAK,QAAQ;YACX,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5C;YACE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;QACnB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAAC,OAAO,GAAG,CAAC,OAAO,CAAC;YAAC,SAAS;QAAC,CAAC;QACjD,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC3B,IAAI,GAAG,EAAE,CAAC;gBAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAAC,GAAG,GAAG,EAAE,CAAC;YAAC,CAAC;YACrC,SAAS;QACX,CAAC;QACD,GAAG,IAAI,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,GAAG;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6DAA6D;AAC7D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB;IAClD,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,OAAO,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,EAAE;QAC5C,MAAM,IAAI,GAAG;YACX,GAAG,eAAe,EAAE;YACpB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;YACpD,KAAK,EAAE,GAAG,EAAY,OAAO;YAC7B,KAAK,EAAE,OAAO,EAAQ,mBAAmB;YACzC,IAAI,EAAE,KAAK;YACX,WAAW,EAAE,OAAO;YACpB,QAAQ,EAAc,sBAAsB;SAC7C,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClF,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtC,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,CAAC;oBAC1C,sCAAsC;oBACtC,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBAChE,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO;YACT,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,6DAA6D;AAC7D;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,MAAoB;IACrE,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO,KAAK,CAAC;IAElC,yEAAyE;IACzE,uDAAuD;IACvD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,MAAoB;IACxD,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACtC,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC5E,IAAI,KAAK,CAAC;QACV,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAAC,QAAQ,GAAG,IAAI,CAAC;gBAAC,IAAI,CAAC;oBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;gBAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;QACzG,CAAC,CAAC;QACF,IAAI,MAAM;YAAE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,MAAM;gBAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAAC,QAAQ,GAAG,IAAI,CAAC;gBAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;YAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,+BAA+B;QAC/B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAA+B,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB;IACxB,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,OAAO;YACV,kEAAkE;YAClE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAG,wDAAwD;QACpF,KAAK,QAAQ;YACX,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAChC;YACE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,MAAoB;IAC5D,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACtC,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,qCAAqC;QACrC,MAAM,IAAI,GAAG;YACX,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,KAAK,EAAE,GAAG;SACjB,CAAC;QACF,IAAI,KAAK,CAAC;QACV,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAAC,QAAQ,GAAG,IAAI,CAAC;gBAAC,IAAI,CAAC;oBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;gBAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;QACzG,CAAC,CAAC;QACF,IAAI,MAAM;YAAE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,MAAM;gBAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAAC,QAAQ,GAAG,IAAI,CAAC;gBAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;YAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAA+B,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC;AA0BD,MAAM,SAAS,GAA+B;IAC5C,OAAO,EAAa,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE;IACnG,iBAAiB,EAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAG,WAAW,EAAE,IAAI,EAAE,EAAE;IACnG,gBAAgB,EAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;IACtD,YAAY,EAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;IACtD,MAAM,EAAc,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE;IACnG,OAAO,EAAa,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;CACvD,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc;IAC3C,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,OAAO,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAc;IACxC,8EAA8E;IAC9E,6DAA6D;IAC7D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,0EAA0E;IAC1E,0EAA0E;IAC1E,6EAA6E;IAC7E,6BAA6B;IAC7B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,WAAmB;IAClD,OAAO,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,EAAE;QAC5C,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,kBAAkB,IAAI,aAAa,WAAW,EAAE;YACtD,KAAK,EAAE,GAAG;YACV,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,KAAK;YACX,WAAW,EAAE,OAAO;YACpB,QAAQ;SACT,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QACpF,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAeD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAU,GAAG,EAAE;IAClD,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,MAAM,IAAI,GAAG;QACX,GAAG,eAAe,EAAE;QACpB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;QACpD,KAAK,EAAE,GAAG;QACV,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,OAAO;QACpB,QAAQ;KACT,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAChF,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,sCAAsC;IACtC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAc,CAAC,CAAC,CAAC;IAE9C,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,YAAY,GAAwC,IAAI,CAAC;IAC7D,MAAM,WAAW,GAAG,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,EAAE,GAAG,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,IAAI,CAAC,QAAQ,IAAI,YAAY,EAAE,CAAC;YAC9B,QAAQ,GAAG,IAAI,CAAC;YAChB,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,IAAI,CAAC,QAAQ,IAAI,YAAY,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;YAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,uDAAuD;YACvD,IAAI,CAAC;gBAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YACpD,IAAI,CAAC;gBAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YAC/C,uDAAuD;YACvD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/F,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC;YAC9B,YAAY,CAAC,MAAM,CAAC,CAAC;YACrB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,KAAK,EAAE,GAAG,EAAE;YACV,IAAI,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -14,6 +14,53 @@ const DEFAULT_CONFIG = {
|
|
|
14
14
|
maxTokens: 8192,
|
|
15
15
|
temperature: 0.3,
|
|
16
16
|
permissionMode: 'ask',
|
|
17
|
+
// Thinking / reasoning shown by default — gives users live "the model isn't
|
|
18
|
+
// dead" feedback during long turns. Toggle off with /thinking.
|
|
19
|
+
showThinking: true,
|
|
20
|
+
// Voice / accessibility is OFF by default. ffmpeg is optional. Users opt in
|
|
21
|
+
// via `/voice on` (and set the two API keys via `/voice config`). The
|
|
22
|
+
// sub-blocks define what becomes active once enabled; this just primes them
|
|
23
|
+
// with reasonable defaults so first use Just Works.
|
|
24
|
+
voice: {
|
|
25
|
+
enabled: false,
|
|
26
|
+
stt: {
|
|
27
|
+
// apiKey unset — falls back to top-level apiKey for OpenAI-compatible
|
|
28
|
+
// providers. Whisper specifically requires a real OpenAI key; users
|
|
29
|
+
// configure a separate one via /voice config when their main provider
|
|
30
|
+
// isn't OpenAI.
|
|
31
|
+
baseURL: 'https://api.openai.com/v1',
|
|
32
|
+
model: 'whisper-1',
|
|
33
|
+
dictationKey: 'INS',
|
|
34
|
+
autoSubmit: false,
|
|
35
|
+
},
|
|
36
|
+
tts: {
|
|
37
|
+
// apiKey unset — no fallback (ElevenLabs is a distinct provider). User
|
|
38
|
+
// must run /voice config to provide it.
|
|
39
|
+
baseURL: 'https://api.elevenlabs.io/v1',
|
|
40
|
+
model: 'eleven_turbo_v2_5',
|
|
41
|
+
// Rachel + Domi — both available on every ElevenLabs free tier; using
|
|
42
|
+
// two distinct presets gives instant blind-accessibility benefit
|
|
43
|
+
// (assistant ≠ user voice).
|
|
44
|
+
assistantVoiceId: '21m00Tcm4TlvDq8ikWAM',
|
|
45
|
+
userVoiceId: 'AZnzlk1XvdvUeBnXmlld',
|
|
46
|
+
echoUser: true,
|
|
47
|
+
skipCode: true,
|
|
48
|
+
speed: 1.0,
|
|
49
|
+
stability: 0.5,
|
|
50
|
+
similarityBoost: 0.75,
|
|
51
|
+
},
|
|
52
|
+
accessibility: {
|
|
53
|
+
// screenReader OFF by default — it's lossy for sighted users (no ANSI
|
|
54
|
+
// means no syntax highlight). Blind users turn it on via /accessibility
|
|
55
|
+
// screenReader on.
|
|
56
|
+
screenReader: false,
|
|
57
|
+
audioCues: true,
|
|
58
|
+
announceErrors: true,
|
|
59
|
+
announceModeSwitches: true,
|
|
60
|
+
askBeforeDestructive: true,
|
|
61
|
+
longResponseThreshold: 300,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
17
64
|
};
|
|
18
65
|
export function getConfigDir() {
|
|
19
66
|
return CONFIG_DIR;
|
|
@@ -57,7 +104,7 @@ function validateConfig(config) {
|
|
|
57
104
|
config.permissionMode = 'ask';
|
|
58
105
|
}
|
|
59
106
|
// Warn on unexpected fields
|
|
60
|
-
const expectedFields = new Set(['apiKey', 'baseURL', 'model', 'provider', 'maxTokens', 'temperature', 'permissionMode', 'dryRun', 'theme', 'showThinking']);
|
|
107
|
+
const expectedFields = new Set(['apiKey', 'baseURL', 'model', 'provider', 'maxTokens', 'temperature', 'permissionMode', 'dryRun', 'theme', 'showThinking', 'voice']);
|
|
61
108
|
for (const key in config) {
|
|
62
109
|
if (!expectedFields.has(key)) {
|
|
63
110
|
console.warn(`Warning: Unexpected config field: ${key}`);
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,wEAAwE;AACxE,0EAA0E;AAC1E,4DAA4D;AAC5D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AAC/E,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,MAAM,cAAc,GAAoB;IACtC,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,8BAA8B;IACvC,KAAK,EAAE,2BAA2B;IAClC,QAAQ,EAAE,YAAY;IACtB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG;IAChB,cAAc,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|