Files
deepseek-harness/packages/experimental/forge-github/README.zh.md
T
Yichen Jiang d0fc1f6458 feat(forge): show the changes of a Session and of its change requests
The forge panel opens a changes view in the right sidebar for the
checkout's local changes and for the diff of each change request.

- ForgePanelController reads local diffs in the branch, uncommitted,
  unstaged, and staged scopes through Git in the Session's read-only
  sandbox, change request diffs through the forge provider, and the text
  of a changed file to expand unchanged lines. Change request patches stay
  cached by head commit and base branch within maxCachedDiffBytes. A local
  diff over maxDiffBytes fails as forgePanel/diff-too-large, and a provider
  read over its output limit fails as too-large, which the view explains
  with a link to the code host; a gh timeout fails as unavailable.
- forge adds the diff, fileText, and fileUrl provider methods and the
  too-large failure code, and forge-github implements them with gh.
- The panel shows a local changes card that opens the view and asks the
  Agent for a change request. The view collapses files past a line
  budget, draws lines side by side or in one column with optional
  wrapping, expands unchanged lines on request, and collapses or expands
  every file from its toolbar; file headers use a bare chevron.
- The checkout row copies the worktree or project directory path, the
  refresh glyph turns while a refresh runs, change request cards keep
  their actions while collapsed, and the header entry uses the shared
  compact button.
- client-ui-forge classifies changeRequestKey and FsError as
  peer-required Host imports, which keeps forge and dsh-fs as its peers.
2026-10-20 13:34:27 +08:00

