Chris233
fc38edd1a3
refactor: consolidate Core 2.0 and restore cross-platform behavior ( #1019 )
...
* refactor: split Linux egui host from shared backend
* fix: keep CI contracts portable across runners
* fix(ci): preserve CRLF while removing qwen dependency
* fix(ci): regenerate target lockfile and install ripgrep
* fix(ci): gate desktop-only selection voice module
* ci: limit native build parallelism on cross-platform runners
* fix(host): expose blocking task seam to coordinator
* fix(settings): avoid macOS default hotkey collision
* docs: record cross-platform CI evidence
* ci: expose Linux validation package artifact
* ci: grant reusable Linux package permissions
* refactor: remove legacy coordinator dictation facade
* ci: skip unsupported MSI prerelease builds
* ci: install minisign only for signed Linux releases
* fix: keep test-only coordinator session helper
* refactor: move style preview diagnostics into core
* fix: import shared preferences type from core
* refactor: centralize enabled vocabulary projection
* ci: install ripgrep for Linux package gates
* test: make source contract line-ending agnostic
* fix: keep Linux desktop entry standards compliant
* docs: expose core style diagnostics contract
* ci: resolve Linux package version in app directory
* refactor: centralize ASR vocabulary priority
* fix: use shared vocabulary note constant
* refactor: keep vocabulary priority inside core
* test: retain starting-stop queue coverage
* ci: scope Linux updater URL to the current repository
* docs: close implementation and artifact evidence
* docs: record final CI artifact evidence
* fix(android): align updater plugin versions
* fix(android): pin updater crate exactly
* refactor(core): remove unused type anchor
* docs: record final artifact runs
* fix(remote-input): preserve beta status fields
* fix(tauri): finish beta host merge
* fix(asr): pass scoped operation to native qwen adapter
* fix(macos): bundle mlx metallib as a resource
* test(remote-input): update status wire contract
* feat: share Less Computer voice flow with Linux
* refactor(core): centralize host-independent runtime policy
* refactor(core): complete 2.0 backend consolidation
* fix(ci): prepare Sherpa after cache restore
* fix(macos): route native model paths through Core store
* fix(macos): use ModelStore catalog API
* fix(ci): serialize macOS native test build
* test(ci): preserve macOS cargo diagnostics
* fix(macos): release input source lock before await
* test(core): replace legacy hotkey injection gate
* test(core): move Codex sandbox contract into Core
* fix(core): close final runtime policy gaps
* fix(windows): terminate coding agent process trees
* fix(core): complete local model migration
* fix(credentials): align Core LLM model account
* fix(core): restore 1.x parity across shared backend
* fix(android): complete shared backend stubs
* fix: close cross-platform migration review gaps
* fix: complete migration lifecycles and platform compatibility
* docs: define desktop 2.0 acceptance and Linux handoff
* fix: close desktop parity and session lifecycle gaps
* fix: finish voice lifecycle and desktop feedback parity
* fix: close desktop cancellation and feedback race gaps
* fix: honor proxy settings and reject stale session effects
* fix: dispatch native cleanup on host runtimes and order events
* fix: keep optional recording effects best effort
* fix: close desktop agent model and QA lifecycle gaps
* fix: preserve desktop raw voice and QA turn ownership
* fix: finalize desktop dictation and QA feedback
2026-09-06 18:39:46 +08:00
zhou zhichao and Chris233
fc9824eecc
fix(remote-input): 开关已开时启动也要拉起局域网服务 ( #1002 )
...
* fix(remote-input): start the LAN server on launch when already enabled
Toggling the setting only refreshed the server on a prefs change. After restart the switch stayed on but port 8443 never bound, so the phone page could not open.
* fix(remote-input): unstick Windows startup and settings
On Windows, NIC enumeration and Tauri path APIs from the async runtime can stall the LAN server, and set_remote_locale's main-thread tray refresh deadlocks the settings page. Start the server on Ready and keep those calls off the UI thread.
* fix(remote-input): harden LAN discovery and startup lifecycle
* fix(remote-input): feed phone PCM into ASR instead of the PC mic
Remote dictation still opened the computer microphone and never assigned
the phone sink, so Safari audio was dropped. Arm a deferred bridge on
start and skip the local capture device for remote sessions.
* fix(remote-input): scope PCM cleanup to active session
* test(remote-input): import RMS helper
* fix(remote-input): clear idle PCM sink on cancel
---------
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-27 12:51:26 +08:00
Murphy
18e1aaf403
fix(polish): 润色流式请求让取消检测和网络等待赛跑,不再悬挂到 budget 结束 ( #1001 )
...
* fix(polish): 润色流式请求让取消检测和网络等待赛跑,不再悬挂到 budget 结束
配置为 qwen-audio-3.0-asr-flash + deepseek-v4-flash 时,若润色阶段对话模型
接口迟迟不返回,取消操作(点击胶囊关闭按钮 / 按快捷键重新发起)会晚至
32~53 秒才生效,期间胶囊卡死在屏幕上、快捷键无响应,只能强制重启 App
才能恢复(本机日志复现,见 issue)。
根因:chat_completion_messages_streaming 的取消检测只在 SSE 循环顶部轮询
一次,真正等待网络数据的两处 await(建连/发送请求、逐帧读取)都不会被
取消打断,只能等到数据到达或 budget(首字 30s+ / 空闲 20s / 硬顶 900s)
自然超时。同一类问题在转写(ASR)阶段已在 #798 修过,但没有推广到润色
阶段——这是一处遗留的修复范围缺口。
用同款 tokio::select! 赛跑模式补齐:新增 wait_until_cancelled helper
(75ms 轮询,与 wait_for_processing_cancel 同款间隔),分别和
send_with_transient_retry、response.chunk() 赛跑,命中取消就复用既有的
"空流 → InvalidResponse" 错误路径。不改变任何超时预算数值,不改变
already_streamed 语义,不改变 dictation.rs 状态机。
Fixes #1000
* test(polish): 补上 SSE 循环内取消的回归测试,并修正建连阶段取消的状态码
上一版新增的 cancellation_before_response_arrives_* 只覆盖了「服务端连状态行
都不回」的建连阶段,走的是 send_with_transient_retry 之前那个 select!。而
issue #1000 日志里打出的是 "cancelled by caller after 0 deltas ... breaking
SSE loop",说明 response 头已到达、代码已进入 SSE 循环,真正卡住的是
response.chunk() 那一次 await——也就是本次修复的核心那处 select!,此前没有
任何回归测试覆盖:把它还原成旧写法,原用例照样通过。
补 cancellation_mid_stream_does_not_wait_out_the_budget:服务端立刻回 200
header 让客户端进入 SSE 循环,随后长时间不发 delta,取消后必须在一个轮询
周期内返回,而不是等满 30s 首字预算。
顺带把建连阶段取消返回的 status 从编造的 200 改成 0:那条路径上一个 HTTP
响应字节都没收到,日志打成 "status 200" 会让人误以为服务端回了 200 空body。
两个用例的断言因此分别锁 status 0 / 200,互相不会冒充。
* fix(polish): 读取非 2xx 错误 body 时也让取消赛跑,并给 select! 加 biased
外部 review(codex)指出前两版仍漏了一处不可取消的网络等待:收到非 2xx
响应头后的 response.text()。polish_client 走的是 POLISH_CLIENT_HARD_CAP_SECS
(900s)总超时,服务端只要回一个 500 头就挂住不发 body,取消完全不生效,
最坏卡死 15 分钟——症状与 issue #1000 一致,且比原路径的 30s 首字预算严重
一个数量级。
补 cancellation_while_reading_error_body_does_not_hang:服务端回 500 头并
声明 1KB body 却一字节不发。去掉这次赛跑后该用例实测耗时 5.01s(真实场景
连接不关就是等满 900s)。
三处 select! 统一加 biased,让取消分支先于网络分支被 poll,消掉「budget 归
零与取消同时就绪时随机选分支」的竞态。
按 review 意见收紧措辞与注释:原注释称 Response 被 drop 会中断底层 TCP,
在 HTTP/2 多路复用与连接池下未必成立,改为只声明放弃这次请求的等待;
wait_until_cancelled 与两个既有用例的说明各压掉约一半。
2026-08-26 16:15:02 +08:00
Jimmy Lee and Chris233
2cf5069846
fix(asr): 修复 macOS MLX 后端闪退与发布资源缺失 ( #999 )
...
* fix/local-qwen-asr-exit: 修复使用本地的qwen3-asr识别闪退的问题 #986
* add mlx error
* 修复github action打包出来的dmg运行本地qwen3-asr-rs时崩溃的问题
* fix(asr): 隔离 macOS MLX worker 并修复发布资源
* fix(asr): 修复 macOS worker 超时与 socket 测试
* fix(asr): scope MLX cancellation to owning operation
* fix(asr): preserve abort semantics on target switch
---------
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-26 13:25:11 +08:00
3cc6a59dd6
feat(selection-voice): Windows 选区语音编辑 MVP,划词提问面板预览与意图分流 ( #987 ) ( #995 )
...
* feat(selection-voice): Windows 选区语音编辑 MVP(issue #987)
选区 + 专用快捷键 + 语音指令:指令润色后按 auto/manual/heuristic 分流到 QA 或 EditPlan 确定性编辑,含设置页、预览窗与热键集成。
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): 修复 Windows 编译(展平 session 模块结构)
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): 用 polish_text 替代 ActiveLLMProvider::complete
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(ci): 补全 mock trait 与 SessionId 单元测试类型
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(release): feature 分支跳过 MSI 并上传 NSIS 安装包
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): post-utterance intent picker and merged settings
Let users choose question vs edit after speaking (default prompt mode), merge polish and voice into one settings card, keep hotkey supervisor polling, and show capsule errors when trigger preconditions fail.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(i18n): add selectionWorkspace keys for ja, ko, zh-TW
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): compare hotkey supervisor signatures as Option<&str>
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(coordinator): gate selection_voice_intent_prompt init to Windows
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-workspace): unify voice and polish hotkey with edge prefetch
Reuse the selection polish shortcut for voice edit and prefetch selection at hotkey press to avoid Alt clearing the selection before capture.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): align auto/toggle hotkey modes and intent UX
Match dictation auto short/long-press semantics, fix toggle stop blocked by busy flag, block overlapping dictation, and invert intent toggle to heuristic-off / AI-on.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(ci): gate selection-voice dictation block to Windows only
selection_voice_session is Windows-gated; non-Windows builds failed with E0433 when dictation referenced it unconditionally.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): surface end-workflow errors instead of stuck loading
When stopping a voice session, failures during ASR, intent, or edit-plan steps now reset state and show a user-facing capsule error with stage hints.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): annotate end-workflow async block error type as String
Windows CI failed because the async block inferred Result<_, str> instead of Result<_, String>.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): route translation edits through translate pipeline
Infer target language from voice instructions like translate-to-English and build a full_rewrite plan via translate_text instead of fragile EditPlan JSON. Also normalize common LLM JSON aliases and improve parse fallbacks.
Co-authored-by: Cursor <cursoragent@cursor.com >
* feat(selection-voice): use XML EditPlan format for LLM edit responses
Switch voice-edit system prompt to XML envelopes with child elements for multiline text. Add parse_edit_plan with XML-first parsing and JSON fallback for legacy outputs.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(edit-plan): correct XML entity match string literals
Fix E0762 unterminated character literal in decode_xml_text that broke all platform builds.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(edit-plan): resolve XML parser type errors for CI
Use Option for find_open_tag, fix unwrap_or types, bool attr matching, and promote_alias_field slice arity.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(edit-plan): fix remaining XML parser compile errors
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(edit-plan): fix tuple arity, map remove keys, and borrow in normalize
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): unify voice edit with QA panel and improve intent
Route voice edits through QaPanel for shared preview/confirm UX, hide capsule when the session ends, prioritize heuristic edit cues for auto intent, and fix translation identity checks.
Co-authored-by: Cursor <cursoragent@cursor.com >
* feat(selection-voice): 统一语音编辑为 QA 面板预览模式并支持回退
将选区语音编辑流程统一到 QA 面板,新增预览与回退功能。
- 新增 `revert_selection_voice_preview` Tauri 命令及 IPC 调用,支持回退到上一轮编辑预览
- 在 QA 面板中新增 `editRevertAvailable` 状态,处理预览模式下的错误与空闲状态
- 优化 `emit_selection_voice_end_error` 逻辑:预览模式下错误回退到 Idle 状态并关闭面板,其他模式下显示错误胶囊
- 新增翻译结果与原文相同时的错误提示
- 跟踪 `previous_preview_text` 以支持回退操作
- 同步更新多语言(zh-CN、zh-TW、en、ja、ko)编辑按钮文案及新增回退文案
* fix(ci): gate selection-voice QA follow-up to Windows and fix compile errors
Add missing selection_voice_preview_mode helper, cfg-gate revert command registration, and release QA mutex before async follow-up edit to satisfy Send.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(ci): stub selection module in backend-tests harness
hotkey.rs now prefetches workspace selection on polish shortcut; provide no-op stub for Rust-only test crate.
Co-authored-by: Cursor <cursoragent@cursor.com >
* feat(qa): route intent by interrogative and add edit-instruction mode
Detect question vs non-question for selection-voice Auto intent, polish QA mic ASR, and gate ask/edit on the panel checkbox so text and voice stay consistent.
Co-authored-by: Cursor <cursoragent@cursor.com >
* feat(selection-voice): 增强语音编辑功能,优化 QA 面板状态同步
* fix(selection-voice): stop legacy edit keywords from misrouting to QA
Filter pre-#987 default keywords like 「改成」 so edit imperatives no longer match question heuristics, and reset qa_stream_cancelled before streaming so prior QA cancellations do not yield empty-stream failures.
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(selection-voice): address review blockers
* fix(selection-voice): gate QA preview cleanup to Windows
---------
Co-authored-by: Cursor <cursoragent@cursor.com >
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-25 23:34:52 +08:00
Chris233
58c0ade3ab
fix(windows-ime): make TSF shutdown fully cancelable ( #991 )
...
* fix(windows-ime): make TSF shutdown fully cancelable
Remove the uncancelable named-pipe flush, post owned submit requests to the TSF owner thread, cancel pending edit sessions during shutdown, and keep the DLL loaded while asynchronous edit sessions remain alive.\n\nRelated to #954 .
* fix(windows-ime): handle uncertain submits and startup failures
* fix(windows-ime): keep untrusted responses outcome-unknown
2026-08-25 22:29:50 +08:00
Chris233
5d379f2849
chore(release): 1.3.18-Beta.7
2026-08-24 22:36:11 +08:00
Mark
2981bf28c3
fix(macos): 避免 Keychain 授权弹窗重复出现 ( #990 )
2026-08-23 22:47:41 +08:00
Chris233
6efc8396ea
feat(macos): auto-select newline mode for terminal apps ( #988 )
...
* feat(macos): add line feed newline option
* feat(macos): auto-select newline mode by target app
* style(macos): localize newline fallback comment
2026-08-23 16:30:17 +08:00
Chris233
3f59b1352e
fix(asr): clarify Volcengine API Key source
2026-08-23 16:10:41 +08:00
Chris233
1abc7f595b
feat(translation): inherit active style pack ( #984 )
...
* feat(translation): inherit active style pack
* fix(translation): resolve style prompt conflicts
2026-08-23 02:08:01 +08:00
浩彬(^-^) and Cursor
ec33bd5dd2
fix(android): 修复小屏大字号下的设置与风格页面排版 ( #960 ) ( #983 )
...
* fix(android): 修复移动端设置与润色页排版及底栏遮挡 (#960 )
设置弹窗 z-index 低于底栏导致底部控件无法点击;润色风格/市场页与 Android 权限区补齐 mobile 布局。
Co-authored-by: Cursor <cursoragent@cursor.com >
* feat(ui): 通用设置新增易读布局,大字号小屏防溢出换行
新增 stackedRowLayout 偏好与 useLayoutStack;设置外观区可手动开启同行控件换行,覆盖老人机等极限场景。关联 #960。
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(android): 安全查询悬浮窗权限,修复 HyperOS canDrawOverlays 闪退
WebView IPC 线程不再直接 JNI 调用 Settings.canDrawOverlays,改走 Kotlin 主线程桥接并捕获异常,避免 Redmi/HyperOS 在权限轮询时崩溃。
Co-authored-by: Cursor <cursoragent@cursor.com >
* feat(ui): 保守排版开关与易读布局 min-width 增强
新增 conservativeLayout 偏好与 ol-conservative-scope 单列满宽规则;易读布局补充 min-width 换行;设置与主要页面支持双开关独立并存。
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(android): can_draw_overlays JNI 生命周期以通过 Android CI 编译
为 env 与 context 绑定同一 lifetime,满足 call_static_bool_with_context_class 的借用约束。
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(android): 恢复 AccessibilityService 对 Settings.Secure 的 import
isEnabled 仍使用 Settings.Secure 查询无障碍状态,与 canDrawOverlays 移除的 import 无关。
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(ui): 将易读/保守排版开关独立为「布局」区块并置顶
原开关藏在「外观」卡片深处不易发现;现于设置→通用页录音输入下方展示独立「布局」卡片。
Co-authored-by: Cursor <cursoragent@cursor.com >
* fix(ui): 统一易读与保守排版布局规则
---------
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-08-23 00:22:21 +08:00
Chris233
a19830d312
Ignore local Reasonix and Codex files
...
Update .gitignore to exclude local Reasonix metadata and the .codex directory so editor-generated or local inference files stay out of the repository.
2026-08-22 22:50:10 +08:00
Chris233
2770c74355
fix(local-asr): hide redundant model dashboard on Windows
2026-08-22 22:08:22 +08:00
2b796d067e
fix(macos): Fn 键可被录制为听写触发键 ( #979 ) ( #981 )
...
* fix(macos): Fn 键可被录制为听写触发键 (#979 )
浏览器/WebView 不向网页层下发 Fn 的 keydown(系统修饰键被隐藏),
ShortcutRecorder 无法通过键盘事件捕获 Fn。运行时本可检测 Fn(CGEventTap 看
keycode 63 + kCGEventFlagMaskSecondaryFn),但仅能通过「设置」写入,录制流程录不进。
- ShortcutRecorder:加 allowFn 开关,菜单提供「Fn」一键设置(绕过录制限制)
- macOS CGEventTap:录制态检测 Fn 边沿 → 上报 FnRecordingPressed → coordinator
emit fn-shortcut-pressed → 前端提交 {primary:'Fn'}
- 关键修复:MacHotkeyAdapter 缺 set_recording_active override,录制态从未传到监听器,
Fn 检测永不触发
- i18n: 补 comboFnLabel / comboFnHint 五语言文案
refs #979
Co-Authored-By: Claude <noreply@anthropic.com >
* fix(android): gate desktop Fn recording bridge
* refactor(macos): record Fn through backend event
---------
Co-authored-by: Claude <noreply@anthropic.com >
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-22 05:19:45 +08:00
bigsong
aa0acf8827
chore(dsh): 跟上游插件改名 dsh-events,并删掉一条会随机变红的联机验收 ( #980 )
...
* rename: 上游插件改名 dsh-jsonl -> dsh-events,同步 vendor 与常量
插件仓库改了名。`jsonl` 说的是输出格式,不是它给你什么——目标用户是想把 dsh 接进
GUI / 编辑器 / CI 的人,他们脑子里的词是「事件」,不是「JSON Lines」。而且别家都不这么
叫(Claude Code 是 --output-format stream-json,Codex 是 --json,OpenCode 是
--format json),有人来找这个能力时搜的是 "dsh json output"。
趁 npm 还没发布、还没对外宣传时改,代价只有改几个文件。旧 URL 有 GitHub 重定向兜底,
但留着迟早会成为断链。
跟着改的:vendor 文件名、同步脚本名、两个常量、环境变量名、模块文档与注释里的链接。
vendor 文件是用改名后的脚本重新生成的,不是手改——review 时加进来的来源与 MIT 许可头
原样保留。
* test(dsh): 删掉一条红绿取决于模型心情的联机验收
`tmp_is_writable_by_design_and_we_cannot_narrow_it` 想把「$TMPDIR 可写且收不掉」这个
dsh 既有行为钉成契约。但验证它必然要让模型去写文件,而 dsh 有**两道松紧不同的围栏**:
bash(seatbelt 子进程沙箱) 工作目录 + /tmp + $TMPDIR
write / edit(进程内 fs 围栏) 只有工作目录
prompt 里写了「用 bash 执行」,模型照做就绿,改用 write 就红。实测两种都出现过:一次
文件真落下去(bash),一次模型回 DONE 但文件根本没建(write)。这条测试的红绿反映的是
模型当次的选择,不是被测系统的行为——正是它上面那条注释批评过的毛病,我自己又犯了一遍。
那张「两道围栏」的表挪进模块文档,并写明为什么不做成测试。留下的
`sandbox_blocks_writes_outside_the_workspace` 打的是家目录,两道围栏都挡,不受工具选择
影响,那条才作数。
2026-08-22 02:11:25 +08:00
b7ac91f0e6
feat(coding-agent): Less Computer 接入 dsh(DeepSeek Harness),自带事件插件补齐流式与工具展示 ( #975 )
...
* fix(coding-agent): 版本号解析认预发布号
dsh 的真实输出是 `0.1.0-rc.6`,而解析器要求严格的三段全数字:它被切成
["0","1","0-rc","6"] 四段,判定失败。用这个判「装没装」的地方就会说它没装。
改成认 `-rc.6` / `+build.7` 这类预发布与构建后缀,并原样保留(用户看到的版本号才是
真的)。同时把排版噪声挡在外面:`(1.2.3)` 取到的是 1.2.3,不是 `1.2.3)`。
单测里的样例串是手抄的,抄错了测试照样绿。所以另加一条 #[ignore] 的 live 测试,直接问
本机四个 CLI 要 --version 输出再喂给解析器——那才是「设置页会不会误报没装」的可信证据。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* fix(coding-agent): 「装没装」改看命令能否跑通,不再依赖版本号解析
上一条修的是解析器,那只是补了一个洞。根子在于判据选错了:
installed: version.is_some() // 解析不出版本号 = 判定没装
版本字符串是这些 CLI 里最容易变的东西——改排版、加后缀、换前缀,对它们都不算 breaking
change,但对「拿版本号当判据」的我们就是。
改成:命令跑通(进程起得来且 exit 0)= 装了;版本号只用来显示,解析不出来最多让界面少
显示一个号码,不会把能用的后端说成没装。三个后端共用一个 probe_cli,顺手删掉了三份
几乎一样的 detect_* 。
单测拿 `echo` 当替身——`echo --version` 会原样打印并 exit 0,正是「跑得通但读不出版本号」
这个形状,且不依赖本机装了哪些 agent CLI。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* feat(dsh): 无头 dsh 后端,自带事件 tap 插件
dsh(DeepSeek Harness)的 headless 只在结束时往 stdout 打一行最终文本——没有 JSON、
没有逐字流、没有工具事件。但这不是它缺数据:它内部的会话事件总线上 assistant/chunk、
tool/call、turn/end 一应俱全,只是 headless 汇总完就丢了。
dsh 是插件栈架构,`--patch` 是官方留给外部叠自己那层的入口。这里挂上一个订阅
session/event 的小插件,把需要的事件规范化成 NDJSON 打到 stderr,stdout 的「只打最终
文本」契约原样不动。挂载不侵入用户的 profile,插件随运行落到临时目录、跑完删掉。
上游耦合被刻意压缩在那个 30 行的 JS 里:它把 dsh 的内部事件翻译成我们自己定义的稳定
形状,上游改字段只需要改 JS,Rust 的解析和单测都不用动。tap 是纯增益——挂不上也只是
少了逐字流和工具展示,最终结果照样从 stdout 拿得到。
prompt 不进 argv:dsh 的启动器不认 `--` 作为选项终止符(实测 `dsh --profile headless
"--version"` 会真的去执行 --version),所以以 `-` 开头的转写会被劫持成 flag。既然本来
就要写 patch 文件,索性用它直接覆盖 runner 的 task 配置,prompt 连进程列表都不会出现
——这点比另外三家都严。
护栏走 DSH_PERMISSION_MODE 三档沙箱,沙箱根 = 子进程工作目录。和 Codex 一样没有逐命令
deny 清单,所以审批卡对它同样不生效,撞墙时如实报错。
模型解析永远返回 None:headless profile 没有 --model,模型由 dsh 自己的 profile 决定,
返回 Some 只会让调用方以为选得动。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* feat(settings): Less Computer 后端下拉加入 dsh
第四项。它的能力面和另外三家不一样,设置页如实反映,不给假开关:
- 模型那一行**整行不显示**,换成一句说明:dsh 的 headless 没有模型开关,模型由它自己的
profile 决定,在这里改不了。给个选不动的下拉比不给更糟。
- 复用 Codex 那条沙箱护栏说明(两家都只有粗粒度档位、都不弹审批卡)。
- 装没装当场检测;可执行文件 placeholder 跟着后端走。
文案 5 语言齐全。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* refactor(dsh): tap 插件抽成独立项目 dsh-jsonl,OpenLess 改消费它的公开 schema
原来这个插件是内嵌在 dsh.rs 里的一段 Rust 字符串,只发我们自己要的 4 类事件、用我们
自己的私有形状。它要开源出去(dsh 缺结构化输出,而上游不收 PR,第三方插件是这个能力
唯一可能存在的形式),于是有了「两份会各自跑偏的代码」这个问题。
解法是保证世界上只有一份这个 JS:
- 源头在 github.com/bigsongeth/dsh-jsonl,发完整的、有文档、有版本的事件词表。
- OpenLess 用 include_str! 内嵌一份逐字副本(vendor/dsh-jsonl.js),带版本标记。
内嵌而不是依赖 npm 包:用户装机即用,不需要网络、不需要 npm i,也不碰用户自己的
dsh profile 配置。
- Rust 侧改成解析那个公开 schema(text.delta / tool.call / turn.end),不再有私有形状。
用不上的事件按 schema 的兼容性约定忽略——上游加新事件不会把我们打挂。
**跨仓库没有任何自动同步**,这点没被消除,只是变便宜了:
- scripts/vendor-dsh-jsonl.sh 把同步变成一条命令
- 单测盯着 vendor 文件的版本标记与 VENDORED_DSH_JSONL_VERSION 一致,防止有人直接手改副本
- 插件报的 schema 大版本与我们支持的不一致时留警告日志(不中止:最终结果始终从 stdout
拿得到,流式展示只是锦上添花)
- 真的对不上时,live::tap_plugin_delivers_streaming_and_tool_events 会红
顺带把「禁止任何 import」的断言放宽成「只准 node: 内置」——公开插件要写文件,用了
node:fs,而 node: 内置不需要 node_modules,不影响从临时目录绝对路径加载。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* test(dsh): 沙箱验收的靶子选错了,它一直是靠运气过的
那条「沙箱挡得住工作目录之外的写入」把靶子放在 $TMPDIR。但 dsh 的 workspace-write 把
可写根写死成 [工作目录, "/tmp", $TMPDIR](见 @deepseek-ai/dsh-sandbox 的 writableRoots)
——往 $TMPDIR 写**本来就是允许的**。
它之前能过,只是因为模型碰巧挑了受限更严的 `write` 工具;这次挑了 `bash`,文件就真的
落下去了。也就是说这条测试的成败取决于模型当次的选择,不取决于沙箱是否失效。
改成打真正的边界(家目录),实测会被拒:
bash: /Users/…: Operation not permitted [sandbox: file access denied under workspace-write mode]
另加一条把 dsh 的既有行为钉成契约:$TMPDIR 可写,且**没有配置项能收掉**——Codex 那边
有 -c sandbox_workspace_write.exclude_* 可以收紧,dsh 没有对应物。哪天 dsh 收紧了这条
会红,那是好消息,届时删掉它并更新文档。
所以对用户的措辞只能是「撞到限制会如实报错」,不能说成「写入限制在工作目录内」。
模块文档里把这个边界写清楚了。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* fix(dsh): 收紧运行协议与权限边界
* fix(dsh): 修复权限与连续对话审查项
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-22 00:14:17 +08:00
Chris233
c61e3dc6d0
fix(asr): validate Bailian endpoints by channel scope
...
Provider validation used the globally active ASR provider when deciding whether to derive Bailian protocol endpoints. Non-active Bailian channels therefore sent their WebSocket endpoint through HTTP-only validation for synchronous models.
2026-08-21 23:56:38 +08:00
5ba0fa725c
feat(coding-agent): Less Computer 接入 Codex,语音使唤电脑不再只能用 Claude ( #974 )
...
* fix(coding-agent): 从用户 shell 取真实 PATH,打包后也找得到 CLI
macOS 从 Finder 启动的 GUI 进程拿到的是一份极简 PATH,不经过用户的 shell 配置。
后果是:凡是版本管理器装的 agent CLI 在打包版里一个都找不到——`opencode` 官方脚本
装在 `~/.opencode/bin`,全局 npm 前缀和 nvm 的路径更是带版本号、根本没法硬编码。
用户只能手动去高级设置里填绝对路径。
改成先问用户的 shell 要一份真实 PATH。三个细节是踩出来的,都写进注释了:
- 用 `-lic` 而不是 `-lc`。nvm 这类版本管理器通常在 .zshrc 里初始化,而 .zshrc 只有
交互式 shell 才读;`-lc` 拿到的 PATH 里 nvm 排在 /usr/local/bin 之后,
`#!/usr/bin/env node` 会命中错版本的 node,子进程直接崩。
- 拼接必须保序。逐项前插等于把整个 PATH 倒过来,同样会选错解释器。
- 分隔符交给 std::env::split_paths / join_paths,不能手写 `:`。Windows 用 `;`,
而且盘符自带冒号,手写会把 `C:\Windows` 切成两半、整条 PATH 报废。
shell 卡住有 5 秒硬上限,超时回落到静态目录列表。整段探测限定 unix:Windows 没有
「登录 shell 的 PATH」这个概念,装了 Git Bash 的机器 SHELL 有值,真去跑只会莫名其妙
拉起一个 bash。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* feat(codex): 无头 Codex 适配器
Less Computer 现在只认 Claude Code 和 OpenCode,因为每个后端都得手写一套适配器。
这个是 Codex 的那套,形状和前两家一致,共用同一套请求/事件/错误类型。
- 运行:`codex exec --json`,逐行解析 JSONL。
- prompt 走 stdin(末尾的 `-`),不进 argv,也不会出现在进程列表里。
- 续接用 `resume --last`。参数顺序有坑:`-s` / `--json` 这些必须排在 `resume` 之前,
写反了 CLI 直接报 unexpected argument,已对 0.146.0 核实并写进注释。
- 工具展示会剥掉 `/bin/zsh -lc '…'` 这层 shell 包装,胶囊里显示的是真正执行的命令名。
- 护栏:Codex 给不了逐命令 deny 清单(`.rules` 只从 $CODEX_HOME / 项目目录读,实测
`-c rules=[…]` 会被静默忽略)。它的护栏是自带的 seatbelt 沙箱,走 `-s <mode>`。
额外关掉 workspace-write 对 /tmp 与 $TMPDIR 的默认放行——不关的话「写入限制在工作
目录内」就是句假话,实测任务真的能在 $TMPDIR 里落文件。
有一处刻意不做:Codex 会把「模型元数据没找到」这类警告也塞成 error 事件,本机每次运行
都会发一条。把它当终局失败会让所有运行都被误判,所以只认 turn.failed。
联机验收默认 #[ignore],其中一条不调模型不花钱:它比对加固前后实际生效的可写根,
盯住护栏别被上游无声改宽(codex 对未知 -c 键是静默接受的,改名了不会报错)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* feat(coding-agent): Less Computer 可选 Codex 后端,审批卡按能力启用
把 Codex 接进语音链路,后端从两家变三家。
护栏这块两类后端不一样,代码里如实分开:Claude / OpenCode 有逐命令 deny 清单,撞了能
弹审批卡、批准后放行那一条重跑;Codex 只有粗粒度沙箱档位,唯一的「放行」办法是整体
降档,那等于把护栏关掉,不是放行这一条。
所以给 provider 加了一个能力位,只有支持逐命令放行的后端才弹审批卡。否则用户点了批准、
重跑还是同样被拦,那是个假承诺。撞墙时直接把失败如实报出去。
模型解析也按后端分开:Codex 收裸模型名(gpt-5 / o3 这种),留空交给它自己的
~/.codex/config.toml,不替用户瞎猜一个默认。
另加一个通用的安装检测命令:选了后端却没装 CLI 时,在设置页当场看到,而不是等说完
一句话才发现跑不起来。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* feat(settings): Less Computer 后端下拉加入 Codex
设置页的后端下拉从两项变三项,并且如实反映能力差异,不给假开关:
- 模型:Claude 用别名下拉,OpenCode 拉账号可用列表,Codex 改成自由文本——它的模型名
是裸名(gpt-5 / 自建网关的任意名字),枚举不过来;留空 = 用 Codex 自己的默认。
- 护栏:选了 Codex 会挂一条说明,讲清楚它只有粗粒度沙箱、撞到限制会直接报错而不是弹
「批准这条命令」的卡片。免得用户按 Claude 的心智去用。
- 装没装:当场检测并提示,没装时按警示色显示。
- 可执行文件的 placeholder 跟着后端走。
文案 5 语言齐全。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* fix(coding-agent): harden Codex execution
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-21 22:07:10 +08:00
Chris233
62a3d86721
[cask] openless 1.3.18 (manual after release) [skip ci]
2026-08-21 21:45:07 +08:00
Chris233
cb3d3f8a3a
fix(local-asr): preserve child state across refreshes
2026-08-21 20:07:30 +08:00
Chris233
86012fce42
chore(release): prepare 1.3.18-Beta.6
2026-08-21 18:37:23 +08:00
sim
3d2811dcae
fix(release): link Apple compiler runtime for MLX
2026-08-21 14:49:55 +08:00
sim
1933a283c6
chore(release): prepare 1.3.18-Beta.5
2026-08-21 14:24:56 +08:00
zhou zhichao and Cursor
7800071087
fix(settings): remount RemoteInputSection on the General tab ( #978 )
...
1.3.14 split settings into tabs and left the existing panel unmounted. Desktop only, matching the PC HTTPS remote-input server.
Closes #977
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-08-21 14:20:02 +08:00
Chris233
892f37c820
fix: localize Windows tray menu labels ( #957 ) ( #972 )
...
* fix(tray): localize Windows tray labels (#957 )
* fix(ci): register qwen3 ASR submodule
* fix(tray): preserve renamed builtin style names
2026-08-20 22:52:50 +08:00
Chris233
1ee93576b0
fix(linux): avoid audio OSD on startup and exit ( #968 ) ( #973 )
...
* fix(linux): avoid audio streams during permission checks (#968 )
* fix(ci): remove stale qwen3 submodule gitlink
* fix(ci): restore qwen3 submodule mapping
2026-08-20 22:04:29 +08:00
Jimmy Lee and Chris233
42c1b31754
本地模型增加whisper相关模型的支持; 增加qwen3-asr的rust版本, 相比C版本速度更快 ( #940 )
...
* feat: add selectable local ASR backends
* fix(build): 修复本地 ASR 多平台构建与旧渠道兼容
* fix(asr): 修复 MLX 权重跨线程 stream 错误
* fix(ci): exclude MLX Qwen3 from non-macOS jobs
* fix(ci): use app-relative ASR submodule path
* fix(android): skip qwen-asr C backend
* fix(android): guard qwen-asr by target triple
* fix(ci): 修正语法错误
* fix(ci): remove invalid checkout step options
* fix(asr): harden local backend integration
* fix(asr): 处理 PR #940 审查发现(9 项)
- strip: 全局保留 symbols,macOS release profile 单独退回 debuginfo(Homebrew rustc 的 LINKEDIT 问题仅限 macOS)
- 转录超时改为驱逐引擎而非无效 cancel():spawn_blocking 解码任务无法被中止,驱逐后下次会话加载新引擎而非排队
- Turbo/Q5 共享目录模型在 is_downloaded/downloaded_bytes/delete_model 上互相认账
- MLX 临时 WAV 用 RAII guard 兜底清理;HF tree API 改 Link rel=next 游标分页(offset 被服务器静默忽略),带防御上限与 5 个单测
- Intel Mac 渠道下拉不再闪现 MLX 预设;MetalToolchainGuide 默认折叠并标注仅源码构建期要求
- qwen3-asr-rs 子模块 URL 与 gitlink 指向 Open-Less org 镜像,嵌套 mlx-c 同步改指 org(供应链 N-6)
- README/注释补充:所有平台源码构建均需递归初始化子模块(path 依赖跨 target 解析)
* fix: harden local whisper model lifecycle and downloads
* fix(asr): address PR 940 review findings
* fix(ci): add local ASR model stub to backend tests
* fix(linux): bundle and sync fcitx5 selection plugin
* fix(macos): avoid duplicate whisper test module
* fix(history): make detail sibling keys unique
* fix(ci): stub macos whisper model constant
* test(ci): avoid macOS streaming timeout race
---------
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-20 20:22:02 +08:00
Chris233
fac8ddc685
fix(ui): 修复模型选择刷新闪烁 ( #970 )
...
* fix(ui): 修复模型选择刷新闪烁 (#958 )
* test(polish): 放宽流式首字测试时序裕量
* fix(ui): ignore stale LocalAsr refresh results
2026-08-20 19:03:01 +08:00
Chris233
7a66ca625b
docs(readme): 移除对 jiangmuran 的赞助商感谢信息
2026-08-20 19:01:46 +08:00
Chris233
b4099362d2
docs(readme): 更新 bigsong 的角色为“贡献者/测试”
2026-08-20 18:54:14 +08:00
Chris233
9bf492e04d
docs(readme): 更新开发者信息和链接格式
2026-08-20 18:52:45 +08:00
Chris233
dcf9b0d332
更新 README.zh.md
2026-08-20 16:46:46 +08:00
Chris233
6f4ed5b128
更新 README.md
2026-08-20 16:42:38 +08:00
Chris233
9cc510e86b
更新 README.md
2026-08-20 16:38:53 +08:00
Muran Jiang
09828b7ea6
docs(readme): restore jiangmuran and Cooper ( #971 )
2026-08-20 13:00:00 +08:00
bigsong and Claude Opus 5
ec5ea4b07a
fix(vocab-card): 收起添加词卡片后,胶囊要回到屏幕中间 ( #969 )
...
* fix(vocab-card): 收起卡片时把胶囊的位置也还回去
卡片和录音胶囊是同一个窗口。弹卡片要把窗口挪到右下角,收卡片时
`hide_vocab_suggestion_card` 还了尺寸、还了鼠标穿透,唯独没还位置 ——
于是下一次录音,胶囊出现在右下角。
漏这一步之所以致命,是因为 `maybe_position_capsule_bottom_center` 有个
去重缓存,而那个缓存只记「显示器 + 翻译态」。卡片这一挪它一无所知,
下次录音时拿到相同的显示器快照就判定「没变化」,直接跳过重新定位。
换句话说:窗口被挪走了,而唯一会把它挪回来的那段代码以为自己不用动。
所以复位和清缓存两件事都做,各堵一个方向:清缓存保证「就算这次复位
失败,下一次 emit_capsule 也一定会重算」;复位保证「就算有哪条路径
绕过 emit_capsule 直接 show,窗口也已经在对的地方」。
顺带把同一形状的另一处堵上:卡片直接调 set_ignore_cursor_events,却没
同步 `capsule_cursor_passthrough` 那个缓存。目前触发不了,但一旦缓存和
窗口真实状态分家,emit_capsule 就会跳过它该调的那一次 —— 表现是经典
胶囊上的 ✓/✕ 点不动。
复位顺序改成先 hide 再改几何:尺寸和位置要一起动,窗口还亮着时改就有
概率被合成出一帧「卡片被拉宽、还横着飞过半个屏幕」。
真机量过(临时脚手架 + CGWindowList 取窗口 frame,外接屏 1920x1080):
修复前 录音 → x=453(居中)→ 卡片 x=1299(右下)→ 收卡片后窗口
仍在 x=1299 → 下一次录音胶囊 x=1299 ← bug
修复后 录音 → x=526(居中)→ 卡片 x=1168(右下)→ 收卡片当场回到
x=453(居中)→ 下一次录音胶囊 x=453 ← 对
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
(cherry picked from commit d3fedcd13da0a3ba002a6f29dda330eeabee62f1)
* test(capsule): 把「卡片借走胶囊窗口必须完整归还」钉成契约
上一条修复(收起卡片时把胶囊位置也还回去)在 8 月丢过一次 —— 它只活在
一个没合并的本地分支上,主线从 PR #917 重新长出了漏还位置的版本,于是
真机 bug 原样复发:用过一次带添加词的卡片,下一次录音的胶囊就出现在
右下角,再也回不到底部居中。
这类不变量单测抓不到:整段是 Tauri 窗口调用,跑在 run_on_main_thread 的
闭包里,没有窗口就没有断言对象。所以按 repo 既有的做法收进
macos-capsule-spaces-contract —— 那个文件已经是「胶囊窗口几何」这类
源码级不变量的归属地(多屏定位缓存那条就在里面)。
守两侧四个函数(词条卡片 + 落字回退卡片):
弹卡片:挪走了共享窗口,就必须让 capsule_layout 去重缓存当场作废,
并同步 capsule_cursor_passthrough
收卡片:穿透、尺寸、位置、两个缓存,一样都不能少;且必须先 hide
再改几何(否则复原会被合成出一帧横飞过半个屏幕的动画)
「还位置」和「清缓存」分开断言是有意的:这两件事各堵一个方向,漏任何
一个 bug 都会回来,所以要能各自报出自己的名字。
验证(三态):
未修复的 coordinator.rs(HEAD~1) → 红,报 show_vocab_suggestion_card
缺 capsule_layout 失效
变异:只删掉 hide_vocab 里那一行
position_capsule_bottom_center → 红,且精确报出「restoring size
alone leaves it in the card's
bottom-right corner」
修复后 → 绿;npm test 全量退出码 0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
2026-08-19 23:30:48 +08:00
bigsong and Claude Opus 5
dbda116415
fix(polish): 超时改成按稿子长度伸缩,流式用首字/空闲两把尺子 ( #966 )
...
7 分钟录音那条(1758 字)落进 Notion 的是满屏「嗯、呃、然后呢」的原始转写,
事后手动重润色 3 次全失败。查下来模型没出错——它每次都返回了完整结果,只是
step-3.7-flash 在吐正文之前先思考了 43 秒(实测 43~75s,思考量 8572 字),
而我们第 30 秒就撒手了。
两处判据不对:
1. 流式用的是 reqwest 的整请求超时。这把尺子分不清「模型还在正常吐字,只是
这段稿子本来就长」和「服务端卡死了」,30s 一到把两者一起砍。现在拆成首字
预算(用户盯着空屏干等的上限)和空闲预算(出字中途卡多久算死),总时长不
再单独设限——还在稳定出字就让它写完。
推理模型思考期的 reasoning_content 是一串正常 chunk,特意不让它给首字预算
续命,否则「干等多久」就失去上限。
2. 30s 不随输入长度伸缩。ASR 侧早有三套 max(30, 系数 × 量 + 余量) 的动态公式,
润色这条路上漏了。现在流式和非流式(重润色)都按输入字数算预算。
顺带补上首字延迟日志——之前日志里没有这个读数,这次只能靠外部实测才量出 43s。
验证:拿失败那条原文真打 stepfun 重放两次,首字 44.3s / 95.7s,旧判据全被砍,
新判据(首字 118s / 空闲 20s)两次都跑完拿到完整润色。单测新增 8 个,其中两个
关键行为做了变异验证:把超时退回整请求语义、让 reasoning chunk 续命,对应测试
都如期失败。全量 1082 passed。
未覆盖:QA 划词追问的流式路径仍是老语义,Gemini / Codex provider 同理。
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
2026-08-19 23:24:58 +08:00
aeoform
cdbd3746b0
fix(linux): 屏蔽 Less Computer / Claude 控制台入口 ( #967 )
...
Less Computer 功能仅 macOS 开放(后端只在 macOS 注册热键/创建窗口),
Linux 设置页不再渲染 CodingAgentSection 和 ClaudeConsoleSection,
避免用户看到无法使用的功能。
- CodingAgentSection: 原仅隐藏 Windows,现同时隐藏 Linux
- tabs.tsx AdvancedTab: os !== 'win' 改为 os === 'mac'
2026-08-19 22:58:58 +08:00
aeoform
68573df66e
fix(settings): 选区润色快捷键录制改用通用修饰键,去掉错误的侧键模式 ( #962 )
...
上游 #851 给 SelectionPolishSection 开了 sideSpecificModifiers(录制
cmd-left/alt-right 等侧特异性标签),但同一 PR 的后端
set_selection_polish_hotkey 用 reject_side_specific_non_dictation 拒绝
非听写功能的侧键(side-aware hook 仅听写支持多 owner,polish 走普通
global-hotkey 注册)——前后矛盾导致带修饰键的组合保存必然失败,且前端
catch 后误报「该快捷键组合不可用」。
修复:去掉该行的 sideSpecificModifiers,录制回落到通用修饰键格式
(alt/ctrl/shift/super),与后端约束一致。听写快捷键(ShortcutsSection、
RecordingInputSection)的侧键能力不受影响。
2026-08-19 22:01:15 +08:00
aeoform and Chris233
33467a36ea
feat(linux): 选区读取集成进 fcitx5 插件(clipboard addon),删除外部工具依赖 ( #961 )
...
* feat(linux): 选区读取集成进 fcitx5 插件(clipboard addon),删除外部工具依赖
- openless 插件新增 GetSelectionText DBus 方法:直读 fcitx clipboard addon
的 PRIMARY 选区缓存(X11 XFIXES / Wayland data-control 统一维护),与
fcitx 剪贴板模块来源一致,不触碰用户剪贴板
- CMake 增加 Fcitx5::Module::Clipboard 依赖
- Rust 侧 selection 改走插件 GetSelectionText,删除 wl-paste/xclip/xsel
外部工具路径及 linux_selection_tools_missing 提醒机制(前端
selection_warning 状态机、i18n、测试一并删除)
- acceptQaSessionEvent 的 idle 分支不再依赖 selection_warning 字段,
一律视为新会话 token(事件保序,语义等价)
- 打字提问路径(QA 面板 / less-computer)不再 emit Polishing capsule:
回答在面板内可见,避免 Linux 输入法 auxDown 闪「✨ 润色中...」
(cherry picked from commit 384f8876a490cb3e8e992af05cdad33f2af6a8ec)
* fix(linux): bundle and sync fcitx5 selection plugin
(cherry picked from commit 7e8bf825c08f5e935c7a25746c121136d92b7926)
* fix(linux): use DBus selection reader during validation
(cherry picked from commit d13403343b08fe1b4070e0f0d2f219a0a69d363e)
* refactor(linux): 收尾 PR 961 审查发现的小毛病
- capsule 反馈参数从裸 bool 改为具名枚举 CapsuleFeedback(Show/Hide):
语音/听写路径 Show、打字路径 Hide,调用点自文档化,避免将来误传
- AppImage 插件子路径提取为 APPIMAGE_PLUGIN_SUBDIR 常量并注明与 CI
bundle.resources 的契约,避免三处硬编码静默失配
- selection.rs 移除文件级 Linux 大赦(lib.rs 的 crate 级兜底仍在),
Duration import 按平台限定,消除 Linux unused 隐患
---------
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-19 20:34:10 +08:00
789c82051e
fix(history): 详情面板同层 key 去重,切换条目不再残留「播放录音」按钮 ( #964 )
...
* fix(history): 详情面板同层 key 去重,切换条目不再残留「播放录音」按钮
详情面板里 AudioRecordingPlayer 和 RepolishPanel 是同一层的兄弟节点,两个都用
裸 `item.id` 当 key。同层重复 key 下 React 只打警告(Encountered two children
with the same key)不报错,但 reconcile 匹配不上旧 fiber,旧的播放器节点删不掉:
每切换一次历史条目就在 DOM 里多留一个「播放录音」按钮,一直开着不关的窗口能叠出
一整列,把下面的流水线信息挤走。
改成 `audio-${item.id}` / `repolish-${item.id}`,key 仍随条目 id 变化(切换条目
时照旧重挂载、重置播放与润色状态),但同层不再撞车。
另加契约测试 scripts/history-detail-sibling-keys.test.mjs:扫详情面板里所有
key 表达式,断言互不相同且都带 item.id,后续再往这层加带 key 的兄弟组件会被拦下。
复现与验证(浏览器 dev,mock 条目打开 hasAudioRecording):
- 修复前:连续切换 12 次条目 → 播放按钮 1→12,控制台每次都刷重复 key 警告
- 修复后:同样切换 12 次 → 播放按钮恒为 1,重复 key 警告 0 条
- npm test(tsc + vite build + 全部前端测试)exit=0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
* test(history): validate sibling keys at runtime
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com >
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-19 01:08:15 +08:00
Chris233
9f360e20f7
fix(asr): fallback to CPU after Foundry CUDA failure ( #945 )
...
* fix(asr): fallback to CPU after Foundry CUDA failure (#941 )
* fix(asr): preserve Foundry primary across CPU fallback
* fix(asr): harden Foundry fallback lifecycle
* fix(asr): 修复 PR #945 审查发现(P1-1/P1-2/P1-3/P2-1/P2-2)
- P1-1: 静默重试循环感知终态 Foundry 回退错误并立即短路(RetranscribeError
分类 + retry_error_outcome 决策),避免重复命中同一 CUDA 路径
- P1-2: 转写完成后 cancel 收窄至 Foundry(非 Foundry 恢复 base 行为)
- P1-3: lifecycle 锁粒度 trade-off 文档化;release_now 锁等待 >=100ms 记日志
- P2-1: 删除无调用方的 transcribe_audio_file(Windows + 非 Windows stub)
- P2-2: 终态错误面向用户消息精简(共用 FOUNDRY_FALLBACK_TERMINAL_USER_MESSAGE),
原始 GPU/CPU SDK 错误保留在日志与 err 字段
* fix(asr): scope Foundry cancellation to recording route
2026-08-17 19:12:15 +08:00
bigsong
f42f3e60f0
feat(dictation): 落字失败时把话交还给用户,换行不再劈开聊天消息 ( #943 )
...
两件事,本质是同一个:说出来的话没落到该去的地方。
**一、换行会把聊天消息从中间劈开发出去。**
macOS 把 U+000A 当 Return 键,而聊天框里 Return 就是「发送」。一条带空行
的两段话逐字上屏时,第一个换行直接把上半句发了出去,下半句留在输入框里。
改成发真实的 Shift+Return:聊天框里是软换行不发送,编辑器、终端、网页输入
框里就是普通换行。
做成设置而不是硬编码——风格市场里有靠换行把一段话拆成多条消息的风格包,
那种效果要的正是真回车。默认 Shift+Return,需要的人切回 Return。
**二、落字失败时,那段话会悄无声息地消失。**
密码框挡着(Secure Input)、辅助功能掉了权限、粘贴被拒——这些时候唯一的
兜底是把文本写进剪贴板。可它既依赖一个默认可关的开关,就算开着,屏幕上也
没有任何东西告诉你文本在那儿。用户看到的只是胶囊一闪而过,然后是个空输入框。
现在屏幕底部会弹一张卡片,里面是**完整**的那段话,一键复制。20 秒后自己
消失,鼠标停在上面就不走。
顺带修正一处数据失真:逐字上屏打到一半断掉时,此前一律报 InsertStatus::
Inserted(屏幕上明明只有半截),history 里的 insertStatus 因此是错的。
2026-08-15 22:21:05 +08:00
TRIP
2ca2a48c52
chore(cask): update OpenLess to 1.3.17
...
Release follow-up: apply the cask update through the required PR path after the automated direct push was rejected.
2026-08-15 21:19:18 +08:00
sim
ac1e9f49aa
[cask] openless 1.3.17 [skip ci]
2026-08-15 21:18:25 +08:00
Chris233
f008cc6f05
fix(windows): allow synthetic hotkeys to trigger OpenLess ( #948 )
2026-08-14 22:04:47 +08:00
Chris233
94db63f248
fix(ui): keep vocab delete action visible for long entries ( #950 ) ( #951 )
2026-08-14 22:03:52 +08:00
40cd1365e2
fix(asr): 火山渠道「验证」接入真实 WS 连通检查,修复必报「API Key 为空」 ( #944 )
...
* fix(asr): 火山渠道「验证」接入真实 WS 连通检查,修复必报「API Key 为空」
validate_asr_provider 此前没有火山分支,火山渠道点「验证」会掉进 OpenAI
兼容 HTTP 兜底——那条路只认 asr.api_key(火山从不写入的槽位),导致无论
哪种鉴权模式、凭据填得多对,连接检查都报「API Key 为空」。
- 新增 validate_volcengine_asr_provider:按鉴权模式取各自槽位凭据
(旧版 volcengine.access_key / 新版控制台 volcengine.api_key),
真连官方 WS 端点 + 1s 静音 + 收尾,与讯飞验证器同构;纯静音会话
服务端不回 final(NoFinalResult)不算失败——握手成功已证明凭据有效
- 凭据缺失按模式返回哨兵串(volcengineAppIdMissing 等),前端映射为
多语言文案,直接指出该补哪个输入框(en/ja/ko/zh-CN/zh-TW 同步)
- 握手被拒(401/403)/ 被限流(429)的报错原样透传给验证按钮,
不再折叠成笼统的「操作失败」
- 补 volcengine_missing_credential_error 单测锁定两种模式的判定
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
* fix(asr): 统一火山 Resource ID 空白回退
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com >
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-12 12:50:12 +08:00
King and Chris233
c84bfb98f3
chore(ci): optimize CI caching, concurrency, and Tauri security ( #937 )
...
* ci: optimize CI caching, concurrency, and Tauri security
Address multiple CI/CD efficiency and security gaps identified during
project optimization analysis. The changes reduce PR build times,
prevent wasteful concurrent runs, tighten the Tauri security boundary,
and eliminate unnecessary submodule fetches on non-macOS jobs.
CI workflow improvements:
- Add swatinem/rust-cache@v2 to both ci.yml jobs (android-check and
cross-platform), matching the caching already present in
release-tauri.yml. This converts PR Rust compilation from full
rebuilds to incremental builds, saving an estimated 60-80% of
compile time per run.
- Add concurrency groups to all three workflows. PR pushes cancel
superseded runs to free concurrency slots; tag pushes and manual
dispatches are isolated by run_id to avoid mutually canceling
release builds. Previously, rapid PR pushes triggered redundant
parallel CI runs with no cancellation.
- Unify Node version to 22 across release-tauri.yml and
android-apk.yml, which were previously pinned to 20. This ensures
consistent build environments across all workflows.
Submodule and security hardening:
- Conditionally fetch the vendor/qwen-asr submodule only on macOS
jobs across all three workflows. The submodule is compiled
exclusively by build.rs on macOS (build_qwen_asr_macos); Linux,
Windows, and Android builds never reference it. Removing the
unconditional recursive checkout eliminates a network fetch and
a submodule-availability failure point on every non-macOS job.
- Set withGlobalTauri to false in tauri.conf.json. The frontend
exclusively uses @tauri-apps/api imports and never references the
window.__TAURI__ global, so disabling it removes an unnecessary
XSS attack surface without functional impact.
Dependency hygiene:
- Move @types/dompurify from dependencies to devDependencies in
package.json. Type declaration packages are build-time only and
should not ship in the production bundle.
* fix(ci): address review findings
* fix(ci): isolate manual CI workflow runs
---------
Co-authored-by: Chris233 <h-chris233@outlook.com >
2026-08-10 23:06:12 +08:00