# git 分支刷新规则设计（dsh-git-branch）

## 目标

在输入框工具行的「模式」控件（访问模式 / Plan 模式）之后，实时展示**当前工作区**的 git 分支。
核心难点在于：用户可能在**另一个工具**（终端、IDE、Git GUI）里执行了 `git switch`，而浏览器端无感知，
因此必须设计一套可靠的「刷新时机」，在不过度打扰、不污染会话日志的前提下尽快反映外部分支变化。

## 数据来源与读取方式

- 工作区路径取自会话的持久化 `cwd`（host 侧 `session.header.cwd`，client 侧 `SessionSummary.cwd`）。
- 分支通过**向上逐级查找最近的 `.git`** 并读取其 `HEAD` 得到：
  - `ref: refs/heads/<name>` → 分支名 `<name>`（覆盖 worktree / submodule 的 `.git` 文件与 `gitdir:` 指向）。
  - 40 位 SHA → detached HEAD，展示短 SHA（前 7 位）。
  - 找不到 `.git` → 无 git，**不渲染**（满足「存在 git 才展示」）。
- 读取 `.git/HEAD` 而非每次都 `git` 子进程：快、无依赖，且 `git switch` 会原子性地改写 `HEAD`，
  因此**外部切分支后立即可读到新分支名**。

## 刷新时机（事件驱动为主，轮询兜底）

按「收益 / 成本」排序，前端组件在以下时机触发一次拉取：

### 1. 挂载 / 会话或工作区切换（必选）
- 组件首次挂载、`sessionId` 或 `cwd` 变化时立即拉取。
- 覆盖：打开新会话、切换会话、切换工作区。

### 2. 窗口重新获得焦点 `window.focus`（关键规则）
- 用户「去另一个工具切分支 → 切回 DSH 页面」时，浏览器窗口重新聚焦，立即拉取。
- 这是「在其他工具切换了分支」场景下的**主触发源**，也是本次设计的核心。

### 3. 页面重新可见 `visibilitychange → visible`
- 覆盖某些浏览器/场景下仅切标签页不触发 `focus` 的情况（后台标签 → 前台）。

### 4. 手动点击 chip（必选）
- 点击分支 chip 立即重拉并进入加载态；`title` 提示该行为。
- 覆盖：用户明确知道刚切了分支、主动要求刷新；以及 2/3 未命中时的兜底。

### 5. 慢速轮询（可选兜底，默认 60s，可关闭）
- `setInterval` 周期兜底，防「焦点事件漏发 / DSH 页面持续处于焦点但外部仍在切分支」等边角场景。
- 默认 `POLL_INTERVAL_MS = 60000`；设为 `<= 0` 关闭。常量位于 `src/client/index.tsx` / `lib/client.js`。

## 权衡与已知限制

- **传输通道**：为保持「第三方插件零侵入核心包」，分支数据走既有插件可扩展通道
  `ctx.remote.commands.execute(sessionId, "/git-branch")`（与内置 `/plan off`、`/permission` 同一通道）。
- **会话日志成本**：该命令每次执行会追加两条 log-only 的 `command/run` / `command/done` 事件（不进入模型上下文），
  且我们注册了 `conversation.chat.commandview` 的 `git-branch` 键位渲染为 `null`，**在对话流中不可见**。
  代价是每拉取一次日志文件多两条记录。因此把轮询设计为「慢速、默认低频、可关闭」，
  优先依赖零日志增量的 focus / visibility / 手动触发。
- **升级路径**：若未来需要高频推送（例如 host 侧 `fs.watch` 监听 `.git/HEAD` + 自定义 Typert Remote 推送），
  需要接入 monorepo 的 Typert 代码生成并在 `dsh-api-remotes` 装配，属于核心改造，不在本插件范围内。
- **多标签页**：各标签页独立监听 `focus`，各自刷新即可；无跨标签状态需要同步。

## 状态机

```
hidden  ——(cwd 存在, 触发刷新)——>  loading ——(成功) ——> ready(branch | detached)
   ^                                |                  |
   |          (无 git / 空)         |                  |
   +--------------------------------+                  |
   ^                              (失败)                |
   |                                v                  |
   +------------------------------ error <-------------+
```