106 lines
6.9 KiB
Markdown
Raw 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.
---
description: "通过宿主上的 GitHub CLI 为实验性 forge 注册表服务 GitHub 主机。"
kind: "package-reference"
---
# @deepseek-ai/dsh-experimental-forge-github
[English](README.md) | 中文
## 概述
借助宿主上已登录的 GitHub CLI,为 `ctx.forge` 读取 GitHub 与 GitHub Enterprise 的 pull request。每次轮询对每个主机只发一个 GraphQL 查询,读取所有到期 pull request 的状态、改动行数、检查、评审结论、可合并性与未解决的评审讨论。
## 目录
- [使用本包](#use-this-package)
- [了解实现](#understand-the-implementation)
- [深入探索](#further-exploration)
- [模型体验](#model-experience)
- [已知限制与待办工作](#known-limitations-and-deferred-work)
- [开发备注](#dev-note)
-----
<a id="use-this-package"></a>
## 使用本包
在 forge 注册表之后挂载提供方,并显式列出每个 GitHub Enterprise 主机。
```yaml
- name: '@deepseek-ai/dsh-experimental-forge'
- name: '@deepseek-ai/dsh-experimental-forge-github'
config:
hosts: [github.com, ghe.example.com]
```
即使 Session 在其他执行环境中运行命令,提供方也以宿主进程的形式运行 `gh`。每个主机执行一次 `gh auth login --hostname <host>` 完成登录。子进程继承的宿主环境去掉了 `DSH_*` 变量以及名称包含 `KEY`、`PASSWORD`、`SECRET` 或 `TOKEN` 的变量,因此 `GH_TOKEN` 与 `GITHUB_TOKEN` 不会被转发,`gh` 使用自己的凭据存储。交互提示、更新提醒、分页器与颜色输出均被关闭。`ghCommand`、`hosts`、`timeoutMs` 与 `maxOutputBytes` 见[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-experimental-forge-github)。
当主机在配置中时,提供方服务 `https`、`http`、`ssh`、`git` 形式的远端 URL,以及 `[email protected]:owner/name.git` 这类 scp 形式。它服务 `https://<host>/<owner>/<name>/pull/<number>` 形式的 pull request URL,允许其后附带任意路径、查询或片段,并以去掉这些后缀的形式作为规范 URL。就绪探测运行 `gh auth status --hostname <host>`:退出码为 0 时为 `ready`,其他退出码为 `unauthenticated` 并带第一行诊断,`gh` 无法启动时为 `unavailable`。按 head 分支查找时,最多返回 20 个以该分支为 head 的打开状态 pull request,按创建时间从新到旧排列,不包含来自 fork 的 pull request;查找默认分支时返回空结果。
检查运行(check run)在完成前映射为 `pending`,完成后映射为 `success`、`failure`(失败、超时、启动失败或需要操作)、`cancelled`、`skipped` 或 `neutral`。检查运行保留其开始与完成时间。提交状态上下文把 `SUCCESS` 映射为 `success`,把 `FAILURE` 与 `ERROR` 映射为 `failure`,其余状态均映射为 `pending`,且不带时间。GraphQL 的 `NOT_FOUND` 错误转为 `not-found` 失败。`gh` 没有输出 JSON 时,提到身份验证或 `gh auth login` 的诊断转为 `unauthenticated`,其他诊断转为 `unavailable`。
pull request 处于打开状态、不是草稿、GitHub 报告其合并状态为 `CLEAN`、`HAS_HOOKS` 或 `UNSTABLE`,且已登录用户具有 write、maintain 或 admin 权限时,`mergeReady` 为真。`mergeMethods` 列出仓库允许的压缩合并、合并提交与变基合并方式,用户默认的合并方式排在最前。标记为可评审运行 `gh pr ready <number> --repo <host>/<owner>/<name>`。合并经 `gh api` 调用 `PUT repos/<owner>/<name>/pulls/<number>/merge`,带上合并方式与预期的 head SHA,因此有新提交到达后 GitHub 会拒绝,报告为 `stale`。与 `gh pr merge` 不同,它从不启用自动合并、从不加入合并队列,也从不删除 head 分支。被拒绝的操作报告 GitHub 的原因,提到身份验证的诊断转为 `unauthenticated`。
`diff` 运行 `gh pr diff <number> --repo <host>/<owner>/<name> --color never`。`fileText` 经 `gh api` 以 raw 媒体类型读取 `repos/<owner>/<name>/contents/<path>?ref=<commit>`,只接受完整的 40 位或 64 位十六进制提交。`fileUrl` 返回 `https://<host>/<owner>/<name>/blob/<commit>/<path>`。两者的路径都逐段做百分号编码。被拒绝的读取在 HTTP 404 时为 `not-found`,诊断提到身份验证时为 `unauthenticated`,GitHub 报告 `too_large` 错误时(diff 超过其自身大小上限即会如此)为 `too-large`,其余为 `unavailable`,并带有 GitHub 的原因。输出超过 `maxOutputBytes` 的读取为 `too-large`,超过 `timeoutMs` 的为 `unavailable`。
-----
<a id="understand-the-implementation"></a>
## 了解实现
<details>
<summary>实现细节——点击展开</summary>
一次读取按主机对引用分组,每个主机发送一个 `gh api graphql` 查询。查询内联经过校验的 owner、name 与编号,并为每个 pull request 设置别名,因此局部 GraphQL 错误只影响对应的别名。出现局部错误时 `gh` 以非零状态退出,但仍会输出完整响应;提供方先解析该响应,再检查退出码。
| 源码 | 职责 |
|---|---|
| [`src/index.ts`](src/index.ts) | 配置校验与提供方注册 |
| [`src/provider.ts`](src/provider.ts) | URL 映射、按主机分组与失败分类 |
| [`src/graphql.ts`](src/graphql.ts) | 构造查询,并校验和映射响应 |
| [`src/gh.ts`](src/gh.ts) | 在宿主上执行 `gh`,清理环境变量并施加限制 |
| [`src/urls.ts`](src/urls.ts) | 解析远端 URL 与 pull request URL |
</details>
-----
<a id="further-exploration"></a>
## 深入探索
- [Forge 注册表](../forge/README.zh.md)——提供方注册与共享轮询。
- [Forge 子系统](../../../docs/subsystems/forge.zh.md)——提供方契约与变更请求类型。
- [子进程环境](../../subprocess/subprocess/README.zh.md)——共享的环境变量清理规则。
-----
<a id="model-experience"></a>
## 模型体验
无:提供方为宿主侧监听方读取 pull request 状态,不贡献模型上下文。
#### KV Cache 影响
无。提供方的输出只到达宿主侧监听方。
## 已知限制与待办工作
<a id="known-limitations-and-deferred-work"></a>
- **宿主需要 GitHub CLI**——必须安装 `gh` 并为每个已配置主机登录;环境变量中的令牌不会被转发。不在 `hosts` 中的主机永远不会被读取。
- **前 100 个检查与评审讨论**——head 提交的检查超过上限时以 `checksTruncated` 标记;前 100 个之后的未解决讨论不计入。
- **不发现 fork**——按 head 分支查找时,不包含 head 位于其他仓库的 pull request。
- **速率限制**——每次轮询都会以已登录账号的速率配额为每个主机消耗一次 GraphQL 查询。
- **不支持合并队列**——要求合并队列的基准分支会拒绝直接合并,提供方也不会把变更请求加入队列。
<a id="dev-note"></a>
### 开发备注
<details>
<summary>维护者的工作上下文——点击展开</summary>
无。
</details>