Files
CodePilot/docs/exec-plans/active/git-terminal-integration.md
7418andClaude Opus 4.6 0eabed8c27 feat: Git integration, terminal, unified layout — full Phase 1-5 implementation
**Layout refactor (Phase 1):**
- UnifiedTopBar replacing Header.tsx — chat title editing, project folder,
  commit/push split button, Git branch+dirty badge, terminal/file-tree toggles
- PanelZone renders FileTree, GitPanel, PreviewPanel side-by-side on the right
- Independent panel toggle states in PanelContext
- ResizeHandle unified across all panels
- Removed old RightPanel, Header, DocPreview components

**Git backend (Phase 2):**
- src/lib/git/service.ts — execFile-based Git operations with timeout + injection safety
- API routes: status, branches, checkout, log, commit, push, commit-detail, worktrees, derive
- Worktree derive creates DB session inheriting source session settings

**Git frontend (Phase 3):**
- GitPanel with 4 collapsible sections: Status, Branches, History, Worktrees
- CommitDialog with commit vs commit-and-push modes
- GitBranchSelector with inline error, worktree-occupied branches disabled
- GitWorktreeSection with switch-to/derive actions, current/dirty indicators
- useGitStatus polled in AppShell, derived into context (no redundant setState)

**Terminal (Phase 4):**
- electron/terminal-manager.ts — child_process.spawn fallback (PTY upgrade documented)
- IPC handlers + TerminalDrawer/TerminalInstance components

**Polish (Phase 5):**
- Push inline feedback with 4s auto-dismiss
- Branch detection fix, commit diff exit-code handling
- Removed redundant git state: currentBranch/gitDirtyCount now derived, not setState
- useTerminal isElectron uses lazy initializer instead of effect
- i18n keys (en + zh), user tutorial docs, handover document

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:38:00 +08:00

