Commit Graph
577 Commits
Author SHA1 Message Date
millionart 593cf766a2 fix: clean up Foundry transcribe failures 2026-05-07 11:15:12 +08:00
millionart 5c92e87bc6 fix: initialize coordinator hotkey fields on macos 2026-05-07 10:46:44 +08:00
millionart b1cf0d4b36 fix: cancel Foundry prepare before release 2026-05-07 10:39:51 +08:00
millionart 3d4d82f23d fix: cancel Foundry prepare with provider 2026-05-07 10:38:12 +08:00
millionart a54ca77e9b fix: guard Foundry release and cancel stale transcripts 2026-05-07 10:08:36 +08:00
millionart 2290a6cbee merge upstream main into windows local asr 2026-05-07 09:37:24 +08:00
millionart b3c5554da7 merge upstream main into windows local asr 2026-05-07 09:34:39 +08:00
TRIP 2c9dca531d Merge pull request #307 from appergb/fix/post-pr236-i18n-selectionask-ui
fix(i18n,ui): 修 PR #236 合并后 ja/ko 缺键 + SelectionAsk 启用开关右置
2026-05-07 09:33:17 +08:00
baiqing 1e04433443 fix(i18n,ui): 补 ja/ko 缺失 key + SelectionAsk 启用开关右置
PR #236 合并后两处后续修复:

1. ja.ts / ko.ts 缺 PR 引入的 7 个 comboRecord* 键和 1 个
   triggers.custom 键,导致 main 的 npm run build 直接 TS 报错。
   补齐后 tsc 通过。

2. SelectionAsk 划词追问页:触发快捷键卡片把"右上角状态徽标 +
   下方启用按钮"换成与 Style 页一致的右上角 36×20 toggle;
   保存历史卡片同步从底部 44×24 开关改成右上角同款 toggle。
   抽出 CardHeaderToggle 复用,跟 design_handoff Style 页对齐。
2026-05-07 09:27:59 +08:00
TRIP 98da5970bf Merge pull request #236 from LeslieLeung/feature/key-binding
feat: add configurable shortcut bindings
2026-05-07 09:24:33 +08:00
millionart 60b4d45823 fix: restore Foundry model on prepare failure 2026-05-07 09:03:51 +08:00
Chris233 69e566277d Merge pull request #264 from weikeyi/capsule-windows-shadow-inset
fix(capsule): center Windows pill within shadow inset
2026-05-07 00:04:25 +08:00
millionart eaab08148f fix: use Foundry ASR keep-loaded TTL 2026-05-06 23:38:54 +08:00
weikeyi 62005a6391 test(capsule): tighten host centering regex 2026-05-06 23:32:28 +08:00
weikeyi 94e9686a45 fix(capsule): restore non-windows box sizing contract 2026-05-06 23:18:16 +08:00
millionart 0421ced5be fix: split Foundry prepare and transcription timeouts 2026-05-06 23:06:38 +08:00
millionart 4dc0246022 fix: bound Foundry ASR transcription wait 2026-05-06 23:01:32 +08:00
millionart f358260866 merge upstream main into windows local asr 2026-05-06 21:28:41 +08:00
baiqing d5fa5b7df3 chore(release): 1.2.21
主要修复
─────────
- fix(windows): TSF DLL 静态链接 CRT,防 host 进程(QQ 等)私有
  MSVCP140 劫持导致切微软拼音崩溃 0xc0000005(PR #287 + #289 + Codex
  P1 review)。
- fix(windows): 移除 DisableThreadLibraryCalls — /MT 下 CRT 需要
  thread attach/detach 通知做 per-thread TLS 清理,禁用反而触发崩溃。
- fix(recording): 录音条出现时 mic 已 capture,按 Option 不再吞开头
  字。emit Recording 加 race 检查避免短按时覆盖 stop/cancel UI 信号。
