update.json 一直发布四个关于安装包的字段(installerName / installerUrl / installerSha256 / signed),而设置页的 UpdateManifest 类型只声明了 version 和 releaseUrl,另外两个字段发布出来却没有任何人消费。结果是:在安装包未签名的当下,SHA256 是用户唯一的完整性防线,服务端早已算好,却要用户自己去官网翻。 现在发现新版本的对话框会显示:signed 为 false 时给出明确警告(SmartScreen 会拦截、uiAccess 失效导致候选窗无法浮在提权程序之上),以及 Get-FileHash 命令和应得到的摘要,可选中复制。 「不做后台自动检查」是 PRIVACY.md 明示的隐私设计,没有改动——改的只是用户按下检查更新之后看到什么。 校验与展示逻辑抽到 update-manifest.ts:validateManifest 收紧了 releaseUrl 的判断(此前 startsWith 前缀匹配会放过 …/releases.attacker.example 这类同前缀域名),并对三个可选字段做格式校验——安装包名会进入一段让用户粘贴的命令,限制成发布流水线实际产出的形状;格式不对的可选字段按缺失处理,不让整次更新检查失败,老版本 manifest 仍然可用。 接入 vitest,11 个用例覆盖版本解析与排序(0.10.0 > 0.9.0、0.3 == 0.3.0)、manifest 校验的拒绝路径、以及签名/未签名/未声明三种状态下的展示。CI 在 build 之前加一步 pnpm test。
Metasequoia IME UI HTML
水杉输入法 Windows 端的界面资源。Server 加载这里的页面来渲染候选窗、悬浮工具栏、托盘菜单和设置窗口。
webview2/shared/ 是 Engine web 契约的副本,由 scripts/sync-contracts.py 从 ../vendor/MetasequoiaImeEngine/contracts/webview/ 生成,CI 用 --check 验证两者一致。要改契约请改 Engine,不要直接改这个目录。
同仓的相关组件:../windows/(TSF 前端)、../server/(后端与窗口宿主)。
目录
| 路径 | 内容 |
|---|---|
webview2/candwnd/ |
候选窗,含 skins/ 下的皮肤 |
webview2/ftb/ |
悬浮工具栏 |
webview2/menu/ |
托盘菜单 |
webview2/settings/ime-settings/ |
设置页,唯一需要构建的部分,Vite + TypeScript |
webview2/default-themes/、webview2/other-themes/ |
主题 |
除设置页外都是直接分发的静态资源,改完即生效。
构建设置页
设置页是发布安装包的必要输入之一,pnpm build 的产物 dist/ 会被打包脚本收集。
cd webview2/settings/ime-settings
corepack enable
pnpm install --frozen-lockfile
pnpm build
pnpm 版本由 package.json 的 packageManager 字段固定,corepack enable 之后不用自己装。开发时用 pnpm dev 起本地服务。
本地调试
把本仓链接到 Server 的数据目录,改页面就不用重新打包:
$target = Join-Path $env:LOCALAPPDATA 'metasequoiaime\html'
if (Test-Path -LiteralPath $target) {
Remove-Item -LiteralPath $target -Recurse -Force
}
New-Item -ItemType SymbolicLink -Path $target -Target (Resolve-Path .).Path
必须用绝对路径,Resolve-Path 就是用来把当前目录转成绝对路径的。设置页走这条路时链接的仍是仓库目录,页面读的是 webview2/settings/ime-settings/dist/,所以改完设置页要重新 pnpm build。
与 C++ 侧的边界
窗口归 Server,页面归本目录。HWND、尺寸、位置、DPI、Z-order 和 WebView2 controller 的生命周期都在 ../server/src/window/ 与 ../server/src/webview2/;页面结构、样式和浏览器端交互在这里。
C++ → 页面主要经 WebView2 导航和脚本执行,页面 → C++ 经 window.chrome.webview.postMessage(...)。改消息 type、JSON 字段、页面导出的 JS 函数或 DOM 标识时,必须同步检查 Server 的消息解析与拼接代码,两边没有编译期约束。
候选内容和输入状态的权威在 Server 和引擎,页面只负责展示与发出用户动作;不要在页面侧复制候选选择、翻页、输入模式或配置持久化的状态机。
完整的组件边界约定见仓库根 AGENTS.md。