verbalcoding 0.2.2 → 0.2.3

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/.env.example CHANGED
@@ -26,6 +26,7 @@ STT_LANGUAGE="ko"
26
26
 
27
27
  TTS_BACKEND="edge" # edge | openvoice | speechswift | supertonic
28
28
  EDGE_TTS_COMMAND="edge-tts"
29
+ TTS_VOICE_TYPE="korean_female" # edge: korean_male | korean_female | korean_multilingual_male | english_male | english_female
29
30
  TTS_VOICE="ko-KR-SunHiNeural"
30
31
  TTS_RATE="+10%"
31
32
  TTS_MAX_CHARS="495"
@@ -66,8 +67,9 @@ OPENVOICE_STYLE="default"
66
67
  OPENVOICE_TIMEOUT_MS="90000"
67
68
  OPENVOICE_PROGRESS="0" # keep progress prompts fast via Edge unless set to 1
68
69
  REQUIRE_WAKE_WORD="0"
69
- MIN_UTTERANCE_SECONDS="1.4"
70
- UTTERANCE_IDLE_MS="2000"
70
+ MIN_UTTERANCE_SECONDS="1.0"
71
+ # Wait for natural thinking pauses before STT. Lower for faster but more fragmented turns.
72
+ UTTERANCE_IDLE_MS="4500"
71
73
  MIN_MEAN_VOLUME_DB="-35"
72
74
  MIN_MAX_VOLUME_DB="-12"
73
75
  BARGE_IN_MIN_SECONDS="1.4"
@@ -80,4 +82,4 @@ PLAYBACK_BARGE_IN_REQUIRE_BOTH="1"
80
82
  BARGE_IN_CONSERVATIVE_MIN_SECONDS="1.8"
81
83
  BARGE_IN_CONSERVATIVE_MIN_MEAN_VOLUME_DB="-27"
82
84
  BARGE_IN_CONSERVATIVE_MIN_MAX_VOLUME_DB="-12"