312 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Git + 终端集成规划
> 创建时间:2026-03-12
> 最后更新:2026-03-12
> 参考基线:Codex `main@917c2df`(本地参考副本:`/tmp/codex-main-latest`)
## 状态
| Area | 目标 | 状态 | 备注 |
|------|------|------|------|
| Terminal | 独立终端会话层 | 📋 待开始 | 参考 Codex `command/exec` 语义 |
| Git | 工作区 git 状态层 | 📋 待开始 | 先做只读,再做变更操作 |
| Approval | 终端 / git 统一审批 | 📋 待开始 | 复用现有 permission 机制 |
| UI | 底部终端面板 + repo 状态栏 | 📋 待开始 | 尽量不打断现有聊天主链路 |
## 目标
- 让 CodePilot 拥有类似 Codex 的“可观察、可控制、可审批”的终端执行层,而不是只显示 Claude SDK 工具输出。
- 让 git 从“用户自己在外部终端运行命令”升级为应用内的一等工作区状态服务。
- 保持现有桌面聊天主链路稳定:`remote disabled = current desktop behavior unchanged`。
## 非目标
- 第一阶段不做完整 IDE 式 Source Control 面板。
- 第一阶段不做复杂 git 流程 UI,如 rebase、cherry-pick、conflict editor。
- 第一阶段不重写现有 Claude Agent SDK 聊天链路。
- 第一阶段不把终端能力直接塞进 Electron `main` / `preload` 的零散 IPC。
## 当前项目现状
### 已有能力
- Electron 主进程已经会读取用户 login shell 环境,并构造扩展后的 `PATH`,再传给内部服务进程。
- Claude SDK 子进程也继承了工作目录、环境变量、权限模式和 Git Bash 探测逻辑。
- 聊天流里已经能显示 `tool_use`、`tool_result`、`tool_progress`,也已经有权限审批持久化与恢复。
### 当前缺口
- 还没有“独立终端会话”概念。前端目前只能消费聊天流中的工具事件,没有 `start/write/resize/terminate` 这类终端控制面。
- `preload` 只暴露了 `openPath`、目录选择、安装器和 bridge 状态,没有终端或 git IPC。
- 数据层只有 `chat_sessions.working_directory` / `sdk_session_id`,没有 repo root、branch、HEAD、dirty、remote diff 等 git 元数据。
- git 相关逻辑仍以“Claude 工具可能调用 git”或“外部终端自己执行”为主,应用本身没有统一 git service。
## Codex 参考结论
### 终端集成
Codex 的关键不是“会跑命令”,而是把命令执行抽象成独立协议:
- `command/exec` 有明确的 `processId`、`tty`、`streamStdin`、`streamStdoutStderr`、`timeoutMs`、`cwd`、`env`、`sandboxPolicy`。
- 跟随接口有 `command/exec/write`、`command/exec/resize`、`command/exec/terminate`。
- 终端输出不是一次性结果,而是流式 delta。
- 会话管理是连接级的,不是“临时跑一个 shell 命令然后丢掉”。
### Shell / 环境集成
Codex 不只在启动时读取一次环境,而是有 `shell_snapshot` 机制,为每个 session 生成并校验 shell 快照文件,解决别名、导出变量、shell 初始化脚本差异等问题。
### Git 集成
Codex 既有轻量 git 探测,也有专门的 git tooling:
- 轻量层负责 repo root、HEAD、branch、remote、dirty、recent commits、diff-to-remote。
- tooling 层负责 git 仓库校验、repo root 解析、路径归一化、命令错误上下文。
- `gitDiffToRemote` 是独立接口,不把“比较当前工作区和远端”塞到 UI 层临时拼接。
## 建议的目标架构
### 一、Workspace Runtime 层
在现有 Next.js server 进程内新增一个独立的运行时层,建议放在:
- `src/lib/workspace-runtime/terminal-session-manager.ts`
- `src/lib/workspace-runtime/git-service.ts`
- `src/lib/workspace-runtime/approval-broker.ts`
职责拆分:
- `TerminalSessionManager`
负责终端 session 生命周期、PTY / pipe 管理、输出流、stdin 写入、resize、terminate、超时和清理。
- `GitService`
负责 repo 探测、repo root、branch、HEAD、dirty、remote URLs、recent commits、diff to remote。
- `ApprovalBroker`
负责把“Claude 工具权限请求”和“应用内终端 / git 高风险操作”收口到一个审批模型。
### 二、传输契约
不必照搬 Codex 的 JSON-RPC / WebSocket 形态,但建议尽量复用它的语义。
### Terminal API
- `POST /api/terminal/sessions`
创建终端会话,参数包含 `cwd`、`shellProfile`、`envOverrides`、`tty`、`cols`、`rows`。
- `GET /api/terminal/sessions/:id/stream`
通过 SSE 推送 stdout / stderr / exit / error / metadata。
- `POST /api/terminal/sessions/:id/write`
写入 stdin。
- `POST /api/terminal/sessions/:id/resize`
调整 PTY 大小。
- `POST /api/terminal/sessions/:id/terminate`
终止会话。
### Git API
- `GET /api/git/status?cwd=...`
- `GET /api/git/diff-to-remote?cwd=...`
- `GET /api/git/commits?cwd=...&limit=...`
- `GET /api/git/branches?cwd=...`
原则:
- Phase 1 只提供只读接口。
- 变更类接口如 `stage`、`unstage`、`commit`、`checkout` 放到后续阶段。
### 三、UI 结构
### Terminal
- 底部抽屉式终端面板,默认折叠,不打断聊天。
- 同一工作目录允许多个终端 tab,但同一 chat session 默认绑定一个“主终端”。
- 前端建议使用 `xterm.js` + `xterm-addon-fit`。
### Git
- 会话头部显示 repo 状态:仓库名 / branch / dirty / ahead-behind。
- 聊天页侧边或 Inspector 区域增加 Git 卡片:
- 当前分支
- 最近提交
- 与远端 diff 摘要
- 未提交文件计数
### Approval
- 当 Claude 触发 git 命令时,审批卡片展示 repo root、命令分类和风险等级。
- 当用户直接从终端面板触发高风险操作时,也走同一审批中心,而不是绕开现有 permission 体系。
## 分阶段落地
### Phase 0:契约与边界
目标:先把终端 / git 从“实现细节”提升为产品层能力。
任务:
- 定义 `TerminalSession`、`TerminalEvent`、`GitWorkspaceState`、`GitDiffSummary` 类型。
- 抽出 `workspace-runtime` 目录,不把逻辑继续堆到 `electron/main.ts` 或 `claude-client.ts`。
- 约定审批模型:哪些终端命令 / git 操作要走审批,哪些在 Full Access 下可自动放行。
交付标准:
- 类型、API 契约、错误码和 UI 事件模型先固定下来。
### Phase 1:Terminal MVP
目标:先拿到“像终端一样工作的终端”。
实现建议:
- 后端 MVP 使用 `node-pty`,挂在当前 Next.js server 进程中。
- 通过接口封装 PTY 实现,保留未来替换成 sidecar / Rust helper 的空间。
- 会话创建时继承当前 Electron 已构造好的环境,并保留 `envOverrides` 能力。
- 支持:
- 创建 session
- 实时输出
- stdin 写入
- resize
- terminate
- idle / exit 清理
暂不做:
- 会话恢复
- 复杂 shell snapshot
- 多 Host / 远程共享终端
### Phase 2:Git Read-only MVP
目标:先把 git 状态变成产品内可见上下文。
实现建议:
- 建一个 `GitService`,集中封装所有 git 命令,统一超时和错误处理。
- 参考 Codex 做法:
- repo root 检测
- HEAD / branch / remote URL
- dirty 状态
- recent commits
- diff to remote
- 所有 git 调用都设置短超时,避免大仓卡 UI。
建议新增缓存:
- 进程内 LRU 缓存,用于最近一次 git 状态读取。
- 如需持久化,只缓存快照,不缓存“事实真相”;真相仍以实时 git 命令为准。
### Phase 3:聊天链路集成
目标:把终端和 git 变成聊天场景的原生上下文,而不是外挂面板。
任务:
- 每次 session 切换时同步当前 `GitWorkspaceState`。
- 在 Claude 权限请求里增强 git 命令展示:
- 命令分类(只读 / 写索引 / 写工作区 / 远端网络)
- 目标 repo
- 可能影响的路径
- 聊天页支持从消息上下文跳到对应终端输出或 git 状态卡片。
关键决定:
- Claude SDK 工具输出仍保留。
- 但“独立终端面板”不依赖 Claude 消息流才能工作。
### Phase 4:Git 操作能力
目标:在只读稳定后,再开放少量高价值写操作。
优先顺序:
1. `stage / unstage`
2. `commit`
3. `checkout existing branch`
4. `create branch`
继续后置:
- rebase
- merge conflict resolution
- interactive staging hunk editor
### Phase 5:Shell Snapshot / 高级一致性
目标:解决“终端环境”和“Claude SDK 环境”长期不一致的问题。
建议:
- 先继续沿用当前 Electron `loadUserShellEnv()` 方案作为 MVP 基线。
- 待 Terminal MVP 稳定后,再引入类似 Codex 的 per-session shell snapshot:
- 生成 shell bootstrap 文件
- 校验可执行性
- 让终端与 Claude SDK 共用同一环境基线
这样可以避免一次性把复杂度全部压进首版。
## 关键技术决策
- 不在 Electron `preload` 里继续堆大量终端 / git IPC;核心状态应留在 server 进程。
- 不直接把 git 逻辑散落到页面组件;必须集中到 `GitService`。
- 不让 Terminal MVP 依赖 Claude SDK;它应该可以单独工作。
- 传输层可以保留现有 HTTP + SSE 风格,但语义尽量对齐 Codex 的 `command/exec`。
- Windows 继续沿用现有 `findGitBash()` 与 shell 兼容逻辑,不额外发明新约定。
## 风险与规避
#### 风险 1:`node-pty` 的 Electron 打包和 ABI 复杂度
规避:
- 放在隔离的 manager 抽象后面。
- 首版只做 macOS / Linux 稳定,Windows 作为兼容目标但不阻塞 Phase 1。
#### 风险 2:git 命令阻塞大仓库
规避:
- 所有 git 调用统一超时。
- 使用只读快速命令优先,如 `status --porcelain`、`rev-parse`、`remote -v`。
#### 风险 3:终端和 Claude SDK 环境不一致
规避:
- 首版承认现状,统一走 Electron 已加载的环境。
- 后续用 shell snapshot 收敛。
#### 风险 4:审批流分裂
规避:
- 应用内终端 / git 高风险操作接入同一审批中心。
- 不做第二套“终端专用审批 UI”。
## 推荐实施顺序
1. Phase 0:先定契约和数据模型
2. Phase 1:终端 MVP
3. Phase 2:git read-only MVP
4. Phase 3:聊天链路集成
5. Phase 4:git 变更操作
6. Phase 5:shell snapshot
## 与当前代码的直接对接点
- `electron/main.ts`
继续负责外层环境准备和 server 启动,但不承载终端会话细节。
- `src/lib/claude-client.ts`
保留 Claude SDK 集成;后续只增强审批和 git 上下文展示。
- `src/app/api/chat/permission/route.ts`
继续作为审批落点,后续扩展为终端 / git 共用审批入口。
- `src/lib/db.ts`
后续需要补充 git 快照或终端审计相关表,但不建议把终端实时输出写进 DB。
## 下一步建议
如果继续推进,建议下一步直接做:
1. Phase 0 的类型与 API 契约草案
2. Terminal MVP 的 manager 骨架
3. GitService 的只读接口骨架
这样能最快把“讨论”转成可跑的基础设施。