Skip to content

feat(history+polish): time-based retention + conversation-aware polish#355

Merged
appergb merged 3 commits into
betafrom
feat/history-retention-and-context-polish
May 8, 2026
Merged

feat(history+polish): time-based retention + conversation-aware polish#355
appergb merged 3 commits into
betafrom
feat/history-retention-and-context-polish

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented May 8, 2026

User description

Summary

回应「历史记录功能 + 对话感知 polish」需求。

功能 之前 之后
历史保留策略 仅 200 条硬上限 + 时间维度,超过 N 天的写入新条目时自动清理;与 200 上限并存
历史保留配置 Settings → 录音 → "历史保留天数"(0-365,默认 7)
Polish 上下文 单轮独立,每段听写互不感知 多轮 chat:把最近 N 分钟成功润色的转写作为 prior turns 喂给 LLM,让代词/未完整句子能正确解析
上下文窗口配置 Settings → 录音 → "对话上下文窗口(分钟)"(0-60,默认 5;0=关闭走旧路径)

设计

历史保留

  • `HistoryStore::append_with_retention(session, retention_days)`:写入时一次扫描裁掉 N 天前的条目,无后台轮询
  • `HistoryStore::recent_within_minutes(minutes)`:返回最近 N 分钟(newest-first,take_while 提前终止)
  • 老 `append()` 保留兼容(等价 retention_days=0)

对话感知 polish

  • `polish.rs::polish()` 多 `prior_turns: &[(String, String)]` 参数:空切片 → 走单轮老路径;非空 → 走 `chat_completion_with_polish_history` 构造 system + (user/assistant)... + 当前 user 多轮 chat completion
  • system prompt 末尾追加 `prompts::polish_context_instruction()`:明确告诉 LLM 历史 turns 不要复读——assistant 历史输出已经被插入用户文档,再输出就是重复
  • coordinator 主流水线 Polishing 阶段拉 `recent_within_minutes(prefs.window)` 作为 prior,过滤失败 session 避免喂噪声
  • 翻译 / Raw / repolish 主动跳过上下文(语义不合适)

提取小重构

  • 把 `chat_completion` 的 send/parse 抽成 `send_chat_request`,单/多轮路径共享 HTTP + 解析

顺手修的预存 bug(独立 commit `01e9f00`)

`types::tests::legacy_hotkey_trigger_still_produces_effective_key_codes` 跑测时 fail。跟本 PR 无关,但用户要求中途发现就修:

`HotkeyBinding` `#[serde(default)]` 结构级 default 让旧 prefs(无 `keys` 字段)反序列化后 trigger 跟 keys 不一致——trigger 被 JSON 覆盖成 RightControl,但 keys 仍是 Default 残留的 ["AltRight"]。effective_codes() 信任 keys 不 fallback 到 trigger,于是实际生效的快捷键跟用户当年选的对不上。

修法:`Default::keys = None`,让 effective_codes() 走 `legacy_trigger_code(trigger)` 跟 trigger 自动同步。

验证

  • `cargo check`:clean
  • `cargo test --lib`:135/135 pass(包括之前 fail 的 types::tests)
  • `npm run build`:tsc + vite 干净通过

不在本 PR 的部分

用户原 ask 还提了「连接速度优化 + 提示词排布工程」。这两块需要先 measure 再动(盲改可能让 polish 慢的更慢、prompt 改坏直接影响输出质量),留独立 PR。


PR Type

Enhancement, Bug fix, Tests


Description

  • Add history retention preferences

    • Prune expired sessions on write
  • Feed recent turns into polish

    • Skip translation, raw, and repolish
  • Add recording settings controls

    • Localize new labels and help text
  • Fix compatibility and tests

    • Preserve legacy hotkeys, update fixtures

Diagram Walkthrough

flowchart LR
  Settings["Settings recording panel"]
  Prefs["User preferences"]
  Coordinator["Session coordinator"]
  History["History store"]
  Polish["Conversation-aware polish"]
  LLM["LLM chat completion"]
  Settings -- "save prefs" --> Prefs
  Prefs -- "retention + window" --> Coordinator
  Coordinator -- "append_with_retention" --> History
  Coordinator -- "recent_within_minutes" --> History
  Coordinator -- "prior turns" --> Polish
  Polish -- "multi-turn request" --> LLM
