Commit Graph
781 Commits
Author SHA1 Message Date
baiqing 80e840341b fix(capsule): 入场出场动画加慢加曲线 + thinking 字号/颜色重做
用户在 v1.3.1-5 装机后反馈:
1. 胶囊入场效果不错但希望"再慢一点 + 曲线感"
2. 出场动画"看不到" —— 240ms 太快感知不到
3. thinking 字体"不明显",希望字大 / 色亮 / 滑动清楚

改动:
- @keyframes capsule-in: .26s → .38s,cubic-bezier(.16,.86,.32,1.18)
  spring overshoot 更强,"从中心冒出向左右生长"更弹更曲线
- @keyframes capsule-out: .24s → .36s,cubic-bezier(.55,.06,.68,.19)
  慢启动 + 加速收尾的平滑曲线,让用户能看清"左右收缩 + 下移 + 淡出"
- EXIT_ANIM_MS: 240 → 360 同步加长,避免定时器先于动画结束 unmount

thinking 配色(用户拍板,参考 d 项):
- fontSize 14 → 17(更大)
- fontWeight 500 → 700(更粗)
- 两侧底字:浅亮黄 #FCD34D (amber-300)
- 中段扫光:深蓝 var(--ol-blue) (≈ #2563EB)
- 浅黄暖底 + 深蓝扫光对比强烈但不刺眼,扫光滑过感清晰
2026-05-12 18:18:05 +08:00
baiqing 1a810c1c67 chore(release): bump version to 1.3.1-5 (Beta)
PR #423 合并后 bump。本版本相对 v1.3.1-4-beta 累积:

[3 个 dev task] (worktree-isolated dev agents + 3 个 reviewer)
- 胶囊动画:进入从中心冒出向左右生长,退出左右收缩 + 淡化 + 下移
- Windows 千问3 ASR 灰显 disabled + 不可激活提示 banner
- 5 个 SVG 重画:translate / vocab / history / overview / selectionAsk

[review feedback fix]
- Capsule EXIT_ANIM_MS / INITIAL_VISIBLE_STATE 抽 const
- Qwen3 disabled 区加 inert 让键盘 Tab 跳过
- overview icon 加 sparkline 数据线区分 layout icon
- selectionAsk 气泡尾巴拉到 y=23 防 viewBox 24 底裁切

[用户实机 surface]
- Vocab 词条大椭圆真根因:父 flex minHeight 拉伸子 item,加
  alignSelf:flex-start 阻止
- Windows 原生顶栏 vs 玻璃色差:caption color 0xFFFFFF → 0x00F7F5F5
  跟 glass 起始色一致;glass alpha 0.78 → 0.92 压色差

[polish prompt 反降级]
- Structured task block 加"不可降级到轻度润色"和"多个组合需求归类规则"
2026-05-12 17:46:25 +08:00
TRIP 784f947cf3 Merge pull request #423 from Open-Less/fix/v1.3.1-5
fix(v1.3.1-5): 胶囊动画 + Qwen3 灰显 + 5 SVG 重画 + 6 项 Windows 视觉修复 + polish 反降级
2026-05-12 17:45:27 +08:00
baiqing 76e0723613 fix(polish): Structured prompt 加强反"降级到轻度润色" + 组合需求归类规则
用户报 DeepSeek V4 Flash 走 Structured 模式时仍只做轻度润色(标点 + 断句
+ 去口癖然后输出一段连贯段落),没有按双层 list 结构化输出。模型能力较
弱时容易把"清晰结构"理解成"清楚地表达"而非"双层归类"。

加两条新规则到 Structured task block:
1. **不可降级到轻度润色** —— 明确禁止只补标点然后输出连贯段落,最低
   输出形态是双层 list。即使原文听起来连贯,事项 ≥3 都必须双层化。
2. **多个组合需求处理规则** —— 用户原话:"当用户提出多个组合需求时,
   要分别归入不同大类,并且按照顺序把这些组合需求做结构化整理"。
   写进规则:按语义/领域分大类,按口述顺序排,每个大类用 (a)(b)(c)
   子项,不允许合并丢失或重排到错误大类。

加在原有 # 任务(清晰结构) 标题之后、"**重要前提**"之前。前后顺序与
其他段落兼容,不动 ROLE_BLOCK / COMMON_RULES / OUTPUT / 示例。
2026-05-12 17:32:54 +08:00
baiqing 35d53b8be2 polish: 集成 review 反馈 + 用户新 surface 的 Windows 视觉修复
review 阶段标的 4 个 High 全部处理,加上用户在 v1.3.1-4 装机后新报的 2 个
Windows 视觉问题,本 commit 一次性收:

[review-capsule High]
- Capsule.tsx 抽 EXIT_ANIM_MS / INITIAL_VISIBLE_STATE 两个 const,去掉
  `240` magic number + `isTauri ? 'idle' : 'recording'` 字面量重复
- 修正退出动画调度的 race 描述注释(cleanup clearTimeout 阻止 fire,
  不是"定时器仍会触发")

[review-qwen3 High]
- LocalAsr.tsx Windows Qwen3 disabled wrapper 加 `inert` HTML5 属性,
  让键盘 Tab 也跳过 disabled 区域(仅靠 pointerEvents:none 不挡键盘 +
  aria-disabled 不传给后代)。两个 wrapper 都加。@ts-expect-error
  注释解释为何这里需要绕过 TS lib.dom 旧版未收录 inert 属性。

[review-icons 2 High]
- Icon.tsx `overview`: 在三个 dashboard tile 顶部加 sparkline 数据线
  区分 layout icon(之前几乎一样,14px nav 视觉无法分辨)
- Icon.tsx `selectionAsk`: 气泡尾巴 y=24 → y≈23,避免 strokeLinecap
  round + strokeWidth 1.5 出 viewBox 底边被裁

[用户新 surface — Vocab 词条大椭圆]
- Vocab.tsx VocabChip 加 `alignSelf: 'flex-start'`。真根因(之前 PR
  #422 误判为 button user-agent appearance):父 flex 容器 minHeight: 80
  让 flex item 默认 align-self: stretch 把单个 chip 拉伸到 80px 高,
  borderRadius:999 渲染成超大椭圆。alignSelf:flex-start 阻止拉伸。

[用户新 surface — 顶栏 vs 玻璃色差]
- lib.rs DWMWA_CAPTION_COLOR 从纯白 0xFFFFFF → 0x00F7F5F5
  (rgb 245,245,247) 跟 WindowChrome glass linear-gradient 起始色一致
- WindowChrome.tsx glass alpha 0.78 → 0.92(PR #422 为加强玻璃感降的,
  现在为压缩色差升回去,玻璃感由 backdrop-filter blur+saturate 提供)

后续:用户希望调研"完全取消 Windows 原生顶栏(像微信那样自绘)"——
属于 v1.3.1-6 级别 large rewrite,单独追。
2026-05-12 17:31:41 +08:00
baiqing f44eb5958c feat(icons): redraw translation / vocab / history / selectionAsk SVGs 2026-05-12 17:26:52 +08:00
baiqing a981815b8b feat(localasr): Windows 端千问3 ASR 改为灰显 disabled + 提示 2026-05-12 17:26:52 +08:00
baiqing ad6cd93b10 feat(capsule): center-grow entry + contract-fade exit animation 2026-05-12 17:26:52 +08:00
baiqing a7a9284db6 chore(release): bump version to 1.3.1-4 (Beta)
PR #422 合并后 bump。本版本相对 v1.3.1-3-beta 累积修复:
- Windows 默认字号 'large'(fontScale.ts UA 检测)
- Windows 原生标题栏底色刷成白色,与 sidebar 视觉统一(DWM CAPTION_COLOR)
- 全平台玻璃统一:WindowChrome 撤销 PR #419 留下的"Windows 100% opaque +
  无 backdropFilter"分支,两平台用同一半透明 background + blur saturate(190%),
  alpha 0.92 → 0.78 让玻璃感更明显但不过透
- Vocab 词条大圈再次根治:global.css button reset 补加 outline:none /
  min-width:0 / min-height:0 / box-sizing:border-box
- polish ROLE_BLOCK 撤销 b2325a27 回滚,恢复 7e60bdb5 8-条规则状态
- polish ROLE_BLOCK 「意图难判」规则改为强制结构化(用户拍板的新版)
2026-05-12 17:00:05 +08:00
TRIP ec55d9e509 Merge pull request #422 from Open-Less/fix/v1.3.1-4-multi-tweaks
fix: v1.3.1-4 Windows 字号/顶栏色/玻璃 + Vocab 大圈 + polish 回滚
2026-05-12 16:59:24 +08:00
baiqing 76a4a4131f fix(polish): ROLE_BLOCK"意图难判"规则改为强制结构化
旧版(7e60bdb5 引入):"意图难以判断 → 只做句子层面整理(标点、断句、
口癖去除)"——这条 safety net 在 Structured 模式下会让 LLM 退回 Light/Raw
行为,导致"清晰结构"模式对意图不明的输入不输出双层 list。

新版(用户拍板):意图难判时**强制结构化整理**,输出必须与当前 mode 的
结构要求一致,同时贴近原意不扩写。这样:
- Structured 模式:意图模糊也强制归类成双层 list
- Light / Raw 模式:仍按各自 task block 走(不会强制结构化,因为它们的
  task block 明确写了"保留原句顺序"等约束)

ROLE_BLOCK 其他 7 条规则不动。
2026-05-12 16:48:53 +08:00
baiqing 9e62dfe271 fix: v1.3.1-4 multi-tweaks(字号 / 顶栏色 / 玻璃 / 词条 / polish 回滚)
5 个用户反馈一次性收:

1. Windows 默认字号放大
   fontScale.ts readFontScale() 检测 navigator UA 含 Windows 时新装默认
   返回 'large'(1.1x zoom),已存 localStorage 偏好的用户不受影响。

2. Windows 顶栏白色,与左侧 sidebar 视觉统一
   lib.rs 重新引入 apply_windows_caption_color,用 DWM API DwmSetWindowAttribute
   DWMWA_CAPTION_COLOR=35 (Win11 22H2+) 把原生标题栏底色刷成 0x00FFFFFF。
   pre-22H2 Win 静默失败仅 warn。

3. 全平台玻璃效果统一 & 略浊
   WindowChrome.tsx 撤销 PR #419 留下的"Windows 100% opaque background +
   去 backdropFilter"分支(那是 Win sidebar 完全无玻璃感的根因)。两个
   平台改用同一份半透明 background(alpha 从 0.92 降到 0.78)+ blur
   var(--ol-glass-blur-strong) saturate(190%),让 sidebar 透过磨砂底板。
   Windows 配合 apply_mica + tauri.conf transparent:true 透出 Mica。

4. Vocab 词条大圈再次尝试根治
   global.css button reset 在 appearance:none 基础上再加 outline:none /
   min-width:0 / min-height:0 / box-sizing:border-box。Windows Chromium
   user-agent style 包含上述四项默认值,单一个 appearance:none 不够覆盖
   全部。键盘焦点指示走 .ol-focus-ring + :focus-visible box-shadow,
   不被 outline:0 影响。

5. polish.rs ROLE_BLOCK 撤回 b2325a27 回滚
   用户确认 13:08 之前最近的 polish.rs commit(20756f7e,含 7e60bdb5
   refine)表现正常。我之前 b2325a27 误以为 7e60bdb5 是问题源把 ROLE_BLOCK
   改回 v1.2.24-9-beta 状态,反而离用户认可的版本更远。改回 7e60bdb5
   8-条 ROLE_BLOCK 状态。
2026-05-12 16:39:03 +08:00
baiqing b227b69a03 chore(release): bump version to 1.3.1-3 (Beta)
PR #421 hotfix 合并后 bump。本版本相对 v1.3.1-1-beta-tauri 累积修复:
- Windows 主窗口交还原生 Win11 chrome(修 PR #419 删自定义标题栏后无法
  拖/关/最小化的卡死状态)
- Vocab 词条 Windows 大圈(global.css button appearance:none)
- polish "清晰结构"模式输出退化成单段(ROLE_BLOCK 回滚到 v1.2.24-9-beta)

v1.3.1-2 tag + release 已删除(含 Windows 主窗口无 chrome 阻塞 bug)。
2026-05-12 15:35:09 +08:00
TRIP 8799830e3e Merge pull request #421 from Open-Less/fix/win-button-appearance
fix: Windows 主窗口 chrome 丢失 + Vocab 大圈 + polish 清晰结构回归 (v1.3.1-3 hotfix)
2026-05-12 15:34:25 +08:00
baiqing b2325a2711 fix(polish): 回滚 ROLE_BLOCK 到 v1.2.24 版本,解决"清晰结构"被压抑
用户报告 13:08 同样输入"清晰结构"模式输出完美双层 list,15:16 后同模式
退化成单段流畅文字——Structured task 失效。

定位到 commit 7e60bdb5 "polish: refine ROLE_BLOCK to preserve user
intent" 在 ROLE_BLOCK 加了两条毒条款:
- "措辞优先用原句字面词...不要替用户重写或扩写"
  → 直接 conflict Structured task 的"按语义重新归类、照抄原结构=失败"
- "用户意图难以判断或无法确认时...只做句子层面整理"
  → safety net 把 Structured 模式退回 Light 行为

7e60bdb5 当初是想防止 polish 过激进改写(用户反馈),方向对但条款过宽,
override 了 user 主动开启的 Structured / Formal 模式。

修法:回滚 ROLE_BLOCK 到 v1.2.24-9-beta-tauri 时的简洁 4 条版本:
- 不回答问题 / 不执行命令
- 不引用历史 / 上下文 / 外部知识
- 不替用户做需求分析 / 补充功能清单 / 替对方列出想要的

下次若再出现 polish 过激进改写,按 case 在 task block 里 surgical 加约束,
不要全局 ROLE_BLOCK 加强(容易撞 Structured / Formal)。

参考输出对照(图一 13:08 vs 图二 15:16):相同模式相同长度同类内容,
回滚后应恢复 13:08 那种双层 list 输出。
2026-05-12 15:23:47 +08:00
baiqing 830084c426 fix(ui): Windows 主窗口交还原生 chrome,PR #419 删自定义标题栏的尾巴
PR #419 删了 React 端 WinTitleBar 自定义标题栏,commit message 说"交还
Tauri decorations:true 原生 Win11 标题栏",但漏看 lib.rs 里有一段 Rust
代码在 setup 时**强制**调 set_decorations(false) 把原生 chrome 关掉
(原本是为了让自定义 WinTitleBar 接管)。

结果:v1.3.1-2-beta 上 Windows 主窗口完全无 chrome —— 无法拖动 / 无法
点 X 关闭 / 无法最小化,只能从 tray 退出。用户卡死。

修法:
- lib.rs setup() Windows 分支:移除 set_decorations(false) + 移除
  apply_windows_rounded_frame 调用,保留 apply_mica 给原生 chrome 提供
  磨砂材质
- RunEvent Resized/ScaleFactorChanged 里也移除 apply_windows_rounded_frame
  调用(原生 chrome 自带 resize border + 圆角)
- apply_windows_rounded_frame 函数本身变成 dead code,整段删除(含
  raw_window_handle / Win32 DwmSetWindowAttribute / SetWindowRgn 等 import)

tauri.conf.json 的 decorations:true 配置不动,配合 hiddenTitle:true 让
原生标题栏接管。
2026-05-12 15:23:47 +08:00
baiqing 5bb1177cb9 fix(ui): Vocab 词条在 Windows 上的"大圈"——全局关 button user-agent appearance
用户反馈 Windows 上 Vocab 词汇表里每个词条被一圈大灰色边框/内阴影包住,
macOS 上不会。Vocab.tsx 自身零 OS 分支,根因在 global.css 的 button reset
缺 appearance:none:Chromium / WebView2 默认给 <button> 应用 OS-native 外观
(outset 边框 + 内阴影 + min-width),在 Vocab 词条这种由父级 span 的
padding 决定外形的嵌套 button 上整圈就露出来;macOS WKWebView 对
appearance:auto 处理较弱所以看不出来。

修法是 global.css button reset 加 appearance:none + -webkit-appearance:none,
一行修整仓。所有现有 button 都自己 inline 重写了背景/边框/圆角,关掉
user-agent appearance 不会改变它们的视觉。
2026-05-12 15:13:03 +08:00
baiqing a2a944ea31 chore(release): bump version to 1.3.1-2 (Beta)
PR #419 已合并到 beta,UI 完整版(Windows 原生 chrome / 胶囊缩小 /
自定义下拉 / a11y 焦点指示 + 键盘 scrollIntoView + 视口 clamp)相比
上一轮 1.3.1-1 commit (90b35057) 累积了实质改动,bump patch-build
号到 1.3.1-2 区分。

