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 两版仍绿。
4.1 KiB
4.1 KiB
TUI 与入口重组 —— 验收锚点
本文件是这次改造的 spec:目标、已定决策、每轮的验收判据。改动这个范围之外的代码要重新走一轮 确认;改这个文件里的判据要说明为什么。
目标
把四个入口(主入口 + 备份 / 恢复 / 配置三个动作)与一个零依赖 TUI 落地,同时不破坏已经 建立的四条底线:
- 两个 PowerShell 版本(5.1 与 7)都能跑;
- 全仓解析零错、
test.ps1全绿、真实清单只读冒烟通过; - 无头/无人值守路径行为与今天一致(
exit退出码语义不变); - 零依赖承诺不被破坏(运行备份/恢复不需要任何模块)。
已定决策(细节见对应 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;断言退出码语义 |
| 外科式改写改坏了别的行 | 配置注释丢失、表达式被毁 | 往返断言 + 校验通过才替换 + 时间戳备份 |
| 一次性做三个编辑器把质量摊薄 | 三个都半成品 | 分三轮,每轮独立验收 |