# @chamvi/github 中文文档

规范地址：https://npmcn.com/package/%40chamvi/github/

版本：0\.8\.0
npm 元数据更新时间：2026-11-08T20:16:36.770Z
中文译文更新时间：2026-11-09T10:22:08.458Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40chamvi/github
原文对照：https://npmcn.com/package/%40chamvi/github/?lang=original
项目主页：https://chamvi.dev/
源码仓库：https://github.com/chamvi/chamvi

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：498 kB，12 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=26\.0\.0
- 运行依赖：4 个
- peer 依赖：ai ^7，@chamvi/app ^0\.8\.0，@chamvi/core ^0\.8\.0，@chamvi/http ^0\.8\.0
- 首次发布：2026-10-25T08:42:06.232Z
- 最新版本发布：2026-11-08T20:16:36.439Z
- 近 30 天下载量：2984（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 15 个）

## 中文简介

GitHub 频道和 chamvi 代理工具: App webhooks in, 发出评论.

## 安装

```sh
npm install @chamvi/github
```

也可以使用：`pnpm add @chamvi/github`、`yarn add @chamvi/github`、`bun add @chamvi/github`

## README

![@chamvi/github](https://raw.githubusercontent.com/chamvi/chamvi/master/.github/assets/logo.svg)

# @chamvi/github (英语)

**GitHub 频道和chamvi代理的工具.**  
经核实的交付成为每个匹配代理的一次重复运行,回答土地作为问题评论,  
gitHub 在重试、恢复或崩溃后.

[![npm version](https://img.shields.io/npm/v/@chamvi/github)](https://www.npmjs.com/package/@chamvi/github) [![CI](https://github.com/chamvi/chamvi/actions/workflows/ci.yml/badge.svg)](https://github.com/chamvi/chamvi/actions/workflows/ci.yml) [![License](https://img.shields.io/npm/l/@chamvi/github)](https://github.com/chamvi/chamvi/blob/master/packages/github/LICENSE)

* * *

**目录**

-   [安装](https://npmcn.com/package/%40chamvi/github/#readme-installation)
-   [GitHub 应用程序设置](https://npmcn.com/package/%40chamvi/github/#readme-github-app-setup)
-   [使用量](https://npmcn.com/package/%40chamvi/github/#readme-usage)
-   [入境:交货](https://npmcn.com/package/%40chamvi/github/#readme-inbound-deliveries)
-   [订阅](https://npmcn.com/package/%40chamvi/github/#readme-subscriptions)
-   [输出: 注释](https://npmcn.com/package/%40chamvi/github/#readme-outbound-comments)
-   [核准](https://npmcn.com/package/%40chamvi/github/#readme-approvals)
-   [工具](https://npmcn.com/package/%40chamvi/github/#readme-tools)
-   [警卫](https://npmcn.com/package/%40chamvi/github/#readme-security)
-   [A. 背景情况](https://npmcn.com/package/%40chamvi/github/#readme-context)
-   [使用@ chamvi/ app](https://npmcn.com/package/%40chamvi/github/#readme-with-chamviapp)
-   [选项](https://npmcn.com/package/%40chamvi/github/#readme-options)
-   [API 密码](https://npmcn.com/package/%40chamvi/github/#readme-api)
-   [许可证](https://npmcn.com/package/%40chamvi/github/#readme-license)

## 安装

```bash
npm install @chamvi/github @chamvi/http @chamvi/core ai --save
```

仅限无害环境管理,节点.js `>=26.0.0`。 。 。 . `@chamvi/core`, (中文(简体) ), [`@chamvi/http`](https://npmcn.com/package/%40chamvi/http) (服务于频道的交付)和 `ai` 是同伴的依赖关系。 GitHub 通过 [`@octokit/core`](https://www.npmjs.com/package/@octokit/core) 带有页形插件; App JWT、 安装符和 Webhook 签名 `node:crypto`。 。 。 .

## GitHub 应用程序设置

每个代理仓库(或组织)一个 GitHub App :

1.  创建 GitHub 应用程序。设置 **网络锁定 URL** 改为 `https://<host><basePath>/channels/github` (频道名称) **内容类型为 `application/json`** (手工创建的钩子默认为 `application/x-www-form-urlencoded`,该频道以 `415`)和a 数据 **网络隐藏秘诀**。 。 。 .
2.  授予您所需的工具权限 : _问题_ 阅读和写作标签、评论、收尾和 `github_create_issue`· ; _调取请求_ 读取( 写为 `github_create_pull_request` 财务报告和审定财务报表 `github_merge_pull_request`(三); _检查_ 财务报告和审定财务报表 _提交状态_ 读取为 `github_get_pull_request_checks` 和合一的守护者; _元数据_ 读取; _目录_ 读取为 `github_get_file`, (中文(简体) ), `github_get_latest_release`, (中文(简体) ), `github_list_releases` 财务报告和审定财务报表 `github_compare` (为推动的工作空间读写, _工作流量_ 写入以将更改推入 `.github/workflows`) (中文(简体) ). 订阅您的订阅名称( 例如 ) . _问题_) (中文(简体) ).
3.  生成一个私人密钥, 并在代理商可能操作的寄存器上安装 App( 若干账户和组织都很好: 每个工具都能找到它命名的寄存器的安装) 。 从不将 App 放在规则绕行列表或分支保护例外中: `github_merge_pull_request` 拒绝不安全的合并本身, 但是一个绕行会让 GitHub 报告一个被屏蔽的拉动请求为 `clean`。 。 。 .
4.  递接 App id, 私钥 (PKCS# 1 或 PKCS# 8 PEM; 有字面的一行 env var) `\n` 和网络隐藏的秘密 `createGithubApp()`设置 `slug` 在生产中,所以机器人登录不需要 `GET /app`。 。 。 .

## 使用量

`createGithubApp()` 持有App证书. `githubChannel({ app })` 是频道: 在引擎上注册并列出 `createHttpApp({ channels })`服务于在 `POST /channels/github`。代理人订阅 `github.on(events)`· ; `gh.readTools()` 编号 : `gh.writeTools()` 是简单的AI SDK `ToolSet`编号:

```typescript
import type { LanguageModel } from 'ai';
import {
    Engine,
    ToolDeniedError,
    createMemoryStore,
    defineModelAgent,
} from '@chamvi/core';
import { createGithubApp, github, githubChannel } from '@chamvi/github';
import type { GithubAppOptions } from '@chamvi/github';
import { createHttpApp, createShutdown, staticTokens } from '@chamvi/http';

export async function createTriageServer(
    model: LanguageModel,
    options: Pick<GithubAppOptions, 'fetch' | 'clock'> = {},
) {
    const {
        GITHUB_APP_ID,
        GITHUB_PRIVATE_KEY,
        GITHUB_WEBHOOK_SECRET,
        CHAMVI_TOKEN,
    } = process.env;

    if (!GITHUB_APP_ID || !GITHUB_PRIVATE_KEY || !GITHUB_WEBHOOK_SECRET || !CHAMVI_TOKEN) {
        throw new Error('Set GITHUB_APP_ID, GITHUB_PRIVATE_KEY, GITHUB_WEBHOOK_SECRET and CHAMVI_TOKEN.');
    }

    const gh = createGithubApp({
        appId: GITHUB_APP_ID,
        privateKey: GITHUB_PRIVATE_KEY,
        webhookSecret: GITHUB_WEBHOOK_SECRET,
        ...options,
    });
    // deliveries in, issue comments out
    const channel = githubChannel({ app: gh, clock: options.clock });

    const triage = defineModelAgent({
        name: 'triage',
        model,
        instructions: 'Label new issues and thank the author in one comment.',
        // one run per issues.opened delivery, deduplicated by the delivery id
        channels: [github.on('issues.opened')],
        tools: () => ({ ...gh.readTools(), ...gh.writeTools() }),
        hooks: {
            // closing waits for the owner, asked in a comment on the issue
            async beforeToolExecution({ toolName, input }, ctx) {
                if (toolName !== 'github_close_issue') {
                    return undefined;
                }

                const { approved } = await ctx.channels.findOneOrFail('github').approve({
                    title: 'Close this issue?',
                    body: JSON.stringify(input),
                });

                if (!approved) {
                    throw new ToolDeniedError('The owner keeps the issue open.');
                }

                return undefined;
            },
        },
    });

    const engine = new Engine({
        store: createMemoryStore(),
        agents: [triage],
        channels: [channel],
    });

    const shutdown = createShutdown({ engine });
    const app = createHttpApp({
        engine,
        auth: staticTokens({
            tokens: [{
                value: CHAMVI_TOKEN,
                id: 'ci',
                permissions: ['*'],
            }],
        }),
        // POST /channels/github: point the App's webhook URL here
        channels: [channel],
        shutdown,
    });

    await engine.start();

    return {
        app,
        engine,
        shutdown,
    };
}
```

## 入境:交货

`POST /channels/github` (频道的) `in`在 http 应用程序下 `basePath`; 第二个信道 `githubChannel({ name: 'github-ent' })` 服务于 `/channels/github-ent`检查,按此顺序:

| 检查 | 答复 |
| --- | --- |
| 频道以下的路径( A) :`/channels/github/...`(中文(简体) ) | `404` |
| `X-Hub-Signature-256` 缺少 | `401` |
| `X-GitHub-Event` 没有 `^[a-z0-9_]+$`, (中文(简体) ), `X-GitHub-Delivery` 非 1至 255 个字符 | `400` |
| 在频道上方 `bodyLimit` (默认为 1 MiB) | `413` |
| 非JSON内容类型(例如. `application/x-www-form-urlencoded`(中文(简体) ) | `415` |
| `sha256=` 原生体的 HMAC 字节在任何网络隐藏的秘密下 | `401` |
| 身体不是 JSON 对象 | `400` |

向每个有匹配的代理人发送经核实的交货 `github.on()` 订阅此频道, **每个代理最多运行一次** (它第一次匹配订阅),与 `channel: 'github'`,则 `GithubEvent` (或 `check_suite` 或者说 `check_run` 准确列出一个牵引请求, 发送存储处,地址 `<owner>/<repo>#<number>` (单位:千美元)`run.address`时 `ctx.channels.findOne()` 页:1 答案是,我们.. `202 { delivery, runs: [{ agent, runId, deduplicated }] }`,用于 `ping`,对于没有订阅匹配的事件和 App 自己发送的事件 (`runs: []`) (中文(简体) ).

-   **脚踏车**: 二重奏键是送出id(或订阅) `idempotencyKey(event)`),所以重递返回现有的运行 `deduplicated: true`。签名只涵盖身体,而不涵盖 `X-GitHub-Delivery` 也没有 `X-GitHub-Event` 页眉 (e)`e.delivery`, (中文(简体) ), `e.name`:无论谁持有一个签名的快递(一个代理日志,一个支持的垃圾堆),都可以在新的快递ID下重放,或者在另一个事件名下,一个代理监听,每次开始一个新的跑. 在被曝光的端点上,仅从体域中取出密钥,例如:. `` idempotencyKey: (e) => `${e.action}:${e.payload.repository?.full_name}#${e.payload.issue?.number}@${e.payload.issue?.updated_at}` ``,然后让一个 `filter` 检查身体是否带有事件名称的含义(`issue` 无 `comment` 页:1 `issues`, (中文(简体) ), `comment` 页:1 `issue_comment`, (中文(简体) ), `pull_request` 页:1 `pull_request`) (中文(简体) ).
-   **失败**: 物剂的匹配和发送顺序和故障(抛出) `filter` 或键函数,键 `dispatch` 拒绝,发送失败)不会阻止其他人;每次失败都到频道的 `onError`,而答案是,现在 `500`。 。 。 . **GitHub 不自动转发失败的交付**: 转发 `4xx`编号 :`5xx` 手递(App's _高级_ 选项卡)或通过再发送 API。 重递会保存送货的ID, 所以已经得到他们的运行的代理被复制.
-   **自卫队**: 其 `sender` 是 App 的自有机器人 (`<slug>[bot]`, (中文(简体) ), `type: 'Bot'`)开始不跑,所以一个特工不会被自己的评论所唤醒. 其他项目(`dependabot[bot]`,同一寄存器上的第二个 chamvi App)是普通发件人;使用订阅 `filter` 以打破两个 Apps 之间的循环.
-   **体积**: 问题和评论交付量远远低于1个小米 `bodyLimit` 打开 `githubChannel()` 用于大型 `push` 或者说 `pull_request` 交货(GitHub发送最多25 MB),否则答复 `413`。 。 。 .
-   频道路由与http app的每条路由一样受限(默认情况下每客户端地址每分钟300个路由),从未被其认证人认证:签名为证书.

## 订阅

```ts
github.on(['issues.opened', 'issue_comment.created'], {   // 'issues' matches every action
    filter: (event) => event.payload.repository?.full_name === 'octo/demo',
});
```

| 选项 | 默认 | 说明 |
| --- | --- | --- |
| `events` | 所需经费 | `'<event>'` 或者说 `'<event>.<action>'`,一个或多个数组 |
| `id` | `github:<events joined by ','>` | 订阅 id; 对相同事件的两次订阅需要不同的ID |
| `filter` | 无 | `(event) => boolean`,在事件匹配之后; 也可以打破两个 Apps 之间的环路,它们互相视同普通bots |
| `idempotencyKey` | 发送编号 | `(event) => string | undefined` |
| `concurrencyKey` | `<owner>/<repo>#<issue or pull request number>` (检查套件或检查跑道:关于地址,它唯一的拉动请求),否则 `<owner>/<repo>` | `(event) => string | undefined`; 在一个问题上运行, 互相等待 |
| `selfEvents` | 无 | 活动`name` 或者说 `name.action`) App的自有bot可能开始此订阅,例如. `['pull_request.opened', 'pull_request.synchronize', 'check_suite.completed']` 对于拉动请求,代理机打开或推入( 将动作命名为: 空 `pull_request` 也带 `labeled`, (中文(简体) ), `closed`, (中文(简体) ), `synchronize` 代理商自己的标签,合并和推出原因, 所以每次这样的写作重新开始, 每一次发送一个新的运行; 一个推动的代理商 `synchronize` 每推一次重新启动本身; 第一次订阅, 匹配开始的名称; `issue_comment`, (中文(简体) ), `issues` 财务报告和审定财务报表 `pull_request_review_comment` 被拒绝,因为机器人自己的评论 会重新开始代理 |

`github.on()` 订阅命名的频道 `github`;第二个频道使用自己的订阅 `channel.on()`运行的有效载荷是 `GithubEvent { name, action?, delivery, installationId?, payload }`时 `payload` 是整个GitHub的身体。 超过 255 个字符或带有 NUL 的密钥会像掷出一样失败 `filter` (见 _失败_) (中文(简体) ).

## 输出: 注释

频道的 `out` 评论某一问题或拉动请求。 工具通过核心到达 : `ctx.channels.findOne()` 关于频道开始运行问题的回答, `ctx.channels.findOne('github')` 涉及任何问题`github.to({ repo, number })` 构建地址 `<owner>/<repo>#<number>`:

```ts
import { defineTool } from '@chamvi/core';
import { github } from '@chamvi/github';

const answer = defineTool({
    description: 'Answer on the issue.',
    inputSchema: z.object({ body: z.string() }),
    async execute({ body }, { context }) {
        await context.channels.findOne()?.emit({ body });
        await context.channels.findOneOrFail('github').emit({ title: 'Triage log', body }, github.to({ repo: 'octo/ops', number: 1 }));
        return 'sent';
    },
});
```

每个消息频道 :

1.  解析地址( 仅此而已 ) `owner/repo#n` 是一个 `ValidationError`)并选择安装:该事件是运行此频道从同一个寄存器上启动,否则App在地址的寄存器上安装(`installationFor()`),否则事件,否则 `installationId` 从 `createGithubApp()`没有它扔 `InvalidAgentDefinitionError` 在任何评论请求之前,
2.  列出自运行以来更新的问题评论 `receivedAt` 倒数一个小时, 当 App bot 旁边有一个时返回(`<slug>[bot]`,比较不敏感大小写) `effectMarker(message.key)`, (中文(简体) ),
3.  其它则张贴评论: `mention` 登录, `### <title>` (当给定时),栅栏中的尸体,为了批准,批准线,跑道和标志:

````md
@octocat

### Close this issue?

```
{ "repo": "octo/demo", "number": 7 }
```

Waiting for approval until 2026-10-22T09:00:00.000Z. Approve or deny: https://chamvi.example/ui/approvals?run=<runId>&approval=<approvalId>
Run `<runId>` of agent `triage`.

<!-- chamvi:effect=<runId>:<approvalId> -->
````

消息密钥( a) `emit`'内容处理键,一个批准' `<runId>:<approvalId>`)按原样入入入标记;带有字符的密钥为 HTML 注释无法持有(`--`,白空间)或超过255个字符被替换为 `sha256:<hex>`因此,失去反应是无害的:下一次尝试会发现评论。 每一次失败都意味着 `ChamviError` 有代码 `github_request` (单位:千美元)`GitHub <status>: <message>`),如不内部回复的 GitHub `timeoutMs` (30 s, 用于评论列表和帖子;符号交换和 `GET /app` 以App本身为界限; 终止了打电话者的信号拒绝及其理由.

## 核准

打开代理工具 `hooks.beforeToolExecution` 具有耐用性 `approve()`,如用法示例对 `github_close_issue`数字 : `ctx.channels.findOneOrFail('github').approve({ title, body })` 暂停运行,引擎将请求作为对运行问题的一则评论(关键) `<runId>:<approvalId>`,由 `tick()` 直到它熄灭, 从来没有两次。 车主在Chamvi UI(`approvalUrl` 链接)或通过 `POST /runs/:id/approve`;然后从头开始 `approve()` 返回决定. `approve(ctx, { title })` 从核心问起,没有注释(仅输入和API).

## 工具

每个工具都起到安装它命名的寄存器的作用: `github` 频道从该寄存器上启动( 没有请求), 否则 App 的安装 `installationFor()`, (中文(简体) ), `GET /repos/{owner}/{repo}/installation` 与App JWT,缓存10分钟),否则交付的或 `installationId` 从 `createGithubApp()` (所以App未安装的公用寄存器仍可读取). 没有,这个调用是一个工具错误(`github_request`),从未失败运行. 输入将寄存器命名为 `owner/name` (GitHub的名字字符; ); `.` 财务报告和审定财务报表 `..` (b) 拒绝。 每一个安装请求都带有运行的信号,所以取消,排出和运行的超时中止一个被停顿的GitHub呼叫. App认证请求(代号交换和 `GET /app` 为bot登录)由每个等待运行和送出共享,所以它们携带无运行信号;每个在应用程序的时钟上30s后中止,下一个呼叫者重复. 一个失败的 GitHub 呼叫到达模型为 `GitHub <status>: <message>`永远不要与请求或它的象征.

| 工具 | 仁爱 | 投入 | 结果 |
| --- | --- | --- | --- |
| `github_get_issue` | 读取 | `repo`, (中文(简体) ), `number` | `number`, (中文(简体) ), `title`, (中文(简体) ), `body`, (中文(简体) ), `state`, (中文(简体) ), `labels`, (中文(简体) ), `author`, (中文(简体) ), `url`, (中文(简体) ), `createdAt`, (中文(简体) ), `comments`, (中文(简体) ), `isPullRequest` |
| `github_search_issues` | 读取 | `query`, (中文(简体) ), `limit?` (1至20,默认为10) | `total`, (中文(简体) ), `items: [{ repo, number, title, state, url }]` |
| `github_list_labels` | 读取 | `repo` | `[{ name, description }]`每页 |
| `github_get_pull_request` | 读取 | `repo`, (中文(简体) ), `number` | `number`, (中文(简体) ), `title`, (中文(简体) ), `body`, (中文(简体) ), `state`, (中文(简体) ), `draft`, (中文(简体) ), `merged`, (中文(简体) ), `base`, (中文(简体) ), `head`, (中文(简体) ), `author`, (中文(简体) ), `url`, (中文(简体) ), `changedFiles`, (中文(简体) ), `headSha`, (中文(简体) ), `headRepo` (一个被删除的分叉的空白), `fork`, (中文(简体) ), `authorType`, (中文(简体) ), `labels`, (中文(简体) ), `mergeable` (在GitHub计算它时,不要动), `mergeableState`, (中文(简体) ), `maintainerCanModify`, (中文(简体) ), `mergeCommitSha` |
| `github_get_file` | 读取 | `repo`, (中文(简体) ), `path`, (中文(简体) ), `ref?` | `{ path, size, content, truncated }` (切到65 536个字符)或 `{ path, entries }` 用于目录 |
| `github_get_latest_release` | 读取 | `repo` | `{ tag, name, publishedAt, url, body }` 或者说 `{ none: true }` |
| `github_list_releases` | 读取 | `repo`, (中文(简体) ), `from?`, (中文(简体) ), `to?`, (中文(简体) ), `tagPrefix?`, (中文(简体) ), `exhaustive?` | `{ releases: [{ tag, name, publishedAt, url, prerelease, body, bodyTruncated }], truncated }`: 发布后 `from` 最高和包括 `to` (单位:千美元)`v1.2.3` 财务报告和审定财务报表 `1.2.3` 两者都匹配),最古老的,最多为20个,音符被切为8000个字符;没有 `from` 最新20份; 草稿被跳过; 阅读在100份的第一页停止,其发行量均在或低于 `from` (按出版日期列出), `exhaustive: true` 每页读取最多1 000页 |
| `github_compare` | 读取 | `repo`, (中文(简体) ), `base`, (中文(简体) ), `head` | `{ status, aheadBy, behindBy, totalCommits, url, commits: [{ sha, message, author, date }], files: [{ path, status, additions, deletions }], truncated }`: 承诺一行(最多100行)并更改文件(最多300行) |
| `github_list_repositories` | 读取 | `includeArchived?` | `{ repositories: [{ repo, installationId, account, private, archived, fork, defaultBranch, url }], truncated }`:每个安装的每一个存储器(`GET /app/installations`),按名称排序,存档者不按要求丢弃,最多1000个 |
| `github_list_issues` | 读取 | `repo`, (中文(简体) ), `labels?`, (中文(简体) ), `limit?` (1至100,默认为100) | `{ issues: [{ number, title, author, labels, comments, createdAt, updatedAt, url }], truncated }`: 未决问题, 将请求拉出, 最近一次更新 |
| `github_list_pull_requests` | 读取 | `repo`, (中文(简体) ), `base?`, (中文(简体) ), `limit?` (1至100,默认为100) | `{ pullRequests: [{ number, title, author, authorType, draft, base, head, headSha, headRepo, fork, labels, createdAt, updatedAt, url }], truncated }`: 打开拉出请求 |
| `github_get_pull_request_checks` | 读取 | `repo`, (中文(简体) ), `number` | `{ number, headSha, base, state, pending, failing, checks: [{ name, kind, status, conclusion, outcome, required, url }], required: { known, contexts, missing }, truncated }`: 最新的检查运行(最多300次)并输入头部状态; 分支保护和规则所需的上下文(`known: false` 当时,GitHub拒绝给他们看; `state` 实值 `none` 没有任何报告 `pending` 当检查运行或所需的上下文没有报告时, 永远不要绿色 |
| `github_get_push_target` | 读取 | `repo`, (中文(简体) ), `number` | `{ number, headRepo, headBranch, headSha, fork, installationId, contents, workflows, maintainerCanModify, canPush, reason }`: App能否将固定器推向头分支(App从未安装在一分叉上是: App sords不能使用维护者编辑) |
| `github_add_labels` | 效果 | `repo`, (中文(简体) ), `number`, (中文(简体) ), `labels` (1至20个) | `{ labels }`: 每次运行和输入一次(标签是一组) |
| `github_create_comment` | 效果 | `repo`, (中文(简体) ), `number`, (中文(简体) ), `body` | `{ id, url }`数字 : **每个示范步骤每期1个评论** |
| `github_close_issue` | 效果 | `repo`, (中文(简体) ), `number`, (中文(简体) ), `reason?` (单位:千美元)`completed`, (中文(简体) ), `not_planned`(中文(简体) ) | `{ number, state, stateReason }`; 已经关闭的问题不再补丁 |
| `github_create_issue` | 效果 | `repo`, (中文(简体) ), `title`, (中文(简体) ), `body`, (中文(简体) ), `labels?` | `{ number, url }`: 一旦每次运行和输入; 机体带有效果标记, 所以一个再操作步骤会发现 App 的问题而不是打开第二个 |
| `github_create_pull_request` | 效果 | `repo`, (中文(简体) ), `head` (单位:千美元)`branch` 或者说 `owner:branch`, (中文(简体) ), `base?` (默认分行), `title`, (中文(简体) ), `body`, (中文(简体) ), `draft?` | `{ number, url, base, head }`: 每次运行和输入后,再次以其标记查找; GitHub 的 `422` 对于一个已有的拉动请求是一个工具错误 |
| `github_propose_change` | 效果( opt- in) | `repo`, (中文(简体) ), `path`, (中文(简体) ), `content`, (中文(简体) ), `reason` | `{ number, url, base, head }`: 为此代理/ 路径创建或更新一个稳定的分支并打开 PR, 永远不合并 |
| `github_merge_pull_request` | 效果 | `repo`, (中文(简体) ), `number`, (中文(简体) ), `sha`, (中文(简体) ), `method?`, (中文(简体) ), `commitTitle?`, (中文(简体) ), `commitMessage?` | `{ number, sha, method, alreadyMerged }`: 见下面的合并后警卫 |

`github_propose_change` 缺席,除非 `createGithubApp()` (或 `githubModule()`获得 `proposals: { repos: { 'owner/repo': { paths: ['config/**', 'README.md'] } } }`。此政策在创建时被验证和复制 `writeTools()` 揭发了工具. 这需要 _目录_ 财务报告和审定财务报表 _调取请求_ 写作。 路径是寄存器相对的光彩,与节点相匹配 `path.matchesGlob`绝对的路径,倒行逆施, `.github/**`, (中文(简体) ), `.husky/**`, (中文(简体) ), `CODEOWNERS` 财务报告和审定财务报表 `.gitmodules` 在任何文件夹和Unicode格式字符(类别 Cf: bodi 覆盖, 0-width 字符)中,在 GitHub 请求之前总是被拒绝,同样作为允许列表 globs 。 提案总是外出 所以有污点的运行需要通过核心的外出门得到批准.

最初的分支是 `chamvi/<agent>/<path-slug>-<path-hash>`,基于寄存器的默认分支。 后来运行再使用其开放的PR. 关闭或合并后,新提案使用新分支,其中 `-g-<previous-pr-number>` 后缀来自当前默认分支;针对该基点的相同建议失败,因为没有更改验证错误,而不是打开空的PR. 效果键 `<runId>:propose:<repo>:<path>:<sha256 of content>:<model step>` 允许每跑一次建议,路径,内容和模式步骤,所以同一路径在一次运行中更正的内容是新的承诺,而后退一步则是回到更早的内容,而不是第一个建议的记录. 被 Pagized PR 承诺列表对丢失的效果记录进行校正,即使在另一个运行改变内容后,PR被合并,或者分支被删除,而不与可变的后相提并论的SHA. 未公布的分行通过他们自己拥有的,单亲家庭的承诺链回溯到被绑定的比较的合并基础;模棱两可的先祖未能关闭. 调和还原原公关而不恢复后期运行. 关于公开公关的成功不变提案也记录了一项标记承诺。 保留建议书和公关所有权标识用于回收。 发现者要求每一代的分支(`head=<owner>:<branch>`)),因此寄存器的PR计数无关紧要,在一个分支的完整第10个100-PR页上或250代后未能关闭;每个历史PR都有独立的历史限制,并立即有一个匹配的标记返回. 在 GitHub 250 承诺的 PR 封口中缺失的标记失败了 。 一旦有249个公开提案承诺:关闭或合并后,新的更新就会被拒绝,以便下一次更新可以使用新一代. 已经封装的历史公关可能需要人工回收。 执行会刷新PR的发现, 以保证货币安全, 而不是缓冲调节快照 .

工具走被绑起的 Git 树并需要正则文件模式(`100644` 或者说 `100755`; 符号链接,子模块和非指令性父母被拒绝,包括当内容已经匹配时. 它以被观察的头目作为它的独生母构建一个承诺,并且无武力推进裁判. 完整 diff 对照被钉底/ 头 SHA 进行检查, 包括重命名源; 缺失/ 被记录的数据和 GitHub 的 300 文件比较封顶失败 。 它既检查了公关发布前的活性迁移的参考文献,又检查了之后的建议书分支(写作后移动的默认分支不是一个错误). 现有的公关需要一个建议标记;没有公关的非空分行需要一个标记头的承诺.

**提议分支需要该工具的专属写入.** 序列化运行针对同一种代理/存储/路径,不外推,强制重置或删除活性建议分支. 鉴定范围包括被观察的头,而不是所有未来的分支状态. GitHub的 ref更新和PR发布是独立的操作,而不是原子交易:被检测到的移动失败了关闭,但可以留下已经发布的PR或无法到达的Git对象进行复核. 这些检查不能使公关分支永久化,也不能在最后观察之后保证其内容。 合并前审查当前PR头.

写作工具是效果工具(`defineEffectTool` (从核心). `github_create_comment` 按运行、发行和模式步骤键`<runId>:github_create_comment:<owner>/<repo>#<n>:<step>`,自 GitHub 以不敏感方式解决它们后, 将密钥嵌入为隐藏标记(`<!-- chamvi:effect=... -->`) (中文(简体) ). 当效果记录被丢失(GitHub接受评论和检查点之间发生相撞事件)后,再取出App自己用该标记的评论(自收到运行记录后更新了评论,少于一小时)并返回,而不是再次发帖,尽管模型写了不同的文字. 同一步骤中第二次呼吁同一问题回回首评论,因此工具描述要求模型将一个问题的所有内容都放入一个评论.

`github_merge_pull_request` 绝不绕过保护:在合并请求之前,它拒绝(`ToolDeniedError`,工具错误),一个已关闭或合并的拉取请求,一个从 `sha` (再次读取支票),一个草稿,一个可合并的 GitHub 尚未计算, a `mergeable_state` 外部 `MERGE_STATES` (单位:千美元)`clean`, (中文(简体) ), `unstable`, (中文(简体) ), `has_hooks`· ; `dirty` 冲突, `blocked` 保护, `behind` 没有绿色或未报告的任何要求的检查,要求的检查,它不能读取(在基准分支或其规则上是403或404:绕行列表上的符号不能合并它看不到的过去检查;用手将这样的拉取请求合并),一个尚未报告过任何检查的头(CI尚未开始),以及任何仍在运行,需要或没有进行的检查. 不需要的失败检查不能阻止它(`unstable`); 代理想要每张支票绿色读取 `github_get_pull_request_checks` 并请求 `state === 'success'` 自己来 合并请求只发送 `sha`, (中文(简体) ), `merge_method` gitHub的专辑 `405`编号 :`409` 保留工具错误。 方法是 `method`,则 `writeTools({ mergeMethod })`,则 `DEFAULT_MERGE_METHOD` (单位:千美元)`squash`) (中文(简体) ). 哪个拉并请求(作者,版本出错)是代理商的政策,从来不是工具的.

大门破坏性工具`github_close_issue`, (中文(简体) ), `github_merge_pull_request` 任何您的政策不单独合并),并获得批准 `hooks.beforeToolExecution`,参见 [核准](https://npmcn.com/package/%40chamvi/github/#readme-approvals)。 。 。 .

## 警卫

-   安装标志每次安装都会被缓存,并在到期前5分钟被更换,因此在批准后数小时后恢复运行. 托肯斯,私钥和JWT从未被登录,也从未被存储在跑道,步道或效果中.
-   这些工具可以到达安装可以到达的每一个寄存器. 问题机构是不信任的输入:它所引导的模型可以在其中任何一个寄存器上行动,因此只有在代理人可能采取行动时才安装App,并且通过批准来打开破坏性工具.
-   审批意见向能读出问题的人公开. 与 `approvalUrl` 它在 chamvi UI(仅运行和批准id)中链接到批准,所有者在其中签名(`agent:<agent>:approve` 来回答, `run:read` 或者说 `agent:<agent>:run` 没有它,线说在UI里或者通过 `POST /runs/:id/approve`。 。 。 .
-   信息体坐在一个栅栏里 一个背影比任何背影都长 所以 `@login`, (中文(简体) ), `@org/team` 或者说 `#123` 里面没有通知任何人 连线什么也没有 没有输入可以关闭围栏 Backtick跑出超过31个被先用U+200B零宽空格打破,所以栅栏会保持短距离;车身被切成6万个字符(GitHub拒绝超过65 53.6个评论),从未在一对代行者中出现. 标题中的"白空间"运行被倒塌为一个空间. 仅配置 `mention` 登录被通知,除App bot之外,任何人的评论,复制一个标记不计为发送.
-   `requireToolPermission()` 从 `@chamvi/core` 拒绝每个工具在没有引用器的情况下运行,而交付运行则没有. 使用 GitHub 代理 `requireToolPermission({ withoutInvoker: 'allow' })` 或者把它包起来.
-   Webhook 秘密可以旋转:通过 `webhookSecret: [old, new]` gitHub 开关时.

## 工作空间的 Git 证书

`githubAppCredentials(app, { permissions? })` 让工作空间 `@chamvi/sandbox` 检查并按下 App 的寄存器, 仅限一个寄存器 : `contents: read` 读取, `contents: write` 加号 `permissions` 来推动。 它不会为另一个主机或App未安装的寄存器解答任何问题,所以下一个源(或匿名取出)会随之而来. 它在结构上打入,所以此软件包不依赖于 `@chamvi/sandbox`。 。 。 .

```ts
const workspaces = createWorkspaceManager({
    provider,
    credentials: githubAppCredentials(gh, { permissions: { workflows: 'write' } }),
    author: await gh.botIdentity(), // { name: '<slug>[bot]', email: '<id>+<slug>[bot]@users.noreply.github.com' }
});
```

`gh.repositoryToken({ owner, repo }, { permissions })` 代码是相同的,缓存到到期前5分钟.

## A. 背景情况

`provideGithubContext(engine, gh)` 提供引擎上的 App; 工具或工具厂读取它 `injectGithubContext(ctx)`,因此工具无需关闭实例:

```ts
import { injectGithubContext, provideGithubContext } from '@chamvi/github';

const triage = defineModelAgent({
    name: 'triage',
    model,
    instructions: 'Label the issue.',
    tools: (ctx) => injectGithubContext(ctx).readTools(),
});

provideGithubContext(engine, gh); // once, after new Engine()
```

缺少 App 丢弃 `ContextNotProvidedError` 名称 `github` (在工厂,运行失败 之前任何型号呼叫).

## 使用@ chamvi/ app

`githubModule({ channel? })` 从 `@chamvi/github/module` 构建 App 从 `GITHUB_APP_ID`, (中文(简体) ), `GITHUB_APP_PRIVATE_KEY`, (中文(简体) ), `GITHUB_WEBHOOK_SECRET`, (中文(简体) ), `GITHUB_INSTALLATION_ID`, (中文(简体) ), `GITHUB_APP_SLUG` 财务报告和审定财务报表 `GITHUB_API_URL` 当唤作是`.app` 捐款 `githubChannel()` (单位:千美元) `channel` 选项,来自 `CHAMVI_PUBLIC_URL` 除非 `channel.approvalUrl` 被赋予, app的时钟) 到应用程序的频道, http模块在其中服务 `/channels/github`,贡献 `githubAppCredentials()` (单位:千美元) `credentials` 选项; `credentials: false` 关掉) `sandboxModule()`'工作空间,并提供引擎上的 App. `@chamvi/app` 是可选的对等点;主条目从不导入.

```ts
import { createApp } from '@chamvi/app';
import { githubModule } from '@chamvi/github/module';

export default createApp({ agents: [triage], modules: [githubModule()] });
```

## 选项

`createGithubApp(options)`数字 :

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `appId` | `string | number` | 所需经费 | App 代码 |
| `privateKey` | `string` | 所需经费 | PEM( PKCS# 1 或 PKCS# 8); 文字 `\n` 序列成为新行 |
| `webhookSecret` | `string | string[]` | 所需经费 | 交付经过其中任何一种检验 |
| `installationId` | `number` | 无 | 对于不是以快递开始的运行,以及代表他们的评论 |
| `slug` | `string` | `GET /app` 一次 | App的弹片是 `github.com/apps/<slug>` (小写),用于机器人登录 `<slug>[bot]` |
| `baseUrl` | `string` | `https://api.github.com` | GitHub 企业服务器 : `https://<host>/api/v3` (绝对 https URL; 空指默认) |
| `clock` | `IClock` | `systemClock` | 托肯过期和JWT时间 |
| `fetch` | `typeof fetch` | 全球 `fetch` | 每个 GitHub 请求 |

`createGithubApp` 掷出 `InvalidAgentDefinitionError` 为空 `appId`,一个没有RSA私有密钥的密钥,一个空密钥,一个 `installationId` 这不是正整数, a `baseUrl` 不是绝对的 https URL( 或有查询或散列) 和 a `slug` 这不是App的小写弹片(`^[a-z0-9]+(-[a-z0-9]+)*$`时,如 `github.com/apps/<slug>`被误杀的人会无声地禁用自卫队).

`githubChannel(options)`数字 :

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `app` | `IGithubApp` | 所需经费 | 从 `createGithubApp()` |
| `name` | `string` | `'github'` | 频道名称(代理名称规则),服务于 `/channels/<name>` |
| `mention` | `string | string[]` | 无 | 登录( 无) `@`在每条评论的顶端提及 |
| `approvalUrl` | `({ runId, approvalId, agent }) => string` | 无 | 与chamvi UI中的批准相关联,例如. `https://<app>/ui/approvals?run=<runId>&approval=<approvalId>`它没有符号 |
| `timeoutMs` | `number` | `30_000` | 注释列表和帖子的边界 `clock` |
| `bodyLimit` | `number` | `1_048_576` | 交付可能包含的字节(`413` 上文) |
| `onError` | `(error) => void` | `console.error` | 每个代理人都无法向 |
| `clock` | `IClock` | `systemClock` | 超时的时间来源 |

每个选项都会在 `githubChannel()` 被叫作;一个被弃置的 `InvalidAgentDefinitionError`。 。 。 .

## API 密码

| 导出 | 仁爱 | 目的 |
| --- | --- | --- |
| `createGithubApp` | 函数 | 应用: `octokit(installationId)`, (中文(简体) ), `botLogin()`, (中文(简体) ), `botIdentity()`, (中文(简体) ), `installationFor({ owner, repo })`, (中文(简体) ), `repositoryInstallation({ owner, repo })` (包括同一缓存中的全部安装、权限), `installations()`, (中文(简体) ), `repositoryToken()`, (中文(简体) ), `verifySignature()`, (中文(简体) ), `readTools()`, (中文(简体) ), `writeTools({ mergeMethod? })` |
| `githubAppCredentials` | 函数 | 存储范围 : `@chamvi/sandbox` 工作空间 |
| `DEFAULT_GITHUB_GIT_HOST`, (中文(简体) ), `GITHUB_TOKEN_USERNAME` | 常数 | `'github.com'`, (中文(简体) ), `'x-access-token'` |
| `githubChannel` | 函数 | 频道:交付 `in`,评论 `out`附加时 `on()` 财务报告和审定财务报表 `to()` 约束在名称上 |
| `github` | 对象 | `github.on(events, options?)` 订阅费和 `github.to({ repo, number })` 命名频道的地址 `github` |
| `GITHUB_CHANNEL_NAME`, (中文(简体) ), `GITHUB_CHANNEL_TIMEOUT_MS`, (中文(简体) ), `COMMENT_BODY_MAX_LENGTH` | 常数 | `'github'`, (中文(简体) ), `30_000`, (中文(简体) ), `60_000` |
| `DEFAULT_GITHUB_API_URL` | 常数 | `https://api.github.com` |
| `INSTALLATION_CACHE_TTL_MS` | 常数 | `600_000`,多长时间 `installationFor()` 保存仓库的安装 |
| `DEFAULT_MERGE_METHOD`, (中文(简体) ), `MERGE_METHODS`, (中文(简体) ), `MERGE_STATES` | 常数 | `'squash'`, (中文(简体) ), `['merge', 'squash', 'rebase']`, (中文(简体) ), `['clean', 'unstable', 'has_hooks']` |
| `GITHUB_REQUEST_ERROR_CODE` | 常数 | `'github_request'`,则 `code` gitHub 请求失败 |
| `provideGithubContext`, (中文(简体) ), `injectGithubContext` | 函数 | 在引擎上提供App,从a读取 `ToolContext` |
| `REPO_PATTERN` | 常数 | 这个 `owner/name` 格式化接受的工具(正则表达式源; `.` 财务报告和审定财务报表 `..` 区段不匹配) |

类型 : `GithubAppOptions`, (中文(简体) ), `IGithubApp`, (中文(简体) ), `GithubOctokit`, (中文(简体) ), `GithubPermissions`, (中文(简体) ), `GithubRepositoryToken`, (中文(简体) ), `GithubBotIdentity`, (中文(简体) ), `GithubInstallation`, (中文(简体) ), `GithubWriteToolsOptions`, (中文(简体) ), `GithubMergeMethod`, (中文(简体) ), `IGithubGitCredentials`, (中文(简体) ), `GithubGitCredentialRequest`, (中文(简体) ), `GithubGitCredential`, (中文(简体) ), `GithubAppCredentialsOptions`, (中文(简体) ), `GithubChannel`, (中文(简体) ), `GithubChannelOptions`, (中文(简体) ), `GithubApprovalRef`, (中文(简体) ), `GithubEvent`, (中文(简体) ), `GithubPayload`, (中文(简体) ), `GithubSubscriber`, (中文(简体) ), `GithubSubscriptionOptions`, (中文(简体) ), `GithubTarget`, (中文(简体) ), `GithubWebhookResult`, (中文(简体) ), `GithubIssue`, (中文(简体) ), `GithubIssueSearch`, (中文(简体) ), `GithubLabel`, (中文(简体) ), `GithubPullRequest`, (中文(简体) ), `GithubFile`, (中文(简体) ), `GithubDirectory`, (中文(简体) ), `GithubRelease`, (中文(简体) ), `GithubComment`, (中文(简体) ), `GithubIssueLabels`, (中文(简体) ), `GithubClosedIssue`, (中文(简体) ), `GithubRepository`, (中文(简体) ), `GithubRepositoryList`, (中文(简体) ), `GithubIssueSummary`, (中文(简体) ), `GithubIssueList`, (中文(简体) ), `GithubPullRequestSummary`, (中文(简体) ), `GithubPullRequestList`, (中文(简体) ), `GithubPushTarget`, (中文(简体) ), `GithubCheck`, (中文(简体) ), `GithubCheckOutcome`, (中文(简体) ), `GithubChecksState`, (中文(简体) ), `GithubPullRequestChecks`, (中文(简体) ), `GithubCreatedIssue`, (中文(简体) ), `GithubCreatedPullRequest`, (中文(简体) ), `GithubMergeResult`。 。 。 .

`@chamvi/github/module`数字 : `githubModule`, (中文(简体) ), `GithubModule`, (中文(简体) ), `GITHUB_MODULE_NAME`,类型 `GithubModuleOptions`, (中文(简体) ), `GithubModuleChannelOptions`。 。 。 .

## 许可证

原载 [Apache 许可证 2.0](https://npmcn.com/package/%40chamvi/github/LICENSE)。 。 。 .

## 常见问题

### @chamvi/github 是什么？

GitHub 频道和 chamvi 代理工具: App webhooks in, 发出评论\.

### 如何安装 @chamvi/github？

在项目目录运行 npm install @chamvi/github，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：ai（^7）、@chamvi/core（^0\.8\.0）、@chamvi/http（^0\.8\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @chamvi/github 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @chamvi/github 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @chamvi/github 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=26\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @chamvi/github 可以商用吗？

@chamvi/github 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @chamvi/github 的下载量有多少？

根据 npm 官方下载统计，@chamvi/github 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,984 次，日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @chamvi/github 还在维护吗？

最新版本 0\.8\.0 发布于 2026/11/09（今天）；至今共发布 15 个版本，其中过去 12 个月发布了 15 个；首次发布于 2026/10/25。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