- fix(startup): splash 透明背景 + 卡片化,避免长启动时左半白屏。
- fix(vault): keyring chunks 用稳定 account name —— macOS Keychain
  Always-Allow 不再因 UUID 轮换失效;不再每次 load 都尝试删 9 个
  legacy entries 触发 ACL 弹窗(与 PR #277 一起)。

新功能
─────────
- feat(security): 凭据从 plaintext JSON 迁移到平台 credential vault
  (macOS Keychain / Windows Credential Manager / Linux libsecret)。
  Windows 2560 byte 限制下用 chunked storage;partial-write safe。
  legacy 多源迁移完成后自动清理(PR #277)。

工程
─────────
- chore(ci): 暂时搁置 macos-13(Intel mac)matrix —— GH Actions
  runner pool 紧张到每次 dispatch queue 1-2h(已观测 4 次)。Apple
  Silicon 用户 dmg 仍发;Intel mac 用户保留 v1.2.20 dmg + Rosetta
  说明(issue #299)。
- chore(devex): CI 加 macOS 矩阵 + 5-way 版本号一致性校验 +
  scripts/bump-version.sh 一行同步 5 处版本号。.gitignore 加
  promo-openless-v2 / node_modules / dist / target 全局兜底(PR #294)。
- docs: docs/audit-2026-05-06.md 工程审计基线,覆盖架构 / UI bug /
  多端一致性 / IPC 1:1 校验 / P0/P1/P2 改进路径。
- chore: 9 个改进 issue (#295-#303) 跟踪 audit 列出的所有 P1/P2/P3
  问题。
2026-05-06 21:24:51 +08:00
TRIP b9adb6cf67 Merge pull request #294 from appergb/chore/ci-quality-gate-and-version-bump
chore(devex): CI 加 mac 矩阵 + version-triplet 校验 + bump-version.sh
2026-05-06 21:24:10 +08:00
millionart a1d6e59a1c fix: address Foundry ASR review feedback 2026-05-06 21:18:15 +08:00
baiqing 97fca4abab fix(devex): bump-version 修 BSD sed / lock 失败吞错 / package-lock 未同步
Codex 在 PR #294 上提了 3 个 P2,全部采纳:

P2-A: BSD sed 不支持 GNU 行号范围 0,/.../
  原 sed -E -i.bak "0,/^version = .../s//.../" 在 macOS 默认 BSD sed 上
  会 fail。换成 awk first-match 替换(mac BSD awk + GNU awk 都支持)。

P2-B: Cargo.lock 同步失败被 `|| true` 吞了
  原 cargo update -p openless ... || true 会让脚本继续,validate 又只
  校验 Cargo.toml 不校验 Cargo.lock。删 || true,让 set -euo pipefail
  在 cargo update fail 时立刻退出;同时 validate 加 Cargo.lock 校验。

P2-C: package-lock.json 未跟着同步
  npm 把 root version 也存在 package-lock.json 里(root + packages['']
  两处)。原脚本只 sed package.json 不更 lock,会让 npm ci 在 CI 出现
  EUSAGE。换成 npm version --no-git-tag-version --allow-same-version
  一次更两个文件。

ci.yml 的 verify step 也升级到校验 5 处一致:
  package.json / package-lock.json root+nested / tauri.conf.json /
  Cargo.toml / Cargo.lock 的 [openless] 包。

dry-run 已验证(用当前版本 1.2.20 跑一遍输出全部一致)。
2026-05-06 21:04:28 +08:00
millionart 091bbdc2f3 fix: release inactive Foundry runtime 2026-05-06 21:00:29 +08:00
baiqing 938c6a74b9 docs: 工程审计基线 (audit-2026-05-06.md)
完整工程审计报告(系统化逐项检查):
- 后端架构总评 + 5 个 P1/P2 优化点(coordinator/commands 拆分等)
- 前端 4 个 UI bug(tab 切换竞态、流式滚动打断 QA 等)
- 工程化水平评估 + 4 条改善(CI 门禁 / E2E / gitignore / 版本号)
  → 其中 3 条已在本 PR 实现(CI matrix + gitignore + bump-version 脚本)
- 多端逻辑与体验一致性表(macOS vs Windows 平台差异 vs 行为一致性)
- UI/后端 IPC 1:1 映射校验(全部命令前后端对齐 ✓)
- 改进建议汇总:P0 无;P1 5 项;P2 6 项
- 总结:项目整体健康,建议下迭代处理 coordinator 拆分 + 前端动画竞态

把这份基线纳入 git,让 main 留下 v1.2.20→v1.2.21 这一阶段的工程现状
锚点,后续审计有 baseline 对照。
2026-05-06 20:57:38 +08:00
millionart 4fa34b486e merge upstream main into windows local asr 2026-05-06 20:55:25 +08:00
baiqing b997f5fca2 chore(devex): CI 加 mac 矩阵 + version-triplet 校验 + bump-version.sh
审查反馈:
1. CI 缺质量门禁 — 仅 windows-latest 1 job,mac 端 cargo check 路径
   无 PR-time 验证,每次 release-tauri.yml 才暴露平台问题
2. .gitignore 不全 — promo-openless-v2/ 反复出现在 git status;
   node_modules / dist / target 没全局兜底
3. 版本号同步风险 — package.json + tauri.conf.json + Cargo.toml 三处
   人工改,每次发版都担心漏一处

改动:

A. .github/workflows/ci.yml
   - 单一 windows-tauri job → matrix(macos-latest + windows-latest)
   - mac job:cargo check + npm run build 验证跨平台编译
   - Windows job:保留原 preflight + ps1 tokenize
   - 新加 step:Verify version triplet stays in sync(两端都跑)—
     一旦 package.json / tauri.conf.json / Cargo.toml 三处 drift 立刻
     fail,给发版工程加 long-running guard

B. .gitignore
   - 加 promo-openless-v2/(已实测出现在 untracked)
   - 加 node_modules/ + dist/ + target/ 全局兜底(避免某子目录漏配
     时 build artifact 进 PR)
   - 加 .cargo/registry / .cargo/git 兜底

C. scripts/bump-version.sh(新文件)
   - 1 个参数(X.Y.Z),sed 同步改 3 个文件 + cargo update -p openless
     同步 Cargo.lock
   - 验证三处一致后输出后续 git 操作建议
   - 跨 macOS sed / GNU sed 兼容(-i.bak 后 rm)

下次发版:./scripts/bump-version.sh 1.2.21 一行搞定。
未来 PR 漏改版本号 CI 立刻 fail,不需要靠人记忆。
2026-05-06 20:55:03 +08:00
millionart 018cacad4f fix: skip Foundry transcription timeout 2026-05-06 20:48:26 +08:00
TRIP 095e3127bb Merge pull request #277 from H-Chris233/fix/issue-230-credential-storage-model
对齐凭据存储策略与威胁模型
2026-05-06 20:27:13 +08:00
TRIP c0118ee481 Merge pull request #290 from appergb/chore/skip-macos-13-runner
chore(ci): 暂时搁置 macos-13 (Intel mac) 构建 — GH runner pool 卡死
2026-05-06 20:27:08 +08:00
TRIP 08b5b882f1 Merge pull request #291 from appergb/fix/startup-splash-transparent
fix(startup): splash 透明背景 + 卡片化,避免长启动时左半白屏
2026-05-06 20:27:03 +08:00
baiqing 0505c2fc54 fix(vault): keyring chunks 用稳定名 + 不再每次 load 都删 legacy
用户实测:首次允许 Keychain 后仍反复弹窗十几次。

根因:
1. save_credentials 每次都生成新 UUID 作为 chunk account 命名前缀
   (credentials.v1.chunk.<NEW_UUID>.0/.1)。macOS Keychain 的「始终允许」
   绑定到 (binary 签名, entry 名),每次保存设置都让 chunk entry 名变 →
   之前 ACL 全失效 → 重新弹。
2. load_credentials / load_credentials_for_update 每次都调
   remove_legacy_keyring_credentials() —— 对 9 个旧 stable account
   各做一次 keyring delete。delete 在 macOS 上仍触发 ACL 检查,
   每次 load 都弹 9 次「OpenLess 想删除 X」。

合计每次 IPC 触发的 load 12 次弹窗,跟实测吻合。

修复(数据安全优先):

A. chunk account 命名稳定化
   - chunk_account(generation: Option<&str>, idx) 接受可选 generation
   - save_credentials 总用 None(稳定 credentials.v1.chunk.{idx})
   - 新 manifest 不写 generation 字段(serde skip_serializing_if=None)
   - 旧 manifest 仍可读(generation: Option<String>,含 UUID 时按旧格式
     读)→ 一次 save 后无缝迁移到新格式 + 删除旧 UUID chunks

B. partial-write 安全
   - 仍保留「先写所有 chunks,再写 manifest」顺序
   - chunks 数量减少时主动删除 idx >= new count 的旧 entries
   - 旧 UUID chunks 保留删除路径(迁移用)

C. legacy keyring delete 仅在 migration 路径触发
   - load_credentials / load_credentials_for_update 不再调用
     remove_legacy_keyring_credentials()
   - migrate_legacy_sources_for_update 内部仍调用一次 → 首次成功迁移
     就清干净;之后 load 不再尝试 delete 不存在的 entries
   - legacy 文件 delete 不需 ACL,best-effort 调用保留

D. 不影响 Windows
   - Windows Credential Manager 没有 ACL 弹窗概念
   - 仍走 chunked storage(2560 byte 限制需要分块)

修复后体感:
- 首次启动迁移:~3 次弹(manifest + 2 chunks),用户点 Always Allow
- 之后启动 / 保存设置:0 次弹(ACL 长期有效)
2026-05-06 20:18:02 +08:00
millionart 2a03f15292 Merge remote-tracking branch 'upstream/main' into codex/windows-local-asr
# Conflicts:
#	openless-all/app/src-tauri/Cargo.lock
#	openless-all/app/src-tauri/src/commands.rs
#	openless-all/app/src-tauri/src/coordinator.rs
#	openless-all/app/src-tauri/src/lib.rs
2026-05-06 20:15:12 +08:00
baiqing fa30161f52 fix(startup): splash 透明背景 + 卡片化,避免长启动时左半白屏
用户反馈:当启动时间较长时(凭据迁移 / 权限 probe / hotkey hook 还没
ready),窗口左侧出现白色矩形并显示「OpenLess 正在启动」,本应是纯
磨砂玻璃背景。

根因:main window 在 tauri.conf.json 是 transparent + macOSPrivateApi
(NSVisualEffectView vibrancy)。但 StartupShell 之前用:

    background: linear-gradient(180deg, rgba(245,245,247,0.96), ...)

96% 不透明渐变盖过 vibrancy。在窗口内容布局首帧或啥的时候,左侧 paint
StartupShell 浅灰,右侧未完成 vibrancy → 视觉割裂「左白右磨砂」。

修:StartupShell 容器改 background: transparent 让 vibrancy 全屏展开;
提示文字 + icon 用一个圆角 pill 卡片承载(rgba(255,255,255,0.55) +
backdrop-filter blur),跟 Capsule 视觉一致。
2026-05-06 20:05:46 +08:00
millionart 2d07493d40 feat: improve Foundry local ASR setup 2026-05-06 20:02:28 +08:00
baiqing b2868378bf chore(ci): 暂时搁置 macos-13 (Intel mac) 构建
GitHub Actions 把 macos-13 runner 标记为 deprecated,pool 容量紧张到
每次 dispatch 都 queue 1-2h 拿不到分配。已观测 4 次 release run
(25415755417 / 25417633813 / 25419948896 / 25420193625)均因 mac-13
卡 queue 整个 run conclusion 永远不变 success,阻塞自动化判断。

暂时把 macos-13 matrix 项注释掉:
- macOS arm64 (Apple Silicon) 仍发 dmg
- Windows x64 + Linux 不变
- Intel mac 用户在 v1.2.21+ 期间用 Apple Silicon dmg + Rosetta(性能稍降但可用)

恢复条件(任一):
- GH 把 macos-13 pool 容量恢复
- GH 提供 macos-14-x86_64 或 macos-15-large-x86_64 替代 runner
- 项目 self-host runner

恢复方法:删除注释符即可。
2026-05-06 19:49:45 +08:00
TRIP ab65432c1c Merge pull request #289 from appergb/fix/recording-no-swallow-first-words
fix(recording): 录音条出现时 mic 已 capture,不再吞开头字
2026-05-06 19:21:13 +08:00
TRIP 96ca96609f Merge pull request #287 from appergb/fix/windows-ime-static-crt
fix(windows-ime): 静态链接 CRT 防 host 进程 MSVCP140 劫持(修 QQ 切微软拼音崩溃)
2026-05-06 19:21:09 +08:00
baiqing 5c5b5758b6 fix(recording): emit Recording 加 race 检查,避免覆盖 stop/cancel
Codex P2 (PR #289):上一版我把 emit_capsule(Recording) 放到
stop_recorder_if_pending_start_stop 之后,且无条件 emit。这会让短按热键
(用户在 Recorder::start 仍在 cpal init 期间松开)的场景出现 UI 闪烁:
stop / cancel 路径已经发出 Transcribing / Cancelled,本行又把 UI 覆盖
回 Recording,并在 Volcengine 路径的 open_session().await 期间持续保持。

修复(按 Codex 建议):
1. emit 挪到 stop_recorder_if_pending_start_stop 之前
2. emit 之前在同一 lock 内检查 phase / pending_stop / cancelled / session_id;
   只有 recorder 真的会继续运行时才 emit
3. 不满足条件就让 stop / cancel 路径接管 UI 信号

不改变首次说话不丢字的修复目标(emit 仍在 Recorder::start 成功后),
只让 race 路径下的 UI 一致。
2026-05-06 19:13:50 +08:00
baiqing 02dd8c56ea fix(recording): 录音条出现时 mic 已 capture,不再吞开头字
用户反馈:按 Option 键后看到录音条,但开口的前几个字被吞掉。

根因:begin_session() 在 line 1128 立刻 emit_capsule(Recording),但
Recorder::start 还要再走 ~57 行(read creds / new ASR / new bridge /
acquire mute / cpal init),其中 cpal init 在 macOS 上有 50-200ms 启动
延迟。窗口期内:
- 视觉:录音条已显示
- 物理:mic 还没产生第一帧 PCM
- 用户开口的前几个字物理上无法被 capture(不是丢字,是没录到)

DeferredAsrBridge 已经能覆盖 "recorder 已开 → ASR 没连上" 的间隙(缓存
PCM 等 ASR attach 后按顺序后送),但 "录音条已显 → recorder 没开" 这段
之前没人覆盖。

修复(surgical):把 emit_capsule(Recording) 从 begin_session() 挪到
start_recorder_for_starting() 内部 Recorder::start 成功的 Ok 分支里。
三条 ASR 路径(Local Qwen3 / Whisper / Volcengine)共用同一函数,自动
受益。代价是用户按热键到看到录音条多 50-200ms 延迟,但「录音条出现 =
mic 100% 在 capture」体感诚实,开头不再丢。

ASR 慢连接的兜底逻辑(DeferredAsrBridge 按顺序缓冲 + attach 后 drain)
保持不变。
2026-05-06 19:09:32 +08:00
baiqing 901e9dfe3f fix(windows-ime): 移除 DisableThreadLibraryCalls — /MT 下需 thread 通知
Codex P1 (PR #287):DLL 改用 /MT 静态链接 CRT 后,仍调
DisableThreadLibraryCalls(instance) 会让静态 CRT 拿不到 DLL_THREAD_DETACH
通知,per-thread TLS 初始化/清理断裂 — 在 host 进程(QQ / Office /
微软拼音切换)创建新 input thread 时反而把这次想修的崩溃问题重新引回。

Microsoft 文档 DisableThreadLibraryCalls 备注明确:使用 static CRT 的
DLL 不应禁用 thread library calls。

修复:删除该调用;保留 g_module 缓存。
2026-05-06 19:07:54 +08:00
millionart f03499576e fix: show Foundry ASR option on Windows 2026-05-06 18:49:23 +08:00
millionart 05f4fce895 fix: gate Foundry local ASR to Windows 2026-05-06 18:34:11 +08:00
millionart 19977bc52e test(windows): add local ASR smoke mode 2026-05-06 18:14:21 +08:00
baiqing 80de07851c fix(windows-ime): 静态链接 CRT 防 host 进程 MSVCP140 劫持
用户反馈:在 Windows 11 切到微软拼音时 QQ (QQEX.exe v9.9.26.44725) 崩
0xc0000005,故障模块 D:\program\QQ\versions\<ver>\resources\app\
MSVCP140.dll @ 偏移 0x13080。

根因(DLL Hell 经典场景):
1. QQ 把私有版本的 MSVCP140.dll 放在 app/ 目录,DLL 搜索顺序优先于系统
2. ctfmon 切微软拼音 → 把所有已注册 TSF DLL 加载进 QQ 进程
3. 我们 OpenLessIme.dll 此前用 MSBuild 默认 RuntimeLibrary(=
   MultiThreadedDLL,动态链接 MSVCP140.dll/VCRUNTIME140.dll/UCRT)
4. 在 QQ 进程内被绑给 QQ 自带的旧版 MSVCP140 → 调 std::wstring /
   std::thread / std::mutex 等跑的是 QQ 那份 → ABI 行为漂移 → AV

修复:
- vcxproj 4 处 ItemDefinitionGroup(Debug/Release × Win32/x64)显式声明
  <RuntimeLibrary>MultiThreaded</RuntimeLibrary>(Release)/
  <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>(Debug)。
- DLL 自带 CRT 副本,QQ 私有 MSVCP140 劫持不到。
- DLL 体积 +~300 KB;DLL 内部 STL 不能跨边界共享,但我们 IPC 走 named
  pipe + JSON(C ABI 友好),不受影响。

不动的部分:
- TSF 接口本身已是 COM C ABI(vtable + COM-typed 参数),无需改
- 重量级 ASR/LLM/polish 早已在 OpenLess.exe 主进程,DLL 只做 TSF text
  service hooks + IPC(已合规"组件极简,IPC 通信"原则)

QQ 客观脆弱性已整理详细报告(桌面 PDF/DOCX + GitHub issue),用于上报
TSRC:app/ 目录下 MSVCP140 劫持系统 CRT、版本号目录嵌套混乱、无 IME
崩溃隔离机制、CRT 漂移。
2026-05-06 18:08:21 +08:00
millionart a2f56840e5 feat(ui): add Foundry local ASR model controls 2026-05-06 17:55:44 +08:00
millionart 71240e2c3d feat(ui): add Foundry local ASR provider 2026-05-06 17:28:52 +08:00
millionart 05e45b41fb feat(asr): route dictation through Foundry local Whisper 2026-05-06 17:02:16 +08:00
millionart 702e09405e feat(asr): expose Foundry local ASR status 2026-05-06 16:43:47 +08:00
millionart 28ffe03cbf feat(asr): add Foundry local Whisper provider 2026-05-06 16:16:08 +08:00
H-Chris233 1d04131bed Preserve strict credential gate for real regression mode
Real regression runs that explicitly pass -RequireCredentials should still fail fast when credentials cannot be confirmed. This keeps the real-ASR signal strict while leaving the default runtime smoke suite decoupled from legacy credentials.json.\n\nConstraint: default smoke suite must not depend on migrated plaintext JSON.\nRejected: Keep warning-only behavior in real regression mode | allows credential-missing runs to appear as valid real-ASR regressions.\nConfidence: high\nScope-risk: narrow\nDirective: Keep -RequireCredentials in windows-real-regression as a hard gate unless credential-vault probing is added.\nTested: git diff --check\nNot-tested: Running Windows PowerShell regression scripts in Linux environment.\nRelated: #230
2026-05-06 15:49:28 +08:00