扫描完成。以下是 voxt 源码中**文档 DEVELOPMENT.zh-CN.md 尚未覆盖**、对「低延迟语音输入转文字」有借鉴价值的发现，按 10 类组织。

---

## 1. 录音交互

- **Esc 三级取消**（热键层全局拦截）：`Hotkey/HotkeyManager.swift:468-480` 在事件 tap 里截获 Esc（过滤 autoRepeat），回调 `onEscapeKeyDown`，返回 true 才吞事件；`App/HotkeyLifecycle.swift:234-272` 分三级处理：① 取消"防抖中的待启动"（pendingTranscriptionStartTask，热键按下但录音尚未真正开始时按 Esc 可撤销）② 取消活动会话 ③ 关闭答案面板。由设置项 `escapeKeyCancelsOverlaySession`（默认开，`Settings/Shell/AppPreferenceKey.swift:67`）控制。**强烈建议借鉴**：Esc 取消是对按错热键最重要的逃生门，且「Esc 能取消 pending 启动」这个细节很容易漏。
- **取消 ≠ 失败的静默拆除**：`App/Recording/RecordingSessionFlow.swift:326-348` `cancelActiveRecordingSession()` 立即作废代次、清空目标 PID/BundleID、停采集、恢复系统音频，无任何错误提示。文档只提了网络层取消不算错误，这里是会话层的对应物。**值得借鉴**。
- **悬浮层明确不可拖拽、无右键菜单、录音中点击穿透**：`Windows/RecordingOverlayWindow.swift:39,41,220-225`（`isMovableByWindowBackground=false`、`ignoresMouseEvents` 仅在答案态/语言选择态放开）。文档已知 ignoresMouseEvents 的切换，这里补充结论：录音态没有任何鼠标交互，定位全靠设置项。**符合预期，无新增交互可抄**。
- **结果态（answer）卡片按钮组**：注入 / 复制（复制后图标变对勾 + 文案变 "Copied" 2s，`Windows/WaveformAnswerCardComponents.swift:754,806-852`）/ 继续追加录音 / 查看详情 / 关闭；且有 **Space 快捷键续录**（`RecordingOverlayWindow.swift:105-120` `handleAnswerSpaceShortcut` + `HotkeyLifecycle.swift:224-227`）。主项目润色若要「先看结果再决定注入」，这套卡片交互可参考；若坚持直接注入则不适用。
- **弹出菜单点击外部关闭**：`WaveformAnswerCardComponents.swift:451-486` 用 local event monitor（left/right/otherMouseDown）判断点击是否在菜单 bounds 外，`cancelTracking()` + 单次 dismiss 回调防重入。**小而实用，可借鉴**。
- **快捷键处理慢日志**：`HotkeyLifecycle.swift:213-222` 单次 overlay 快捷键处理 ≥40ms 即打日志。**值得借鉴**（低成本性能哨兵）。
- **Prompt 回显抑制**：`App/Recording/RecordingSessionSupport.swift:126-172` LLM 把 system prompt 吐进结果时的检测（强标记串 + 弱标记 ≥2 命中 + 与原 prompt 的包含比较），命中则输出空串。主项目启用润色后**一定会遇到**这个问题。**强烈建议借鉴**。
- **录音中实时文本只读**：`Windows/RecordingOverlayState.swift` 无任何编辑路径；文本变换通过 `setTranscribedTextTransformer`（:195-198）注入（用于词典高亮修正显示）。即 voxt 没有「录音中改字」功能。无新增。

## 2. 菜单栏与全局功能

菜单树全貌在 `App/MenuWindowCoordinator.swift:80-160`：Dashboard / 通用 / 功能 / 历史（按类型子菜单）/ 词典 / **麦克风（Auto Switch 开关 + 设备列表带 checkmark）** / 分隔 / **最近 5 条历史（点击复制全文）** / 检查更新 / 反馈 /（有新版本时插入禁用态版本号行）/ 退出。