Loading

File Walkthrough

Relevant files
Enhancement
7 files
commands.rs
Pass empty context to validation polish                                   
+1/-0     
coordinator.rs
Wire retention and context-aware polish flow                         
+38/-3   
persistence.rs
Prune old history during append                                                   
+42/-0   
polish.rs
Build multi-turn polish chat requests                                       
+204/-3 
types.rs
Add new user preference fields                                                     
+39/-2   
types.ts
Extend frontend preferences type definitions                         
+4/-0     
Settings.tsx
Add numeric controls for new settings                                       
+39/-0   
Documentation
5 files
en.ts
Localize new recording settings strings                                   
+4/-0     
ja.ts
Localize new recording settings strings                                   
+4/-0     
ko.ts
Localize new recording settings strings                                   
+4/-0     
zh-CN.ts
Localize new recording settings strings                                   
+4/-0     
zh-TW.ts
Localize new recording settings strings                                   
+4/-0     
Configuration changes
1 files
ipc.ts
Seed mock preferences with new defaults                                   
+2/-0     
Tests
1 files
stylePrefs.test.ts
Update preference fixture defaults for tests                         
+2/-0     

baiqing added 2 commits May 8, 2026 10:45
回应用户「历史记录功能 + 对话上下文 + 提示词调优」需求。

新增 2 个用户偏好(types.rs + UserPreferencesWire + Default + Deserialize 全套兼容):
- history_retention_days: u32(默认 7;0=不按时间清理仅受 200 上限)
- polish_context_window_minutes: u32(默认 5;0=关闭走原有单轮 polish)

后端:
- persistence.rs:
  - HistoryStore::append_with_retention(session, retention_days):写入新条目时
    顺手把超过 N 天的会话裁掉,不需要后台轮询
  - HistoryStore::recent_within_minutes(minutes):返回最近 N 分钟内的会话(newest-
    first,take_while 利用 newest-first 顺序提前终止)
  - 老 append() 保留,等价 append_with_retention(s, 0)
- polish.rs:
  - polish() 多一个 prior_turns 参数;不为空时走 chat_completion_with_polish_history
    构造 system + (user/assistant)... + 当前 user 多轮 chat completion
  - 把 chat_completion 的 send/parse 抽成 send_chat_request 复用
  - prompts::polish_context_instruction():明确告诉 LLM 历史 turns 仅作语义上下文,
    不要复读已经被插入到用户文档里的 assistant 输出
- coordinator.rs:
  - 主流水线在 Polishing 阶段拉 recent_within_minutes(prefs.window) 作为 prior_turns,
    过滤掉失败的 session(error_code/empty final_text)避免喂噪声
  - 翻译路径 / Raw 模式 / repolish 主动跳过上下文(语义不合适)
  - 3 个 history.append 改成 append_with_retention(session, prefs.history_retention_days)
- commands.rs / coordinator.rs:repolish / polish.rs::tests / commands.rs::testProvider:
  原 polish() 调用全部加 &[] 空 prior_turns 参数

前端:
- types.ts:UserPreferences 加 historyRetentionDays / polishContextWindowMinutes
- ipc.ts mockSettings + stylePrefs.test.ts mockPrefs:补默认值
- Settings.tsx Recording 区加 2 个 number input(裸 input + clamp,retention 0-365 天,
  context window 0-60 分钟)
- i18n 5 locale(zh-CN / zh-TW / en / ja / ko)补 4 个 key:
  historyRetentionLabel / Desc + polishContextWindowLabel / Desc

性能注意:retention 在 append 时 O(n) 一次扫描裁切;recent_within_minutes 使用
take_while 利用 newest-first 顺序提前终止,平均 O(window 内条目数) 不是 O(总历史)。

cargo check + commands::tests (30/30) + polish::tests (10/10) + npm run build 全 pass。
预先存在的 types::tests::legacy_hotkey_trigger 失败跟本 PR 无关(macOS 平台特有)。

