docs: 补齐 Windows 端控制台文档(含三次 run 的失败-修复-实证全过程)
README / CHANGELOG / docs/console-plan.md 三处同步: - README:补 Windows 双架构安装包实测体积、第三条断言(解开安装包查内容)、 以及实测解出的 node.exe 体积与 PE Machine。 - CHANGELOG:新增「Windows 端控制台安装包」整节,含双架构理由、 为什么用原生 ARM runner、cfg!(windows) 分支首次被编译器看到、 以及三次 run 的完整过程(体积断言写错 → `&` 调 GUI 程序不等待 → 双绿)。 - docs/console-plan.md:断言表 2 条 → 3 条;新增三节实测记录; 产物形态表补实测体积;8.2 指标验收的「Win 安装包 < 40MB(待实测)」补上实测值。 另修复:`## 界面观感约定(2026-10-11)` 标题被上一轮编辑误吞 (正文直接从「两轮纯界面调整」开始),已恢复。 留下两条可迁移教训: 1. 体积阈值属于「中间逻辑自洽」式断言 —— 判据要落在产物内容上; 且压缩容器与未压缩目录的体积不可直接比。 2. `msiexec.exe` / NSIS 安装包是 GUI 子系统程序,PowerShell `&` 调用 既不等待也不设 $LASTEXITCODE → 必须 Start-Process -Wait -PassThru。
This commit is contained in:
1 parent
e616e80819
commit
c20e71bddc
3 files changed
+222
-6
No files matched your search
@@ -97,6 +97,59 @@
|
||||
**新步骤必须逐条核对前置产物由哪一步生成、顺序是否在其后** —— 本地验证时产物早就在,会把这层依赖完全掩盖)。
|
||||
- `.github/workflows/windows-e2e.yml`:步骤名与注释同步为含 `agent.mjs` 的说明。
|
||||
|
||||
### 新增 —— Windows 端控制台安装包(`.github/workflows/console-windows.yml`)
|
||||
|
||||
控制台此前**只在 macOS 上出过包**(`.app` / `.dmg`),而它的主战场恰恰是
|
||||
「在 Windows 上管控其他机器」。本轮补上 Windows 构建:**双架构矩阵** ——
|
||||
`windows-latest` 出 x64 `.msi` + NSIS `-setup.exe`,`windows-11-arm` 出 arm64 NSIS `-setup.exe`。
|
||||
|
||||
- **为什么必须双架构**:与 v2.0.2 那次事故同源 —— 包里装着错架构的 `node.exe` 时,
|
||||
ARM Windows 上「能启动、能 listen,但 TLS 握手不完成」,而 macOS 侧 100% 复现不出。
|
||||
控制台更甚:它内含 node 运行时,还要用这个 node **托起本机被控端**,即自己就是 TLS 服务端。
|
||||
- **为什么用原生 ARM runner 而非交叉编译**:`prepare-console.mjs` 的自检要**真执行 `node.exe`**,
|
||||
x64 机器跑不了 arm64 二进制;交叉编译会逼着引入「跳过自检」这类**削弱验证**的开关 ——
|
||||
而产出错架构运行时的时候,自检正是唯一能拦住它的那道闸。
|
||||
- **`cfg!(windows)` 分支第一次被编译器看到**:macOS 上的 `cargo check` **不会编译 `cfg(windows)` 代码**,
|
||||
故 `taskkill` 收进程树、PowerShell 计划任务、`node.exe` 路径等分支此前从未产出过 Windows 产物。
|
||||
- **实测产物**:x64 `.msi` **34.2 MiB** / NSIS **23.2 MiB**;arm64 NSIS **19.5 MiB**(均低于 40MB 目标)。
|
||||
`if-no-files-found: error` + `fail-fast: false`:一条架构没产出就报错,同时一条挂了不掩盖另一条的结果。
|
||||
- **尚未接入 `scripts/release.mjs`**:安装包目前只作为 CI artifact 产出,未随 Release 发布。
|
||||
|
||||
> **首个 run 两个 job 全红,但错的不是构建,是断言。**(run `38151366534`)
|
||||
> 两个 job 的失败点完全一致,而日志显示构建链路**一路全绿**:构建机架构(arm64 runner 上
|
||||
> `process.arch = arm64`,原生属实)、随包 `node.exe` 的 PE Machine(`0x8664` / `0xaa64`)、
|
||||
> `tauri build`、产物自举(打包内 node v22.23.3 真跑起打包内 sidecar)四步全 success。
|
||||
> 死掉的是本步自己写的守卫 —— 原断言「安装包体积 > 50MB」,理由是「含 Node 运行时约 80MB」,
|
||||
> 这**把未压缩的目录形态(`.app` ≈ 92 MiB)当成了压缩安装包的体积**:
|
||||
> LZMA 下 `node.exe` 自身能压到 1/3~1/4,实测 `.msi` 34.2 MiB、NSIS 19.5~23.2 MiB,阈值必然误杀。
|
||||
>
|
||||
> 更根本的问题是:**体积阈值属于「中间逻辑自洽」式断言**。包大不等于 `node.exe` 真在里面
|
||||
> (可能打进的是别的大文件),包小也不等于没在里面(压缩率会随 Node 版本漂移)。
|
||||
> 判据必须落在**产物内容**上,不能落在**间接指标**上。
|
||||
>
|
||||
> 改为**解开安装包查内容**(`.msi` 走 `msiexec /a` 管理安装、NSIS 走 `/S /D=` 静默安装,
|
||||
> 两者都是各自格式的核心能力,不引任何外部依赖),一次钉死三件事:
|
||||
> ① `node.exe` / `sidecar.mjs` / `agent.mjs` **三样随包资源必须都在**(缺任一,真机上就是
|
||||
> 「应用能开、但托不起被控端」);② `node.exe` 的 **PE Machine = 目标架构**(最终交付物级架构断言);
|
||||
> ③ `node.exe` 解压后 **> 40MB**(体积在这是**正确用法**:内容已验明后的自明性检查,
|
||||
> 而不是「运行时在不在」的**替代判据**)。附带收益:**真装一遍本身就是安装器冒烟**。
|
||||
> 另给该步加 `timeout-minutes: 8`,避免静默安装万一卡住把 job 拖满 60 分钟。
|
||||
>
|
||||
> **第二个 run(`38152850819`)两 job 仍同点红,但已是另一处原因,且同样是静默失效**:
|
||||
> 日志里 `msiexec /a 失败(退出码 )` —— `$LASTEXITCODE` 是**空的**,而整步从开始到抛错
|
||||
> 只过了 **0.8 秒**。根因是 `msiexec.exe` 与 NSIS 安装包都是 **GUI 子系统程序**,
|
||||
> PowerShell 用 `&` 调用时**既不等待其结束、也不设置 `$LASTEXITCODE`**
|
||||
> (`$null -ne 0` 判真 → 安装器还没跑完就抛错,报错读起来像「安装失败」,实为「压根没等」);
|
||||
> arm64 那条没有 MSI、直奔 NSIS,失败形态一模一样,正是同一根因的第二个样本。
|
||||
> 修法:改 `Start-Process -Wait -PassThru` 读 `.ExitCode`;参数拼成**单个字符串**传,
|
||||
> 避免数组被自动加引号而破坏 NSIS `/D=` 的「原样、不加引号、且居末」硬要求;
|
||||
> 加 `Wait-PayloadRoot`(30 秒收敛)防安装器「自己先退出、子进程继续装」的竞态误报。
|
||||
>
|
||||
> **第三个 run(`38154282653`)双绿**,断言给出产物实证 —— x64 `.msi`/`-setup.exe` 内均解出
|
||||
> **`node.exe` 82.9 MB / PE `0x8664`**、arm64 `-setup.exe` 内解出 **`node.exe` 73.5 MB / PE `0xaa64`**,
|
||||
> 三样随包资源齐全(sidecar 232 KB、agent 1060 KB)。
|
||||
> 这一步证明的恰是体积断言永远无法区分的那件事:**19.5MB 的压缩包里真的装着 73.5MB 的 arm64 运行时**。
|
||||
|
||||
### 变更 —— 界面一律不使用图标
|
||||
|
||||
- **去掉全部 emoji 图标**:路由表 `meta.icon` 字段整体移除,侧栏导航由「图标 + 标题」改为**纯文字**。
|
||||
|
||||
@@ -347,6 +347,9 @@ Tauri 侧经 Cargo path 依赖),**不引入第二套协议实现**。
|
||||
默认页面就是「本机服务」——点按钮即可启动 / 停止 / 重启本机被控端,
|
||||
并支持检查更新、查看日志、后台常驻(托盘)、开机自启。
|
||||
|
||||
**界面**:导航为**纯文字**(不使用图标);配色为两套中性灰阶主题 ——
|
||||
「简约白」与「高级灰」,侧栏底部一键切换。
|
||||
|
||||
| 页面 | 能力 |
|
||||
|---|---|
|
||||
| **本机服务**(默认) | 本机被控端启停/重启、连接本机、节点 ID 与密钥、开机自启、后台运行、异常自动重启、检查并应用更新 |
|
||||
@@ -360,12 +363,29 @@ Tauri 侧经 Cargo path 依赖),**不引入第二套协议实现**。
|
||||
| 审计 | `system.audit.list` 筛选 + `system.audit.verify` 链完整性校验 + 导出 JSONL |
|
||||
|
||||
```bash
|
||||
pnpm -r build # 含 console 前端
|
||||
cd apps/console && pnpm tauri dev # 开发态(起 Vite + Tauri 窗口)
|
||||
pnpm --filter nodeagent-console bundle # 打包(含 sidecar + Node 运行时 + 被控端脚本)
|
||||
# macOS 实测:.app 90.8 MiB / .dmg 33.78 MiB(分发件,其中 Node 运行时 86MB)
|
||||
pnpm -r build # 含 console 前端
|
||||
cd apps/console && pnpm tauri dev # 开发态(起 Vite + Tauri 窗口)
|
||||
pnpm --filter nodeagent-console bundle # 打包(含 sidecar + Node 运行时 + 被控端脚本)
|
||||
# macOS 实测:.app 92.2 MiB / .dmg 33.78 MiB(分发件,其中 Node 运行时 86MB)
|
||||
```
|
||||
|
||||
Windows 版由 CI 产出(`.github/workflows/console-windows.yml`),**双架构各一套**:
|
||||
|
||||
| 架构 | runner | 安装包 | 实测体积 |
|
||||
|---|---|---|---|
|
||||
| x64 | `windows-latest` | `.msi`(企业批量部署)+ `-setup.exe`(NSIS,双击安装) | 34.2 MiB / 23.2 MiB |
|
||||
| arm64 | `windows-11-arm` | `-setup.exe`(NSIS) | 19.5 MiB |
|
||||
|
||||
> 为什么必须两套:控制台内含 Node 运行时,且要用它**托起本机被控端**(即自己就是 TLS 服务端)。
|
||||
> 若在 ARM Windows 上装到 x64 的运行时,会**能启动、能监听,但 TLS 握手不完成** ——
|
||||
> 客户端只见超时,且开发机上 100% 复现不出。CI 里为此加了三道断言:
|
||||
> 「构建机架构 ⇄ 目标架构」、「随包 `node.exe` 的 PE Machine」、
|
||||
> 以及**解开安装包查内容**(三样随包资源齐全 + 包内 `node.exe` 的 PE Machine 对得上 ——
|
||||
> 前两条查的是打包**前**的中间产物,这一条查的才是**最终交付物**;
|
||||
> 实测解出 x64 `node.exe` 82.9 MB / `0x8664`、arm64 73.5 MB / `0xaa64`)。
|
||||
|
||||
> 控制台安装包目前**只作为 CI artifact 产出**,尚未接入 `scripts/release.mjs` 随 Release 发布。
|
||||
|
||||
⚠️ 平台差异:`app.*` 与 `system.service.list` **仅在被控端为 Windows 时可用**,
|
||||
非 Windows 被控端会返回 `E_UNSUPPORTED_PLATFORM`。控制台连接后会探测
|
||||
`system.info.os` 并**事前禁用**这些入口,而不是发出注定失败的请求。
|
||||
|
||||
+145
-2
@@ -224,7 +224,7 @@ nodeagent/
|
||||
| 命令闭环成功率 | 成功返回 ÷ 发起 | ≥ 95% |
|
||||
| 内网调用 P95 时延 | 前端点击到结果渲染 | < 3s |
|
||||
| 应用内存占用 | Mac 版空闲常驻 RSS | < 150MB(远低于 Electron) |
|
||||
| 打包体积 | **用户实际下载的分发件** | Mac `.dmg` < 40MB(实测 **33.8MB** ✓)/Win 安装包 < 40MB(待实测) |
|
||||
| 打包体积 | **用户实际下载的分发件** | Mac `.dmg` < 40MB(实测 **33.8MB** ✓)/Win 安装包 < 40MB(实测 ✓ `.msi` **34.2 MiB**、NSIS **19.5~23.2 MiB**) |
|
||||
| 双端编译 | `pnpm build` 一次产出两端 | 100% |
|
||||
|
||||
> **⚠️ 口径调整(2026-10-11,待确认)**:原指标写的是「Mac `.app` < 30MB / Win 安装包 < 40MB」。
|
||||
@@ -580,9 +580,152 @@ node 去跑打包内的 sidecar,并走一次真实 JSON-RPC 握手 —— 源
|
||||
> 整个模式不匹配 —— 于是「写错的变量名」反而逃过检查。放宽到 `[^)\s,;]+` 后才真正生效。
|
||||
> 教训:**注入故障不只是验证守卫有没有,还要验证它是否覆盖了目标形态**。
|
||||
|
||||
## Windows 端控制台(2026-10-11)
|
||||
|
||||
### 起因
|
||||
|
||||
控制台此前**只在 macOS 上出过包**(`.app` / `.dmg`)。而它的主要用户场景恰恰是
|
||||
「在 Windows 机器上管控其他机器」——只出 macOS 版等于把主战场让开了。
|
||||
|
||||
排查后发现:代码层面对 Windows 其实是备好的(`cfg!(windows)` 分支、`node.exe` 路径、
|
||||
`creation_flags`、PowerShell 计划任务、`.ico` 图标、`prepare-console.mjs` 的平台自适应都在),
|
||||
**缺的只是「真在 Windows 上构建一次」这一环**。
|
||||
|
||||
> 这里有个容易被忽视的点:macOS 上的 `cargo check` **不会编译 `cfg(windows)` 代码**,
|
||||
> 所以那些 Windows 分支在此之前**从未被编译器看过一眼**。而 `cfg!(windows)` 这种运行时宏
|
||||
> 虽然两边都会编译,却也只是类型检查、从未产出过 Windows 产物。
|
||||
|
||||
### 为什么必须双架构
|
||||
|
||||
被控端发布包出过「arm64 包里装的其实是 x64 `node.exe`」的事故,后果是:
|
||||
在 ARM Windows 上**能启动、能 listen,但 TLS 握手不完成**(客户端只见超时),
|
||||
且 macOS 侧 100% 复现不出。
|
||||
|
||||
控制台同理,而且更甚 —— 它内含 node 运行时,还要用这个 node **托起本机被控端**,
|
||||
即自己就是 TLS 服务端。所以 x64 / arm64 必须各出一套,不能只出默认架构。
|
||||
|
||||
### 为什么用原生 ARM runner,而不是交叉编译
|
||||
|
||||
GitHub 提供 ARM64 Windows runner(`windows-11-arm`,公共仓库免费),
|
||||
本仓库是 public,故 arm64 可以在它上面**原生构建**。
|
||||
|
||||
交叉编译(在 x64 runner 上编 arm64)看似省事,实则要付两笔代价:
|
||||
1. 需要 VS 的 ARM64 工具链,且 Tauri 的 NSIS/MSI bundler 对 arm64 支持面较窄;
|
||||
2. 更关键:`prepare-console.mjs` 的**自检要真执行 `node.exe`**
|
||||
(x64 机器跑不了 arm64 二进制),会逼着引入「跳过自检」这类**削弱验证**的开关。
|
||||
而当产出的是「架构错的运行时」时,自检正是唯一能拦住它的那道闸。
|
||||
|
||||
宁可等原生 runner,也不引入削弱验证的分支。
|
||||
|
||||
### 三条断言是必需项,不是顺手检查
|
||||
|
||||
| 断言 | 为什么不能省 |
|
||||
|---|---|
|
||||
| **构建机架构 ⇄ 目标架构**(`node -p process.arch`) | ARM runner 镜像里确实存在 x64 模拟的组件(社区实测 python 即为 AMD64)。一旦 Node 也是模拟版,`process.arch` 会是 `x64` → 把 x64 的 `node.exe` 打进 arm64 安装包 → **真机上能启动但 TLS 握手不完成,而 CI 全绿** |
|
||||
| **随包 `node.exe` 的 PE Machine**(打包前,查 `src-tauri/runtime/`) | 与 `pack.mjs` 的双架构校验同源:不只看「脚本跑完了」,而是直接读最终要打进包的那个二进制头。中间逻辑再自洽,也可能因上游给了错架构的二进制而产出错包。放在打包前,是为了让失败点更靠近原因 |
|
||||
| **安装包里确实装着三样东西**(打包后,解开安装包查内容) | 见下节。它才是**最终交付物级**的断言 |
|
||||
|
||||
### 首个 run 双双失败:错的不是构建,是断言本身
|
||||
|
||||
`console-windows.yml` 的第一个 run(`38151366534`)两个 job 全红,且**失败点完全一致**。
|
||||
但取日志后发现,**构建链路一路全绿**:
|
||||
|
||||
| 步骤 | x64 job | arm64 job |
|
||||
|---|---|---|
|
||||
| 构建机架构 | ✓ | ✓ `process.arch = arm64`(原生 ARM runner 属实) |
|
||||
| 随包 `node.exe` PE | ✓ `0x8664` | ✓ `0xaa64`(73.5 MB) |
|
||||
| `tauri build` | ✓ `.msi` 34.2 MiB + `-setup.exe` 23.2 MiB | ✓ `-setup.exe` 19.5 MiB |
|
||||
| 产物自举 | ✓ 打包内 node v22.23.3 真跑起打包内 sidecar | ✓ |
|
||||
| **体积断言** | ✗ `34.2 < 50` | ✗ `19.5 < 50` |
|
||||
|
||||
死的是最后一步,而这一步是**守卫自己写错了**。原断言是「安装包体积 > 50MB」,
|
||||
|
||||
> 另断言安装包体积 > 50MB:含 Node 运行时时 x64 约 82MB / arm64 约 72MB,
|
||||
> 体积过小意味着运行时没打进去 —— 那种包能装,但一启动就找不到 node。
|
||||
|
||||
错在把**未压缩的目录形态**(`.app` ≈ 92 MiB)当成了**压缩安装包的体积**。
|
||||
安装包是压缩容器:LZMA 下 `node.exe` 自身就能压到 1/3~1/4,实测 `.msi` 34.2 MiB、
|
||||
NSIS 19.5~23.2 MiB,阈值 50MB 必然误杀。
|
||||
|
||||
> 更根本的问题:**体积阈值属于「中间逻辑自洽」式断言**。包大不等于 `node.exe` 真在里面
|
||||
> (可能打进的是别的大文件),包小也不等于没在里面(压缩率会随 Node 版本漂移)。
|
||||
> 这与「被控端 zip 里塞了错架构的 node」那条教训是同一类 —— 判据必须落在**产物内容**上,
|
||||
> 不能落在**间接指标**上。
|
||||
|
||||
改为**解开安装包、查内容**(`.msi` 走 `msiexec /a` 管理安装、NSIS 走 `/S /D=` 静默安装,
|
||||
两者都是各自格式的核心能力,不引外部依赖),一次钉死三件事:
|
||||
|
||||
| 检查 | 挡住什么 |
|
||||
|---|---|
|
||||
| `node.exe` / `sidecar.mjs` / `agent.mjs` **三样都在** | 缺任一,真机上就是「应用能开、但托不起被控端」 |
|
||||
| `node.exe` 的 **PE Machine = 目标架构** | 「arm64 包里装的是 x64 node.exe」那类**只在真机暴露**的事故 |
|
||||
| `node.exe` 解压后 **> 40MB** | 塞了个占位文件(这里是「体积」的**正确用法**:作为内容已验明后的自明性检查,而不是作为「运行时在不在」的**替代判据**) |
|
||||
|
||||
附带收益:**真装一遍本身就是安装器冒烟** —— 比只读目录更强。
|
||||
另给该步加 `timeout-minutes: 8`,避免静默安装万一卡住把 job 拖满 60 分钟。
|
||||
|
||||
### 第二个 run 仍红:`&` 调 GUI 程序不等待,也不设退出码
|
||||
|
||||
第二个 run(`38152850819`)两个 job **仍同点红**,但已是另一处原因,且同样是**静默失效**。
|
||||
日志里只有一行关键信息:
|
||||
|
||||
```
|
||||
msiexec /a 失败(退出码 ):nodeagent-console_2.0.2_x64_en-US.msi
|
||||
```
|
||||
|
||||
`$LASTEXITCODE` 是**空的**,而整步从开始到抛错只过了 **0.8 秒** —— 根本没等安装器跑完。
|
||||
|
||||
**根因**:`msiexec.exe` 与 NSIS 安装包都是 **GUI 子系统程序**,PowerShell 用 `&` 调用时
|
||||
**既不等待其结束、也不设置 `$LASTEXITCODE`**。于是 `$null -ne 0` 判真,
|
||||
在安装器还没跑完时就当场抛错 —— 报错读起来像「安装失败」,实为「压根没等」。
|
||||
(arm64 那条没有 MSI、直奔 NSIS,失败形态一模一样,正是同一根因的第二个样本。)
|
||||
|
||||
**修法**:
|
||||
- 两处都改 `Start-Process -Wait -PassThru`,读 `$p.ExitCode`(确定性等待),并打印实际退出码;
|
||||
- 参数拼成**单个字符串**传 `-ArgumentList`,避免数组被 PowerShell 自动加引号 ——
|
||||
那会破坏 NSIS `/D=`「必须原样、不加引号、且是最后一个参数」的硬要求;
|
||||
- 新增 `Wait-PayloadRoot`(最多 30 秒收敛):安装器可能「自己先退出、由子进程继续装」,
|
||||
避免竞态误报「找不到 node.exe」;
|
||||
- `msiexec` 退出码 3010(成功但需重启)按成功处理。
|
||||
|
||||
### 第三个 run:双绿,且断言给出了产物实证
|
||||
|
||||
第三个 run(`38154282653`)**两个 job 全绿**,第 14 步的实际输出:
|
||||
|
||||
| 检查对象 | 安装包体积 | 安装器退出码 | 解开后 `node.exe` | PE Machine | 另两样 |
|
||||
|---|---|---|---|---|---|
|
||||
| x64 `.msi` | 34.2 MiB | 0 | **82.9 MB** | **`0x8664`** ✓ | sidecar 232 KB / agent 1060 KB |
|
||||
| x64 `-setup.exe`(NSIS) | 23.2 MiB | 0 | **82.9 MB** | **`0x8664`** ✓ | 同上 |
|
||||
| arm64 `-setup.exe`(NSIS) | 19.5 MiB | 0 | **73.5 MB** | **`0xaa64`** ✓ | 同上 |
|
||||
|
||||
这一步的价值在于:**它证明的正是「19.5MB 的压缩包里真的装着 73.5MB 的 arm64 `node.exe`」** ——
|
||||
这恰是体积断言永远无法区分的那件事(19.5MB 与「没打运行时」的包在体积上无法区分)。
|
||||
另:`/D=` 确实生效(安装位置即 `pkg-extract\nsis`),故 NSIS 的默认安装位置候选列表是备用保险。
|
||||
|
||||
### 产物形态
|
||||
|
||||
| 架构 | runner | 安装包 | 实测体积 |
|
||||
|---|---|---|---|
|
||||
| x64 | `windows-latest` | `.msi`(企业批量部署)+ `-setup.exe`(NSIS,普通用户双击) | **34.2 MiB** / **23.2 MiB** |
|
||||
| arm64 | `windows-11-arm` | `-setup.exe`(NSIS)—— WiX 的 arm64 MSI 支持面较窄,不值得为它引入不确定性 | **19.5 MiB** |
|
||||
|
||||
对照 macOS:`.app` 92.2 MiB(目录形态)/`.dmg` 33.8 MiB(压缩分发件)。
|
||||
**两者不可直接比** —— 这正是上面那条错断言的来源。
|
||||
|
||||
工作流 `console-windows.yml` 与 `windows-e2e.yml` **刻意分开**:
|
||||
后者是「被控端在 Windows 上的行为验证」,跑一遍约 4 分钟、含安装/卸载真机冒烟;
|
||||
前者要装 Rust 工具链、编 Tauri(冷编 10 分钟级)。目标不同、耗时量级不同,
|
||||
混在一起会让「改一行前端也要等 15 分钟」。
|
||||
|
||||
### 仍未做
|
||||
|
||||
- **控制台尚未接入 `scripts/release.mjs`**(该脚本目前只出被控端包)。
|
||||
控制台的安装包目前只作为 CI artifact 产出,未随 Release 发布。
|
||||
- 真机安装冒烟(在真实 Windows 上装一遍、点一遍)仍需图形环境人工执行。
|
||||
|
||||
## 界面观感约定(2026-10-11)
|
||||
|
||||
两轮纯界面调整,方向都是「少即是多」。理由记下来,免得日后被当成"没做完"再补回去。
|
||||
两轮纯界面调整,方向都是「少即是多」。理由记下来,免得日后被当成「没做完」再补回去。
|
||||
|
||||
### 一、一律不使用图标
|
||||
|
||||
|
||||
Reference in new issue
Block a user