@chamvi/github

中文文档
0.8.0发布于 2026/11/09Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 2984

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

中文使用文档
文档目录15 节
  1. 安装
  2. GitHub 应用程序设置
  3. 使用量
  4. 入境:交货
  5. 订阅
  6. 输出: 注释
  7. 核准
  8. 工具
  9. 警卫
  10. 工作空间的 Git 证书
  11. A. 背景情况
  12. 使用@ chamvi/ app
  13. 选项
  14. API 密码
  15. 许可证

@chamvi/github

@chamvi/github (英语)

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

npm version CI License


目录

安装

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

仅限无害环境管理,节点.js >=26.0.0。 。 。 . @chamvi/core, (中文(简体) ), @chamvi/http (服务于频道的交付)和 ai 是同伴的依赖关系。 GitHub 通过 @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编号:

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个路由),从未被其认证人认证:签名为证书.

订阅

github.on(['issues.opened', 'issue_comment.created'], {   // 'issues' matches every action
    filter: (event) => event.payload.repository?.full_name === 'octo/demo',
});
选项默认说明
events所需经费'<event>' 或者说 '<event>.<action>',一个或多个数组
idgithub:<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>:

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> (当给定时),栅栏中的尸体,为了批准,批准线,跑道和标志:
@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, (中文(简体) ), numbernumber, (中文(简体) ), 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, (中文(简体) ), numbernumber, (中文(简体) ), 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,参见 核准。 。 。 .

警卫

  • 安装标志每次安装都会被缓存,并在到期前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。 。 。 .

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),因此工具无需关闭实例:

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 是可选的对等点;主条目从不导入.

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

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

选项

createGithubApp(options)数字 :

选项类型默认说明
appIdstring | number所需经费App 代码
privateKeystring所需经费PEM( PKCS# 1 或 PKCS# 8); 文字 \n 序列成为新行
webhookSecretstring | string[]所需经费交付经过其中任何一种检验
installationIdnumber无对于不是以快递开始的运行,以及代表他们的评论
slugstringGET /app 一次App的弹片是 github.com/apps/<slug> (小写),用于机器人登录 <slug>[bot]
baseUrlstringhttps://api.github.comGitHub 企业服务器 : https://<host>/api/v3 (绝对 https URL; 空指默认)
clockIClocksystemClock托肯过期和JWT时间
fetchtypeof 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)数字 :

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

每个选项都会在 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。 。 。 .

版本与发布记录

@chamvi/github 共发布 15 个版本,首次发布于 2026/10/25;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.8.0latest2026/11/09今天
0.7.32026/11/063 天前
0.7.22026/11/053 天前
0.7.12026/11/054 天前
0.7.02026/11/045 天前
0.6.12026/11/045 天前

关于 @chamvi/github 的常见问题

@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 和提交记录判断。