不包含:连接 / 厂商 / 提示词排布优化(用户也提了)——那些需要先 measure 再动,
不能盲改,留给独立 PR。
…mismatch)

跑测试时发现 types::tests::legacy_hotkey_trigger_still_produces_effective_key_codes
fail,原因跟本 PR 无关,但用户要求中途发现 bug 顺手修。

Bug:HotkeyBinding 用 `#[serde(default)]` 结构级 default。反序列化时整个 struct
先按 Default 填充,JSON 字段覆盖。如果 Default 里 keys 预填具体 codes(macOS
Default ["AltRight"] / Windows ["ControlRight"]),那么旧 prefs 写
`{"trigger":"rightControl","mode":"toggle"}`(无 keys)反序列化后会变成:
  trigger = RightControl  ← JSON 覆盖
  keys = Some([HotkeyKey { code: "AltRight" }])  ← Default 残留,跟 trigger 不一致

effective_codes() 在 keys 是 Some 时直接信任 keys、不再 fallback 到
legacy_trigger_code(trigger),于是用户选的 trigger 跟实际生效的 keys 对不上。

修法:Default::keys = None。这样 keys 缺省时 effective_codes() 走 legacy_trigger_code
路径,跟 trigger 自动同步;JSON 显式写 keys 时仍可以覆盖。

types::tests 8/8 pass,全 lib 测试 135/135 pass。
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

PR Reviewer Guide 🔍

(Review updated until commit d55298e)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected

…tests

用户的核心顾虑:上下文感知 polish 不能让 LLM 把上文吐出来。PR #355 设计了
两层防御(chat structure + system prompt 显式指令),但**没写过 explicit 测试**
盯死这条不变量——回归就听天由命。这次把它锁住。

把 chat_completion_with_polish_history 里 inline 的 messages 构造抽成纯函数
build_polish_history_messages(system_prompt, prior_turns, user_prompt) → Vec<Value>,
方便可测,行为零变化。

新增 4 个 polish::tests:

1. build_polish_history_messages_empty_prior_falls_back_to_two_messages
   prior 空时只剩 [system, user],跟单轮 chat_completion 等价

2. build_polish_history_messages_orders_prior_oldest_to_newest_then_current
   入参 prior_turns 是 newest-first(match HistoryStore::recent_within_minutes
   返回顺序),chat 需要 oldest-first 时间序——验证 reverse 没漏。
   顺序错了 LLM 会看到「未来→过去→当前」错乱时间轴,对话就废了。

3. build_polish_history_messages_keeps_polished_text_at_assistant_role
   关键不变量:历史 polish 必须挂 role=assistant,**不能**误挂 user。
   typo 把它放进 user role 会让 LLM 当成新输入再润色 → 输出复读上文,
   直接违反"不复读"目标。这个 test 把这条锁死,重构时一改就 fail。

4. polish_context_instruction_explicitly_forbids_repeating_prior_assistant_output
   第二层防御:仅靠 chat structure 不够(一些模型在长上下文里仍可能 echo prior turns)。
   验证 system prompt 末尾追加的指令含「不要 / 复读 / assistant-or-已经整理 /
   当前最新」四组关键词,文案可以改但语义不能丢。

cargo test --lib:139/139 pass(135 之前 + 4 新增),完全无回归。
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit d55298e

@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 8, 2026

@claude 检查一下这段代码是否能正常合并。

@claude
Copy link
Copy Markdown

claude Bot commented May 8, 2026

Claude finished @appergb's task in 3m 17s —— View job


合并检查完成 ✓

  • 分析请求
  • 检查合并冲突(git diff origin/beta...HEAD)
  • 审查核心 Rust 变更(persistence.rs、polish.rs、coordinator.rs、types.rs)
  • 审查前端变更(Settings.tsx、types.ts、ipc.ts)
  • 审查 i18n 变更
  • 审查测试变更
  • 总结合并可行性

合并可行性:✅ 可以合并

分支干净,基于最新 beta(merge-base = 6c5eee6),无冲突。以下是逐层检查结果:


