grilling 三轮把设计树走完了,这里把它落成文件,避免决策只活在对话里。 ADR-0010 零依赖自研 TUI:三个候选库全部实测排除 —— ConsoleGuiTools 的 PSGallery 元数据声明最低 7.2(5.1 装不上);Spectre.Console 0.49.1 能在 5.1 加载但要塞 4 个第三方 DLL 且不支持鼠标;Terminal.Gui 1.15.0 能反射接线到真的渲染出窗口,但 Application.Shutdown() 在两端都抛 NRE。同时记下两条实测坑:无控制台时 $Host.UI.SupportsVirtualTerminal 会撒谎返回 True(第一道闸门必须是 [Console]::IsOutputRedirected),以及 5.1 的 RawUI.LengthInBufferCells 对中文返回 2、对边框字符返回 6(都不能用来排版)。 ADR-0011 进度回调这个例外:它是注入点不是状态,无头路径为 $null 时行为与今天完全一致。 ADR-0012 入口改名与垫片:这次留垫片而 Common.psm1 直接删,是因为前者是外部接口(断了是静默没用)后者是内部实现(断了当场报错)。并纠正了自己的一个伪前提 —— 本机实测没有注册任何 BakNRet 计划任务。 ADR-0013 TUI 写配置:外科式改写 + 校验通过才原子替换。硬事实是 SoftwareCatalog.psd1 根本不能被 Import-PowerShellDataFile 读入(动态表达式),任何"解析成对象再序列化"的方案都会毁掉表达式与注释。 .scratch/tui/spec.md 是这次改造的验收锚点:9 条已定决策 + 三轮的判据 + 风险表。 验收:Parse 两版仍绿。
69 lines
4.1 KiB
Markdown
69 lines
4.1 KiB
Markdown
# TUI 与入口重组 —— 验收锚点
|
||
|
||
本文件是这次改造的 spec:目标、已定决策、每轮的验收判据。**改动这个范围之外的代码要重新走一轮
|
||
确认**;改这个文件里的判据要说明为什么。
|
||
|
||
## 目标
|
||
|
||
把四个入口(主入口 + 备份 / 恢复 / 配置三个动作)与一个**零依赖 TUI** 落地,同时**不破坏**已经
|
||
建立的四条底线:
|
||
|
||
1. 两个 PowerShell 版本(5.1 与 7)都能跑;
|
||
2. 全仓解析零错、`test.ps1` 全绿、真实清单只读冒烟通过;
|
||
3. 无头/无人值守路径**行为与今天一致**(`exit` 退出码语义不变);
|
||
4. 零依赖承诺不被破坏(运行备份/恢复不需要任何模块)。
|
||
|
||
## 已定决策(细节见对应 ADR)
|
||
|
||
| # | 决策 | 出处 |
|
||
| --- | --- | --- |
|
||
| D1 | 零依赖自研 TUI;不用 ConsoleGuiTools / Spectre / Terminal.Gui | ADR-0010 |
|
||
| D2 | 界面**行内**(不平屏),只有状态行原地重画 | 本轮决策 |
|
||
| D3 | 第一道闸门是 `[Console]::IsOutputRedirected`;TUI 异常**不改退出码** | ADR-0010 |
|
||
| D4 | 日志:文件全量不变,TUI 下控制台输出降级为只写文件 | 本轮决策 |
|
||
| D5 | 进度用可注入回调(无头为 `$null`) | ADR-0011 |
|
||
| D6 | 入口改名 + 只留一轮的薄垫片;`Handle-Config` → `Edit-Config` | ADR-0012 |
|
||
| D7 | 三个配置界面:清单=行编辑器、配置=表单、名录=树+只读字段 | ADR-0013 |
|
||
| D8 | 写回=外科式改写,校验通过才原子替换;保存前留时间戳备份 | ADR-0013 |
|
||
| D9 | `-InputScript @('Down','Enter')` 作为输入缝;序列用尽仍在交互界面 → 直接报错退出 | 本轮决策 |
|
||
|
||
## 分三轮(每轮独立提交、独立断言、门禁全绿)
|
||
|
||
### 第一轮:TuiKit + 菜单骨架 + 清单编辑器
|
||
|
||
- `BakNRet/Public/` 里新增 TUI 积木:`Get-BakNRetCellWidth`(East-Asian-Wide 表 + 代理对)、
|
||
read-key 包装、`Write-BakNRetAt`(带"无控制台"退化)、菜单渲染、多选、确认。
|
||
- 入口重组:`Manage-Backup.ps1`(TUI + `-Action`/`-Quiet` 无头)、`Backup-Data.ps1`、
|
||
`Restore-Data.ps1`、`Edit-Config.ps1`;`Backup.ps1`/`Restore.ps1` 变垫片。
|
||
- `Edit-Config` 只做**清单行编辑器**。
|
||
|
||
**判据**:
|
||
- `Get-BakNRetCellWidth`:ASCII=列数、中文 2 列、字体边框 1 列、全角拉丁 2 列、半角片假名 1 列、
|
||
emoji(代理对)2 列、控制字符 0 列 —— 全部有断言。
|
||
- 清单编辑器**往返断言**:解析 → 改一个字段 → 写回 → 重新解析,除目标字段外逐字段相等,
|
||
注释行数不变。
|
||
- 无头闸门:把 `test.ps1` 的输出重定向时跑 `Manage-Backup -Action Backup -DryRun`,
|
||
断言不出现任何 TUI 输出、且退出码语义与今天一致。
|
||
- `-InputScript` 驱动:`@('Down','Enter')` 能走完"打开菜单 → 选备份 → 干跑 → 退出",序列用尽
|
||
却仍在交互界面时报错退出(不是挂起)。
|
||
- 垫片:`Backup.ps1` 转发后退出码与 `Backup-Data.ps1` 一致。
|
||
|
||
### 第二轮:配置编辑器(`BackupConfig.psd1` 扁平表单)
|
||
|
||
**判据**:往返断言(同上);非法取值被拒绝且**不落盘**;`logs/config-backups/` 里出现时间戳副本。
|
||
|
||
### 第三轮:名录编辑器(树 + 只读字段)
|
||
|
||
**判据**:往返断言;`Encrypt`/`Description` 可改,`Path`/`Exclude`/`Include` 只读;改完写回后
|
||
`Import-BaknretDataFile` 仍能读出**与改前逐字段相等**的内容(动态表达式与拼接串原样保留)。
|
||
|
||
## 风险
|
||
|
||
| 风险 | 表现 | 对策 |
|
||
| --- | --- | --- |
|
||
| 无控制台时 API 静默返回假值 | `RawUI.WindowSize` 给 `160x40`、`KeyAvailable` 恒 True | D3 的闸门;TUI 段全包 try/finally |
|
||
| 中文宽度算错 | 菜单右边框歪、光标定位偏 | 第一轮的宽度断言(含半角片假名/emoji) |
|
||
| TUI 吃掉了退出码 | 计划任务显示成功但备份失败 | TUI 异常绝不 `exit`;断言退出码语义 |
|
||
| 外科式改写改坏了别的行 | 配置注释丢失、表达式被毁 | 往返断言 + 校验通过才替换 + 时间戳备份 |
|
||
| 一次性做三个编辑器把质量摊薄 | 三个都半成品 | 分三轮,每轮独立验收 |
|