# 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`;断言退出码语义 | | 外科式改写改坏了别的行 | 配置注释丢失、表达式被毁 | 往返断言 + 校验通过才替换 + 时间戳备份 | | 一次性做三个编辑器把质量摊薄 | 三个都半成品 | 分三轮,每轮独立验收 |