persistence.rs

append_with_retention 逻辑正确:

  • retention_days == 0 时完全退化成旧 append(向后兼容)
  • 时间裁剪先做、再受 HISTORY_CAP 约束,顺序正确
  • 日期解析失败 → unwrap_or(true) 保守保留,避免数据丢失 ✓

recent_within_minutes 使用 take_while 依赖 sessions 是 newest-first 的不变量,与 appendinsert(0, session) 一致 ✓

一个微小边角情况:若 sessions 中间有 created_at 格式损坏的条目,take_while 会提前终止(unwrap_or(false) = 不在窗口内),导致上下文被提前截断。由于 created_at 始终由 chrono::Utc::now().to_rfc3339() 写入,实际不可能触发,可接受。


types.rs

  • 两个新字段 (history_retention_days/polish_context_window_minutes) 在 UserPreferencesUserPreferencesWireDefault impl、Deserialize 的 4 处都做了同步 ✓
  • HotkeyBinding::default 的 bugfix(keys = None)逻辑正确:serde 结构级 #[serde(default)] 在旧 prefs 反序列化时,keys 字段缺失会用 Default,改成 Noneeffective_codes()legacy_trigger_code(trigger) 与 trigger 自动同步 ✓

coordinator.rs

  • repolish 显式传 &[] ✓(单条手动重润色不应混入其他会话上下文)
  • prior_turns 构造只在 !translation_active && mode != PolishMode::Raw && window > 0 时生效 ✓
  • 过滤 error_code.is_none() && !s.final_text.trim().is_empty(),避免喂入失败会话的 raw 兜底文本 ✓
  • prior_turnsappend_with_retention 之前拉取,当前会话不会把自己喂给自己 ✓
  • end_session 有两处 append 调用(早退出路径 + 正常路径),两处都已更新 ✓
  • end_qa_session 也同步更新 ✓

polish.rs

  • build_polish_history_messages 将 newest-first 的 prior_turns 反转成 oldest-first 后组装 chat messages,顺序正确 ✓
  • prior_turns 中每对展开为 (role=user, role=assistant):raw 走 user_prompt 包装,polished 直接作为 assistant 输出,LLM 自然不复读 ✓
  • send_chat_request 抽取共用 HTTP + 解析路径,消除重复 ✓
  • 4 个新单元测试将核心不变量锁死(空 prior、时序、role 正确性、system prompt 含禁止复读指令)✓

小样式问题(不影响合并):polish_context_instruction() 中间夹了几个 Unicode 转义(\u{4EE5} = 以,\u{4FBF} = 便,等),与同字符串中的直接中文字符风格不一致,但功能完全正确。


前端(Settings.tsx / types.ts / ipc.ts)

  • clamp 函数范围限制正确(0–365 天、0–60 分钟)✓
  • parseInt(raw, 10) 带进制、NaN 检查 ✓
  • mock defaults 与 Rust 默认值一致(7 天、5 分钟)✓

微小 UX 注意(不影响功能):用户清空输入框再输入新值时,每次 onChange 都会立即保存(空字符串 → 存 0),会短暂把功能置为"关闭"状态。对实际使用影响极小,可在后续 PR 中用 onBlur 优化。


i18n

zh-CN、zh-TW、en、ja、ko 五个文件均添加了 4 个新 key,各语言翻译均为实质性翻译(非复制),位置插入到正确的 recording 命名空间内 ✓


测试

stylePrefs.test.ts 仅在 previousPrefs 中添加新字段,nextPrefs 用 spread ...previousPrefs 继承,无需单独修改 ✓
cargo test --lib 135/135 pass,npm run build 干净 ✓(来自 PR 描述,代码层面无理由怀疑)


总结

代码架构清晰,沿用现有模块纪律(leaf modules 不跨模块、新逻辑通过 coordinator 串联),两大功能(时间保留 + 多轮上下文)均有充分的单测覆盖,边角情况处理保守稳妥,无安全风险,无合并冲突。可以合并到 beta。

