Issue 82 Validation - ShaoClean/Alune GitHub Wiki
Issue #82:UI 设计与本地 Git 验收记录
- Issue:https://github.com/ShaoClean/Alune/issues/82
- PR:https://github.com/ShaoClean/Alune/pull/106
- 设计:本地 Git 与 SSH 统一工作区
- 日期:2026-09-26
- 代码基线:
f6ce4aca3d82a5a4133f5d6d5326531baa0cfca6 - 记录分两阶段:保留初始 UI 原型验证,后附 2026-09-26 真实产品实现验证;跨平台 CI 结果另列。
实际完成的 UI 验证
环境:macOS,Codex 内置 Chromium 浏览器。默认视口 1280 × 720;紧凑桌面视口 1024 × 768。所有数据均为示例,原型操作只改变页面内存。
| 场景 | 实际结果 |
|---|---|
| 当前工作区基线 | 从当前源码构建,打开现有隔离 workspace fixture 并采集截图 |
| 浅深主题 | 实际打开并检查,来源、增减色、弹窗及文本可辨认 |
| 小窗口 | 1024 × 768 下文档宽度等于视口宽度;六个视图与同步入口保留,Diff 内单独横向滚动 |
| 暂存与提交 | 暂存 RepositoryPicker.tsx 后与原有 README.md 一起提交;剩余两个未暂存文件保留 |
| 禁用状态 | 空摘要或没有已暂存文件时不能提交;首次提交前推送不可用 |
| 首次提交 | 将未跟踪 README.md 暂存并创建首次提交,随后显示无远程提示;干净工作区可切换分支 |
| 路径错误 | 相对路径被拒绝,原输入保留;选择示例目录后恢复打开;已登记仓库聚焦已有标签 |
| 危险确认 | 丢弃按钮在勾选前禁用;勾选后只移除所选未暂存文件,已暂存 README.md 保留 |
| Worktree | 在独立标签打开关联目录;关闭标签后该 Worktree 仍在列表;删除目录按钮在勾选前禁用 |
| 同步取消 | 发起推送显示进度;取消后显示已完成步骤不回滚的说明 |
| 同名来源与草稿 | 本机 alune 的草稿不会出现在 SSH alune;切回本机后恢复原草稿,路径显示正确 |
| 搜索与空态 | 用 /srv/ 只命中远程仓库;无匹配查询显示明确空态 |
| 运行时日志 | 本次所测页面未捕获浏览器 error / warn |
| 语法检查 | 提取原型脚本后 node --check 通过 |
| 基线构建 | 先构建 @alune/shared,再构建 web 通过;首次单独构建 web 因本地产物陈旧缺少共享类型而失败,更新依赖产物后通过,未改动生产源码 |
设计 QA 记录见 design-qa.md。
视觉证据
| 证据 | 链接 |
|---|---|
| 现有产品基线 | baseline-workspace.png |
| 整屏同尺寸比较 | comparison.png |
| 标签 / 提交区局部比较 | comparison-details.png |
| 浅色 / 深色 | 浅色 / 深色 |
| 紧凑窗口 | 1024 × 768 |
初始产品验收计划(历史记录)
以下为实现前建立的计划,不作为已经通过的测试;实际执行结果在后文独立记录。macOS、Windows、Linux 分别记录系统版本、Git 版本、架构、提交 SHA、命令与结果。CI 的平台测试不能替代安装包中的系统目录选择器、凭据助手与交互式权限真机验证。
| 类别 | 必测情形 | macOS | Windows | Linux |
|---|---|---|---|---|
| 登记与目录 | 根目录 / 子目录 / Worktree、重复路径、目录选择取消、重启恢复 | 待运行 | 待运行 | 待运行 |
| 路径 | 空格、中文、单 / 双引号、命令替换字面字符、Windows 盘符 / UNC | 待运行 | 待运行 | 待运行 |
| 基本闭环 | 打开、查看改动、暂存、取消暂存、提交、分支切换、推送 | 待运行 | 待运行 | 待运行 |
| Git 状态 | 无 HEAD、无远程、浅克隆、游离 HEAD、部分暂存、重命名 | 待运行 | 待运行 | 待运行 |
| 预览 | 文本、图片、二进制、过大文件、链接与子模块边界 | 待运行 | 待运行 | 待运行 |
| 分支与合并 | 创建、重命名、安全删除、占用保护、合并成功 / 冲突 | 待运行 | 待运行 | 待运行 |
| 同步 | Fetch、Pull、Push、首次设置上游、凭据失败、非快进拒绝、强推租约 | 待运行 | 待运行 | 待运行 |
| Stash | 创建 / 查看 / 应用 / Pop / 删除、未跟踪文件、应用冲突保留 | 待运行 | 待运行 | 待运行 |
| Worktree | 创建 / 打开 / 删除、关标签不删目录、当前 / 脏 / 锁定保护 | 待运行 | 待运行 | 待运行 |
| 长操作 | 进度、取消、超时、失败后刷新、并发写保护、切换标签归属 | 待运行 | 待运行 | 待运行 |
| 数据兼容 | 旧数据库迁移、连接和草稿保留、离线本地可用、SSH 回归 | 待运行 | 待运行 | 待运行 |
| 错误恢复 | Git 缺失、权限、只读、不受信任目录、锁文件、作者缺失 | 待运行 | 待运行 | 待运行 |
已知原型限制
- 原型不访问文件系统、不运行 Git、不测试凭据或平台进程取消;“打开目录”使用示例结果。
- Diff、历史和错误内容为固定演示;正式产品继续复用已有文本 / 图片 Diff 与分支图实现。
- 原型中的“切换有改动分支”展示保守冲突状态;真实实现须由 Git 判断是否会覆盖改动。
- 原型展示核心新状态,不重建已有 SSH 认证、完整设置、面板拖动、标签排序和 AI 服务配置。
- UI 设计验证不等于 #82 功能完成;正式产品验收项仍需逐项完成后再关闭 Issue。
2026-09-26:真实产品实现验证
主体实现:69ce79e;最终验证提交:e4b4f23。本机环境:macOS 15.5 / arm64,Git 2.43.1,Node 25.5.0,Electron 44.2.0。CI 使用 Node 22.22.0。测试均使用隔离的临时仓库、SQLite 数据库和本地 bare 远程,不操作用户项目。
| 检查 | 命令 / 方法 | 实际结果 |
|---|---|---|
| 服务端 | npm test -w server -- --runInBand |
14 套件、114 项通过 |
| Git transport / SSH 解析回归 | npm test -w @alune/ssh-client |
78 项通过、2 项 Windows 专属测试在 macOS 跳过 |
| 前端状态与交互逻辑 | npm test -w web |
141 项通过 |
| 桌面单元测试 | npm run desktop:test:unit |
42 项通过;一次并发验证中 hdiutil 返回资源暂不可用,单独重跑通过 |
| 构建 | npm run desktop:build |
shared、ssh-client、server、web、desktop 共 5 项通过 |
| Electron 完整烟测 | 在 apps/desktop 执行 node scripts/smoke.mjs |
write / restore 两个进程均退出 0;本地真实首次提交、分支切换、目录选择 IPC、重启布局 / 排序持久化通过;本地来源另经实际页面重载与状态序列化验证 |
| 真实 SSH Worktree 回归 | 在 apps/desktop 执行 node scripts/test-worktrees.mjs |
退出 0;独立标签、已暂存 Diff、暂存隔离、重复打开、关闭保留、游离 HEAD、320 px 布局通过 |
| 最终提交构建与桌面烟测 | npm run desktop:build + node scripts/smoke.mjs |
e4b4f23 生产代码构建及 write / restore 均通过;包含最终 MSYS 取消修复 |
| 差异检查 | git diff --check |
通过 |
真实 Git 自动化覆盖
local-git.spec.ts 使用真实 Git + SQLite + HTTP:根目录与子目录去重、本地 / SSH 同路径隔离、无 HEAD 暂存 / 取消暂存 / 首次提交、部分暂存、中文 / 空格 / 单引号 / 字面美元与方括号路径、分支创建 / 切换 / 重命名 / 删除 / 合并及冲突、Stash 包含未跟踪文件与查看 / Apply / Pop / Drop、Fetch / Pull / Push / 上游、浅克隆补全、本地 Worktree 创建 / 打开 / 删除和保护、文本 / 图片 / 二进制读取、确认令牌文件删除、旧数据库迁移。
新增回归确认:分支不存在且有同名跟踪文件时,切换失败并保留文件改动;上游目标与本地分支不同仍推送当前提交;拒绝 :branch 删除 refspec 和游离 HEAD 上游设置。
local-connection.test.cjs 验证字面 argv、二进制字节、严格 UTF-8、输出上限、真实阻塞 pre-commit hook 的取消与暂存保留、继承 Git 目录环境变量隔离、盘符 / UNC 路径辅助函数。UNC 辅助函数测试不等于真实网络共享验收。
真实界面手动验证
| 场景 | 结果 |
|---|---|
| 打开 → Diff → 暂存 → 提交 → 历史 | 真实本地仓库完成;提交只包含已暂存内容,未跟踪 notes.md 保留;历史显示新提交 |
| 首次提交仓库 | 正确显示无提交、无远程和缺少作者;作者表单仅写入当前仓库 |
| 路径错误 | 相对路径被拒绝,输入保留,可修正重试 |
| 添加远程 / 首次推送 | 添加临时 bare 远程;首次推送选择上游后成功 |
| Worktree | 在仓库外创建新目录与分支并打开独立标签;关闭标签后目录与登记保留 |
| 删除目录确认 | 未勾选时按钮禁用,勾选后可用;此 UI 检查取消确认,实际删除与保护由真实 Git 集成测试验证 |
| 长操作取消 | 临时 pre-commit hook 延迟提交;界面显示耗时与取消,取消后暂存内容和摘要保留,错误清楚;测试 hook 已清理 |
| 浅深主题 / 紧凑桌面 | 1280 × 720 与 1024 × 768;紧凑窗口文档宽度等于视口,全部 12 个工具栏按钮可达 |
| 浏览器日志 | 所测真实页面未捕获 error / warn |
正式实现截图
- 浅色工作区 / 深色工作区 / 1024 深色
- 打开本地仓库 / 设置上游
- Worktree 删除确认 / 取消耗时操作
- 设计与实现同尺寸对比
验证中发现并修正的问题
- Git 的全局 literal-pathspecs 会影响 Stash 内部未跟踪文件清理:Stash 无用户路径参数,执行时显式恢复 Git 内部 pathspec 语义,增加真实仓库回归。
- 隐藏父目录下的桌面预览返回 index 404:静态首页使用 sendFile 的 root 参数,不再把隐藏路径当作被拒绝的请求路径。
- 连接页路由调整后计数误用仓库数:修正为连接数。
- 分支切换的 checkout 文件回退风险和不同名上游推送:分别改为 switch 分支命令与完整当前分支 refspec,并增加测试。
- 桌面烟测暴露过时的分组数、preload 字段、布局默认值和分支选择器;按当前 UI 修正。空 DELETE 响应不再按 JSON 解析;存储清理测试在卸载界面后运行,避免活动应用合法重写设置。
三平台 CI
最终代码:e4b4f23f3eadd8070f6b845e57753c19d367740c。移除临时诊断后的 PR 检查 36223278350 与 push 检查 36223275586 均全部通过;四工作区单元测试与提交规范检查也通过。各平台执行相同的 4 项 transport 测试与 10 项真实 Git / SQLite / HTTP 集成测试,Node 固定 22.22.0。
| 平台 / 架构 | Git | Runner 镜像 | 4 项 transport | 10 项真实集成 | Hook 取消用例耗时 |
|---|---|---|---|---|---|
| macOS 14.8.9 / arm64 | 2.55.0 | macos-14-arm64 / 20260831.0302.1 | 全部通过 | 全部通过 | 72 ms |
| Ubuntu 22.04.5 / x64 | 2.55.0 | ubuntu-22.04 / 20260920.303.1 | 全部通过 | 全部通过 | 53 ms |
| Windows Server 2025 10.0.26100 / x64 | 2.55.0.windows.5 | windows-2025-vs2026 / 20260922.246.2 | 全部通过 | 全部通过 | 1,031 ms |
上表耗时取最终 PR 检查日志,包含该测试的断言与清理。Windows 使用 Git for Windows;CI 原生系统进程与 Git 测试通过,不代表安装包和操作系统交互已人工验收。
排查与复验记录
历史失败保留如下,不能将早期部分通过等同于最终版本通过。
| 运行 / 提交 | 实际结果与后续修正 |
|---|---|
36220675236 / 69ce79e |
macOS、Linux 和四工作区单元测试通过。Windows 初始化失败:Git 不接受 Node os.devNull 设备路径作为配置文件。ccc76b6 改用临时空配置文件。 |
36221170637 / 9e5d9c3 |
Windows 参数、字节与真实 Hook 取消通过;目录环境隔离测试因 8.3 短路径与完整路径比较失败。532d86c 统一用 realpathSync.native。 |
36221465462 / 532d86c |
路径别名回归通过;Windows 取消 Hook 出现间歇性 30 秒残留子进程。 |
36221921417 / 8401618 |
尝试先捕获 Windows 后代再终止、重扫,仍取消超时;同轮 Windows 10 项服务端集成测试全部通过。 |
5e6ed4c / 6a52ea9 诊断 |
首次诊断字符串替换的转义错误已修正。36222696766 确认 sleep.exe 的 Windows 父 PID 已不存在;Git 在约 454 ms 退出,输出管道到约 30,111 ms 才关闭。 |
36223066272 / 3e80ef6 |
合并 MSYS 逻辑父子关系后 Windows 4 + 10 项通过;取消用例共约 1.26 秒,Git 输出管道约 678 ms 关闭。暂存内容、工作区文件和无遗留 index.lock 的断言通过。 |
e4b4f23 |
移除临时进程诊断,兼容 MSYS 停止 / 等待输入输出标记,并固定进程列表宽度;最终 PR / push 两轮三平台 CI 全部通过,Windows 取消用例约 1.03 秒。 |
Windows 根因:MSYS 的 exec 会保留逻辑 PID,却创建新的 Windows PID;新进程的原生父进程可能已经退出,因此单靠 CIM / taskkill /T 会漏掉 Hook 后代。取消时读取当前 Git 安装自带的 usr/bin/ps.exe -W,把逻辑 PID / PPID 映射到实际 Windows PID,再合并原生树终止后代。正常 Git 调用仍通过结构化 argv 执行。缺少 MSYS 工具时保留原生树与 taskkill 回退;其他 Git 发行版及受限 PowerShell 环境尚未单独验收。取消测试始终保留 12 秒上限,没有放宽断言。
复查另外修正远程引用切换与名称保留(e1fb314):远程引用继续以游离 HEAD 打开,名为 origin/... 的本地分支保持字面名称;分支列表排除游离状态描述和符号 HEAD。新增测试最初按 Git 原始输出断言 (detached),后按共享 API 的空分支约定修正并验证真实 Git HEAD(9e5d9c3)。
尚未执行的原生平台验收
- Windows / Linux 安装包、OS 目录选择器人工交互、真实 SSH Agent / HTTPS 凭据助手与权限弹窗。
- macOS 系统目录选择器的人工选择;本次 Electron 自动化验证使用对话框返回桩。
- Windows 实际 UNC 共享、受限权限目录、系统 Git 缺失和不受信任所有权的真机操作。
- 屏幕阅读器和系统高对比模式。
这些项不能由 UI 原型或 CI 通过推断为已验证。首期功能和跨平台 Git 自动化记录与发布前真机验收分开维护;不在本任务发布安装包或合并 PR。