- **菜单打开期间合并重建**：`MenuWindowCoordinator.swift:81-87` 菜单被 AppKit 跟踪时替换菜单会打断高亮/子菜单，所以 `buildMenu()` 在 `isStatusMenuOpen` 时只置 `statusMenuNeedsRebuild` 标记，`menuDidClose`（:786-800）统一补建。**NSMenu 实战坑，值得借鉴**（主项目若用 NSMenu 而非 MenuBarExtra）。
- **所有菜单动作延迟到菜单关闭后执行**：`MenuWindowCoordinator.swift:651-664` `performAfterStatusMenuDismissal` 排队到 `menuDidClose` 再跑，否则更新 UI 会打断菜单跟踪动画。**同上，值得借鉴**。
- **最近历史的懒加载**：hover/重建只用手头快照（`App/StatusMenuHistorySupport.swift` 注释 "no storage reads on hover"），点击时才 `loadEntry` 取全文（`MenuWindowCoordinator.swift:404-415`）；刷新走 50ms debounce + generation guard（:162-180）。**值得借鉴**。
- **菜单预览截断兼容 SQLite**：`StatusMenuHistorySupport.swift:32-46` 按渲染宽度（100pt）逐字符加 "…" 截断，并处理 SQLite `substr` 按 unicode scalar 而非 Swift grapheme 计数的坑。**细节可借鉴**。
- **录音中硬件变化不换麦**：`MenuWindowCoordinator.swift:335-349` `lockedActiveInputDeviceUID`——录音进行中即使设备列表变化，只要当前麦还在就保持，避免录到一半切设备。**值得借鉴**（文档的三档策略没有覆盖这一点）。
- **录音中用户主动切麦 = 热切换**：`App/Recording/RecordingCaptureFlow.swift:273-316` 停不掉的会话里 `restartCaptureForPreferredInputDevice` + Toast "Switched microphone to X"（1.8s）；无可用麦克风则提示并结束会话。**值得借鉴**。
- **系统菜单栏深度链接**：`App/VoxtAppCommands.swift:64-191` Navigate 菜单直达设置页任意 tab/section。锦上添花，优先级低。

## 3. 设置项全集（文档未列的）