@appergb appergb merged commit b86c8d7 into beta May 8, 2026
4 checks passed
@appergb appergb deleted the feat/history-retention-and-context-polish branch May 8, 2026 03:42
appergb added a commit that referenced this pull request May 8, 2026
* feat(history+polish): time-based retention + conversation-aware polish

回应用户「历史记录功能 + 对话上下文 + 提示词调优」需求。

新增 2 个用户偏好(types.rs + UserPreferencesWire + Default + Deserialize 全套兼容):
- history_retention_days: u32(默认 7;0=不按时间清理仅受 200 上限)
- polish_context_window_minutes: u32(默认 5;0=关闭走原有单轮 polish)

后端:
- persistence.rs:
  - HistoryStore::append_with_retention(session, retention_days):写入新条目时
    顺手把超过 N 天的会话裁掉,不需要后台轮询
  - HistoryStore::recent_within_minutes(minutes):返回最近 N 分钟内的会话(newest-
    first,take_while 利用 newest-first 顺序提前终止)
  - 老 append() 保留,等价 append_with_retention(s, 0)
- polish.rs:
  - polish() 多一个 prior_turns 参数;不为空时走 chat_completion_with_polish_history
    构造 system + (user/assistant)... + 当前 user 多轮 chat completion
  - 把 chat_completion 的 send/parse 抽成 send_chat_request 复用
  - prompts::polish_context_instruction():明确告诉 LLM 历史 turns 仅作语义上下文,
    不要复读已经被插入到用户文档里的 assistant 输出
- coordinator.rs:
  - 主流水线在 Polishing 阶段拉 recent_within_minutes(prefs.window) 作为 prior_turns,
    过滤掉失败的 session(error_code/empty final_text)避免喂噪声
  - 翻译路径 / Raw 模式 / repolish 主动跳过上下文(语义不合适)
  - 3 个 history.append 改成 append_with_retention(session, prefs.history_retention_days)
- commands.rs / coordinator.rs:repolish / polish.rs::tests / commands.rs::testProvider:
  原 polish() 调用全部加 &[] 空 prior_turns 参数

前端:
- types.ts:UserPreferences 加 historyRetentionDays / polishContextWindowMinutes
- ipc.ts mockSettings + stylePrefs.test.ts mockPrefs:补默认值
- Settings.tsx Recording 区加 2 个 number input(裸 input + clamp,retention 0-365 天,
  context window 0-60 分钟)
- i18n 5 locale(zh-CN / zh-TW / en / ja / ko)补 4 个 key:
  historyRetentionLabel / Desc + polishContextWindowLabel / Desc

性能注意:retention 在 append 时 O(n) 一次扫描裁切;recent_within_minutes 使用
take_while 利用 newest-first 顺序提前终止,平均 O(window 内条目数) 不是 O(总历史)。

cargo check + commands::tests (30/30) + polish::tests (10/10) + npm run build 全 pass。
预先存在的 types::tests::legacy_hotkey_trigger 失败跟本 PR 无关(macOS 平台特有)。

不包含:连接 / 厂商 / 提示词排布优化(用户也提了)——那些需要先 measure 再动,
不能盲改,留给独立 PR。

* fix(types): HotkeyBinding default keys = None (legacy trigger / keys mismatch)

跑测试时发现 types::tests::legacy_hotkey_trigger_still_produces_effective_key_codes
fail,原因跟本 PR 无关,但用户要求中途发现 bug 顺手修。

Bug:HotkeyBinding 用 `#[serde(default)]` 结构级 default。反序列化时整个 struct
先按 Default 填充,JSON 字段覆盖。如果 Default 里 keys 预填具体 codes(macOS
Default ["AltRight"] / Windows ["ControlRight"]),那么旧 prefs 写
`{"trigger":"rightControl","mode":"toggle"}`(无 keys)反序列化后会变成:
  trigger = RightControl  ← JSON 覆盖
  keys = Some([HotkeyKey { code: "AltRight" }])  ← Default 残留,跟 trigger 不一致

effective_codes() 在 keys 是 Some 时直接信任 keys、不再 fallback 到
legacy_trigger_code(trigger),于是用户选的 trigger 跟实际生效的 keys 对不上。