6 处版本号同步:package.json / package-lock.json (root + nested) /
tauri.conf.json / Cargo.toml / Cargo.lock。
2026-05-12 14:58:08 +08:00
TRIP 993bb90dd3 Merge pull request #419 from Open-Less/fix/windows-ui-417-418
fix(ui): Windows 原生 chrome / 胶囊缩小 / 自定义下拉 (#417 #418)
2026-05-12 14:54:37 +08:00
baiqing 6c7598a858 fix(a11y): SelectLite 键盘高亮自动滚动 + popover 横向 viewport clamp
pr-agent #419 第二轮 review 指出的两个 focus areas:

1. Keyboard scroll:长 dropdown 超过 280px 时 ArrowUp/Down 切换 highlight
   不会把高亮项 scroll into view,键盘用户看不到当前选中。新增 useEffect
   监听 highlight 改变,找到 data-option-index 对应 DOM 元素后
   scrollIntoView({ block: 'nearest' }),已可见的项不会被强行滚动。

2. Viewport clipping:popover 用 trigger.left 作 anchor,没有横向边界
   clamp。窗口右边的 select 弹出后可能溢出屏幕。positionPopover 改成测
   真实 popover 宽度(首次开打用 trigger 宽度估),然后把 left clamp 到
   [8, viewport - width - 8] 区间。

不动 keyboard 导航 / disabled 处理 / vertical flip 等已 verified 行为。
2026-05-12 14:28:19 +08:00
baiqing 70917cb027 fix(a11y): SelectLite / SwitchLite 加键盘焦点指示
pr-agent #419 review 指出两个 button 都用 outline:none 关掉了浏览器默认
焦点 ring 却没替代——键盘 Tab 时用户看不到当前焦点在哪。和 _atoms.tsx
Collapsible 的 pr-agent #407 是同一类问题。

修法:新增 .ol-focus-ring class,:focus-visible 时上 2px 半透明蓝
box-shadow(不是 outline,因为 inline style 的 outline:none 会盖掉
class 里的 outline,但盖不掉 box-shadow)。:focus-visible 只在键盘
focus 时生效,鼠标点击保持干净。
2026-05-12 14:02:48 +08:00
baiqing 8a6ac8b308 fix(ci): 补齐 package-lock.json 的 version 字段对齐
90b35057 bump 到 1.3.1-1 时漏改了 package-lock.json 的 root 与
nested version 字段(都还是 1.3.0),CI "Verify version sync
across 5 files" 卡死所有平台,本 PR 的 build / check 步骤根本
没机会执行。

手动同步到 1.3.1-1,与 package.json / tauri.conf.json /
Cargo.toml / Cargo.lock 对齐。本地复跑 CI 第一步的 node -p 校验
全部一致。
2026-05-12 13:48:44 +08:00
baiqing 5bf6350fd2 fix(ui): Windows 原生 chrome / 胶囊缩小 / 自定义下拉 (#417 #418)
- WindowChrome: 移除 Windows 端自定义标题栏和 resize handles,
  交还 Tauri decorations:true 原生 Win11 标题栏,修复 X 按钮重叠
  与圆角处的黑边/白线
- Capsule (#417): Windows pill 196×52→180×44,textWidth 104→88,
  视觉密度与 macOS 对齐
- SelectLite (#418): 重写为受控下拉组件(portal popover, 键盘导航
  Arrow/Enter/Esc, 视口翻转, a11y combobox/listbox),替换 11 处
  native <select> 以避开 Win32 ComboBox 直角丑框
- SettingsModal: 删除"个性化"中重复的"界面语言"入口,功能保留在
  "设置 → 语言"分区;5 个 locale 同步清理 modal.personalize.language
- SwitchLite: 加 outline:none 解决 Windows 上点击后的黑色焦点框
- global.css: 移入 ol-select-pop 关键帧;不再用全局 outline:none,
  以保留 _atoms.tsx Collapsible 的键盘 outline (pr-agent #407)
2026-05-12 13:34:08 +08:00
baiqing 90b3505794 chore(release): bump version to 1.3.1-1 (Beta)
First beta after Stable 1.3.0. Carries the Settings modularization refactor
(PR #416). Tagged as v1.3.1-1-beta-tauri to trigger the release-tauri.yml
Beta-channel build (prerelease=true, manifest filenames carry -beta suffix
so the Stable in-app updater endpoint cannot pick this up).
2026-05-12 12:50:16 +08:00
TRIPandbaiqing 6baca19e05 refactor(settings): split Settings.tsx into per-section modules + simplify Advanced labels (#416)
Settings.tsx (2835 → ~2150 lines) split by logical responsibility: each tab
now lives in src/pages/settings/. Pure mechanical extraction — no behavior change.

- settings/shared.tsx     — SettingRow, Toggle, inputStyle, AsrPresetId
- settings/AdvancedSection.tsx
- settings/ShortcutsSection.tsx
- settings/PermissionsSection.tsx (incl. PermissionPill / HotkeyStatusPill / WindowsImeStatusPill)
- settings/LanguageSection.tsx
- settings/AboutUpdateControl.tsx
- Settings.tsx keeps RecordingSection + ProvidersSection (their helper tangle
  is large; follow-up PR), re-exports Toggle / AboutUpdateControl so
  SettingsModal's existing imports keep working.

Advanced settings labels: shortened verbose copy across zh-CN / zh-TW / en /
ja / ko. "启用流式输入" → "流式输入", "同步写入剪贴板" → "同步到剪贴板",
desc / hint blocks trimmed; the toggle already conveys enable/disable so the
verb prefix was redundant.

Verified: tsc clean, vite build green, cargo check green, cargo test --lib
222/222 passing.

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-12 12:48:31 +08:00
TRIP 71f2792f09 Merge pull request #415 from H-Chris233/fix/issue-413-streaming-sse-edges
修复流式 SSE UTF-8 切分与部分输入丢失
2026-05-12 10:58:47 +08:00
H-Chris233 20756f7e93 Keep streamed output consistent across SSE edge cases
Streaming LLM output can split UTF-8 codepoints across HTTP chunks, and unicode typing can fail after a prefix has already reached the focused app. The stream path now decodes SSE bytes incrementally and records only confirmed typed prefixes so history and clipboard match what appeared on screen.

Constraint: Issue #413 requires fixing both streaming polish and QA SSE paths plus partial-delta typing loss.

Rejected: Decode each response chunk independently | valid UTF-8 can be split by HTTP frame boundaries.

Rejected: Keep full delta on typing error | it records text that may never have reached the target app.

Confidence: high

Scope-risk: moderate

Directive: Do not re-enable mutating final postprocess for already_streamed text without proving screen/history/clipboard consistency.

Tested: cargo test --manifest-path src-tauri/Cargo.toml --lib

Tested: cargo check --manifest-path src-tauri/Cargo.toml

Tested: git diff --check
2026-05-12 10:32:57 +08:00
baiqing 8ea4e8932f chore(release): bump version to 1.3.0 (Stable) 2026-05-12 10:28:07 +08:00
baiqing e90fe9f7b1 chore(release): correct beta version to 1.3.0-1 (MSI requires numeric pre-release)
上一条 1.3.0-BETA 在 Windows MSI 打包阶段被 Tauri 拒绝:MSI ProductVersion
只接受 \"MAJOR.MINOR.BUILD\" + 数字 pre-release(≤ 65535)。BETA 字面被
canonicalize 时报错 \"optional pre-release identifier in app version must be
numeric-only\"。

按仓库历史 (1.2.24-7/8/9) 同体例改为 1.3.0-1,表示 1.3.0 的第 1 个 Beta。
2026-05-12 09:56:20 +08:00
baiqing 7136cf55cc chore(release): bump version to 1.3.0-BETA 2026-05-12 02:04:32 +08:00
TRIP d4162cf9cc Merge pull request #412 from Open-Less/pr/streaming-cross-platform
feat: cross-platform streaming polish output (Win/Linux/macOS)
2026-05-12 02:02:57 +08:00
baiqing ceda94e73b fix(streaming): clipboard saves the final_text users actually saw
pr-agent #412 二次反馈 \"Clipboard Mismatch\":原来无条件先写 polish 完整 text
到剪贴板,再决定 typer 是否中途失败 → typer 中途失败时屏幕 / history 是
partial typed_text,但剪贴板是完整 polish,Cmd+V 会粘出用户从未见过的内容。

修复:先把 final_text 算出来(typer 失败时 = typed_text,正常时 = 完整 polish),
然后剪贴板、history、返回值统统用同一个 final_text,三处保持一致。

测试:cargo test --lib 222 passed。
2026-05-12 01:33:41 +08:00
baiqing a8ae91c63b fix(streaming): keep history = typed_text + fallback when zero chars typed
pr-agent #412 反馈两条都修:

1. \"Missing fallback\" —— typer 在第一字就失败(最常见:session 开始时已处
   于 macOS Secure Input,或 SendInput / enigo 拒绝),已往返流式但 typed_chars=0。
   旧逻辑仍返 already_streamed=true → 上层跳过 inserter → 用户看不到任何内容。
   新逻辑:typed_chars=0 且 typer_failure 存在时,回退到一次性 inserter 路径
   兜底,让 polish 文本通过正常 insertion 写出。

2. \"Wrong final text\" —— SSE 中途失败但已落字(typed_chars > 0),旧逻辑给
   history 写 raw.text 而屏幕显示 partial polish,二者分叉。新逻辑:typer 持续
   累积 typed_text(屏幕实际落字内容),history 与屏幕保持一致 —— 写 typed_text,
   polish_error 注明 \"streaming polish failed mid-stream after N chars\"。

实现:typer 任务返回值由 (typed_chars, first_failure) 变为 (typed_text, first_failure),
顶层用 typed_text.chars().count() 派生 typed_chars,并把 typed_text 在两个分支
都用上。

测试:cargo test --lib 222 passed。
2026-05-12 01:33:41 +08:00
baiqing 44f1b94c32 feat: cross-platform streaming polish output (Win/Linux/macOS)
让润色 LLM 的 SSE chunk 边到达边逐字模拟键盘事件落到光标,用户感知到的
处理时延显著降低(第一个 token 即开始落字)。Opt-in,不开等价于历史行为。

后端(src-tauri/src/)
- unicode_keystroke.rs(新):跨平台 Unicode 按键合成
  - macOS:CGEvent + 切到 ABC 输入源(规避 CJK/日文 IME 拦截 Unicode 事件)+
    Secure Input 探测;TIS 调用强制调度到主线程,规避 macOS 14+ TSM 断言。
  - Windows:SendInput(KEYEVENTF_UNICODE),绕过 TSF / IME,不切输入法。
  - Linux(实验):enigo Keyboard::text。X11 / XTest 稳定;Wayland 看 compositor
    给不给 libei 权限,失败回落由调用方处理。
- polish.rs:OpenAI-compatible provider 新增 polish_streaming + 共用 SSE 解析
  skeleton(与 QA streaming 同款);Codex provider 返 not-implemented 让上层降级
- coordinator.rs:StreamingPolishOutcome { Streamed, UnsupportedFallback, Failed }
  + polish_or_passthrough_streaming 分发器
- coordinator/dictation.rs::run_streaming_polish:
  · 切到 ABC(macOS)→ spawn_blocking typer 串行读 mpsc → 调流式润色 →
    drop tx → typer drain 退出 → 恢复输入源
  · 中途取消 / typer 失败 / Secure Input 启用:drain 不爆,已流出去的字保留
  · 流式成功:可选写回剪贴板(streaming_insert_save_clipboard,默认 on)
  · 流式失败:已流的部分保留,未流时回落到 raw 一次性
  · end_session 的 cancel 检查识别 already_streamed=true 走完收尾(撤销不掉)
- types.rs:UserPreferences 新增 streaming_insert(默认 false)+
  streaming_insert_save_clipboard(默认 true),Wire/Deserialize/Default 三处同步
- lib.rs:mod unicode_keystroke

前端(src/)
- lib/types.ts + ipc.ts:UserPreferences 同步两字段 + mock 默认值
- lib/stylePrefs.test.ts:测试 fixture previousPrefs 补两字段
- pages/Settings.tsx:AdvancedSection 加流式 Card(Toggle ×2),按平台分发 hint
  文案(mac / win / linux 三套)
- i18n/{zh-CN,en,ja,ko,zh-TW}:advanced 新增 8 个 streamingInsert* key,5 个
  locale 完全对齐

验证范围
- macOS host:cargo check + cargo test --lib (222 pass) + npm run build (tsc + vite)
- Windows/Linux cfg 分支只走过 cargo check(cross-target 验证依赖 CI runner)
2026-05-12 01:33:41 +08:00
TRIP af07795e25 Merge pull request #407 from Open-Less/pr/settings-vocab-collapsible
refactor(ui): Collapsible groups in Settings & Vocab
2026-05-12 01:25:41 +08:00
baiqing 50daab11e2 fix(a11y): expose Collapsible expanded state + keyboard focus
pr-agent #407 二次反馈:toggle button 缺 aria-expanded(屏幕阅读器无法判断
当前组是否展开),并且 outline: 'none' 把浏览器默认 keyboard focus indicator
也抹掉了(Tab 切换时丢失视觉焦点)。

修复:
- 加 aria-expanded={open}
- 移除 outline: 'none',让浏览器默认 focus ring 显示出来
2026-05-12 00:55:26 +08:00
TRIP 1f11e2574b Merge pull request #408 from Open-Less/pr/capsule-thinking-shine
feat(capsule): animated thinking shine indicator
2026-05-12 00:32:33 +08:00
TRIP 6a1986e0c5 Merge pull request #409 from Open-Less/pr/hotkey-debounce-250ms
fix(hotkey): 250ms debounce on pressed-edge dispatch
2026-05-12 00:32:13 +08:00
TRIP 080fd9c155 Merge pull request #411 from Open-Less/pr/docs-and-empty-asr-zh
docs: refresh CLAUDE.md + localize empty-ASR capsule message
2026-05-12 00:31:55 +08:00
TRIP 051e058838 Merge pull request #410 from Open-Less/pr/polish-role-block-refine
polish: refine ROLE_BLOCK to preserve user intent
2026-05-12 00:31:13 +08:00
baiqing e44dcbc7f1 fix(a11y): make collapsed Collapsible content non-tabbable
pr-agent #407 反馈:grid-template-rows: 0fr 把内容视觉裁掉,但内部的 input /
button / Toggle 仍 mounted 且 tabbable —— 键盘用户折叠 Section 之后仍能 tab
到不可见的控件,屏幕阅读器也会朗读。

修复:内容容器 inert={当未展开} + aria-hidden={当未展开}:
- inert 把整个子树从 tab 顺序、点击事件、a11y 树里同时移除
- aria-hidden 配合 inert 给保守的 AT 兜底

React 18 types 没收 inert,用 spread { inert: '' } 绕过 TS。Chromium 102+ /
Safari 15.4+ 支持,Tauri WebView 远高于此基线。
2026-05-12 00:27:14 +08:00
baiqing f5d9288716 refactor(ui): Collapsible groups in Settings & Vocab
把 Settings/Recording 与 Vocab 三段从单一长 Card 切成可折叠分组,缓解
内容下沉时整段 reflow / overflow 的拥挤感。

新组件:
- _atoms.tsx::Collapsible — grid-template-rows 0fr↔1fr 高度过渡(Chromium
  117+ 解析 1fr 为内容真实高度,比 max-height 固定大值稳);右上角 chevron
  旋转 90° 标示展开
- embedded prop:嵌在 padding=0 的父 Card 里时只画底部分隔线,无独立 border

Settings/RecordingSection:
- 原单 Card 拆为 1 个主 Card + 3 个 Collapsible(插入与剪贴板 / 历史与上下文 /
  启动)
- 滚动容器加 paddingBottom: 16 防 Card 底部 shadow 被裁
- 同步把若干 desc 文案缩短一句,避免 Collapsible 折叠展开时的高度抖动

Vocab:
- 原 3 段 div padding=18 改用 Collapsible(embedded),词条区域 defaultOpen
- 标题从 strong + tip div 改为 Collapsible 自带的 title + desc props

i18n(5 个 locale 全平等更新):
- 新增 4 个 key:vocab.sectionTitle / settings.recording.{insertGroupTitle,
  historyGroupTitle, startupGroupTitle}
- 同步缩短若干 recording 区 desc 文案
2026-05-11 23:45:23 +08:00
baiqing d52c6cda05 feat(capsule): animated thinking shine indicator
把 transcribing / polishing 阶段的胶囊从原来的"三个圆点 + 文案"换成
扫光的 thinking 文字效果:

- 移除 ProcessingDots 组件
- 文字字号 11 → 14,字重 500,扫光 linear-gradient + background-clip: text
- 进入 transcribing / polishing 的头 2 秒走 0.9s/cycle 快速扫光(提示「刚开始」),
  之后切回 2.4s 稳态。React 副作用切 duration 不重启动画,会平滑减速
- 切换 state 时多一道 220ms 淡入(cap-state-enter)让用户更容易感知
- 5 个 locale 的 capsule.thinking 文案统一为 'thinking'(小写英文),与扫光字面
  视觉一致,避免不同语言长度差影响排版

CSS keyframes 改名 cap-dot → cap-shine,并加 cap-state-enter。
2026-05-11 23:41:29 +08:00
baiqing 60ab2418bd fix(hotkey): 250ms debounce on pressed-edge dispatch
避免微动开关回弹 / 用户手抖双击造成的空转写报错和 ASR session 抢资源:
相邻 < 250ms 的 press 边沿直接丢弃,记 log。

- coordinator.rs: Inner 新增 last_hotkey_dispatch_at: Mutex<Option<Instant>>
- coordinator/dictation.rs: HOTKEY_DEBOUNCE 常量 + handle_pressed_edge 入口检查

与 hotkey_trigger_held 互补:held 防 press-without-release,本检查防
press-release-press 三连过快。每个有效边沿都会更新时间戳;用户正常使用
(不会快于 4 次/秒)不会触发。
2026-05-11 23:39:43 +08:00
baiqing 2384351ad8 docs: refresh CLAUDE.md + localize empty-ASR capsule message
CLAUDE.md:
- 模块表加上 coordinator 拆分(dictation/qa/resources)、coordinator_state、qa_hotkey
  与三套并行 hotkey 监听(hotkey / combo_hotkey / qa_hotkey + global_hotkey_runtime)
- 新增 Q&A pipeline 章节,记录 panel 路由、capsule sweep、selection 3-tier fallback、
  selection 4000 char 截断与多轮 messages 行为
- 新增 Insertion paths 章节,区分跨平台默认路径与 Windows IME-IPC 路径
- 顶部 adjacent docs 段落补 AGENTS.md / README.zh.md / USAGE.md 指引

dictation.rs:
- 空转写场景 capsule 文案 "ASR returned empty transcript" → "没有识别到语音",
  与界面其他位置一致。line 907 的内部 Err 字符串保留英文(属于上层日志/调用方
  消费的内部 error code,不直接对用户显示)
2026-05-11 23:37:42 +08:00
baiqing 7e60bdb511 polish: refine ROLE_BLOCK to preserve user intent
把 polish 提示词从"严苛不允许"语气改回贴近用户原意的整理姿态:

- 先分析用户意图,再贴合原本句子做语法整理与必要的结构化
- 措辞优先用原句字面词;理解到的意图用来贴近原话,而不是替用户重写或扩写
- 不创作 / 不补充用户没说过的内容
- 转写里若有未解决问题或待确认事项,全部列为条目保留,不省略也不替用户判断
- 用户意图难以判断时不强行推断,改为只做句子层面整理(标点 / 断句 / 口癖去除)
- 不引用任何会话历史 / 外部知识 / 模型记忆,每次请求独立任务

行为差异:相对于已发布版本,新增"列出未解决问题"规则;移除"补充功能清单"
那一条(与新的"列为条目保留"语义已经覆盖)。
2026-05-11 23:35:04 +08:00
Chris233 e3a6c44d4d Merge pull request #405 from weikeyi/fix/issue-298-wix-glob
fix(windows-ci): WiX 工具按 WixTools* 通配查找,避免 Tauri 升级后路径失效
2026-05-11 17:23:48 +08:00
weikeyi 58c229dace fix(windows-ci): WiX 工具按 WixTools* 通配查找,避免 Tauri 升级后路径失效
Windows MSI Repair 之前硬编码 `C:\Users\22933\AppData\Local\tauri\WixTools314\light.exe`,Tauri 升级到新 WiX 版本(如 WixTools315)后路径不存在,Repair 步骤直接挂。

改为 WixTools* glob,按数字后缀降序回退到名称降序,取最新可用版本。同步更新 windows-package-msvc.ps1::Find-WixTool 和 release-tauri.yml 的 Repair 步骤;保留 -sice:ICE80、NSIS/MSI 两轮 build、bash shell 等 Windows CI 红线不变。

补 4 条 windows-package-msvc.test.mjs 防回归断言:禁止 WixTools314 出现在脚本/workflow,要求两边都按 WixTools* glob 查找。

Refs: #298
2026-05-11 16:50:20 +08:00
baiqing cc215fdce3 chore(release): bump version to 1.2.24-9 (Beta-9) 2026-05-11 13:19:17 +08:00
Chris233 69978a3c47 Merge pull request #404 from H-Chris233/fix/issue-402-llm-thinking-toggle
feat: 增加渠道级 LLM 思考模式开关
2026-05-11 11:48:13 +08:00