- **交互音效**（`Settings/GeneralSettingsSections.swift:74-142` + `Core/InteractionSoundPlayer.swift`）：开始/结束各播一声，10 个系统音预设 + 试听按钮；实现要点：① 预热 `prepareToPlay` 常驻 ② **计算系统音的"可闻时长"**（`InteractionSoundPlayer.swift:149-194` 扫描 PCM 找最后一个超过阈值 0.001 的帧 + 80ms 余量），回调不被 aiff 尾部静音拖延 ③ 播放失败（睡眠/输出设备切换后 player 失效）自动丢弃缓存下次重建（:112-119）④ 独立 `userInitiated` 队列不占主 actor。**开始/结束提示音对「无 UI 感知的录音」价值很高，建议借鉴整套（尤其尾静音裁剪）**。
- **录音时静音系统输出**的所有权模型：`Core/SystemAudioMuteController.swift:79-93` 只在设备原本未静音时才接管（`ownedMute`），恢复时只还原自己接管的；输出设备变化观察 + sessionID 使已排队通知失效（:55-77）；**停录立即解除静音，不等最终转写**（`RecordingCaptureFlow.swift:328-335` 注释）。文档有此设置项但无实现细节。**值得借鉴**。
- **麦克风优先级列表**：`Settings/MicrophonePriorityDialog.swift` 拖拽排序 + 「置顶」+ 每行 "Use Now" + Auto Switch 开关；**记忆已消失设备**（`trackedMicrophoneRecords`，`Core/MicrophonePreferenceModels.swift:31-60` `MicrophoneDisplayEntry.isAvailable`），灰显但保留排序位。比文档的「锁定单设备」更通用。**建议借鉴优先级列表而非单选锁定**。
- **「结果同时保留在剪贴板」与剪贴板恢复互斥**：`App/TextOutputDelivery.swift:69,240-242` `keepResultInClipboard` 为 true 时写入后不注册恢复（`restorePrevious: !keepResultInClipboard`）。**值得借鉴**（两个功能天然冲突，voxt 用一个开关统一）。
- **自定义粘贴热键**：`TextOutputDelivery.swift:190-213` 把「最近一次注入结果」重新粘贴的全局热键；内存缓存 `latestInjectableOutputText` 为空时回退到历史最新一条（`Core/History/TranscriptionHistoryStore.swift:250`）。**很有用的补偿交互，建议借鉴**。
- **热键页设置全集**：Esc 取消开关、**区分左右修饰键**（`hotkeyDistinguishModifierSides`）、触发模式（长按松手停 / 点按切换）、双击同热键激活（`HotkeyManager.swift:1335-1347` 用 `NSEvent.doubleClickInterval`）、**鼠标键可作热键**（`hotkeyMouseButtonNumber`，含「鼠标中键+Fn+Shift」激活模式，`Hotkey/HotkeySupport.swift:137-146`）。鼠标键热键对「手在鼠标上」的场景很实用，可考虑。
- **热键冲突校验规则表**：`Settings/HotkeySettingsValidation.swift:14-25` 内置 10 条系统快捷键冲突规则（fn+Space 输入法、⌘Space Spotlight、⌘Tab、⌘`、⌘Q/H/M/W/V）+ 组间重复绑定 + 无修饰键校验，设置页实时黄条提示。**强烈建议照抄规则表**。
- **代理设置**：`GeneralSettingsSections.swift:544-609` 系统/关闭/自定义（HTTP/HTTPS/SOCKS5 + 用户名密码），`Core/VoxtNetworkSession.swift` 应用到 app 网络请求。国内访问 OpenAI/Gemini 的刚需。**建议 v1 就做**。
- **日志调试开关**：热键 debug 日志 / 模型 debug 日志两个独立开关 + 查看日志（`GeneralSettingsSections.swift:487-520`），运行期可开，避免默认刷日志。**值得借鉴**。
- **历史保留策略是双维度**：保留期（默认 90 天）+ 保留条数，两者同时生效（`TranscriptionHistoryStore.swift:733-740`）；另有**音频归档**（可选保存录音、自选目录 security-scoped bookmark、统计占用、一键导出，`Settings/History/HistoryAudioSettingsSheet.swift`）。主项目 v1 不存音频，但「目录选择 + bookmark + 占用统计」的 UX 可留作参考。
- **悬浮窗样式实时预览**：`GeneralSettingsSections.swift:244-314` 设置页内嵌一张背景图 + 波形 mock，改透明度/圆角即时反映；数值输入用 `ClampedIntegerTextField`（:316-390，过滤非数字 + 范围钳制 + 提交同步）。**值得借鉴**。
- **Onboarding 分步向导**：`Settings/Onboarding/OnboardingSettingsTypes.swift:11-84` 步骤枚举 + 每步状态徽章（Ready/Needs Setup/Optional/Done，:86-117）+ `onboardingLastStepID` 断点续接 + `LaunchPresentationPolicy` 决定启动时是否弹主窗口。主项目 M8 的引导流程可参考其「状态徽章 + 可跳过 + 断点」结构。
- **Dock 显隐与激活策略联动**：`Core/AppBehaviorController.swift:8-16` `showInDock=false` 时平时 `.accessory`，主窗口可见期间临时 `.regular`（否则窗口没 Dock 支撑）。**做 Dock 显隐必抄**。

## 4. 历史记录 UX

- **搜索维度**：`Settings/History/HistorySettingsData.swift:48-72` 全文 + displayTitle + **聚焦 App 名** + 词典命中词。按「哪个 App 里说的」搜历史对语音输入很自然。**建议借鉴（至少文本 + 目标 App 名）**。
- **按天分组 + 智能时间**：`HistorySettingsData.swift:191-217` 列表插 day header（今天/日期）；行首时间是 `HH:mm`（`Core/History/RelativeNoteTimestampFormatter.swift:9-24`，en_US_POSIX 固定格式避免本地化坑）。**值得借鉴**。
- **行交互**：`Settings/History/HistorySettingsComponents.swift:98-186` 点文本即复制（tooltip 明示）、hover 才显示 详情/删除 按钮（0.12s 渐入 + `allowsHitTesting` 联动）。**值得借鉴**。
- **分页 + 行高缓存**：每页 80 条、Load more、`historyPageGeneration` 防旧请求覆盖（`HistorySettingsView.swift:40-56,711`）；`HistoryRowHeightCache` 配合自定义虚拟列表（`Settings/Shell/VirtualizedVerticalList.swift`）。**大数据量才需要，v1 可缓**。
- **批量删除**：按分类（filter tab）删除 + 二次确认（`HistorySettingsView.swift:678-689`）。
- **详情 Sheet 支持手动修正文本**：`Settings/History/HistoryDetailSheetContent.swift:23-35` 修正后回写（还联动词典学习，主项目不需要后半段）。「转错了 → 打开详情改 → 复制」是补救路径。**建议借鉴简化版（详情可编辑 + 重新复制）**。
- **空状态文案动态带当前热键**：`HistorySettingsView.swift:160-180` 用 `HotkeyPreference.displayString` 格式化进空状态提示。**小细节，值得借鉴**。
- **DEBUG 数据灌注**：`App/VoxtAppCommands.swift:226-239` 开发菜单一键灌 2 万/10 万条历史测滚动性能。

## 5. 错误与状态提示

- **三层提示体系**：① `showOverlayStatus`（录音卡片内状态行，clearAfter 自动清，且清除任务只在消息未被新消息覆盖时执行——`App/Recording/RecordingOverlayFlow.swift:14-27`）② `showOverlayReminder`（复用悬浮层显示纯提醒，autoHideAfter 后整体隐藏并 reset，:29-45）③ `showFloatingToast`（独立 240×52 toast）。**结构清晰，值得借鉴**。
- **录音前权限预检**：`App/Recording/RecordingCaptureFlow.swift:239-265` 麦克风未授权 → 阻断 + 指引「Settings > Permissions」；辅助功能缺失 → **不阻断录音**，只提示注入可能不可用。**这个分级（录音必需 vs 注入必需）值得借鉴**。
- **启动失败完整复位**：`RecordingCaptureFlow.swift:200-237,409-416` `resetSessionAfterFailedStart` 把十几个会话状态字段全部归零再隐藏浮层，防脏状态影响下一次录音。**值得借鉴**（主项目的 SessionCoordinator 复位清单）。
- **失败回调分级**：`onStartFailure`（autoHide 3.6s）vs `onRuntimeFailure`（状态行 4.8s，`RecordingCaptureFlow.swift:170-177`）。
- **权限引导直达系统设置指定面板**：`Core/Security/PermissionGuidance.swift:33-44,70-73` 用 PermissionFlow 库 `authorize(pane:)`（带 app 预选 + 用鼠标位置构造 anchor 源矩形，弹窗箭头指向点击处）。主项目若不想引库，可用 `SystemSettings.open` + URL scheme `x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility` 达到类似效果。**引导体验关键，建议借鉴思路**。
- **首次启动权限 Alert**：`MenuWindowCoordinator.swift:724-734` NSAlert（打开系统设置 / 退出）。

## 6. 音频细节

- **电平归一化参数（输入侧）**：`Core/AudioLevelMeter.swift:8-10,72-84` RMS → 噪声门 0.010 → 增益 ×8.5 → 指数 0.88；支持 Float32/Int16/Int32/interleaved 全格式（:86-177，多声道取平均）。注意这与文档 §10.2 的波形增益（`pow(level,0.72)×1.24`）是**两级不同的映射**——voxt 在进波形状态机前先做这一级。**值得借鉴两级映射**。
- **AGC / 硬件增益 / 降噪 / 回声消除 / 声道选择：无新增**——全树 grep 确认 voxt 不设置 `voiceProcessing`、不读写 `kAudioDevicePropertyVolumeScalar`、无输入增益设置项，多声道一律平均成 mono。文档不需要补。
- 系统输出静音、录音中热切换麦克风见上文第 2/3 类。

## 7. 热词/自定义词表

- **按引擎差异化的热词下发**（这是最有参考价值的部分）：
  - StepFun：`payload["hotwords"] = 短语串`（`Transcription/RemoteASR/StepFunPayloadSupport.swift:37`）
  - 阿里：`vocabulary` 字典、词条权重 4（`AliyunRealtimePayloadSupport.swift:106-113`）
  - Gemini：`customVocabulary` 数组（`GeminiLivePayloadSupport.swift:59-61`）
  - OpenAI/GLM：prompt 模板偏置（`ASRHintTarget.supportsPromptEditor`，`Core/ASRHintSettings.swift:42-50`）
  - 词表来源统一为 `contextualPhrasesText`（每行一词）+ 词典条目，经 `RemoteASRRequestContext.swift:27` 组装，每次会话现取（`RecordingCaptureFlow.swift:156-162` `dictionaryEntryProvider`，带 `asrPromptTermLimit` 条数上限）。
- **每引擎独立 hint 设置**：`ASRHintSettings.swift:130-182` 一个 `[ASRHintTarget: ASRHintSettings]` JSON 存储，含 `followsUserMainLanguage / promptTemplate / contextualPhrases / prefersOnDeviceRecognition / addsPunctuation / reportsPartialResults`，读写都做 sanitize（词表去空行、prompt trim）。**主项目的 `ModelParameters.hotwords` 应采用同样的「统一词表 + 按 provider 能力声明下发格式」设计**，文档 §8.3 的 `capability` 字段正好承载。

## 8. 多语言/语言选择

- **用户主语言 = 多选有序表**：`Settings/GeneralLanguageSelection.swift:111-127` 多选勾选 + 星标置主语言（首位）+ 搜索 + 已选项排前面；至少保留一项（:113-117）。持久化为 `userMainLanguageCodes`（有序数组）。**比单选语言更贴合中英混说场景，建议借鉴**。
- **主语言驱动下游**：各 provider 的 language hints 从中推导；豆包简繁跟随主语言（`ASRHintSettings.swift:81`）；Xiaomi 只支持 auto/zh/en（:87）。
- **简繁归一化输出**：`App/Recording/RecordingSessionSupport.swift:105-123` 识别结果经 `ChineseScriptNormalizer.normalize(preferredMainLanguage:)` 归一到用户主语言的简/繁。**中文用户刚需，建议借鉴**。
- 会话内翻译目标语言切换（录音中弹出语言 picker）：`Windows/RecordingOverlayAnswerFlow.swift:283-301` + picker 点外关闭（见第 1 类）。仅翻译场景，参考价值低。

## 9. 首选项同步/配置导入导出

**无新增**。voxt 没有任何设置导入导出功能（全树确认仅有 `Settings/LogExportDocument.swift` 日志导出与历史音频导出）；远端 provider 配置存在 UserDefaults JSON（`remoteASRProviderConfigurations`），密钥已迁移到 Keychain（`remoteCredentialMigrationVersion` 迁移版本号这个手法可留意——给配置结构升级留迁移开关）。主文档 §8.5.7 的导入导出方案已超前于 voxt。

## 10. 其他聪明细节

- **语音结束命令**（自动停录）：`Settings/VoiceEndCommandSettingsSection.swift` + `App/Recording/VoiceEndCommandFlow.swift` + `RecordingCaptureFlow.swift:527-530`——说完预设口令（如 "over"，可自定义）再静音 1s 自动结束录音；实现上是对**实时转写文本尾部**做后缀匹配（大小写/音调/全半角不敏感、容忍结尾标点，:62-88），命中后再等静音，且**最终文本会剥离命令词与尾部标点**（:90-105）；转写尾部变化会撤销候选（:44-51）。对「锁存模式下懒得再按一次键」很实用。**toggle 模式下建议借鉴**。
- **静音监测单一循环**：`RecordingCaptureFlow.swift:453-538` 200ms tick 同时服务三件事：lastSignificantAudioAt 维护、语音结束命令检测、（本地引擎的）尾静音触发中间转写。主项目虽无本地中间转写，但「一个 tick 管所有时间相关判断」的结构值得沿用。
- **停录即时恢复系统音频**：`RecordingCaptureFlow.swift:328-335`（注释明确：最终 ASR 与增强是停录后的异步工作，不再需要保持静音）。**减少「录完没声音」的感知窗口，值得借鉴**。
- **音效与静音的时序协调**：`RecordingSessionFlow.swift:297-300` 注释——UI 与采集不等音效/静音；若开静音则等开始音效播完（可闻部分）再 mute，保证提示音听得见又不拖采集（`InteractionSoundPlayer.playStartAsync`）。**值得借鉴**。
- **LLM 双时机预热**：`App/LLMWarmup.swift:16-38` 会话开始时 + 停录时（post-ASR 前）两处预热润色模型。主项目润色路径可抄。
- **注入后可选补键**：`App/TextOutputDelivery.swift:115-162` `pressAutoKeyAfterTextInjection`（0.12s 后补 Enter/任意快捷键，先校验前台 PID 未变）。对应文档的 `inject.followupKey`，实现细节（PID 复验 + 自触发标记）可抄。
- **注入目标恢复的三级兜底**：`TextOutputDelivery.swift:30-52` PID 存活 → bundleID 找同 app 任一实例 → 放弃并记日志。文档只提了 activate，这个兜底链值得补进设计。
- **热键 stale 状态自愈**：`HotkeyManager.swift:438-451,1444+` 两个入口——空闲间隙推断状态过期 + 潜在 Fn/Globe 键丢事件时重置瞬态（modifier-only 热键 + tap 模式的组合坑）；外加事件 tap 被系统禁用后的自动重装 `recoverEventTapIfNeeded`（:251-269）。**用纯修饰键做热键必遇，强烈建议借鉴**。
- **commonStopKey**：`HotkeyManager.swift:1319-1333` tap 模式 + 纯修饰键热键时，录音中**再按一次同一修饰键 = 停止**（否则修饰键 keyup 语义已耗尽）。modifier-only 热键的语义补丁。
- **深空闲内存回收状态机**：`App/IdleMemoryReclamation.swift:18-60` 只有「无 pending 工作 + 模型已卸载 + 不在录音/会议」才释放 allocator 缓存，否则等待/重试，并输出 blockerSummary 日志。常驻引擎的主项目可借鉴其判定清单。
- **窗口几何防抖**：`RecordingOverlayWindow.swift:174-176` frame 差异 <0.5pt 即跳过 setFrame（配合文档已知的脱离动画事务）；设置主窗口有 `recenterMainWindowIfNeeded`（`MenuWindowCoordinator.swift:58-74`，窗口跑出屏幕自动回中，修复显示器拔掉后的失联窗口）。**值得借鉴**。
- **OverlayState 显式 deinit**：`RecordingOverlayState.swift:88-96` 注释记录 macOS 26 测试宿主上 @Published 析构 malloc 崩溃，显式 deinit 规避。低成本的兼容性保险。

---

**优先级建议（就主项目核心场景而言）**：第一梯队——Esc 三级取消、热键冲突规则表、热键 stale 自愈、prompt 回显抑制、交互音效（含尾静音裁剪）、麦克风优先级列表 + 录音中不换麦/热切麦、两层电平归一化；第二梯队——菜单栏懒加载最近历史 + 关闭后执行动作、历史搜索含 App 名 + hover 操作、状态三层提示体系、简繁归一化、多选主语言、统一热词表按 provider 下发；第三梯队（按需）——语音结束命令、自定义粘贴热键、代理设置、分步 Onboarding、Dock 联动。