修法:Default::keys = None。这样 keys 缺省时 effective_codes() 走 legacy_trigger_code
路径,跟 trigger 自动同步;JSON 显式写 keys 时仍可以覆盖。

types::tests 8/8 pass,全 lib 测试 135/135 pass。

* test(polish): lock down "no echo prior context" with 4 explicit unit tests

用户的核心顾虑:上下文感知 polish 不能让 LLM 把上文吐出来。PR #355 设计了
两层防御(chat structure + system prompt 显式指令),但**没写过 explicit 测试**
盯死这条不变量——回归就听天由命。这次把它锁住。

把 chat_completion_with_polish_history 里 inline 的 messages 构造抽成纯函数
build_polish_history_messages(system_prompt, prior_turns, user_prompt) → Vec<Value>,
方便可测,行为零变化。

新增 4 个 polish::tests:

1. build_polish_history_messages_empty_prior_falls_back_to_two_messages
   prior 空时只剩 [system, user],跟单轮 chat_completion 等价

2. build_polish_history_messages_orders_prior_oldest_to_newest_then_current
   入参 prior_turns 是 newest-first(match HistoryStore::recent_within_minutes
   返回顺序),chat 需要 oldest-first 时间序——验证 reverse 没漏。
   顺序错了 LLM 会看到「未来→过去→当前」错乱时间轴,对话就废了。

3. build_polish_history_messages_keeps_polished_text_at_assistant_role
   关键不变量:历史 polish 必须挂 role=assistant,**不能**误挂 user。
   typo 把它放进 user role 会让 LLM 当成新输入再润色 → 输出复读上文,
   直接违反"不复读"目标。这个 test 把这条锁死,重构时一改就 fail。

4. polish_context_instruction_explicitly_forbids_repeating_prior_assistant_output
   第二层防御:仅靠 chat structure 不够(一些模型在长上下文里仍可能 echo prior turns)。
   验证 system prompt 末尾追加的指令含「不要 / 复读 / assistant-or-已经整理 /
   当前最新」四组关键词,文案可以改但语义不能丢。

cargo test --lib:139/139 pass(135 之前 + 4 新增),完全无回归。

* fix(icons): pad bundle icon to Apple HIG ~10% transparent margin (#354)

issue #354:在 macOS 26 以下系统,Dock 里的 OpenLess 图标比其他 app 大约 25%。

根因:原 icon.png 内容 100% 填满 1024×1024 画布,没留 Apple HIG 推荐的
~10% 透明 padding。macOS 26 自带 Liquid Glass squircle 容器会自动套圆角 +
裁切,掩盖了这个问题;但 macOS 11-15 把 icon PNG 原样渲染到 Dock,
所以视觉尺寸明显比标准 app 大一圈。

修法:
- 用 PIL 把 1024×1024 master 缩到 820×820 居中、四周各 102px 透明 padding
  (内容占比 ≈ 80%,符合 Apple HIG 约定)
- 重新生成 Tauri bundle 的 5 个 PNG:icon.png / 32×32 / 64×64 / 128×128 / 128×128@2x
- 用 iconutil 重新打包 icon.icns(含 16/32/128/256/512 + @2x 共 10 张)
- 不动 frontend public/AppIcon.png——那个是 React UI 内部用的小图(14-56px +
  CSS borderRadius),padding 反而会让它在固定容器里显得偏小

校验:python PIL 读新 icon.png,bbox 显示画布 512×512、内容 416×416 居中、
四周 padding 各 48px,内容占比 81.2%——接近 80% 推荐值。

不影响 macOS 26 渲染:Liquid Glass 看到的视觉内容仍是同一张图,
只是周围多了透明像素,Apple 自动 squircle 会无视它。

---------

Co-authored-by: baiqing <lbx12309@icloud.com>
appergb pushed a commit that referenced this pull request May 8, 2026
…ound mode)

回应用户「Windows 端开机启动时不弹软件界面、自动后台启动」需求。