83
- MAX_DEFERRED_PROCESSING_UTTERANCES="3"
85
+ MAX_DEFERRED_PROCESSING_UTTERANCES="0"
@@ -57,7 +57,7 @@ export function normalizeInstallAnswers(input = {}) {
57
57
  OPENVOICE_PROGRESS: input.openvoiceProgress === true || input.OPENVOICE_PROGRESS === '1' ? '1' : '0',
58
58
  REQUIRE_WAKE_WORD: input.requireWakeWord === true || input.REQUIRE_WAKE_WORD === '1' ? '1' : '0',
59
59
  MIN_UTTERANCE_SECONDS: clean(input.minUtteranceSeconds || input.MIN_UTTERANCE_SECONDS, '1.0'),
60
- UTTERANCE_IDLE_MS: clean(input.utteranceIdleMs || input.UTTERANCE_IDLE_MS, '2000'),
60
+ UTTERANCE_IDLE_MS: clean(input.utteranceIdleMs || input.UTTERANCE_IDLE_MS, '4500'),
61
61
  HERMES_TASK_TIMEOUT_MS: clean(input.taskTimeoutMs || input.HERMES_TASK_TIMEOUT_MS, '0'),
62
62
  HERMES_CHAT_TIMEOUT_MS: clean(input.chatTimeoutMs || input.HERMES_CHAT_TIMEOUT_MS, '45000'),
63
63
  AGENT_VERBOSE_PROGRESS: input.verboseProgress === true || input.AGENT_VERBOSE_PROGRESS === '1' ? '1' : '0',
@@ -63,7 +63,7 @@ test('normalizeInstallAnswers maps supported harnesses to backend env', () => {
63
63
  assert.equal(answers.SUPERTONIC_LANGUAGE, 'ko');
64
64
  assert.equal(answers.OPENVOICE_LANGUAGE, 'KR');
65
65
  assert.equal(answers.REQUIRE_WAKE_WORD, '0');
66
- assert.equal(answers.UTTERANCE_IDLE_MS, '2000');
66
+ assert.equal(answers.UTTERANCE_IDLE_MS, '4500');
67
67
  });
68
68
 
69
69
  test('buildEnvFile writes configurable CLI harness and Discord settings without comments leaking into values', () => {
package/app-node/main.mjs CHANGED
@@ -217,7 +217,10 @@ const BARGE_IN_CONSERVATIVE_MIN_MAX_VOLUME_DB = Number(process.env.BARGE_IN_CONS
217
217
  const SENSITIVITY_MODE_DEFAULT = (process.env.BARGE_IN_SENSITIVITY_MODE || 'normal').toLowerCase() === 'conservative' ? 'conservative' : 'normal';
218
218
  const SENSITIVITY_OUTDOOR_SECONDS = Number(process.env.BARGE_IN_OUTDOOR_SECONDS || '900');
219
219
  const SUBSCRIBE_AFTER_SILENCE_MS = Number(process.env.SUBSCRIBE_AFTER_SILENCE_MS || '2200');
220
- const UTTERANCE_IDLE_MS = Number(process.env.UTTERANCE_IDLE_MS || '2000');
220
+ // Wait long enough for natural mid-sentence pauses before sending audio to STT.
221
+ // If this is too short, a long thought gets split: the first fragment starts an
222
+ // agent turn and the rest is treated as barge-in/processing speech.
223
+ const UTTERANCE_IDLE_MS = Number(process.env.UTTERANCE_IDLE_MS || '4500');
221
224
  const MIN_MEAN_VOLUME_DB = Number(process.env.MIN_MEAN_VOLUME_DB || '-35');
222
225
  const MIN_MAX_VOLUME_DB = Number(process.env.MIN_MAX_VOLUME_DB || '-12');
223
226
  const STT_START_VOICE_NOTICE = !['0', 'false', 'no', 'off'].includes((process.env.STT_START_VOICE_NOTICE || '1').toLowerCase());
@@ -37,7 +37,7 @@ AGENT_COMMAND="my-harness run --non-interactive"
37
37
  AGENT_TASK_TIMEOUT_MS=0
38
38
  AGENT_CHAT_TIMEOUT_MS=45000
39
39
  AGENT_VERBOSE_PROGRESS=0
40
- UTTERANCE_IDLE_MS=2000
40
+ UTTERANCE_IDLE_MS=4500
41
41
  LATENCY_LOG_PATH=./.logs/latency.jsonl
42
42
  ```
43
43
 
@@ -74,7 +74,7 @@ TTS_VOLUME="1.0"
74
74
 
75
75
  REQUIRE_WAKE_WORD="0"
76
76
  MIN_UTTERANCE_SECONDS="1.0"
77
- UTTERANCE_IDLE_MS="2000"
77
+ UTTERANCE_IDLE_MS="4500"
78
78
  HERMES_TASK_TIMEOUT_MS="0"
79
79
  HERMES_CHAT_TIMEOUT_MS="45000"
80
80
  AGENT_VERBOSE_PROGRESS="0"
@@ -112,6 +112,24 @@ TTS_VOICE_CONFIG="config/tts-voices.json"
112
112
 
113
113
  For OpenVoice, SpeechSwift, or Supertonic, keep the backend-specific voice/reference settings in the sections below; the same voice catalog file can still track the active voice type.
114
114
 
115
+ Backend-specific voice options:
116
+
117
+ | Backend | Settings | Voice choices |
118
+ |---|---|---|
119
+ | Edge | `TTS_VOICE_TYPE`, `TTS_VOICE` | Built-in types above, plus any voice returned by `edge-tts --list-voices` |
120
+ | Supertonic | `SUPERTONIC_VOICE`, `SUPERTONIC_LANGUAGE` | `M1`–`M5`, `F1`–`F5`; language `ko`, `en`, `es`, `pt`, `fr` |
121
+ | OpenVoice | `OPENVOICE_REF_AUDIO`, `OPENVOICE_STYLE`, `OPENVOICE_LANGUAGE` | User-provided permitted reference WAV; style defaults to `default` |
122
+ | SpeechSwift / CosyVoice | `SPEECHSWIFT_REF_AUDIO`, `SPEECHSWIFT_ENGINE`, `SPEECHSWIFT_SPEAKER`, `SPEECHSWIFT_MODEL_ID` | Reference-sample voices for CosyVoice, or backend-supported speaker/model IDs |
123
+
124
+ ## Utterance Segmentation
125
+
126
+ `UTTERANCE_IDLE_MS` controls how long the bridge waits after a speech segment before it decides the user is done and starts STT. The default is `4500` ms to preserve longer spoken instructions with natural pauses. Lower values feel faster for short commands but can split long dictation; higher values are safer for thoughtful speech.
127
+
128
+ ```bash
129
+ UTTERANCE_IDLE_MS="4500" # balanced default
130
+ UTTERANCE_IDLE_MS="6000" # safer for long dictation with pauses
131
+ ```
132
+
115
133
  ## MCP Server
116
134
 
117
135
  VerbalCoding ships a stdio MCP server so Hermes Agent or any MCP client can control the bridge through tools instead of relying on skills or free-form shell commands.
package/docs/RELEASE.md CHANGED
@@ -25,7 +25,7 @@ VerbalCoding is a Discord voice bridge for controlling CLI-based coding agents b
25
25
  - npm package install path: `npm install -g verbalcoding`, `vc setup --yes`, and `vc start`.
26
26
  - Optional verbose progress mode for text-only middle-step updates during long agent work.
27
27
  - Always-on JSONL latency metrics plus `!latency` / `!metrics` summary for pipeline optimization.
28
- - Lower default utterance idle wait (`UTTERANCE_IDLE_MS=2000`) so STT starts about 0.6s sooner after speech ends.
28
+ - More patient utterance idle wait (`UTTERANCE_IDLE_MS=4500`) so long spoken instructions with natural pauses are not split into a partial prompt plus ignored processing-time speech.
29
29
  - Multi-instance Hermes profile isolation: `vc instance setup <name>` auto-clones a Hermes profile to `~/.hermes/profiles/<name>` with the instance workdir, seeds SOUL.md, and writes `HERMES_HOME` into the instance env so per-project memory and skills stay separate; `vc instance start` self-heals a missing profile, and `vc doctor` checks profile-dir presence and `terminal.cwd` consistency.
30
30
 
31
31
  ### Pre-release checklist
package/docs/USAGE.md CHANGED
@@ -88,6 +88,27 @@ Built-in Edge voice types:
88
88
 
89
89
  For persistent manual config, set `TTS_BACKEND=edge`, `TTS_VOICE_TYPE=<voice-type>`, and optionally `TTS_VOICE=<edge-voice>` in `.env`, or edit `config/tts-voices.json` for custom voice catalogs.
90
90
 
91
+ Backend-specific voice knobs:
92
+
93
+ | Backend | Voice setting | Common choices |
94
+ |---|---|---|
95
+ | Edge | `TTS_VOICE_TYPE`, `TTS_VOICE` | `korean_male`, `korean_female`, `korean_multilingual_male`, `english_male`, `english_female`; any Edge voice from `edge-tts --list-voices` |
96
+ | Supertonic | `SUPERTONIC_VOICE` | `M1`–`M5`, `F1`–`F5`; set `SUPERTONIC_LANGUAGE=ko|en|es|pt|fr` |
97
+ | OpenVoice | `OPENVOICE_REF_AUDIO`, `OPENVOICE_STYLE` | a permitted reference WAV plus style such as `default` |
98
+ | SpeechSwift / CosyVoice | `SPEECHSWIFT_REF_AUDIO`, `SPEECHSWIFT_ENGINE`, `SPEECHSWIFT_SPEAKER` | reference WAV for CosyVoice, or backend-supported speaker/model values |
99
+
100
+ For Supertonic and local clone backends, use the backend env vars above plus `!voice-test <text>` to audition changes. Voice-command switching currently maps the built-in Edge-style voice types; richer backend catalogs can be added in `config/tts-voices.json`.
101
+
102
+ ## Long Dictation and Pauses
103
+
104
+ VerbalCoding waits for an idle window before sending speech to STT. The default `UTTERANCE_IDLE_MS=4500` is intentionally a bit patient so a natural pause in a long instruction does not split the sentence, start an agent turn too early, and then treat the rest as a processing-time interruption.
105
+
106
+ If you prefer faster short commands, lower it in `.env`; if long Korean dictation is still being split, raise it:
107
+
108
+ ```bash
109
+ UTTERANCE_IDLE_MS="6000"
110
+ ```
111
+
91
112
  ## Verbose Progress Mode
92
113
 
93
114
  Verbose progress is off by default unless `AGENT_VERBOSE_PROGRESS=1` is set. Enable it with `!verbose on` or a voice command like “상세 진행 켜”. It can emit short progress lines such as:
@@ -45,7 +45,7 @@ AGENT_COMMAND="my-harness run --non-interactive"
45
45
  AGENT_TASK_TIMEOUT_MS=0
46
46
  AGENT_CHAT_TIMEOUT_MS=45000
47
47
  AGENT_VERBOSE_PROGRESS=0
48
- UTTERANCE_IDLE_MS=2000
48
+ UTTERANCE_IDLE_MS=4500
49
49
  LATENCY_LOG_PATH=./.logs/latency.jsonl
50
50
  ```
51
51
 
@@ -82,7 +82,7 @@ TTS_VOLUME="1.0"
82
82
 
83
83
  REQUIRE_WAKE_WORD="0"
84
84
  MIN_UTTERANCE_SECONDS="1.0"
85
- UTTERANCE_IDLE_MS="2000"
85
+ UTTERANCE_IDLE_MS="4500"
86
86
  HERMES_TASK_TIMEOUT_MS="0"
87
87
  HERMES_CHAT_TIMEOUT_MS="45000"
88
88
  AGENT_VERBOSE_PROGRESS="0"
@@ -120,6 +120,24 @@ TTS_VOICE_CONFIG="config/tts-voices.json"
120
120
 
121
121
  OpenVoice, SpeechSwift, Supertonic을 쓸 때는 아래 백엔드별 reference/voice 설정을 유지하세요. 같은 voice catalog 파일에서 현재 voice type을 추적할 수 있습니다.
122
122
 
123
+ 백엔드별 목소리 옵션:
124
+
125
+ | 백엔드 | 설정 | 목소리 선택지 |
126
+ |---|---|---|
127
+ | Edge | `TTS_VOICE_TYPE`, `TTS_VOICE` | 위 기본 타입, 또는 `edge-tts --list-voices`가 반환하는 모든 voice |
128
+ | Supertonic | `SUPERTONIC_VOICE`, `SUPERTONIC_LANGUAGE` | `M1`–`M5`, `F1`–`F5`; 언어 `ko`, `en`, `es`, `pt`, `fr` |
129
+ | OpenVoice | `OPENVOICE_REF_AUDIO`, `OPENVOICE_STYLE`, `OPENVOICE_LANGUAGE` | 사용자가 제공한 허가된 reference WAV; style 기본값은 `default` |
130
+ | SpeechSwift / CosyVoice | `SPEECHSWIFT_REF_AUDIO`, `SPEECHSWIFT_ENGINE`, `SPEECHSWIFT_SPEAKER`, `SPEECHSWIFT_MODEL_ID` | CosyVoice reference sample voice 또는 백엔드가 지원하는 speaker/model ID |
131
+
132
+ ## 발화 분리 설정
133
+
134
+ `UTTERANCE_IDLE_MS`는 음성 segment가 끝난 뒤 사용자의 말이 끝났다고 판단하고 STT를 시작하기 전까지 기다리는 시간입니다. 기본값은 `4500` ms입니다. 긴 지시 중 자연스러운 멈춤을 보존하기 위한 값입니다. 낮추면 짧은 명령 반응은 빨라지지만 긴 발화가 잘릴 수 있고, 높이면 생각하면서 말하는 긴 dictation에 더 안전합니다.
135
+
136
+ ```bash
137
+ UTTERANCE_IDLE_MS="4500" # 균형 잡힌 기본값
138
+ UTTERANCE_IDLE_MS="6000" # 중간 멈춤이 있는 긴 발화에 더 안전
139
+ ```
140
+
123
141
  ## MCP 서버
124
142
 
125
143
  VerbalCoding은 stdio MCP 서버를 포함합니다. Hermes Agent 또는 MCP client는 자유 형식 shell 명령 대신 도구로 브릿지를 제어할 수 있습니다.
@@ -24,7 +24,7 @@ VerbalCoding은 음성으로 CLI 기반 코딩 에이전트를 제어하기 위
24
24
  - 설정 마법사, `.env.example`, `vc doctor` prerequisite checker, OS 패키지/npm 의존성/Edge TTS helper/기본 whisper.cpp 모델을 준비하는 `./scripts/install.sh --yes` 부트스트랩.
25
25
  - 긴 에이전트 작업 중 텍스트 전용 중간 단계 업데이트를 위한 선택적 verbose progress mode.
26
26
  - 파이프라인 최적화를 위한 JSONL latency metrics와 `!latency` / `!metrics` 요약.
27
- - 낮아진 기본 utterance idle wait (`UTTERANCE_IDLE_MS=2000`)로 사용자가 말한 STT가 0.6초 빨리 시작.
27
+ - 여유 있는 utterance idle wait (`UTTERANCE_IDLE_MS=4500`)로 자연스러운 중간 멈춤이 있는 지시가 앞부분 prompt와 무시되는 processing-time speech로 쪼개지지 않도록 개선.
28
28
  - 멀티 인스턴스 Hermes 프로필 격리: `vc instance setup <name>`이 자동으로 Hermes 프로필을 `~/.hermes/profiles/<name>`에 clone하고, instance workdir을 설정하고, SOUL.md를 초기화하고, instance env에 `HERMES_HOME`을 기록합니다. `vc instance start`는 누락된 profile을 self-heal하고, `vc doctor`는 profile-dir 존재와 `terminal.cwd` 일관성을 검사합니다.
29
29
  - npm 공개 패키지: `npm install -g verbalcoding`, `vc setup --yes`, `vc start` 경로 지원.
30
30
 
@@ -96,6 +96,27 @@ switch speaker to English
96
96
 
97
97
  영구 수동 설정이 필요하면 `.env`에 `TTS_BACKEND=edge`, `TTS_VOICE_TYPE=<voice-type>`, 필요 시 `TTS_VOICE=<edge-voice>`를 설정하세요. 더 많은 커스텀 목소리 카탈로그는 `config/tts-voices.json`에서 관리할 수 있습니다.
98
98
 
99
+ 백엔드별 목소리 설정:
100
+
101
+ | 백엔드 | 목소리 설정 | 자주 쓰는 선택지 |
102
+ |---|---|---|
103
+ | Edge | `TTS_VOICE_TYPE`, `TTS_VOICE` | `korean_male`, `korean_female`, `korean_multilingual_male`, `english_male`, `english_female`; `edge-tts --list-voices`의 모든 Edge voice |
104
+ | Supertonic | `SUPERTONIC_VOICE` | `M1`–`M5`, `F1`–`F5`; `SUPERTONIC_LANGUAGE=ko|en|es|pt|fr` |
105
+ | OpenVoice | `OPENVOICE_REF_AUDIO`, `OPENVOICE_STYLE` | 사용 허가가 있는 reference WAV와 `default` 같은 style |
106
+ | SpeechSwift / CosyVoice | `SPEECHSWIFT_REF_AUDIO`, `SPEECHSWIFT_ENGINE`, `SPEECHSWIFT_SPEAKER` | CosyVoice reference WAV 또는 백엔드가 지원하는 speaker/model 값 |
107
+
108
+ Supertonic과 로컬 clone 백엔드는 위 env를 바꾼 뒤 `!voice-test <text>`로 바로 들어보세요. 현재 음성 명령 기반 전환은 기본 Edge-style voice type에 매핑되어 있고, 더 풍부한 백엔드 카탈로그는 `config/tts-voices.json`에 추가할 수 있습니다.
109
+
110
+ ## 긴 발화와 중간 멈춤
111
+
112
+ VerbalCoding은 말을 STT로 보내기 전에 idle window를 기다립니다. 기본값 `UTTERANCE_IDLE_MS=4500`은 일부러 조금 여유 있게 잡혀 있습니다. 긴 지시 중 자연스러운 멈춤을 문장 끝으로 오해해 앞부분만 에이전트에 보내고, 뒷부분을 processing 중 끼어들기로 처리하는 문제를 줄이기 위해서입니다.
113
+
114
+ 짧은 명령 반응을 더 빠르게 하고 싶다면 `.env`에서 낮추고, 긴 한국어 dictation이 여전히 잘리면 더 올리세요.
115
+
116
+ ```bash
117
+ UTTERANCE_IDLE_MS="6000"
118
+ ```
119
+
99
120
  ## 자세한 진행 모드
100
121
 
101
122
  자세한 진행은 기본적으로 꺼져 있습니다. `.env`에 `AGENT_VERBOSE_PROGRESS=1`을 설정하거나 Discord에서 `!verbose on`, 또는 음성으로 “상세 진행 켜”라고 말해 켤 수 있습니다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verbalcoding",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Discord voice bridge for CLI coding agents.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/run.sh CHANGED
@@ -8,7 +8,7 @@ mkdir -p /tmp/verbalcoding-node-debug
8
8
  export NODE_AUDIO_DEBUG_DIR="${NODE_AUDIO_DEBUG_DIR:-/tmp/verbalcoding-node-debug}"
9
9
  export MIN_UTTERANCE_SECONDS="${MIN_UTTERANCE_SECONDS:-1.0}"
10
10
  export SUBSCRIBE_AFTER_SILENCE_MS="${SUBSCRIBE_AFTER_SILENCE_MS:-2200}"
11
- export UTTERANCE_IDLE_MS="${UTTERANCE_IDLE_MS:-2600}"
11
+ export UTTERANCE_IDLE_MS="${UTTERANCE_IDLE_MS:-4500}"
12
12
  export MIN_MEAN_VOLUME_DB="${MIN_MEAN_VOLUME_DB:--35}"
13
13
  export MIN_MAX_VOLUME_DB="${MIN_MAX_VOLUME_DB:--18}"
14
14
  export TTS_RATE="${TTS_RATE:-+10%}"
@@ -53,7 +53,7 @@ TTS_VOICE="en-US-GuyNeural"
53
53
  TTS_RATE="+0%"
54
54
  TTS_VOLUME="1.0"
55
55
  REQUIRE_WAKE_WORD="0"
56
- UTTERANCE_IDLE_MS="2000"
56
+ UTTERANCE_IDLE_MS="4500"
57
57
  LATENCY_LOG_PATH="./.logs/latency.jsonl"
58
58
  ENV
59
59
  chmod 600 .env
@@ -66,7 +66,7 @@ note('Allowed users configured', env.DISCORD_ALLOWED_USERS ? '[REDACTED]' : 'not
66
66
  note('Auto-join channels', env.AUTO_JOIN_VOICE_CHANNELS || 'default: 일반,General,general');
67
67
  note('Verbose progress default', ['1', 'true', 'yes', 'on'].includes(String(env.AGENT_VERBOSE_PROGRESS || env.VERBALCODING_VERBOSE_PROGRESS || '0').toLowerCase()) ? 'on' : 'off');
68
68
  note('Auto restart voice bot after commits', autoRestartVoiceBotEnabled(env) ? 'on' : 'off');
69
- note('Utterance idle wait before STT', `${env.UTTERANCE_IDLE_MS || '2000'} ms`);
69
+ note('Utterance idle wait before STT', `${env.UTTERANCE_IDLE_MS || '4500'} ms`);
70
70
  note('STT language', env.WHISPER_CPP_LANGUAGE || env.STT_LANGUAGE || 'ko');
71
71
  note('Progress/voice language', env.VOICE_LANGUAGE || env.WHISPER_CPP_LANGUAGE || env.STT_LANGUAGE || 'ko');
72
72
  note('Latency log path', env.LATENCY_LOG_PATH || './.logs/latency.jsonl');
@@ -58,7 +58,7 @@ async function main() {
58
58
  const openvoiceRefAudio = await ask('OpenVoice reference audio path', process.env.OPENVOICE_REF_AUDIO || './voice-samples/user-reference.wav');
59
59
  const requireWake = (await ask('Require wake word? 1/0', process.env.REQUIRE_WAKE_WORD || '0')) === '1';
60
60
  const verboseProgress = (await ask('Verbose progress by default? 1/0', process.env.AGENT_VERBOSE_PROGRESS || process.env.VERBALCODING_VERBOSE_PROGRESS || '0')) === '1';
61
- const utteranceIdleMs = await ask('Utterance idle wait before STT, ms', process.env.UTTERANCE_IDLE_MS || '2000');
61
+ const utteranceIdleMs = await ask('Utterance idle wait before STT, ms', process.env.UTTERANCE_IDLE_MS || '4500');
62
62
  const latencyLogPath = await ask('Latency JSONL log path', process.env.LATENCY_LOG_PATH || './.logs/latency.jsonl');
63
63
 
64
64
  const values = normalizeInstallAnswers({