十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Omi Windows 桌面端「What‘s New」更新日志体系解析:从 changelog Fragment 到丙烯酸 Toast 的完整链路

Omi Windows 桌面端「What‘s New」更新日志体系解析:从 changelog Fragment 到丙烯酸 Toast 的完整链路 Omi Windows 桌面端「Whats New」更新日志体系解析从 changelog Fragment 到丙烯酸 Toast 的完整链路【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend本篇技术指南聚焦 Omi本仓库Friend项目Windows 桌面端更新后「Whats New」更新日志功能的完整实现以 desktop/windows/changelog/README.md 为骨架结合whatsNew.ts运行时逻辑、InsightToast.tsx渲染层、appSettings.ts持久化存储与whatsNew.test.ts单元测试逐层展开。读完你将领会如何用极轻量的 JSON fragment 组织版本更新说明、如何用「版本号递增比对」实现仅真实更新才弹窗、全新安装静默基线的产品策略以及这一机制与 macOS 端的镜像关系与待迁移的演进路线。一、功能定位为什么需要一个独立的更新日志系统Omi 是看得见你的屏幕、听得见你的对话的 AI 桌面助手。当用户通过自动更新升级到新版本时产品希望第一时间告知新功能但又不希望打扰刚完成全新安装的用户。为此Windows 端建立了一套与 macOS 端完全镜像的changelog fragments更新日志碎片机制每个用户可见的功能变更对应一个 JSON 碎片文件放在unreleased/目录下应用启动时由主进程读取碎片与上次已展示过更新说明的版本号做比对只有版本号真实递增即发生了一次真正的更新时才把碎片内容渲染进共享的丙烯酸acrylicToast 窗口展示过的版本号被持久化同一版本永不重复打扰。该机制在仓库中的物理落点即 desktop/windows/changelog/README.md 及其 unreleased/ 碎片目录运行时实现位于desktop/windows/src/main/与desktop/windows/src/renderer/。二、碎片编写规范一个 JSON 文件描述一次用户可见变更2.1 目录与命名约定每个用户可见变更在unreleased/下新增一个碎片命名遵循YYYY-MM-slug.json格式年月 简短语义化 slug。截至当前仓库快照desktop/windows/changelog/unreleased/下已有 35 个碎片覆盖了 Phase 8 Windows 重构、Rewind 捕获质量、聊天面板、SSOT单一事实源、Linux 合成器等主题例如2026-07-phase-8-windows-redesign.json2026-07-rewind-capture-quality.json2026-08-chat-panel-background-refresh.json2026-08-ssot-ai-profile.json2026-09-external-app-setup-url.json2.2 数据 Schema与 macOS 端完全一致碎片使用与 macOS 应用相同的 JSON 结构两种写法均被接受// 写法一多变更数组推荐用于一个版本包含多条说明 { changes: [Short, user-facing sentence., Another change.] } // 写法二单行字符串 { change: single line }仓库中真实碎片 2026-07-phase-8-windows-redesign.json 展示了多变更数组的完整形态{ changes: [ A cleaner, Windows 11-native redesign — refined type, rounded surfaces, and native Mica window chrome., A neutral white accent throughout, matching the Omi brand (no more purple)., Search your screen history in Rewind — press CtrlF to jump back to any moment. ] }2.3 行文约束面向 360×168 丙烯酸 ToastREADME 明确给出了硬性排版约束碎片文案必须保持简短因为它们最终渲染在一个360×168 的丙烯酸 Toast 窗口渲染组件为 desktop/windows/src/renderer/src/components/insight/InsightToast.tsx中。从渲染源码可以看到Toast 卡片对变更列表做了slice(0, 3)截断——最多展示前 3 条完整列表通过一次点击「View release notes」按钮跳转。因此碎片规范天然要求把最重要、最用户可感知的变化放在数组最前面每条一句话说清变了什么。三、运行时机制whatsNew.ts的版本递增判定3.1 决策逻辑全貌核心运行时实现位于 desktop/windows/src/main/whatsNew.ts。其主函数maybeGetWhatsNew()用一段简洁的状态机决定本次启动是否弹 Toast并以副作用方式推进存储标记保证每个版本最多触发一次场景判定条件行为全新安装 / 该功能上线后的首次运行存储中lastShownChangelogVersion为null静默基线记录当前版本号不弹窗用户并非更新到这些说明真实更新存储版本号 当前构建版本号返回{ version, changes }载荷并记录当前版本同版本重复启动存储版本号 当前构建版本号返回null永不重弹无可用说明CHANGES数组为空返回null关键实现片段export function maybeGetWhatsNew(): WhatsNewPayload | null { const current app.getVersion() const stored getAppSettings().lastShownChangelogVersion if (stored current) return null // already shown for this build // Advance the marker regardless, so we never re-prompt for this version. setAppSettings({ lastShownChangelogVersion: current }) // Fresh install / first run after this feature shipped: baseline silently. if (stored null) return null if (CHANGES.length 0) return null return { version: current, changes: CHANGES } }注意「先推进标记、再决定是否弹窗」的微妙顺序即使本次因某些原因不展示标记也会被推进从而彻底杜绝重复提示never nags again。3.2 碎片 Schema 的解析容错whatsNew.ts中的changesFromFragment()负责把两种合法 Schema 归一为string[]function changesFromFragment(fragment: unknown): string[] { const raw fragment as { changes?: string[]; change?: string } if (Array.isArray(raw.changes)) return raw.changes if (typeof raw.change string) return [raw.change] return [] }非法结构静默降级为空数组不会让主进程崩溃——这与仓库整体畸形数据必须静默失败的防御式风格一致。3.3 当前构建期碎片来源过渡态由于 macOS 端的碎片合并脚本尚未移植到 Windows现阶段whatsNew.ts直接在构建时 import 单个未发布碎片将它们拼接为当次构建的变更集import phase8Fragment from ../../changelog/unreleased/2026-07-phase-8-windows-redesign.json import chatRefreshFragment from ../../changelog/unreleased/2026-08-chat-panel-background-refresh.json const CHANGES: string[] [ ...changesFromFragment(phase8Fragment), ...changesFromFragment(chatRefreshFragment), ]也就是说当前构建要展示哪些说明由这段 import 硬编码决定直到合并脚本落地后改为读取按版本编译好的文件详见第六节。四、持久化app-settings.json与lastShownChangelogVersion版本标记存储在主进程的轻量设置存储中实现在 desktop/windows/src/main/appSettings.ts。其设计要点以 JSON 文件形式落在 ElectronuserData目录app.getPath(userData)/app-settings.jsonlastShownChangelogVersion: string | null字段语义为其更新说明上次被展示的应用版本号null表示从未展示全新安装或功能上线前读取采用进程内缓存 磁盘兜底文件缺失或损坏时readFromDisk()捕获异常并返回全默认值永不抛出每次setAppSettings()写入都会同步更新内存缓存并回调订阅者onAppSettingsChanged保证生命周期标记跨重启可靠存活。该字段在sanitizeAppSettings()中的清洗规则为仅当磁盘值是合法字符串时保留否则一律规整为null即退回静默基线语义。五、渲染层InsightToast.tsx中的 Whats New 卡片碎片内容最终呈现在共享的丙烯酸 Toast 窗口中。InsightToast组件desktop/windows/src/renderer/src/components/insight/InsightToast.tsx是一个多用途消息宿主统一承载三类载荷insight主动式洞察insight:payloadmeeting会议检测通知Phase 5meeting:toastwhatsnew更新日志卡片Phase 8WhatsNewPayloadWhatsNewCard是更新日志卡片的专用实现结构清晰function WhatsNewCard({ p }: { p: WhatsNewPayload }): React.JSX.Element { return ( div classNameinsight-card onMouseEnter{...} onMouseLeave{...} div classNameinsight-head span classNameinsight-catWhatapos;s new/span button classNameinsight-x onClick{() window.omi.insightDismiss()}✕/button /div div classNameinsight-headlineNew in Omi {p.version}/div ul classNamewhatsnew-list {p.changes.slice(0, 3).map((c, i) li key{i}{c}/li)} /ul div classNamewhatsnew-actions button classNamemeeting-btn meeting-btn-primary onClick{() window.omi.whatsNewOpenNotes()} View release notes /button /div /div ) }几个值得注意的工程细节头部标题带版本号New in Omi {p.version}让用户一眼看到本次更新到达的具体版本Hover 暂停复用同一 IPCinsightHoverStart/insightHoverEnd与洞察、会议卡片共用Toast 的显示与自动消失完全由主进程统一掌控main owns visibility auto-dismiss启动竞态兜底组件挂载时先订阅whatsNewToast事件再拉取whatsNewGetPending待处理载荷——若 Toast 窗口加载期间恰逢启动即弹更新说明推送会落在订阅之前此兜底可避免载荷丢失AUMID 前置设置如 README 所述Toast 弹出前已设置应用用户模型 IDAUMID使打包后的系统通知正确归属于 Omi。六、测试验证whatsNew.test.ts的三条行为契约运行时逻辑由 desktop/windows/src/main/whatsNew.test.ts 用 Vitest 守护。测试通过替换electron模块的app.getVersion()返回值来驱动版本是否递增的判定并配合临时userData目录模拟磁盘状态覆盖了三个核心契约全新安装静默基线无存储版本时maybeGetWhatsNew()返回null但会记录当前构建版本——用户没有更新进这些说明因此不展示更新后只展示一次存储版本0.9.0 当前1.0.0时返回载荷version 1.0.0且changes非空随后存储推进到1.0.0下一次同版本启动返回null同版本不重复展示存储版本等于当前版本时直接返回null。这套测试把弹一次且仅弹一次的产品规则固化为可回归的机器契约是碎片系统可靠性的最后一道防线。七、演进路线待移植的 macOS 合并脚本与 CI 门禁README 明确记录了当前状态的边界与后续计划——macOS 端的两个配套脚本尚未移植到 Windowsdesktop-changelog.py发布时把unreleased/下的碎片合并编译为按版本的releases/version.jsoncheck-desktop-changelog.pyCI 检查脚本拒绝包含用户可见变更但未附任何碎片的 PR从流程上保证每个用户可见变更都有对应的 Whats New 说明。因此当前 Windows 端处于过渡态whatsNew.ts直接 import 单个未发布碎片见 3.3 节。按 README 的规划当 Windows 发布流水线落地后应依次完成移植碎片合并脚本生成按版本编译的releases/version.json加入 CI 门禁强制用户可见变更必须附带碎片将whatsNew.ts改为读取编译后的按版本文件替代当前的直接 import。这一碎片编写 → 发布合并 → 运行时版本比对 → 一次性展示 → CI 强制的闭环正是值得借鉴的桌面应用更新通知工程范式内容生产与展示解耦、版本语义驱动、绝不打扰重复、CI 兜底内容完整性。八、快速上手给贡献者的实践清单如果你要向当前仓库的 Windows 桌面端贡献一条用户可见变更请按以下顺序操作在 desktop/windows/changelog/unreleased/ 下新建YYYY-MM-slug.json使用{ changes: [...] }或{ change: ... }Schema文案保持简短面向 360×168 的丙烯酸 Toast若有多条说明最重要的放最前渲染层只展示前 3 条在 desktop/windows/src/main/whatsNew.ts 的 import 区把新碎片并入CHANGES数组当前过渡态做法运行 desktop/windows/src/main/whatsNew.test.ts 验证仅更新弹窗、仅弹一次契约不回归待合并脚本与 CI 门禁移植完成后第 3 步将改为发布时自动编译、运行时读取按版本文件。这一体系的价值在于用不到十行的主进程逻辑 若干 JSON 碎片就把版本更新告知这一高频产品需求做成了低维护、可审计、跨平台一致的标准化流程。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表