新 pref start_minimized: bool,默认 false 不破坏现有行为。打开后所有
启动路径都不弹主窗口(包括开机自启 + 手动启动),App 仅在菜单栏 / 托盘
运行;用户从托盘进入主窗口。Windows 开机自启场景用得多——本来想要
后台 + 托盘,不想被主窗口打扰。

设计选择:不区分"自启动 vs 手动启动"——开关一开则所有启动统一静默。
理由:避免 argv parsing + 重新注册 autostart 带来的复杂性(tauri-plugin-
autostart 的 args 是 init() 时静态设的、动态切需要重注册)。开关明确
打开 = 接受所有启动都从托盘进。

实现:
- types.rs: UserPreferences 加 start_minimized 字段(含 UserPreferencesWire +
  Default + Deserialize 全套兼容)
- lib.rs setup hook: 读 coordinator.prefs().get().start_minimized;为 true
  时跳过 main.show()。OPENLESS_SHOW_MAIN_ON_START=1 仍保留老的强制 show
  路径(dev 用),优先级高于 prefs
- 前端 types.ts / ipc.ts mockSettings / stylePrefs.test.ts: 加默认 false
- Settings.tsx Recording 区在 AutostartRow 下加 Toggle
- i18n 5 locale (zh-CN / zh-TW / en / ja / ko) 加 startMinimizedLabel +
  startMinimizedDesc 两个 key

顺手修预存 bug(跟 PR #355 副 commit 同源——本 branch 没含那个修复):
HotkeyBinding default keys=None,避免旧 prefs 反序列化时 trigger / keys
不一致。types::tests 8/8 pass。

不在本 PR:Windows IME 切换还原偶发不还原 bug——需要 Windows 日志
+ 复现条件才能定位,盲改可能引入新 bug。已请求用户提供
%LOCALAPPDATA%\OpenLess\Logs\openless.log + 系统版本 + IME 信息。

cargo test --lib: 135/135 pass。npm run build: tsc + vite 干净。
appergb added a commit that referenced this pull request May 8, 2026
…tart) (#357)

回应用户「Windows 端开机启动时不弹软件界面、自动后台启动」需求。

新 pref start_minimized: bool,默认 false 不破坏现有行为。打开后所有
启动路径都不弹主窗口(包括开机自启 + 手动启动),App 仅在菜单栏 / 托盘
运行;用户从托盘进入主窗口。Windows 开机自启场景用得多——本来想要
后台 + 托盘,不想被主窗口打扰。

设计选择:不区分"自启动 vs 手动启动"——开关一开则所有启动统一静默。
理由:避免 argv parsing + 重新注册 autostart 带来的复杂性(tauri-plugin-
autostart 的 args 是 init() 时静态设的、动态切需要重注册)。开关明确
打开 = 接受所有启动都从托盘进。

实现:
- types.rs: UserPreferences 加 start_minimized 字段(含 UserPreferencesWire +
  Default + Deserialize 全套兼容)
- lib.rs setup hook: 读 coordinator.prefs().get().start_minimized;为 true
  时跳过 main.show()。OPENLESS_SHOW_MAIN_ON_START=1 仍保留老的强制 show
  路径(dev 用),优先级高于 prefs
- 前端 types.ts / ipc.ts mockSettings / stylePrefs.test.ts: 加默认 false
- Settings.tsx Recording 区在 AutostartRow 下加 Toggle
- i18n 5 locale (zh-CN / zh-TW / en / ja / ko) 加 startMinimizedLabel +
  startMinimizedDesc 两个 key

顺手修预存 bug(跟 PR #355 副 commit 同源——本 branch 没含那个修复):
HotkeyBinding default keys=None,避免旧 prefs 反序列化时 trigger / keys
不一致。types::tests 8/8 pass。

不在本 PR:Windows IME 切换还原偶发不还原 bug——需要 Windows 日志
+ 复现条件才能定位,盲改可能引入新 bug。已请求用户提供
%LOCALAPPDATA%\OpenLess\Logs\openless.log + 系统版本 + IME 信息。

cargo test --lib: 135/135 pass。npm run build: tsc + vite 干净。

Co-authored-by: baiqing <lbx12309@icloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant