diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d452df1..46dcaa5 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -21,8 +21,17 @@ 1. 从默认分支 `development` 创建工作分支,保持每个 PR 聚焦一个问题。 2. 填写自动加载的 PR 模板,说明行为变化、主要改动、兼容影响和实际验证结果。 3. 完整解决 Issue 时填写 `Closes #编号`;只完成部分工作时使用 `Refs #编号`。 -4. UI 改动附前后截图;涉及持久化、SSH 或桌面更新时,记录相关回归验证。未验证的平台或场景需要明确列出。 +4. UI 改动在 Wiki 验收记录中附前后截图,PR 中引用对应页面或图片;涉及持久化、SSH 或桌面更新时,记录相关回归验证。未验证的平台或场景需要明确列出。 +5. 填写“设计文档(Wiki)”,并在 Wiki 页面补充 Issue / PR 反向链接;不需要独立设计文档的小改动注明原因。 PR 标题和提交信息须遵守 Conventional Commits,使用 `feat: ...`、`fix: ...`、`perf: ...`、`refactor: ...`、`docs: ...` 或 `chore: ...` 等格式;本地 hook 和 CI 会执行校验。完整提交规范、Git hooks 和 Release 说明生成流程见 [CONTRIBUTE.md](../CONTRIBUTE.md),开发和测试命令见[项目 README](../README.md)。 +## 维护设计文档 + +[GitHub Wiki](https://github.com/ShaoClean/remote-git/wiki) 是功能、优化及缺陷修复设计的统一入口。使用 [设计模板](https://github.com/ShaoClean/remote-git/wiki/Design-Template) 新建 `Issue-<编号>` 页面;较长验收记录可拆为 `Issue-<编号>-Validation`。内容包括背景、目标、方案、验收标准、关联 PR 和实际验证结果。 + +新增或更新页面时,同步维护 [功能设计索引](https://github.com/ShaoClean/remote-git/wiki/Feature-Designs) 或 [缺陷修复索引](https://github.com/ShaoClean/remote-git/wiki/Bugfix-Designs),在 Issue / PR 正文填写完整 Wiki 链接。图片和附件存放在 Wiki 仓库的 `assets/issue-<编号>/`,检查页面、图片和附件可访问。PR 审阅时附 Wiki 修订链接或 commit SHA,完整操作见 [Wiki 维护约定](https://github.com/ShaoClean/remote-git/wiki/Contributing)。 + +没有 Wiki 写权限时,可先在 Issue / PR 中提供草案与附件,由维护者整理后补充链接。运行、开发、发布及现行配置说明、测试必需的 fixtures 留在代码仓库;设计文档、验收记录及截图不再在主仓库保留完整副本。已迁移资料的旧路径对应关系见 [迁移清单](https://github.com/ShaoClean/remote-git/wiki/Migration-25)。 + 公开日志与截图请先脱敏,避免提交真实数据库、私人服务器地址、SSH 密码、私钥和访问令牌。 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 796f76f..35ec8f9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -84,3 +84,9 @@ body: attributes: label: 补充资料 description: '可选。说明首次出现的版本、临时绕过方法和相关 Issue;根因推测请注明。' + - type: input + id: design_wiki + attributes: + label: 设计文档(Wiki) + description: '可选。已有设计请填写 Wiki 页面链接;暂无设计可留空,由维护者按 Issue 编号创建并补充反向链接。约定见 https://github.com/ShaoClean/remote-git/wiki/Contributing 。' + placeholder: 'https://github.com/ShaoClean/remote-git/wiki/Issue-<编号>' diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 6862ea1..f6e9455 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -65,3 +65,9 @@ body: attributes: label: 补充资料 description: '可附脱敏截图、草图、关联 Issue、文档及当前应用版本。' + - type: input + id: design_wiki + attributes: + label: 设计文档(Wiki) + description: '可选。已有设计请填写 Wiki 页面链接;暂无设计可留空,由维护者按 Issue 编号创建并补充反向链接。约定见 https://github.com/ShaoClean/remote-git/wiki/Contributing 。' + placeholder: 'https://github.com/ShaoClean/remote-git/wiki/Issue-<编号>' diff --git a/.github/ISSUE_TEMPLATE/optimization.yml b/.github/ISSUE_TEMPLATE/optimization.yml index dbbe59b..da284a3 100644 --- a/.github/ISSUE_TEMPLATE/optimization.yml +++ b/.github/ISSUE_TEMPLATE/optimization.yml @@ -65,3 +65,9 @@ body: attributes: label: 补充资料 description: '可附脱敏日志、截图、已有排查结论及关联 Issue。' + - type: input + id: design_wiki + attributes: + label: 设计文档(Wiki) + description: '可选。已有设计请填写 Wiki 页面链接;暂无设计可留空,由维护者按 Issue 编号创建并补充反向链接。约定见 https://github.com/ShaoClean/remote-git/wiki/Contributing 。' + placeholder: 'https://github.com/ShaoClean/remote-git/wiki/Issue-<编号>' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6767742..5a19a85 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,6 +17,10 @@ +## 设计文档(Wiki) + + + ## 验证 @@ -34,4 +38,5 @@ - [ ] 已自查差异,变更范围与关联 Issue 一致。 - [ ] 已记录必要验证的实际结果及未验证项。 - [ ] 已更新相关文档;不适用时已注明。 +- [ ] 已更新 Wiki 设计 / 验收记录、分类索引及 Issue / PR 双向链接;不适用时已注明。 - [ ] 代码、日志与截图不包含密码、私钥或访问令牌。 diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 774af3c..96aff59 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -2,6 +2,12 @@ RemoteGit 使用 Conventional Commits 描述变更,commitlint 校验提交信息,git-cliff 按提交记录生成中文 Release 说明。版本号和发布时机由维护者决定,推送稳定版本 tag 后由 GitHub Actions 构建和发布。 +## 设计文档与验收资料 + +功能、优化及缺陷修复设计统一维护在 [GitHub Wiki](https://github.com/ShaoClean/remote-git/wiki),包括方案、验收记录、截图和附件。页面按 `Issue-<编号>` 命名,在 Wiki、Issue 和 PR 之间补充双向链接;新增页面使用 [设计模板](https://github.com/ShaoClean/remote-git/wiki/Design-Template),并更新对应分类索引。维护流程、附件路径与修订记录要求见 [Wiki 维护约定](https://github.com/ShaoClean/remote-git/wiki/Contributing)。 + +本指南、README、现行配置说明及测试必需的 fixtures 继续随代码维护。历史资料的原路径与新入口见 [迁移清单](https://github.com/ShaoClean/remote-git/wiki/Migration-25);不要将 Wiki 文档和配套附件的完整副本重新提交到主仓库。Wiki 使用独立 Git 历史,代码 PR 中应提供页面链接及被审阅的 Wiki 修订,代码回退时需单独核对文档。 + ## 初始化开发环境 使用 Node.js 22.12+ 和 npm;CI 固定为 Node.js 22.22.0。首次进入仓库执行 `npm ci`。 diff --git a/README.md b/README.md index d115637..7318a7d 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ 提交规范、Git hooks、PR 检查和 Release 说明生成流程见 [CONTRIBUTE.md](CONTRIBUTE.md)。 +功能、优化与缺陷修复的设计、验收记录及配套附件统一维护在 [GitHub Wiki](https://github.com/ShaoClean/remote-git/wiki):[功能设计索引](https://github.com/ShaoClean/remote-git/wiki/Feature-Designs)、[缺陷修复索引](https://github.com/ShaoClean/remote-git/wiki/Bugfix-Designs)。新增文档按 Issue 编号组织,并在 Issue / PR 中补充双向链接,详见 [Wiki 维护约定](https://github.com/ShaoClean/remote-git/wiki/Contributing)。运行、配置、开发和发布所需的基础说明继续保留在代码仓库;旧资料入口见 [迁移清单](https://github.com/ShaoClean/remote-git/wiki/Migration-25)。 + ## 开发与打包 开发环境使用 Node.js 22.12+ 和 npm。首次构建需要下载 Electron 和原生依赖;原生模块没有预编译包时,需要系统 C++ 编译工具(macOS:Xcode Command Line Tools;Windows:Visual Studio C++ Build Tools 和 Python;Linux:编译工具链和 Python)。 @@ -37,7 +39,7 @@ npm run desktop:test # 构建后执行桌面集成测试 在“AI 服务商”中配置并启用服务商和模型,再在“提交生成”中保存默认模型。提交摘要右侧的星光按钮只分析已暂存改动,一次填入摘要和描述,支持取消、重试及撤销;最终提交仍由用户操作。默认使用简体中文 Conventional Commits。 -支持 OpenAI、Anthropic、Gemini、DeepSeek,以及三个协议的多个自定义服务。API Key 在设置页手动输入并加密保存,无需配置环境变量;桌面版使用系统密钥存储,独立服务自动管理本机加密密钥。配置与限制见 [AI 设置说明](docs/ai-settings.md),截图与验证记录见 [Issue #21 验收](docs/validation/issue-21/README.md)。 +支持 OpenAI、Anthropic、Gemini、DeepSeek,以及三个协议的多个自定义服务。API Key 在设置页手动输入并加密保存,无需配置环境变量;桌面版使用系统密钥存储,独立服务自动管理本机加密密钥。配置与限制见 [AI 设置说明](docs/ai-settings.md),截图与验证记录见 [Issue #21 验收](https://github.com/ShaoClean/remote-git/wiki/Issue-21-Validation)。 ## GitHub 版本更新 @@ -109,10 +111,10 @@ Linux CI 的桌面测试使用 `xvfb-run -a`。测试中的模拟更新适配器 新建文件无需暂存即可查看相对空版本的差异,支持统一、分栏和放大查看。暂存后再次编辑的文件会同时出现在“已暂存”和“未暂存”分组,分别显示暂存内容与后续工作区改动;没有首次提交的仓库也可暂存、取消暂存和预览。 -空文件显示“新增空文件”,二进制文件和无法读取的文件有明确反馈。预览支持 UTF-8 文本,新增文件/暂存内容及差异输出限制为 1 MiB,差异补丁最多 10,000 行;超限时显示提示。预览不写入文件或暂存区。验证范围和结果见 [新增文件差异预览验收](docs/validation/issue-18/README.md)。 +空文件显示“新增空文件”,二进制文件和无法读取的文件有明确反馈。预览支持 UTF-8 文本,新增文件/暂存内容及差异输出限制为 1 MiB,差异补丁最多 10,000 行;超限时显示提示。预览不写入文件或暂存区。验证范围和结果见 [新增文件差异预览验收](https://github.com/ShaoClean/remote-git/wiki/Issue-18-Validation)。 工作区侧栏与改动列表支持拖动调宽,也可从“布局设置”使用滑块调整或恢复默认。分隔线支持方向键、Shift 加速和 Home / End;`Cmd/Ctrl + \` 开关侧栏。布局偏好在本机保存,保留现有工作区树的展开与排序设置。 窄窗口选择文件或提交后进入检查器,使用“返回列表”继续操作。提交摘要和描述在本次页面会话内按仓库保留;刷新页面会清空草稿。 -界面截图、验证结果和测试环境说明见 [工作区布局验收](docs/validation/issue-6/README.md)。 +界面截图、验证结果和测试环境说明见 [工作区布局验收](https://github.com/ShaoClean/remote-git/wiki/Issue-6-Validation)。 diff --git a/TODO.md b/TODO.md index e0874cb..112415b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,342 +1,6 @@ -# Remote Git Manager - 开发计划 +# 项目开发计划 -## 项目概述 - -在本地 Mac 上通过 Web UI 管理远程 Windows 机器上的 Git 仓库,解决挂载盘方式(如 Fork)操作延迟高、体验差的问题。 - -## 架构方案 - -### 推荐方案:混合架构(SSH 为核心 + 可选 Remote Agent) - -``` -┌───────────────── Mac (本地) ─────────────────┐ -│ React Frontend ◄──► NestJS Backend │ -│ │ │ -│ SSH2 / WebSocket │ -│ │ │ -│ ┌──── 内网通道 ────┐ │ -└──────────────┼─────────────────┼──────────────┘ - │ │ -┌──────────────┼─────────────────┼──────────────┐ -│ Windows (远程) │ │ -│ ┌────────────────────────────┘ │ -│ │ SSH Server (OpenSSH) │ -│ │ └─► Git CLI 执行命令 │ -│ │ │ -│ │ [可选] Remote Agent (轻量 NestJS 服务) │ -│ │ └─► 提供 REST/WebSocket API │ -│ │ └─► 文件监听、仓库索引、实时推送 │ -└───────────────────────────────────────────────┘ -``` - -### 核心连接方式:SSH(ssh2) - -**选择理由:** - -- 远程 Windows 已有 SSH Server(OpenSSH),无需额外安装 -- ssh2 是纯 Node.js 实现,跨平台,无需本地 SSH 依赖 -- 支持公钥/密码认证、SFTP 文件传输、端口转发 -- 可以执行任意 shell 命令,天然适配 Git CLI 操作 - -**可选增强:Remote Agent 模式** - -- 在 Windows 上部署一个轻量 NestJS 服务 -- 通过 WebSocket 实时推送仓库状态变更(比轮询 SSH 更高效) -- 支持 chokidar 文件监听,即时反映工作区变化 -- 首期可不做,后期作为性能优化加入 - ---- - -## Phase 0: 项目初始化 - -- [ ] 初始化 monorepo 结构(nx 或 turborepo) - ``` - remote-git/ - ├── apps/ - │ ├── web/ # React 前端 - │ └── server/ # NestJS 后端 - ├── packages/ - │ ├── shared/ # 共享类型/工具 - │ └── ssh-client/ # SSH 连接封装 - ├── package.json - └── turbo.json - ``` -- [ ] 配置 TypeScript、ESLint、Prettier -- [ ] 初始化 NestJS 项目(`nest new`) -- [ ] 初始化 React 项目(Vite + React) -- [ ] 配置 Git 仓库、.gitignore - -## Phase 1: SSH 连接层 - -### 1.1 SSH 连接管理模块 - -- [ ] 安装 `ssh2` 依赖:`npm i ssh2` -- [ ] 实现 SSH 连接服务(`ssh-client` 包) - - 连接配置管理(host, port, username, auth) - - 支持密码认证和公钥认证(`ssh2.Utils.parseKey`) - - 连接池管理(复用连接、超时断开、自动重连) - - 连接状态事件:`connect`, `disconnect`, `error` - - SSH Config 文件解析(`~/.ssh/config`),自动读取已有配置 -- [ ] 实现 SFTP 操作服务 - - 读取远程目录结构(ls / stat) - - 文件内容读写(用于 diff 查看、文件编辑) - - 文件上传/下载(批量操作时使用) - -### 1.2 远程命令执行服务 - -- [ ] 封装 `execCommand(cmd: string, cwd?: string)` 方法 - - 基于 `ssh2.Client.exec()` - - 支持 stdout/stderr 流式输出(用于长时间运行的 git 操作) - - 超时控制与取消(`channel.close()`) - - 返回 `{ exitCode, stdout, stderr }` -- [ ] Git 命令封装层 - - `gitStatus(repoPath)` → 解析 `git status --porcelain=v2 --branch` - - `gitLog(repoPath, opts)` → 解析 `git log --format=...` - - `gitDiff(repoPath, opts)` → 解析 `git diff` 输出 - - `gitBranchList(repoPath)` → 解析 `git branch -a -v` - - `gitStashList(repoPath)` → 解析 `git stash list` - - `gitRemoteList(repoPath)` → 解析 `git remote -v` - - `gitExecute(repoPath, args)` → 通用 git 命令执行 -- [ ] 命令输出解析器 - - porcelain v2 格式状态解析 - - log 格式化解析 - - diff 统一格式解析(可使用 `diff2html` 库渲染) - -## Phase 2: NestJS 后端核心 - -### 2.1 连接管理模块 - -- [ ] `ConnectionModule` / `ConnectionService` - - CRUD 远程主机配置(加密存储密码/密钥) - - 测试连接(SSH handshake 验证) - - 连接状态管理(已连接/断开/重连中) -- [ ] `ConnectionController` - - `POST /connections` - 添加连接 - - `GET /connections` - 列出连接 - - `DELETE /connections/:id` - 删除连接 - - `POST /connections/:id/test` - 测试连接 - -### 2.2 仓库管理模块 - -- [ ] `RepositoryModule` / `RepositoryService` - - 扫描远程目录查找 Git 仓库(`find . -name .git -type d`) - - 仓库收藏/置顶(本地数据库存储) - - 仓库状态概览(branch, status, ahead/behind) -- [ ] `RepositoryController` - - `GET /repositories/scan?connectionId=&path=` - 扫描仓库 - - `GET /repositories/:id/status` - 仓库状态 - - `GET /repositories/:id/log` - 提交历史 - - `GET /repositories/:id/diff` - 文件差异 - - `GET /repositories/:id/branches` - 分支列表 - - `GET /repositories/:id/stashes` - stash 列表 - -### 2.3 Git 操作模块 - -- [ ] `GitModule` / `GitService` - - Stage/Unstage 文件(`git add` / `git reset`) - - Commit(`git commit -m` / 打开编辑器暂不支持,前端输入信息) - - Push/Pull/Fetch(`git push` / `git pull` / `git fetch`) - - Branch 操作(create/switch/delete/merge/rebase) - - Stash 操作(save/pop/apply/drop) - - Checkout 文件(`git checkout -- `) - - Reset(`git reset --soft/--mixed/--hard`) - - Cherry-pick / Revert -- [ ] `GitController` - - `POST /repositories/:id/stage` - stage 文件 - - `POST /repositories/:id/unstage` - unstage 文件 - - `POST /repositories/:id/commit` - 提交 - - `POST /repositories/:id/push` - 推送 - - `POST /repositories/:id/pull` - 拉取 - - `POST /repositories/:id/branch` - 分支操作 - - ...其他 git 操作端点 - -### 2.4 文件浏览模块 - -- [ ] `FileModule` / `FileService` - - 远程目录树浏览(SFTP) - - 文件内容读取(用于查看未追踪文件 diff) - - 简易文件编辑(修改后保存,触发 git diff) - -### 2.5 WebSocket 网关(实时通信) - -- [ ] `EventsGateway`(`@WebSocketGateway`) - - 实时推送命令执行输出(git push/pull 长时间操作) - - 仓库状态变更通知 - - 连接状态变更通知 -- [ ] 事件定义 - - `connection:status` - 连接状态变更 - - `repo:status` - 仓库状态变更 - - `command:output` - 命令执行输出(流式) - - `command:exit` - 命令执行完成 - -## Phase 3: React 前端 - -### 3.1 基础框架 - -- [ ] 项目脚手架(Vite + React + TypeScript) -- [ ] UI 组件库选型与引入 - - 推荐 Ant Design(功能全面,表格/树/表单组件丰富) - - 备选:Arco Design、Shadcn UI -- [ ] 状态管理(Zustand,轻量适合本项目) -- [ ] 路由配置(React Router v6) -- [ ] API 封装(axios + SWR/React Query) -- [ ] WebSocket 连接管理(socket.io-client) - -### 3.2 连接管理页面 - -- [ ] 连接列表页 - - 展示已配置的远程主机 - - 连接状态指示器(在线/离线/重连) - - 添加/编辑/删除连接 -- [ ] 连接配置表单 - - 主机地址、端口、用户名 - - 认证方式切换(密码 / 密钥文件 / SSH Agent) - - SSH Config 导入 - - 连接测试按钮 - -### 3.3 仓库仪表盘 - -- [ ] 仓库列表页 - - 卡片/列表视图切换 - - 显示:仓库名、当前分支、ahead/behind、最后提交 - - 快捷状态图标(clean / dirty / conflicting) - - 扫描新仓库功能 -- [ ] 仓库详情页 - - 左侧:文件树 / 文件列表 - - 右侧:diff 视图 - -### 3.4 Git 操作界面 - -- [ ] **Changes 视图**(核心功能) - - 未暂存文件列表 + 变更类型标识(M/A/D/R/U) - - 已暂存文件列表 - - 文件 diff 查看(side-by-side / unified 切换) - - 单文件 stage/unstage - - 全部 stage/unstage - - Commit 输入框(消息 + 描述) - - 最近 commit 消息快速选择 -- [ ] **History 视图** - - 提交历史列表(虚拟滚动,支持大量 commit) - - commit 详情面板 - - 分支过滤 - - 搜索(作者/消息/SHA) - - diff 查看(commit 间对比、与 HEAD 对比) -- [ ] **Branch 视图** - - 分支列表(local / remote / tags) - - 当前分支高亮 - - 创建/切换/删除分支 - - 合并/变基操作 - - ahead/behind 统计 -- [ ] **Stash 视图** - - Stash 列表 - - apply / pop / drop 操作 - - stash 内容查看 -- [ ] **Remote 视图** - - 远程仓库列表 - - push / pull / fetch 操作 - - force push(需二次确认) - - 冲突提示与解决引导 - -### 3.5 Diff 渲染组件 - -- [ ] 集成 `react-diff-viewer` 或 `diff2html` - - unified / split view 切换 - - 语法高亮(monaco-editor 或 highlight.js) - - 行号显示 - - 文件头部信息(变更统计 +X -Y) - - 文件过滤(只看某类变更) - -## Phase 4: 安全与增强 - -- [ ] 凭据加密存储(使用 `crypto` 模块 AES-256 加密) -- [ ] SSH 密钥安全处理(不落盘,内存中使用) -- [ ] 连接超时与自动重连 -- [ ] 操作审计日志 -- [ ] 危险操作确认(force push、hard reset 等) -- [ ] 大仓库性能优化(diff 分页、log 懒加载) - -## Phase 5: 可选增强(Remote Agent 模式) - -- [ ] Windows 端轻量 Agent 服务 - - 基于 NestJS 的独立微服务 - - 自启动注册(Windows Service 或 PM2) - - 文件系统监听(chokidar → WebSocket 推送) - - 仓库索引缓存 -- [ ] Mac 端自动发现 Agent(UDP 广播或手动配置) -- [ ] 连接模式切换(SSH 直连 / Agent 模式) - ---- - -## 技术栈清单 - -| 层级 | 技术 | 说明 | -| ---------- | --------------------------- | ------------------------ | -| 前端框架 | React 18 + TypeScript | Vite 构建 | -| UI 组件 | Ant Design 5 | 表格/树/表单等企业级组件 | -| 状态管理 | Zustand | 轻量,适合中小项目 | -| 数据请求 | React Query + axios | 缓存与自动刷新 | -| 实时通信 | Socket.IO | 命令输出流式推送 | -| Diff 渲染 | react-diff-viewer-continued | 支持 unified/split | -| 语法高亮 | Prism.js / highlight.js | diff 代码高亮 | -| 后端框架 | NestJS | 模块化架构 | -| SSH 客户端 | ssh2 | 纯 JS 实现,无需本地 SSH | -| 数据存储 | SQLite (better-sqlite3) | 轻量,本地配置/凭据存储 | -| 加密 | Node.js crypto | AES-256-GCM 凭据加密 | -| 进程管理 | PM2(可选) | Agent 模式守护进程 | - -## 关键依赖 - -```json -{ - "dependencies": { - "ssh2": "^1.15.0", - "@nestjs/core": "^10.x", - "@nestjs/websockets": "^10.x", - "@nestjs/platform-socket.io": "^10.x", - "better-sqlite3": "^11.x", - "socket.io-client": "^4.x", - "react": "^18.x", - "antd": "^5.x", - "zustand": "^4.x", - "@tanstack/react-query": "^5.x", - "react-diff-viewer-continued": "^4.x", - "diff2html": "^3.x", - "axios": "^1.x", - "react-router-dom": "^6.x" - } -} -``` - -## 开发顺序建议 - -``` -Phase 0 (项目初始化) - ↓ -Phase 1 (SSH 连接层) ← 核心基础设施 - ↓ -Phase 2.1 + 2.2 (连接 + 仓库管理) ← 最小可用后端 - ↓ -Phase 3.1 + 3.2 + 3.3 (前端基础 + 连接 + 仓库列表) ← 最小可用前端 - ↓ -Phase 2.3 (Git 操作 API) + 3.4 (Changes 视图) ← MVP 核心功能 - ↓ -Phase 2.5 + 3.5 (WebSocket + Diff) ← 体验增强 - ↓ -Phase 2.4 + 3.4 其余 (文件浏览 + History/Branch/Stash) ← 功能完善 - ↓ -Phase 4 (安全增强) ← 生产就绪 - ↓ -Phase 5 (Agent 模式) ← 可选,按需开发 -``` - -## MVP 目标(Phase 0-3.4) - -首个可用版本应实现: - -1. 添加 SSH 连接到远程 Windows -2. 扫描并选择 Git 仓库 -3. 查看 status / stage / commit / push / pull -4. 查看基本 diff +项目开发计划已迁移至 [Wiki 历史规划](https://github.com/ShaoClean/remote-git/wiki/Archive-Development-Plan)。当前任务与进度见 [公开 TODO 看板](https://github.com/users/ShaoClean/projects/1);后续设计文档按 [Wiki 维护约定](https://github.com/ShaoClean/remote-git/wiki/Contributing)更新。 ## 背景 diff --git a/apps/desktop/UPDATE_VALIDATION.md b/apps/desktop/UPDATE_VALIDATION.md deleted file mode 100644 index 3dd031c..0000000 --- a/apps/desktop/UPDATE_VALIDATION.md +++ /dev/null @@ -1,25 +0,0 @@ -# 更新功能验收记录 - -日期:2026-09-10。分支:`feature/github-updater`,基线:`d1c2f4a`。 - -本地环境:macOS 15.5 / arm64,Node.js 25.5.0,Electron 44.2.0。应用实际版本为 1.0.0,桌面集成测试的模拟更新版本为 1.0.1。 - -| 检查 | 结果 | -| --- | --- | -| `npm run desktop:test:unit` | 19 项通过:SemVer、重复请求、取消/重试、校验失败、超时、IPC、安装顺序和完整发布附件校验 | -| `npm run desktop:build` | 通过:前端 TypeScript/Vite、共享包、NestJS、桌面暂存与 Electron SQLite 重建 | -| `npm run desktop:test` | 通过,退出码 0:真实设置界面、版本显示、下载期间刷新、状态恢复、沙箱/认证及后端关闭 | -| `node apps/desktop/scripts/test-packaged.mjs` | macOS arm64 打包应用通过,退出码 0;保留活跃 WebSocket 后仍能完成服务关闭 | -| 发布工作流 | YAML 已解析检查;版本标签及完整发布产物校验使用本地 fixtures 验证,未推送标签、未在 GitHub Actions 实际运行 | - -本地生成 macOS arm64 DMG、ZIP 及 blockmap,文件位于 `release/`。最终打包使用已下载的同版本 Electron 目录(`--config.electronDist`)避免重复网络下载;发布工作流仍使用标准 Electron 下载流程。界面截图为 `release/update-settings.png`,其中 1.0.1 和更新说明来自模拟数据。 - -尚未完成的发布验收: - -- GitHub 仓库仍为私有,尚无可供客户端匿名读取的正式 Release;未修改仓库可见性。 -- Windows x64、Linux x64、macOS x64 未在本次本地环境构建或运行;已加入对应原生 runner 的 CI 构建和打包应用测试。 -- Windows/Linux 尚未用两个真实递增版本验证安装程序启动、版本提升及原有数据保留。 -- macOS 尚未从公开 Release 下载真实 DMG 并实际打开/替换安装;SHA-256、架构匹配、取消、损坏文件和超时使用测试数据验证。 -- macOS 首版未签名/未公证,Windows 未配置签名。没有执行真实安装、公开发布或修改用户已有应用数据。 - -上述未完成项需在首次正式发布前补充版本、系统、架构和实测结果,不能以模拟测试替代。 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..350e8a8 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +# 文档入口 + +[GitHub Wiki](https://github.com/ShaoClean/remote-git/wiki) 统一保存功能、优化与缺陷修复的设计、验收记录及配套图片和附件。 + +- [功能与优化设计](https://github.com/ShaoClean/remote-git/wiki/Feature-Designs) +- [缺陷修复设计](https://github.com/ShaoClean/remote-git/wiki/Bugfix-Designs) +- [历史规划](https://github.com/ShaoClean/remote-git/wiki/Archive) +- [迁移清单与旧路径对照](https://github.com/ShaoClean/remote-git/wiki/Migration-25) +- [设计模板](https://github.com/ShaoClean/remote-git/wiki/Design-Template) 与 [维护约定](https://github.com/ShaoClean/remote-git/wiki/Contributing) + +代码仓库保留运行、开发、发布所需的基础说明与测试 fixtures。本目录的 [AI 设置说明](ai-settings.md) 继续随实现更新;开发与发布命令见 [README](../README.md) 和 [贡献与发布指南](../CONTRIBUTE.md)。 diff --git a/docs/ai-settings.md b/docs/ai-settings.md index ae617a3..7d39f12 100644 --- a/docs/ai-settings.md +++ b/docs/ai-settings.md @@ -60,4 +60,4 @@ API Key 只使用用户在设置页保存的值,不读取服务商的环境变 OpenAI 协议参考官方 [Chat Completions](https://developers.openai.com/api/reference/chat-completions/overview/) 与 [Create a chat completion](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create)。具体账号权限、可用模型 ID、代理兼容性以服务商为准;预置模型可以替换。 -实际执行范围、截图及未验证平台见 [验证记录](validation/issue-21/README.md)。 +设计方案见 [Issue #21 Wiki](https://github.com/ShaoClean/remote-git/wiki/Issue-21);实际执行范围、截图及未验证平台见 [验证记录](https://github.com/ShaoClean/remote-git/wiki/Issue-21-Validation)。 diff --git a/docs/issue-19-validation.md b/docs/issue-19-validation.md deleted file mode 100644 index e547d39..0000000 --- a/docs/issue-19-validation.md +++ /dev/null @@ -1,66 +0,0 @@ -# 新增文件删除:实现与验收 - -Issue: - -基线:`development@6c1e6be`;验证日期:2026-09-15。 - -## 行为 - -- 未跟踪、新增已暂存及新增混合改动的行提供「删除整个新增文件」。混合改动另有「丢弃未暂存改动」,恢复暂存区版本。 -- 打开确认框时读取远端最新状态、文件摘要及暂存记录,展示完整相对路径、删除范围和「直接删除,不进入回收站」。取消不执行删除或取消暂存。 -- 确认时重新核验状态摘要;内容、暂存区或分支发生变化时拒绝旧确认。仅处理仓库内一个文件,拒绝目录、子模块、已跟踪文件、越界路径及带符号链接的父目录。文件本身是符号链接时只删除链接。 -- 暂存新增文件先使用字面路径清理该路径的索引,再通过 SFTP `unlink` 删除磁盘文件,保留空父目录。支持尚无首次提交、intent-to-add、强制暂存的忽略文件,以及磁盘文件/父目录已消失而索引仍存在的情况。 -- 删除期间阻止重复提交;成功和失败均刷新实际状态,并清除当前文件的 Diff 及未完成的旧 Diff 请求。混合改动分组分别展示,总文件数按路径去重。 -- Git 状态使用 porcelain v2、NUL 分隔及完整未跟踪文件列表;SSH 字符串解码保留跨分包的 UTF-8 字符。 - -## 验证 - -环境:macOS、Node.js 25.5.0、系统 Git;补充实际 Windows PowerShell SSH/SFTP 验证。所有写操作均在隔离的临时测试仓库中进行。 - -```sh -npm run build -w @remote-git/shared -npm run test -w @remote-git/ssh-client -npm run build -w server -npm run build -w web -npm run test -w server -- --runInBand new-file-deletion.spec.ts repository.service.spec.ts -npm run test -w web -``` - -- SSH/Git/磁盘测试:33 项。既有本地 Git/文件系统适配测试,也有通过 `ssh2.Server` 在回环地址建立真实 SSH/SFTP 连接的测试。覆盖未跟踪、暂存、混合改动、无 HEAD、特殊路径、符号链接、只读目录、索引锁、断连、并发重新暂存/创建及部分失败后重试。 -- 服务端目标测试:8 项,覆盖真实 Nest HTTP 路由、请求校验、错误原因和状态码、重复请求拦截及仓库状态回归。 -- Web 测试:35 项,包含删除预览后对延迟 Diff 响应的失效处理及原有工作区测试。 -- 前后端构建通过。Vite 仍提示主 bundle 大于 500 kB。 -- ego-browser 配合真实 GitService/Git/磁盘的隔离 fixture 验证:键盘打开/确认、取消后磁盘和索引不变、暂存/取消暂存回归、丢弃未暂存内容保留暂存版本、删除混合内容后计数和 Diff 更新、重复点击仅一个请求、特殊文件名及父目录保留、权限失败反馈/重试、外部修改导致旧确认失效。 - -界面复验入口(先完成上述构建): - -```sh -node apps/web/tests/new-file-deletion-fixture.cjs -``` - -打开命令输出的本地地址,进入「新增文件删除验收」。退出 fixture 时清理临时仓库。 - -## 已知限制与基线问题 - -- Git 索引与 SFTP 文件删除不是跨步骤原子事务。发生错误时分别报告磁盘文件和暂存记录的实际结果;连接中断无法核验时明确显示「无法确认」。不会自动回写旧索引覆盖其他工具的改动。本进程的删除锁不约束外部 Git/文件系统写入。 -- Windows SSH 的 Git 参数使用编码 PowerShell 和原始字节流转发;已完成下述实机回归。 -- 全量 `npm run test -w server -- --runInBand` 中 5 个原有占位测试缺少依赖注入配置而失败:`connection.controller.spec.ts`、`file.controller.spec.ts`、`file.service.spec.ts`、`git.controller.spec.ts`、`git.service.spec.ts`。原始 worktree 中同样可复现;本次新增功能测试通过。 - -## 开发模式启动回归 - -同步修复 `npm run dev` 的页面白屏:Vite 开发服务直接加载共享包的 CommonJS `dist/index.js`,导致浏览器提示缺少 `REPOSITORY_STATUS_REQUEST_TIMEOUT_MS` 导出。Web 的 Vite 配置现将 `@remote-git/shared` 映射到 TypeScript 源码,由 Vite 转换为 ES 模块,也避免前端启动依赖共享包预先构建。 - -实际开发服务的连接页、仓库列表与刷新通过,浏览器未捕获运行时异常;修复后 `npm run build -w web` 和 35 项 Web 测试通过。该配置修复与 issue-18 分支保持一致。 - -## Windows 根目录校验误报修复 - -Windows PowerShell 会将异步流复制的 `GetAwaiter().GetResult()` 返回值输出到管道。实际 Git 根目录的 `rev-parse --show-prefix` 本应只返回换行,但封装命令多输出了两行 `System.Threading.Tasks.VoidTaskResult`,导致服务端误判为仓库子目录,并提示「请从仓库根目录操作此文件」。同样的输出还会污染 Git 状态和索引解析。 - -修复将两次等待结果赋给 `$null`,同时关闭 PowerShell 进度输出,保留 Git 的原始 stdout、stderr 和退出码,继续保留真实子目录的路径校验。 - -验证结果: - -- 在实际 Windows SSH 主机核对根目录命令,输出恢复为单个换行,stderr 为空。 -- `git-shell-windows.test.cjs` 对根目录、子目录、含中文路径的 NUL 状态输出、失败命令逐字节对比原生 Git 与封装结果;实机通过。主机 Node 不支持 `--test`,使用兼容入口执行同一测试文件的断言,未更改系统 Node。 -- 同一 Windows 主机的临时仓库中,未跟踪、已暂存、暂存后再编辑的中文文件均通过真实 SSH/SFTP 删除验证;索引清理、父目录和其他文件保留均正确,测试目录已清理。 -- 本地 SSH 测试 33 项通过,Windows 专用测试在 macOS 上按平台跳过;SSH 包构建通过。 diff --git a/docs/validation/issue-13/README.md b/docs/validation/issue-13/README.md deleted file mode 100644 index 876f7c6..0000000 --- a/docs/validation/issue-13/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Issue #13:Markdown 更新说明验收 - -基线:`origin/development`,提交 `38d6c42`,已包含 macOS 一键重启安装。远程仓库的开发分支名称为 `development`,没有 `dev` 分支。修改前截图采自原始基线 `3709357`,修改后截图及以下验证结果已同步至当前基线。 - -环境:macOS arm64、Node.js 25.5.0、npm 11.8.0、Electron 44.2.0;浏览器验收使用 Ego Lite 和生产构建。 - -## 行为与范围 - -更新说明使用 `react-markdown` 和 `remark-gfm`,支持标题、段落、嵌套有序/无序列表、强调、引用、行内代码、代码块、表格,以及 GFM 删除线和只读任务列表。 - -- 忽略原始 HTML;Markdown 图片保留替代文字,不请求远程图片。 -- 只允许绝对 HTTP/HTTPS 链接;危险协议、相对路径和页内锚点显示为普通文字。 -- 链接使用 `target="_blank"` 和 `rel="noopener noreferrer"`。Electron 主进程再次验证协议后调用系统浏览器,始终拒绝新建应用窗口。 -- 说明区域独立纵向滚动,长链接可换行,代码块与宽表格独立横向滚动。颜色使用现有应用 CSS 变量。 -- 弹窗居中,在应用最小窗口 `1000×680` 下,版本信息、下载及取消按钮仍可见。 -- 空字符串和纯空白保留占位提示;下载进度变化不会重新解析相同的说明。 - -## 自动化验证 - -| 检查 | 结果 | -| --------------------------------- | ---------------------------------------------------------------------------------- | -| `npm test -w web` | 34 项通过,含 Markdown/GFM、代码原文、空白、纯文本、HTML、图片和危险/混淆协议 | -| `npm run desktop:test:unit` | 38 项通过,含系统浏览器协议过滤、更新流程及隔离 macOS 应用的原生升级验证 | -| `npm run desktop:build` | 5 个构建任务成功 | -| Electron smoke(write + restore) | 通过;验证真实渲染、链接到主进程的路径、下载中刷新、重启安装、后台关闭与跨进程恢复 | -| `git diff --check` | 通过 | - -直接在隐藏的 `.worktrees` 路径运行 `npm run desktop:test` 时,现有 Express `sendFile` 的隐藏目录策略使 SPA 回退路由返回 404。将相同 staged app 复制到普通临时目录后,完整 smoke 两阶段通过;没有修改服务器逻辑。可从 worktree 根目录按下列步骤复现: - -```sh -npm run desktop:build -TASK_WORKTREE="$PWD" -SMOKE_ROOT="$(mktemp -d /tmp/remote-git-update-smoke.XXXXXX)" -mkdir -p "$SMOKE_ROOT/dist" -cp -R apps/desktop/dist/app "$SMOKE_ROOT/dist/app" -(cd "$SMOKE_ROOT" && node "$TASK_WORKTREE/apps/desktop/scripts/smoke.mjs") -``` - -## 界面验收 - -生产构建使用 [更新说明样例](../../../apps/web/tests/fixtures/update-notes.md) 和隔离的更新服务替身: - -```sh -npm run build -w @remote-git/shared -npm run build -w web -node apps/web/tests/update-fixture.mjs -``` - -打开命令输出的地址,进入“设置 → 检查更新”。控制台中的 `window.__updateFixture.set(...)` 可模拟说明内容及下载完成状态,`window.__updateFixture.calls` 可核对按钮调用。默认 macOS 快照使用与当前桌面端一致的 `restart` 安装模式。 - -[浏览器断言记录](browser-checks.json) 包含以下结果: - -- 说明区域宽度与 `scrollWidth` 均为 427 px;外层面板宽度与 `scrollWidth` 均为 472 px,没有横向溢出。 -- 代码内容宽 1018 px、容器宽 425 px;宽表格内容宽 577 px、容器宽 427 px;均可独立横向滚动 100 px。 -- 滚动说明时,更新操作按钮位置保持不变;`1000×680` 窗口中的按钮底部约为 627 px。 -- 空说明、纯空白、普通文本及危险输入通过。危险输入未生成 script、iframe 或 img 元素,脚本执行标记保持为 false,仅安全 HTTPS 链接可点击。 -- 实际点击了检查、下载、取消和重启安装入口,调用顺序与替身记录一致;macOS 下载完成后保留 Markdown 渲染并显示“重启安装”。 - -| 原界面 | Markdown 渲染后 | -| ---------------------------- | ---------------------- | -| ![原始 Markdown](before.png) | ![渲染结果](after.png) | - -| 代码块 | 宽表格 | -| --------------------------------- | -------------------------------- | -| ![代码块横向滚动](after-code.png) | ![表格横向滚动](after-table.png) | - -![应用最小窗口](after-minimum-window.png) - -![macOS 重启安装与 Markdown 更新说明](after-restart-install.png) - -## 验证边界 - -浏览器更新操作使用替身;Electron smoke 拦截系统浏览器调用并使用模拟安装包,不执行真实下载或安装。桌面测试已运行隔离 macOS 应用的原生 DMG 挂载、替换及重新打开流程。Windows/Linux 原生运行及真实 RemoteGit 发布包升级未执行。 - -新增解析依赖使前端主包 gzip 从约 381 kB 增至 428 kB;现有依赖版本没有变更。构建保留原有的大 chunk 提示。 diff --git a/docs/validation/issue-13/after-code.png b/docs/validation/issue-13/after-code.png deleted file mode 100644 index 7a00f68..0000000 Binary files a/docs/validation/issue-13/after-code.png and /dev/null differ diff --git a/docs/validation/issue-13/after-minimum-window.png b/docs/validation/issue-13/after-minimum-window.png deleted file mode 100644 index 33b6dd9..0000000 Binary files a/docs/validation/issue-13/after-minimum-window.png and /dev/null differ diff --git a/docs/validation/issue-13/after-restart-install.png b/docs/validation/issue-13/after-restart-install.png deleted file mode 100644 index 1aeca14..0000000 Binary files a/docs/validation/issue-13/after-restart-install.png and /dev/null differ diff --git a/docs/validation/issue-13/after-table.png b/docs/validation/issue-13/after-table.png deleted file mode 100644 index 7bc3586..0000000 Binary files a/docs/validation/issue-13/after-table.png and /dev/null differ diff --git a/docs/validation/issue-13/after.png b/docs/validation/issue-13/after.png deleted file mode 100644 index 35d0bbf..0000000 Binary files a/docs/validation/issue-13/after.png and /dev/null differ diff --git a/docs/validation/issue-13/before.png b/docs/validation/issue-13/before.png deleted file mode 100644 index 76651f8..0000000 Binary files a/docs/validation/issue-13/before.png and /dev/null differ diff --git a/docs/validation/issue-13/browser-checks.json b/docs/validation/issue-13/browser-checks.json deleted file mode 100644 index fb9f746..0000000 --- a/docs/validation/issue-13/browser-checks.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "desktop": { - "notesWidth": 427, - "notesScrollWidth": 427, - "notesHeight": 260, - "notesScrollHeight": 1261, - "panelWidth": 472, - "panelScrollWidth": 472, - "buttonsTop": [732.53125, 732.53125] - }, - "scrolling": { - "code": { - "width": 425, - "scrollWidth": 1018, - "scrollLeft": 100 - }, - "table": { - "width": 427, - "scrollWidth": 577, - "scrollLeft": 100 - }, - "buttonsTop": [732.53125, 732.53125] - }, - "minimum": { - "viewport": [1000, 680], - "buttons": [ - { - "text": "检查更新", - "top": 594.53125, - "bottom": 626.53125 - }, - { - "text": "下载更新", - "top": 594.53125, - "bottom": 626.53125 - } - ], - "width": 427, - "scrollWidth": 427 - }, - "restart": { - "platform": "darwin", - "installMode": "restart", - "notesRendered": true, - "buttons": ["检查更新", "重启安装"] - }, - "updateActions": ["check", "download", "cancel", "install"], - "contentCases": [ - { - "name": "empty", - "text": "此版本未提供更新说明。", - "scripts": 0, - "executed": false, - "links": [] - }, - { - "name": "whitespace", - "text": "此版本未提供更新说明。", - "scripts": 0, - "executed": false, - "links": [] - }, - { - "name": "plain", - "text": "普通文本更新说明。\n第二段保持可读。", - "scripts": 0, - "executed": false, - "links": [] - }, - { - "name": "hostile", - "text": "\n\n危险\n混淆\n文件\n远程图片\n安全链接\n安全内容", - "scripts": 0, - "executed": false, - "links": [ - { - "href": "https://example.com/notes", - "target": "_blank", - "rel": "noopener noreferrer" - } - ] - } - ] -} diff --git a/docs/validation/issue-18/README.md b/docs/validation/issue-18/README.md deleted file mode 100644 index 4d922ef..0000000 --- a/docs/validation/issue-18/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Issue #18:新增文件差异预览 - -基线:`development@6c1e6be`。验证环境:macOS 15.5 arm64、Node.js 25.5.0、Git 2.43.1、Electron 44.2.0。所有测试使用隔离数据目录和临时仓库,没有使用已有连接或修改真实远端仓库。 - -## 行为与限制 - -- 未跟踪文件通过只读 `git diff --no-index` 与 `/dev/null` 比较。退出码 1 在产生差异时视为成功;文件在预检后消失造成的同码错误仍显示读取失败。 -- 暂存预览使用索引中的实际内容,暂存后再次编辑的文件分别显示两条状态。未首次提交时,取消暂存只移除索引条目,保留工作区文件。 -- 状态使用 NUL 分隔并展开未跟踪目录中的文件;路径采用 shell 单引号转义和 Git literal pathspec,覆盖中文、空格、引号、美元符号、反引号、括号、方括号、换行、制表符、反斜杠和前导连字符。 -- 空文件、二进制文件、非 UTF-8 文本、超限文件、权限不足和文件消失各有对应反馈。SSH 输出最多 1 MiB,差异最多 10,000 行;未跟踪文件和索引 blob 也在生成差异前检查 1 MiB 大小限制。 -- 切换文件、比较侧、仓库和关闭检查器时使旧请求失效。状态刷新后重新读取当前比较;历史提交和普通修改/删除仍使用 Git 的比较语义。 - -## 自动验证 - -| 检查 | 结果 | 覆盖 | -| ---------------------------------------------------------------------------------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `npm test -w @remote-git/ssh-client` | 12 项通过 | 回环 SSH 服务执行真实 Git;有/无 HEAD 的状态流、暂存快照、只读索引与文件字节检查、特殊路径、空/二进制/超限/编码/权限/消失、符号链接、普通修改/删除/重命名/历史、SSH UTF-8 分包及输出限额 | -| `npm test -w web` | 38 项通过 | 新增行解析、特殊内容不误认文件头、空/二进制提示、乱序成功/失败、关闭选择和仓库切换;既有前端用例 | -| `npm test -w server -- --runInBand repository.controller.spec.ts git.service.spec.ts repository.service.spec.ts` | 8 项通过 | 比较侧参数、读取失败反馈、暂存/取消暂存调用及仓库状态 | -| `npm run desktop:build` | 通过 | 共享包、SSH 包、Web、服务端和 Electron 暂存应用 | -| `cd apps/desktop && node scripts/smoke.mjs` | 写入和重启恢复两阶段通过 | 实际 Electron UI、统一/分栏/放大、暂存后编辑、取消暂存、异常提示、延迟返回、关闭选择;既有路由/认证/数据库/布局/更新回归 | -| `npm run test:hooks` | 22 项通过 | 既有 Git hooks 回归 | -| `npm run test:release-notes` | 4 项通过 | 既有版本说明回归 | -| `npm run desktop:test:unit` | 37 项通过,1 项超时 | 既有原生 macOS DMG 升级测试在 60 秒后超时;在未修改的 `development@6c1e6be` 单独复测同样超时 | - -Electron 的新增界面用例使用可控 Git 响应来稳定覆盖异步状态,真实 SSH/Git 行为由 SSH 集成测试和下述 Web 验证覆盖。原生 DMG 超时的复测命令是 `node --test --test-name-pattern='macOS native DMG' apps/desktop/test/mac-installer.test.cjs`,未改动安装功能或忽略该测试。 - -## Web 实际链路验证 - -使用 ego-browser 访问本机构建的 Web 与 NestJS 服务,通过回环 SSH 连接隔离的 Git 仓库: - -- `演示/新增 文件.ts` 未暂存时完整显示全部新增行;分栏左侧为空,放大窗口显示同一内容。 -- 通过界面暂存后,在测试仓库中追加 `unstagedOnly`,刷新后显示已暂存与未暂存两条记录。已暂存比较不包含追加内容;未暂存比较显示追加内容。 -- 取消暂存后自动更新预览,将整个当前文件显示为新增内容。 -- 空文件、二进制、大文件分别显示对应提示。文件在列表加载后删除,点击时显示读取失败;刷新后清除失效选择。 -- 切换到另一个空仓库后清除原预览;首次提交的历史 diff 正常显示。 - -## 开发模式启动回归 - -后续在 `npm run dev` 模式复现白屏:浏览器直接加载共享工作区的 CommonJS `dist/index.js`,报错缺少 `REPOSITORY_STATUS_REQUEST_TIMEOUT_MS` 导出。此前构建后的页面验证无法覆盖这个开发服务器差异。 - -已在 Web 的 Vite 配置中把 `@remote-git/shared` 映射到其 TypeScript 源码,让 Vite 转换为浏览器使用的 ES 模块,也避免前端启动依赖共享包预先构建。使用实际 Vite 开发服务复测连接页、仓库列表和刷新,并检查浏览器运行时异常;Web 构建和 38 项前端测试通过。 - -## 截图与未验证范围 - -![Electron 中的新增文件分栏预览](desktop-split.png) - -截图来自隔离的 Electron UI 测试夹具。Web 的 DOM 和实际交互已验证,但本次浏览器截图接口超时,未将其列为截图证据。 - -未验证 Windows/Linux 桌面实机、真实网络 SSH 主机、安装包发布与升级。SSH 集成测试夹具需要 POSIX `/bin/sh`;运行环境没有该 shell 时应在 macOS/Linux 上执行这一组测试。 diff --git a/docs/validation/issue-18/desktop-split.png b/docs/validation/issue-18/desktop-split.png deleted file mode 100644 index 8ba6d63..0000000 Binary files a/docs/validation/issue-18/desktop-split.png and /dev/null differ diff --git a/docs/validation/issue-21/README.md b/docs/validation/issue-21/README.md deleted file mode 100644 index 620e6e8..0000000 --- a/docs/validation/issue-21/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# Issue #21 实现与验证 - -实现基于 `origin/development` 的 `6030c2c`,使用独立 worktree `remote-git-issue-21`、分支 `codex/issue-21-ai-commit-settings`。沿用 [Issue #21](https://github.com/ShaoClean/remote-git/issues/21) 已确认的浅蓝侧栏、独立设置页、服务商三栏结构、提交框内星光按钮和窄窗口逐级导航。 - -2026-09-15,macOS arm64、Node.js 25.5.0、Electron 44.2.0、Ego Lite / Chromium。功能验收使用隔离的 HTTP 模拟服务;Git 检查使用临时真实仓库或既有 smoke 数据,不操作用户远程仓库,不调用真实商业模型。后续 HTTP 423 排查对用户配置的服务做了最小 HTTP 请求对比,没有发送仓库内容或记录密钥;失败请求不计为真实模型连通性通过。 - -## 截图 - -截图为生产前端构建连接真实本地 API、临时 Git 仓库和模拟模型服务的运行结果。地址、仓库和配置均为测试数据。 - -| 场景 | 截图 | -| --------------------------------------------- | ----------------------------------------- | -| 已生成提交信息,保留撤销入口(1440 × 960) | ![提交生成](workspace-wide.png) | -| AI 服务商列表、配置与模型(1440 × 960) | ![服务商设置](providers-wide.png) | -| 默认模型与生成偏好(1440 × 960) | ![提交生成设置](commit-settings-wide.png) | -| 自定义 Anthropic 服务商与手动模型 | ![自定义服务商](custom-provider-wide.png) | -| 普通窗口(1000 × 760) | ![普通窗口](providers-normal.png) | -| 窄窗口服务商列表(390 × 844) | ![窄窗口列表](provider-list-narrow.png) | -| 窄窗口服务商详情(390 × 844) | ![窄窗口详情](provider-narrow.png) | -| 最小宽度提交生成设置(320 × 740,正文可滚动) | ![最小宽度](commit-settings-320.png) | -| 独立服务手动输入 API Key 后连接成功(1200 × 860,无密钥环境变量) | ![手动配置密钥](manual-api-key.png) | -| 选择未启用模型进行连接测试(1502 × 724) | ![选择测试模型](test-model-wide.png) | -| 窄窗口选择测试模型并连接成功(390 × 844) | ![窄窗口测试模型](test-model-narrow.png) | - -真实 Electron 窄窗口(390 px,Retina 2×): - -![原生桌面窄窗口](desktop-native-narrow.png) - -## 自动验证 - -| 检查 | 结果 | -| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `npm run desktop:build` | 共享类型、SSH 包、NestJS、前端及桌面 staging 全部构建通过;保留既有 Vite 大 chunk 提示 | -| `npm test -w web` | 44 项通过,包含 5 项新增 AI 草稿/默认模型测试 | -| 相关服务端 Jest | 58 项通过,覆盖配置持久化、自动本机密钥存储、手动密钥生效且无环境变量回退、三类协议及四个预置/三类自定义服务、显式选择测试模型、模型列表及分页、HTTP 423 拒绝访问提示及失败时保留配置、错误、取消、超时与暂存变化,以及现有仓库/Git 回归 | -| SSH 包 | 47 项通过,1 项 Windows 专用检查在 macOS 跳过;新增 5 项真实 Git 验证覆盖混合改动、空分支、二进制、体积限制、取消、快照变化和提交字面值 | -| AI 密钥/更新器/外链/工作区偏好桌面单元测试 | 28 项通过 | -| Electron 两次独立启动 smoke | 通过;指定未启用模型的连接测试使用正确的模型 ID;真实系统保护的密钥、默认模型及语言偏好跨进程恢复,前端不读取已保存密钥;390 px 原生窗口列表/详情、设置/布局、更新检查、离开设置继续下载、下载中刷新、重启安装按钮及后端关闭保持正常 | - -相关服务端命令: - -```sh -npm test -w server -- --runInBand --testPathPatterns='ai|git.service|new-file-deletion|repository|app.controller|connection.service' -``` - -完整服务端 Jest 仍有 4 个未改动的脚手架测试因缺少依赖注入 mock 失败:`connection.controller.spec.ts`、`file.controller.spec.ts`、`git.controller.spec.ts`、`file.service.spec.ts`。已在原工作区运行相同四个测试并复现;不将这些测试记为通过。 - -完整桌面单元测试中,既有 macOS 原生 DMG staging/替换/启动集成测试达到 60 秒时限。本次没有修改安装器实现;更新器单元测试及桌面 UI/下载/重启安装 smoke 已通过,原生 DMG 升级不记为已通过。 - -## 浏览器交互 - -- 独立服务在未配置任何 AI 密钥环境变量、未注入测试存储适配器时启动。通过页面输入 API Key、切换显隐、保存并测试连接成功;更换、清除和重新输入密钥均通过模拟服务的实际认证头校验。 -- 第二个独立 Node 服务进程读取同一数据目录,无密钥环境变量也能恢复配置并通过认证;配置响应不含密钥明文或密文,配置文件为加密载荷,本机密钥文件权限为 `0600`,检查测试服务日志未发现输入的密钥。 -- “测试模型”初始选择当前服务商的默认提交模型;选择另一个未启用模型后,模拟服务实际收到选定的模型 ID,默认提交模型及模型启用状态保持不变。选择“仅测试模型列表接口”可单独测试列表接口;切换服务商后不沿用上一个服务商的模型。390 px 下选择和测试正常,无整体横向溢出。 -- 未配置 AI 时从星光按钮进入设置;返回后仓库、已选差异、原摘要和含空行的完整描述保留。 -- 保存 DeepSeek 模拟配置,测试生成连接、获取模型;添加独立 Anthropic 与 Gemini 自定义服务,手动添加准确 ID、启停模型并保存;分别验证连接。 -- 设置默认模型、中文 Conventional Commits 和补充提示词。后端实际请求只包含暂存版本,未暂存内容未发送。 -- 生成后同时填入摘要/描述,撤销恢复原稿;再次生成与手动编辑有效,手动编辑后撤销入口收起。 -- 取消、生成中编辑、进入设置、切换仓库均保留用户草稿;模拟服务记录到客户端请求实际中断。第二个仓库的独立草稿保持不变。 -- 模拟 401 认证失败,错误可读、草稿保留、手动重试成功。 -- 模型请求进行时直接重新暂存同一文件:服务端以 blob ID 变化检测到旧快照,返回 409,不填入旧结果。 -- 从 UI 取消暂存全部内容后生成,明确提示先暂存;再次暂存与生成正常。 -- 在临时真实仓库中点击提交,核对 Git 对象中的摘要/描述与生成草稿逐字一致,引号、`$()`、反引号和空行均保留,提交后草稿清空,未跟踪文件不被提交。 -- 390 px 下列表/详情切换、搜索、分类选择可操作;320 px 下没有整体横向溢出。布局滑块支持键盘 End,恢复默认回到 340 px。 -- 非桌面“版本更新”显示原有不支持说明,AI 与布局分类保持可用。 - -## 2026-09-16:模型编辑与删除 - -参考 [LobeHub 模型行内操作](https://github.com/lobehub/lobehub/blob/main/src/features/Settings/provider/features/ModelList/ModelItem.tsx),在每行添加编辑、删除图标,保留启用开关。新增和编辑复用模型表单;操作先更新草稿,通过“保存配置”统一持久化。 - -生产前端连接隔离的本地 API 和模拟模型服务,浏览器验证通过: - -- 修改名称保留默认选择;修改 ID 保留原启用状态,空名称使用 ID。重复、空白及含空格 ID 均被拦截,取消编辑不改动列表,取消添加后重新打开为空表单。 -- 删除需要确认,默认模型的 ID 修改及删除均提示保存后的影响。保存后清空失效的默认引用,测试模型下拉框回退到有效项;刷新页面保留已保存的修改和删除。 -- 模型操作在保存前不写入配置;模拟配置版本冲突时,页面保留未保存草稿,服务端保留原模型。重新加载可恢复服务端列表。 -- 删除最后一个模型后显示空状态,测试模型切换为模型列表接口;再次主动获取时,上游仍返回的模型以停用状态重新加入。 -- 1440 × 1000 和 320 × 740 下可完成编辑、保存、添加、删除,窄窗口列表及弹窗无横向溢出;编辑按钮支持键盘 Enter。删除确认按钮使用红色,避免被既有全局蓝色按钮样式覆盖。 - -| 场景 | 截图 | -| --- | --- | -| 编辑模型 | [宽窗口](model-edit-wide.png) · [320 px](model-edit-320.png) | -| 删除确认 | [默认模型](model-delete-wide.png) · [320 px](model-delete-320.png) | -| 行内编辑、删除及启停 | [320 px 模型列表](model-list-320.png) | - -`npm run build -w web`、`npm run build -w server` 均通过;`npm test -w web` 为 44 项通过,`npm test -w server -- --runInBand --testPathPatterns=ai` 为 46 项通过。新增 3 项服务端回归覆盖删除、更改模型 ID 后清除默认选择并跨重启持久化,以及仅改名称或删除其他模型时保留默认选择。Vite 仍有既有的大 chunk 提示。本次未重新执行 Electron 或 Windows/Linux 原生界面验收。 - -## 2026-09-16:PR 提交前回归 - -在 macOS arm64、Node.js 25.5.0、Electron 44.2.0 上对当前完整改动重新验证: - -| 检查 | 结果 | -| --- | --- | -| `npm run desktop:build` | 5 个构建任务全部通过;Vite 保留既有大 chunk 提示 | -| `npm test -w web` | 44 项通过 | -| 上述相关服务端 Jest 命令 | 9 个测试套件、61 项通过 | -| `npm test -w @remote-git/ssh-client` | 49 项通过;Windows 真实差异预览及 PowerShell 字节保真 2 项平台专用测试跳过 | -| AI 密钥、更新器、外链、工作区偏好桌面单元测试 | 28 项通过 | -| 在 `apps/desktop` 运行 `node scripts/smoke.mjs` | 两次独立启动通过,系统密钥存储可用,AI 配置及密钥跨进程恢复;窄窗口设置、差异预览、布局、更新下载及重启安装按钮回归通过 | - -桌面单元测试命令: - -```sh -node --test apps/desktop/test/ai-secret-storage.test.cjs apps/desktop/test/updater.test.cjs apps/desktop/test/external-links.test.cjs apps/desktop/tests/workspace-preferences.test.cjs -``` - -此次未重跑前文已记录失败的完整服务端脚手架测试及原生 DMG 安装集成测试,也未新增真实商业模型或 Windows/Linux 原生平台验证。截图与浏览器交互记录沿用前文验收结果。 - -## 复现 - -```sh -npm run build -w @remote-git/shared -npm run build -w @remote-git/ssh-client -npm run build -w server -npm run build -w web -node apps/server/test/ai-ui-fixture.cjs -``` - -打开输出的 `repositoryUrl`;`modelUrl` 可填入任意协议的测试服务商基础地址,密钥使用任意测试值。模拟控制接口 `controlUrl` 支持 JSON `{"mode":"slow"}`、`{"mode":"auth"}`、`{"mode":"empty"}`、`{"mode":"no-models"}`、`{"mode":"success"}` 和 `{"restage":true}`。只绑定 loopback,结束时清除它创建的临时仓库与数据目录。 - -验证手动密钥时可向控制接口发送 `{"expectedApiKey":"测试值"}`,模拟服务会校验后续请求的认证头,控制响应只返回 `authenticated` 布尔状态。独立服务使用生产环境的自动本机密钥存储,无需设置密钥环境变量。 - -桌面完整 staging 后在 `apps/desktop` 运行 `node scripts/smoke.mjs`,由脚本创建两个隔离桌面进程。可设置 `REMOTE_GIT_AI_SMOKE_SCREENSHOT` 保存真实窄窗口截图。本机复用了原工作区中相同版本的 Electron 可执行文件;生产构建仍来自本 worktree。 - -未执行真实 OpenAI/Anthropic/Gemini/DeepSeek 账号调用、Windows/Linux 原生密钥存储与安装包验收、Windows 远程 shell 的实际提交,或用户远程仓库写操作。协议、分页、错误和 Windows 参数编码由模拟服务/单元测试覆盖;实际兼容性仍需对应服务账号与平台验证。 diff --git a/docs/validation/issue-21/commit-settings-320.png b/docs/validation/issue-21/commit-settings-320.png deleted file mode 100644 index b97992b..0000000 Binary files a/docs/validation/issue-21/commit-settings-320.png and /dev/null differ diff --git a/docs/validation/issue-21/commit-settings-wide.png b/docs/validation/issue-21/commit-settings-wide.png deleted file mode 100644 index fcfdb74..0000000 Binary files a/docs/validation/issue-21/commit-settings-wide.png and /dev/null differ diff --git a/docs/validation/issue-21/custom-provider-wide.png b/docs/validation/issue-21/custom-provider-wide.png deleted file mode 100644 index 788330f..0000000 Binary files a/docs/validation/issue-21/custom-provider-wide.png and /dev/null differ diff --git a/docs/validation/issue-21/desktop-native-narrow.png b/docs/validation/issue-21/desktop-native-narrow.png deleted file mode 100644 index 1aaf535..0000000 Binary files a/docs/validation/issue-21/desktop-native-narrow.png and /dev/null differ diff --git a/docs/validation/issue-21/manual-api-key.png b/docs/validation/issue-21/manual-api-key.png deleted file mode 100644 index b636725..0000000 Binary files a/docs/validation/issue-21/manual-api-key.png and /dev/null differ diff --git a/docs/validation/issue-21/model-delete-320.png b/docs/validation/issue-21/model-delete-320.png deleted file mode 100644 index c4badde..0000000 Binary files a/docs/validation/issue-21/model-delete-320.png and /dev/null differ diff --git a/docs/validation/issue-21/model-delete-wide.png b/docs/validation/issue-21/model-delete-wide.png deleted file mode 100644 index da9f3bd..0000000 Binary files a/docs/validation/issue-21/model-delete-wide.png and /dev/null differ diff --git a/docs/validation/issue-21/model-edit-320.png b/docs/validation/issue-21/model-edit-320.png deleted file mode 100644 index cefb660..0000000 Binary files a/docs/validation/issue-21/model-edit-320.png and /dev/null differ diff --git a/docs/validation/issue-21/model-edit-wide.png b/docs/validation/issue-21/model-edit-wide.png deleted file mode 100644 index 3457195..0000000 Binary files a/docs/validation/issue-21/model-edit-wide.png and /dev/null differ diff --git a/docs/validation/issue-21/model-list-320.png b/docs/validation/issue-21/model-list-320.png deleted file mode 100644 index 185638d..0000000 Binary files a/docs/validation/issue-21/model-list-320.png and /dev/null differ diff --git a/docs/validation/issue-21/provider-list-narrow.png b/docs/validation/issue-21/provider-list-narrow.png deleted file mode 100644 index ab90134..0000000 Binary files a/docs/validation/issue-21/provider-list-narrow.png and /dev/null differ diff --git a/docs/validation/issue-21/provider-narrow.png b/docs/validation/issue-21/provider-narrow.png deleted file mode 100644 index b08cc78..0000000 Binary files a/docs/validation/issue-21/provider-narrow.png and /dev/null differ diff --git a/docs/validation/issue-21/providers-normal.png b/docs/validation/issue-21/providers-normal.png deleted file mode 100644 index 1834b0d..0000000 Binary files a/docs/validation/issue-21/providers-normal.png and /dev/null differ diff --git a/docs/validation/issue-21/providers-wide.png b/docs/validation/issue-21/providers-wide.png deleted file mode 100644 index 8de351d..0000000 Binary files a/docs/validation/issue-21/providers-wide.png and /dev/null differ diff --git a/docs/validation/issue-21/test-model-narrow.png b/docs/validation/issue-21/test-model-narrow.png deleted file mode 100644 index 244c9c1..0000000 Binary files a/docs/validation/issue-21/test-model-narrow.png and /dev/null differ diff --git a/docs/validation/issue-21/test-model-wide.png b/docs/validation/issue-21/test-model-wide.png deleted file mode 100644 index e4c0547..0000000 Binary files a/docs/validation/issue-21/test-model-wide.png and /dev/null differ diff --git a/docs/validation/issue-21/workspace-wide.png b/docs/validation/issue-21/workspace-wide.png deleted file mode 100644 index 11a03f0..0000000 Binary files a/docs/validation/issue-21/workspace-wide.png and /dev/null differ diff --git a/docs/validation/issue-5/README.md b/docs/validation/issue-5/README.md deleted file mode 100644 index 4642298..0000000 --- a/docs/validation/issue-5/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Issue #5:已登记仓库优先展示 - -基线:`9c260f6`(development / v0.2.0)。验证日期:2026-09-10 至 2026-09-11。 - -## 实现与刷新策略 - -- `GET /api/repositories` 只查询本地 SQLite,返回完整的 ID、connectionId、name、path;不建立 SSH 连接,也不查询 Git。前端始终请求完整注册表,连接与搜索筛选在页面中处理。 -- 复用单仓库 `/status` 接口。每个仓库独立保存请求阶段、最近一次有效数据、错误和更新时间。注册列表刷新保留状态缓存;状态响应不触碰工作区排序、折叠或布局偏好。 -- 当前工作区优先,最多 3 个状态请求,其中后台最多 2 个,预留 1 个位置给当前工作区。卡片与侧栏通过 IntersectionObserver 请求可见仓库;离开可见区域会撤销尚未执行的后台请求,折叠或未滚动到的仓库按需读取。 -- 缓存有效期 **60 秒**,只保存在内存。过期后显示“已过期”;再次进入可见区域时刷新。打开工作区或手动刷新不受有效期限制。失败后自动重试 **0 次**,通过“重试状态”或再次打开工作区恢复,避免离线主机反复重试。 -- 单仓库服务端总时限 **10 秒**,涵盖连接与 Git;客户端时限 **12 秒**,留出传输余量。超时关闭当前 Git 命令的 SSH channel,不断开其他仓库共用的连接;连接晚到后不会再启动该次 Git 查询。 -- 前后端均合并同仓库的并行状态请求,同主机的并行连接请求也会合并。切换工作区取消旧的前台请求;删除或完整注册表确认移除的仓库,其晚到状态不能恢复数据。Git 写操作之后会等待旧读取结束,再共享一次新的验证读取。 -- 工作区先使用注册信息展示身份与操作入口,状态独立加载;历史、分支、远程等面板按需加载。未取得状态时显示“分支未知”和读取提示,失败时提供重试,不显示“工作区干净”。 - -## 性能对比 - -环境:macOS arm64,Node.js v25.5.0;生产构建;本机 HTTP;隔离的内存 SQLite;24 个虚构仓库,分布在 2 个连接,另有 1 个空连接。模拟第 1 个仓库耗时 800 ms,其余 23 个各 40 ms,不接触任何真实 SSH 主机或用户仓库。每组运行 3 次,以下使用中位数。 - -| 指标 | 改动前 | 改动后 | -| --- | ---: | ---: | -| 注册列表 HTTP 请求完成 | 1,766.83 ms | 3.49 ms | -| 全部 24 个远程状态完成(从列表请求开始计时) | 1,766.83 ms | 924.86 ms | -| 浏览器注册列表可见(从导航开始计时) | 2,004.00 ms | 211.10 ms | -| 浏览器首屏可见卡片状态完成 | 2,004.20 ms | 1,401.80 ms | - -HTTP 对比使用实际基线 RepositoryService(从 Git 读取后临时转译)与修改后的 RepositoryService;改动后以 2 个并发 worker 读取全部 24 个状态。 - -浏览器对比使用基线与修改后各自的生产构建,Ego Lite 视口 1512 × 756,禁用该页面的 HTTP 缓存。通过 MutationObserver + requestAnimationFrame 记录注册卡片首次出现及当前视口卡片的状态完成。加入更新时间使卡片略高,改动前首屏可见 12 张卡片,改动后为 9 张;因此“首屏状态完成”不能当作相同数量仓库的吞吐对比。全部仓库的同规模对比见 HTTP 测量。浏览器调度及渲染存在抖动,原始三次记录均已保留。 - -原始结果:[HTTP 测量](benchmark.json)、[浏览器测量](browser-benchmark.json)、[桌面冒烟摘要](desktop-smoke.json)。这些数值仅描述上述模拟条件,不代表真实网络或大型 Git 仓库的性能承诺。 - -桌面端额外验证:使用 Electron 44.2.0、独立临时数据目录,先登记仓库,再冷加载 renderer(内存 store 为空)。禁用 SSH 后列表在 **78.1 ms** 内可见(最终构建复测 **83.7 ms**);错误、网络恢复重试、再次失败保留分支和时间戳均通过。完整冒烟还覆盖实际进程重启、SQLite CRUD、认证、沙箱、排序、折叠、布局、滚动及后端关闭。 - -## 验收结果 - -| 场景 | 结果 | -| --- | --- | -| 空注册表、多连接、所有 SSH 阻塞/禁用 | 服务测试通过;浏览器离线仍展示 24 个已登记仓库 | -| 单个 Git 状态超时、其他仓库成功 | 服务 fake timers 与浏览器 10 秒真实超时均通过 | -| 连接迟到、Git channel 迟到或报错 | 不执行过期 Git;关闭迟到 channel;其他命令不受影响 | -| 首次注册列表失败及重试 | 显示明确错误与重试,不显示空列表 | -| 已有列表刷新失败 | 保留全部卡片、状态摘要与偏好,显示刷新失败 | -| 状态未知、失败、旧缓存、自然过期 | 卡片、侧栏及工作区可辨认;未知分支不显示“无分支”或“游离 HEAD” | -| 当前仓库优先、重复刷新、可见区域变化 | 队列上限、预留位置、合并及撤销未执行请求的测试通过 | -| 切换仓库、删除仓库、注册表与状态乱序 | 单元测试通过;旧状态无法覆盖新工作区或恢复删除条目 | -| Git 写操作与正在进行的读取重叠 | 等待旧读取后进行一次新读取,重复验证合并 | -| 连接筛选与排序、折叠偏好 | 浏览器筛选无匹配时侧栏仍有 24 个仓库,保存的偏好完全一致;桌面重启还原通过 | -| 扫描、添加、移除 | 服务注册 CRUD 与浏览器模拟扫描流程验证 | - -相关自动测试:Web **30** 项、Repository/Connection 服务与控制器 **7** 项、SSH command **3** 项、Desktop 单元测试 **21** 项,合计 **61** 项。另执行完整桌面两阶段冒烟及浏览器验收。这里的服务端数量指相关测试文件,不代表执行了其他模块的脚手架测试。 - -界面证据均为虚构数据: - -- [正常列表](loaded.png) -- [首载失败](first-load-error.png) -- [SSH 离线时的完整注册列表](offline-registry.png) -- [工作区状态超时](workspace-timeout.png) -- [刷新失败保留列表与旧状态](stale-cache.png) - -## 重复验证 - -在仓库根目录执行: - -```sh -npm ci -npm run build --workspace=@remote-git/shared -npm run test --workspace=@remote-git/ssh-client -npm run test --workspace=server -- --runInBand repository.service.spec.ts repository.controller.spec.ts connection.service.spec.ts -npm run test --workspace=web -npm run desktop:build -npm run desktop:test:unit -node apps/web/tests/repository-loading-fixture.cjs --benchmark -node apps/web/tests/repository-loading-fixture.cjs -``` - -最后一个命令输出本机临时端口。打开 `/repositories`;仅此测试 fixture 提供 `/__fixture`,可 POST `listError`、`offline`、`slowMs`、`fastMs`、`failIds`、`delayIds` 来切换模拟状态,GET 可读取虚构注册表和调用记录。该控制接口不会被打包到生产服务中。 - -桌面完整冒烟通常执行 `npm run desktop:test`。本次 worktree 路径包含 `.worktrees`;现有 Express `sendFile` 会将绝对路径中的隐藏目录判为 dotfile,导致启动页 404。为测试同一构建产物,将 staged app 复制到普通临时目录,未修改生产静态服务或用户数据: - -```sh -repo_dir="$PWD" -smoke_dir=$(mktemp -d /tmp/remote-git-issue-5-smoke.XXXXXX) -mkdir -p "$smoke_dir/dist" -cp -R apps/desktop/dist/app "$smoke_dir/dist/app" -(cd "$smoke_dir" && node "$repo_dir/apps/desktop/scripts/smoke.mjs") -``` - -重建基线前端供浏览器对比: - -```sh -baseline_dir=$(mktemp -d /tmp/remote-git-issue-5-baseline.XXXXXX) -git archive 9c260f6 apps/web package.json tsconfig.json | tar -x -C "$baseline_dir" -ln -s "$PWD/node_modules" "$baseline_dir/node_modules" -(cd "$baseline_dir/apps/web" && npm run build) -REMOTE_GIT_FIXTURE_WEB_ROOT="$baseline_dir/apps/web/dist" node apps/web/tests/repository-loading-fixture.cjs --legacy -``` - -本次不改数据库结构,不重新登记用户仓库,不保存远程状态到持久化工作区偏好。Vite 构建仍有原有的大 bundle 提示。 diff --git a/docs/validation/issue-5/benchmark.json b/docs/validation/issue-5/benchmark.json deleted file mode 100644 index 32eb65f..0000000 --- a/docs/validation/issue-5/benchmark.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "baseline": "9c260f6", - "node": "v25.5.0", - "platform": "darwin/arm64", - "simulatedLatency": { - "firstRepoMs": 800, - "otherReposMs": 40 - }, - "results": [ - { - "legacy": true, - "run": 1, - "count": 24, - "registryMs": 1801.35, - "remoteCompleteMs": 1801.37 - }, - { - "legacy": true, - "run": 2, - "count": 24, - "registryMs": 1766.83, - "remoteCompleteMs": 1766.83 - }, - { - "legacy": true, - "run": 3, - "count": 24, - "registryMs": 1759.09, - "remoteCompleteMs": 1759.1 - }, - { - "legacy": false, - "run": 1, - "count": 24, - "registryMs": 3.49, - "remoteCompleteMs": 932.59 - }, - { - "legacy": false, - "run": 2, - "count": 24, - "registryMs": 4.02, - "remoteCompleteMs": 924.86 - }, - { - "legacy": false, - "run": 3, - "count": 24, - "registryMs": 0.63, - "remoteCompleteMs": 919.58 - } - ] -} diff --git a/docs/validation/issue-5/browser-benchmark.json b/docs/validation/issue-5/browser-benchmark.json deleted file mode 100644 index 74547a9..0000000 --- a/docs/validation/issue-5/browser-benchmark.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "viewport": [ - 1512, - 756 - ], - "cacheDisabled": true, - "results": [ - { - "version": "before", - "run": 1, - "registryVisibleMs": 2059.7999999523163, - "registeredCount": 24, - "firstVisibleStatusMs": 2059.899999976158, - "visibleStatusCompleteMs": 2059.899999976158, - "visibleCount": 12 - }, - { - "version": "before", - "run": 2, - "registryVisibleMs": 1938.6000000238419, - "registeredCount": 24, - "firstVisibleStatusMs": 1938.7999999523163, - "visibleStatusCompleteMs": 1938.7999999523163, - "visibleCount": 12 - }, - { - "version": "before", - "run": 3, - "registryVisibleMs": 2004, - "registeredCount": 24, - "firstVisibleStatusMs": 2004.1000000238419, - "visibleStatusCompleteMs": 2004.1999999284744, - "visibleCount": 12 - }, - { - "version": "after", - "run": 1, - "registryVisibleMs": 211.09999990463257, - "registeredCount": 24, - "firstVisibleStatusMs": 1256.5, - "visibleStatusCompleteMs": 1401.7999999523163, - "visibleCount": 9 - }, - { - "version": "after", - "run": 2, - "registryVisibleMs": 167.79999995231628, - "registeredCount": 24, - "firstVisibleStatusMs": 1247.5, - "visibleStatusCompleteMs": 1281.6000000238419, - "visibleCount": 9 - }, - { - "version": "after", - "run": 3, - "registryVisibleMs": 416.39999997615814, - "registeredCount": 24, - "firstVisibleStatusMs": 1464.1000000238419, - "visibleStatusCompleteMs": 1464.1999999284744, - "visibleCount": 9 - } - ] -} diff --git a/docs/validation/issue-5/desktop-smoke.json b/docs/validation/issue-5/desktop-smoke.json deleted file mode 100644 index 1bca699..0000000 --- a/docs/validation/issue-5/desktop-smoke.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "electron": "44.2.0", - "platform": "darwin/arm64", - "isolatedUserData": true, - "remoteConnections": "simulated; no real SSH hosts", - "rendererColdRegistryVisibleMs": [ - 78.1, - 83.7 - ], - "finalBuildExitCode": 0, - "passed": [ - "offline registration visible", - "status retry after recovery", - "stale status retained after second failure", - "SQLite CRUD", - "authentication and renderer sandbox", - "tree sorting and folding", - "long list edge scrolling", - "layout persistence", - "backend shutdown", - "preferences restored across process restart" - ] -} diff --git a/docs/validation/issue-5/first-load-error.png b/docs/validation/issue-5/first-load-error.png deleted file mode 100644 index 98ea0f6..0000000 Binary files a/docs/validation/issue-5/first-load-error.png and /dev/null differ diff --git a/docs/validation/issue-5/loaded.png b/docs/validation/issue-5/loaded.png deleted file mode 100644 index 011c8bf..0000000 Binary files a/docs/validation/issue-5/loaded.png and /dev/null differ diff --git a/docs/validation/issue-5/offline-registry.png b/docs/validation/issue-5/offline-registry.png deleted file mode 100644 index a5d7101..0000000 Binary files a/docs/validation/issue-5/offline-registry.png and /dev/null differ diff --git a/docs/validation/issue-5/stale-cache.png b/docs/validation/issue-5/stale-cache.png deleted file mode 100644 index d314e09..0000000 Binary files a/docs/validation/issue-5/stale-cache.png and /dev/null differ diff --git a/docs/validation/issue-5/workspace-timeout.png b/docs/validation/issue-5/workspace-timeout.png deleted file mode 100644 index 5eb98bf..0000000 Binary files a/docs/validation/issue-5/workspace-timeout.png and /dev/null differ diff --git a/docs/validation/issue-6/README.md b/docs/validation/issue-6/README.md deleted file mode 100644 index 21fc4ed..0000000 --- a/docs/validation/issue-6/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# 工作区布局实现与验收 - -对应 [Issue #6](https://github.com/ShaoClean/remote-git/issues/6)。正式应用采用紧凑仓库工具栏、横向视图导航、可调宽的改动列表和检查器。视觉稿外层的编号、标题、布局演示切换和“重置演示”不进入产品。 - -## 使用与兼容 - -- 默认工作区宽度 220 px、改动列表宽度 340 px;检查器使用剩余空间。 -- 工作区可在 184–320 px 调整,收起后为 52 px;改动列表可在 280–520 px 调整,实际可用空间不足时优先保证检查器 360 px。 -- 拖动分隔线,或聚焦后使用左右方向键调整 10 px,Shift 加速为 40 px,Home / End 到达当前边界。布局设置也提供滑块与恢复默认入口。 -- `Cmd/Ctrl + \` 开关工作区。小于 900 px 时使用临时工作区抽屉,选择文件或提交后进入检查器,返回列表时恢复焦点。Escape 关闭抽屉并返回打开按钮。 -- 布局偏好保存到现有 `remote-git-workspace` 的 `state.layout`;保留版本 1 封装,兼容现有 Electron 存储桥及旧树展开、排序数据。缺失或无效字段使用默认值。窗口适配只影响显示,不修改保存的偏好。 -- 提交摘要和描述按仓库保留在页面会话内,切换视图、仓库或布局均保留;刷新页面后草稿清空。完成提交只清除对应仓库已提交的草稿。 -- Git 操作沿用原接口;暂存状态改变后重新加载所选文件差异。仓库切换会清除检查器,旧仓库的迟到请求或操作完成回调不能覆盖当前仓库。 - -## 前后对比 - -截图来自正式应用的生产构建,使用相同的隔离接口数据:1440 × 960、7 个改动文件、选择 `Layout.tsx`,提交草稿相同。测试接口仅改变内存,不连接 SSH,不访问真实仓库。 - -| 区域 | 修改前 | 修改后 | -| ------------ | --------------- | ------------ | -| 仓库头部高度 | 146 px | 52 px | -| 改动面板 | 约 499 × 663 px | 340 × 798 px | -| 检查器 | 约 390 × 663 px | 876 × 798 px | - -| 修改前 | 修改后 | -| ----------------------------- | ---------------------------- | -| ![修改前](before-desktop.png) | ![修改后](after-desktop.png) | - -| 侧栏收起 | 窄窗口检查器 | 短窗口列表与提交区 | -| ---------------------------- | ------------------------------------------- | ----------------------------------- | -| ![侧栏收起](after-focus.png) | ![窄窗口检查器](after-narrow-inspector.png) | ![短窗口列表](after-small-list.png) | - -## 验证记录 - -2026-09-10,macOS,Node.js 25.5.0,Chromium / Ego Lite 与 Electron 44.2.0。 - -| 检查 | 结果 | -| --------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| `npm run build -w web` | TypeScript 检查、生产构建通过;保留原有大 chunk 提示 | -| `npm test -w web` | 18 项通过,覆盖旧配置兼容、偏好边界、窗口适配、树排序、存储失败、独立草稿、迟到差异与刷新 | -| `npm run desktop:build` | 共享包、SSH 包、后端、前端和桌面应用构建通过 | -| `npm run desktop:test:unit` | 21 项通过 | -| Electron 两次独立启动 smoke | 通过;保存 310 / 430 px 与收起状态后,在另一进程、另一服务端口恢复,原树排序保持不变 | -| 桌面既有流程 | 通过;树折叠、键盘与拖动排序、长列表边缘滚动、取消拖动、更新设置、下载中刷新恢复、存储桥鉴权和关闭后端 | -| 浏览器 Git 操作路由 | 通过;单个与批量暂存 / 取消暂存、提交、获取 / 拉取 / 推送、分支切换;核对测试接口接收的仓库 ID 和参数 | -| 检查器与输入 | 通过;文件暂存状态与差异同步、提交历史及单文件差异、按仓库保留草稿、切换仓库清除旧差异 | -| 布局与键盘 | 通过;拖动分隔线、方向键 / Shift / Home / End、收起与恢复、刷新恢复、恢复默认、窄窗口返回焦点、抽屉 Escape 与焦点返回 | -| 尺寸 | 检查 1440 × 960、980 × 760、900 × 800、820 × 800、390 × 844、360 × 640;无整体横向溢出,360 × 640 时提交按钮完整可用 | - -桌面 smoke 的构建产物复制到临时普通目录执行:本地 worktree 位于 `.worktrees` 隐藏目录,现有 Express `sendFile` 会忽略该路径中的静态文件。测试使用隔离用户数据,不触碰个人连接和配置。 - -后端现有 Jest 命令受 TypeScript `rootDir` 配置影响。临时指定测试编译配置后,本分支与基线 `ecd17b0` 均为 1 项通过、8 项失败,失败原因均为脚手架测试未注册 controller / service 的依赖。本次没有修改后端实现或这些测试。 - -未运行 Windows / Linux 原生安装包验收和真实远程 SSH 的写操作。接口回归使用内存测试数据,Electron smoke 验证实际桌面进程和持久化。 - -## 复现浏览器验收 - -```sh -npm run build -w web -node apps/web/tests/workspace-fixture.mjs -``` - -访问命令输出的本机地址并进入 `/repositories/repo-a`。另有 `repo-b` 和 `empty` 用于草稿隔离及空状态检查;`/__fixture/actions` 可查看收到的操作。测试服务只绑定 `127.0.0.1`,测试文件不会被前端打包。 diff --git a/docs/validation/issue-6/after-desktop.png b/docs/validation/issue-6/after-desktop.png deleted file mode 100644 index fc93c5d..0000000 Binary files a/docs/validation/issue-6/after-desktop.png and /dev/null differ diff --git a/docs/validation/issue-6/after-focus.png b/docs/validation/issue-6/after-focus.png deleted file mode 100644 index 8388b7a..0000000 Binary files a/docs/validation/issue-6/after-focus.png and /dev/null differ diff --git a/docs/validation/issue-6/after-narrow-inspector.png b/docs/validation/issue-6/after-narrow-inspector.png deleted file mode 100644 index 9b3abf8..0000000 Binary files a/docs/validation/issue-6/after-narrow-inspector.png and /dev/null differ diff --git a/docs/validation/issue-6/after-small-list.png b/docs/validation/issue-6/after-small-list.png deleted file mode 100644 index c4f44c4..0000000 Binary files a/docs/validation/issue-6/after-small-list.png and /dev/null differ diff --git a/docs/validation/issue-6/before-desktop.png b/docs/validation/issue-6/before-desktop.png deleted file mode 100644 index 576b7c6..0000000 Binary files a/docs/validation/issue-6/before-desktop.png and /dev/null differ diff --git a/docs/validation/restart-update/README.md b/docs/validation/restart-update/README.md deleted file mode 100644 index 63aabf5..0000000 --- a/docs/validation/restart-update/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# macOS 重启安装验证 - -日期:2026-09-11。环境:macOS 15.5 / arm64、Node.js 25.5.0、Electron 44.2.0。 - -关联:[Issue #12 — 更新下载完成后支持一键重启安装,无需手动重新安装](https://github.com/ShaoClean/remote-git/issues/12),跟踪于[公开 TODO 看板](https://github.com/users/ShaoClean/projects/1)。本记录覆盖实现及本地验证,正式安装包的跨平台升级验收仍待完成。 - -下载校验完成后,macOS 与 Windows/Linux 一样显示“重启安装”。点击后先重新校验 DMG、检查安装目录并准备新应用,再关闭本地服务。安装程序等待旧进程退出后替换应用并重新打开。替换或启动命令失败时尝试恢复原应用;恢复失败会保留备份及恢复位置。 - -| 验证 | 结果 | -| --- | --- | -| `npm run desktop:test:unit` | 35 项通过,包含安装顺序、重复点击、损坏/删除安装包后重新下载、目录不可写、后端关闭失败/超时、安装程序启动失败、替换失败、启动命令失败、退出超时和备份保留 | -| macOS 原生安装集成测试 | 隔离的 Mach-O 测试应用从 1.0.0 升级到 1.1.0:实际创建和挂载 DMG、复制并验证应用、等待旧进程退出、替换应用、通过系统 `open` 启动新版本;新进程写出的版本标记正确,独立数据目录中的测试设置保留 | -| `npm run desktop:build` | TypeScript/Vite、桌面暂存和 Electron SQLite 模块重建通过 | -| `node scripts/smoke.mjs`(`apps/desktop` 目录) | 实际 Electron 界面下载完成后出现“重启安装”;刷新保留更新状态;点击按钮只触发一次模拟安装并关闭活跃 WebSocket 和后端;工作区跨进程恢复通过 | -| 本地 macOS arm64 打包及 `node apps/desktop/scripts/test-packaged.mjs` | 打包后的应用通过相同界面、IPC、服务关闭和持久化回归。日志中的无效 `workspace:save` 请求是既有鉴权/输入校验测试的预期错误 | -| 界面截图 | 已检查按钮和提示文案,无截断或重叠 | - -本地打包复用已下载的 Electron 44.2.0,从仓库根目录运行 `npm run pack -w desktop -- --config.electronDist="$PWD/node_modules/electron/dist"`。产物位于 `apps/desktop/release/mac-arm64/RemoteGit.app`,版本号仍为 0.2.0,包含未发布的本次改动。 - -截图均使用隔离测试数据。改动前来自已有的 0.1.1 暂存构建,改动后来自本次打包的 0.2.0 构建;图中“最新版本”和更新说明为模拟数据。 - -![改动前:打开安装包](before.png) - -![改动后:重启安装](after.png) - -尚未验证:macOS x64 实机升级、Windows/Linux 实机安装,以及从公开 Release 下载两个正式 RemoteGit 版本后的完整升级。原生集成测试使用小型测试应用,桌面界面测试使用模拟安装器;这些结果不能替代正式 Electron 安装包的升级验收。系统 `open` 成功受理后发生的应用内部崩溃不在自动恢复范围内。 - -本次没有替换用户已安装的应用、修改现有用户数据、配置开发者签名/公证或发布 Release。已有手动更新版本需要先安装包含本功能的版本,后续才能使用“重启安装”。 diff --git a/docs/validation/restart-update/after.png b/docs/validation/restart-update/after.png deleted file mode 100644 index 8dd4069..0000000 Binary files a/docs/validation/restart-update/after.png and /dev/null differ diff --git a/docs/validation/restart-update/before.png b/docs/validation/restart-update/before.png deleted file mode 100644 index dca01b8..0000000 Binary files a/docs/validation/restart-update/before.png and /dev/null differ diff --git a/ui_refactor_todo.md b/ui_refactor_todo.md deleted file mode 100644 index e837e42..0000000 --- a/ui_refactor_todo.md +++ /dev/null @@ -1,191 +0,0 @@ -# GitLens 风格 UI 重构 TODO - -> 目标:参考 GitLens 在 VS Code 中的「侧栏导航 + 仓库工作区 + Git 信息密度」设计思路,重构 RemoteGit Web 前端。 -> -> 原始重构基线:`11931b4` -> -> 原则:保留现有 Git / SSH 能力,优先重做前端信息架构、视觉层级和交互反馈;本文件完成前不开始大规模 UI 改动。 - -## 0. 基线盘点与约束 - -- [ ] 盘点现有路由、页面、组件和 Zustand 数据流 -- [ ] 盘点现有 API 能力:连接、仓库、status、diff、log、branch、stash、remote -- [ ] 确认 Git 状态数据结构,统一 staged / unstaged / untracked / renamed 等状态映射 -- [ ] 确认当前项目的启动、构建和测试命令 -- [ ] 保留现有后端接口和业务行为,UI 重构不改变 API 契约 - -## 1. 信息架构与页面骨架 - -### 1.1 全局应用壳层 - -- [ ] 将当前 Ant Design 默认 Layout 调整为 GitLens 风格的深色应用壳层 -- [ ] 设计左侧窄图标栏:连接、仓库、设置/帮助入口 -- [ ] 设计可展开的二级导航区:连接列表、仓库列表和仓库分组 -- [ ] 增加顶部工作区栏:当前仓库、当前分支、同步状态、刷新和更多操作 -- [ ] 增加底部状态栏:连接状态、当前路径、最后刷新时间 -- [ ] 统一桌面端最小宽度和窄屏降级策略 - -### 1.2 路由与上下文 - -- [ ] 保持现有路由可用:Connections、Repositories、Repository Detail -- [ ] 让仓库详情页成为主要工作区,不再依赖单一的 Tabs 平铺所有功能 -- [ ] 建立当前连接 / 当前仓库 / 当前分支的上下文展示 -- [ ] 增加空状态、加载状态、错误状态和连接失效状态的页面级承载 - -## 2. 视觉系统与基础组件 - -### 2.1 设计令牌 - -- [ ] 定义 GitLens 风格色板:深色导航、浅色内容区、蓝色主动作、状态色和 diff 色 -- [ ] 定义字体、字号、字重、行高、间距、圆角、边框和阴影令牌 -- [ ] 定义文件状态、分支类型、同步状态、连接状态的统一颜色规则 -- [ ] 移除当前散落的 inline style,集中到 CSS 变量和组件样式 -- [ ] 调整 Ant Design ConfigProvider,使默认控件与新视觉系统一致 - -### 2.2 基础组件 - -- [ ] `AppShell`:全局应用框架和响应式布局 -- [ ] `ActivityBar`:左侧主导航 -- [ ] `RepositoryTree`:连接 / 仓库 / 分组树 -- [ ] `WorkspaceHeader`:仓库、分支、同步和操作入口 -- [ ] `PanelHeader`:面板标题、数量徽标、筛选和动作 -- [ ] `StatusBadge`:统一显示 Git 状态和连接状态 -- [ ] `FileIcon`:按扩展名显示文件类型图标 -- [ ] `EmptyState`、`LoadingState`、`ErrorState`:统一反馈组件 -- [ ] `CommandButton` / `IconButton`:统一按钮密度、Tooltip 和危险操作样式 - -## 3. Connections / Repositories 页面 - -### 3.1 Connections - -- [ ] 将连接列表改为 GitLens 风格的资源树 / 卡片混合布局 -- [ ] 突出在线、离线、连接中和认证失败等状态 -- [ ] 将新增、编辑、删除、测试连接动作收敛到清晰的上下文操作 -- [ ] 优化连接表单的字段分组、校验、密码/密钥提示和错误反馈 -- [ ] 增加连接为空时的引导状态 - -### 3.2 Repositories - -- [ ] 将仓库列表改为可扫描、可搜索、可分组的资源列表 -- [ ] 展示仓库路径、当前分支、变更数量和最近活动 -- [ ] 增加仓库收藏/置顶视觉预留,但不在本轮实现持久化收藏 -- [ ] 优化添加仓库、扫描仓库和删除仓库的确认流程 -- [ ] 点击仓库后保持全局上下文并进入 Repository Detail 工作区 - -## 4. Repository Detail 工作台 - -### 4.1 工作区布局 - -- [ ] 用三栏布局替代当前单一 Tabs:资源导航 / 主内容 / 辅助详情 -- [ ] 左栏展示仓库内部导航:Changes、Commits、Branches、Stashes、Remotes -- [ ] 中栏展示当前面板内容 -- [ ] 右栏按需展示选中文件、提交或分支的详情 -- [ ] 支持收起 / 展开辅助栏,窄屏时转为抽屉或覆盖层 - -### 4.2 仓库头部 - -- [ ] 展示仓库名、远程路径、当前分支和工作区状态 -- [ ] 增加 Fetch、Pull、Push、Refresh 等高频操作入口 -- [ ] 展示 ahead / behind、未提交文件数和最近同步时间 -- [ ] 为危险操作提供二次确认,并统一成功 / 失败反馈 - -## 5. Changes / Source Control 面板 - -- [ ] 将 staged changes、unstaged changes、untracked files 改为分组文件树 -- [ ] 每组增加数量、全选、全部暂存 / 全部取消暂存动作 -- [ ] 文件行展示状态字母、文件图标、路径和行数变化摘要 -- [ ] 支持文件级 stage、unstage、discard,并为 discard 增加确认 -- [ ] 保留点击文件查看 diff 的能力,并让选中文件状态明显 -- [ ] 将 commit message、description 和 Commit 操作整合成紧凑提交面板 -- [ ] Commit 前明确展示将要提交的文件数量 -- [ ] 增加 clean workspace 空状态 - -## 6. Diff Viewer - -- [ ] 将当前纯 `pre` 文本 diff 升级为 GitLens 风格的文件级 diff 视图 -- [ ] 支持 unified / split 两种显示方式 -- [ ] 显示文件路径、修改状态、增删行统计和关闭/返回操作 -- [ ] 使用清晰的新增行、删除行、上下文行背景色 -- [ ] 优化长文件、横向滚动、代码等宽字体和最大高度行为 -- [ ] 统一 `DiffViewer` 与 Changes、History、提交详情之间的数据入口 -- [ ] 对空 diff、二进制文件和 diff 加载失败提供明确提示 - -## 7. History / Commits 面板 - -- [ ] 将提交表格改为时间线 / 提交列表布局,突出提交图、分支和 tag -- [ ] 展示短 hash、提交信息、作者头像/首字母、相对时间和 refs -- [ ] 将 HEAD、local branch、remote branch、tag 统一成不同样式徽标 -- [ ] 点击提交后在右侧打开提交详情 -- [ ] 提交详情展示完整 message、作者、时间、父提交和文件变更列表 -- [ ] 支持从提交详情进入文件 diff -- [ ] 增加历史加载、空状态和分页/加载更多反馈 - -## 8. Branches / Stashes / Remotes 面板 - -### 8.1 Branches - -- [ ] 按 Local、Remote 分组展示分支 -- [ ] 突出当前分支、ahead / behind 和最后提交信息 -- [ ] 提供新建、切换、删除和刷新操作 -- [ ] 对删除当前分支、未合并分支等风险场景提供保护性提示 - -### 8.2 Stashes - -- [ ] 改为列表 + 详情布局,展示 stash 编号、message、创建时间和文件数 -- [ ] 提供 apply、pop、drop 操作并区分危险级别 -- [ ] 支持查看 stash diff -- [ ] 增加无 stash 空状态 - -### 8.3 Remotes - -- [ ] 增加 Remotes 面板(当前详情页缺少独立入口) -- [ ] 展示 remote 名称、fetch URL 和 push URL -- [ ] 为复制 URL、刷新和远程同步预留操作入口 - -## 9. 交互细节与可用性 - -- [ ] 所有图标按钮补充 Tooltip 和可访问名称 -- [ ] 统一键盘焦点、hover、active、disabled 和 selected 状态 -- [ ] 统一 Toast / message 文案和错误展示方式 -- [ ] 处理 API 请求竞态:切换仓库或面板时避免旧请求覆盖新数据 -- [ ] 处理刷新后的选中项保留和无效选中项清理 -- [ ] 为树、列表、diff 和详情面板增加合理的滚动容器 -- [ ] 检查中英文文案长度对布局的影响 - -## 10. 响应式与视觉验收 - -- [ ] 桌面宽屏:三栏工作区布局稳定,文件名和提交信息不异常截断 -- [ ] 中等宽度:辅助栏可收起,主内容保持可操作 -- [ ] 窄屏:侧栏转为抽屉,操作按钮不溢出 -- [ ] 深色导航和浅色内容区的对比度满足可读性要求 -- [ ] 检查 hover / focus / selected / disabled 等状态的视觉一致性 -- [ ] 检查空仓库、无改动、无分支、无 stash、无远程等边界状态 - -## 11. 验证与交付 - -- [ ] 执行前端 TypeScript 检查和生产构建 -- [ ] 执行现有后端测试,确认 UI 调整未影响 API -- [ ] 启动本地前后端,验证 Connections、Repositories、Repository Detail -- [ ] 验证 stage、unstage、commit、push、pull、切换分支和查看 diff 主流程 -- [ ] 检查浏览器控制台无新增错误和明显警告 -- [ ] 汇总本轮完成项、已知限制和后续可选优化 -- [ ] 将 UI 重构作为独立 commit 提交 - -## 建议实施顺序 - -1. 基线盘点与设计令牌 -2. 全局 AppShell、ActivityBar、RepositoryTree、WorkspaceHeader -3. Repository Detail 工作台骨架 -4. Changes + Diff Viewer -5. History + Commit Detail -6. Branches / Stashes / Remotes -7. Connections / Repositories -8. 响应式、可访问性和全流程验证 - -## 本轮暂不处理 - -- 不改动后端 Git 命令实现和 API 路径 -- 不新增复杂的 Git 图谱算法或远程协作能力 -- 不实现收藏/置顶、持久化 UI 布局等非核心状态 -- 不替换 React、Vite、Zustand 或现有 Diff Viewer 依赖,除非验证后确有必要 -- 不为了视觉模拟而牺牲 stage / commit / push / pull 等现有功能