@zhin.js/adapter-github 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +1118 -0
  2. package/README.md +70 -191
  3. package/adapters/github.js +51 -0
  4. package/adapters/github.ts +59 -0
  5. package/agent/prompt-sections/platform.ts +16 -0
  6. package/{skills/github/SKILL.md → agent/skills/github.md} +26 -9
  7. package/agent/tools/bind.ts +13 -0
  8. package/agent/tools/create_pr.ts +20 -0
  9. package/agent/tools/install.ts +13 -0
  10. package/agent/tools/patch_file.ts +19 -0
  11. package/agent/tools/prepare_workspace.ts +15 -0
  12. package/agent/tools/push_branch.ts +18 -0
  13. package/agent/tools/star.ts +16 -0
  14. package/agent/tools/subscribe.ts +16 -0
  15. package/agent/tools/subscriptions.ts +13 -0
  16. package/agent/tools/unbind.ts +13 -0
  17. package/agent/tools/unsubscribe.ts +15 -0
  18. package/agent/tools/whoami.ts +13 -0
  19. package/commands/endpoint/add/[id].js +3 -0
  20. package/commands/endpoint/add/[id].ts +3 -0
  21. package/commands/endpoint/list.js +3 -0
  22. package/commands/endpoint/list.ts +3 -0
  23. package/commands/endpoint/remove/[id].js +3 -0
  24. package/commands/endpoint/remove/[id].ts +3 -0
  25. package/lib/client.d.ts +36 -0
  26. package/lib/client.js +47 -0
  27. package/lib/endpoint.d.ts +36 -0
  28. package/lib/endpoint.js +140 -0
  29. package/lib/gh-client.d.ts +73 -1
  30. package/lib/gh-client.js +109 -7
  31. package/lib/github-bot-handlers.d.ts +27 -0
  32. package/lib/github-bot-handlers.js +76 -0
  33. package/lib/github-channel-context.d.ts +16 -0
  34. package/lib/github-channel-context.js +31 -0
  35. package/lib/github-endpoint-commands.d.ts +1 -0
  36. package/lib/github-endpoint-commands.js +22 -0
  37. package/lib/github-runtime-state.d.ts +1 -0
  38. package/lib/github-runtime-state.js +6 -0
  39. package/lib/github-tool-handlers.d.ts +18 -0
  40. package/lib/github-tool-handlers.js +214 -0
  41. package/lib/index.d.ts +7 -32
  42. package/lib/index.js +7 -385
  43. package/lib/oauth-users.d.ts +33 -0
  44. package/lib/oauth-users.js +38 -0
  45. package/lib/protocol.d.ts +94 -0
  46. package/lib/protocol.js +292 -0
  47. package/lib/types.d.ts +9 -4
  48. package/lib/types.js +1 -2
  49. package/lib/webhook.d.ts +14 -0
  50. package/lib/webhook.js +88 -0
  51. package/lib/workspace-manager.d.ts +21 -0
  52. package/lib/workspace-manager.js +154 -0
  53. package/package.json +77 -22
  54. package/plugin.js +38 -0
  55. package/schema.json +130 -0
  56. package/src/client.ts +65 -0
  57. package/src/endpoint.ts +169 -0
  58. package/src/gh-client.ts +147 -12
  59. package/src/github-bot-handlers.ts +113 -0
  60. package/src/github-channel-context.ts +46 -0
  61. package/src/github-endpoint-commands.ts +23 -0
  62. package/src/github-runtime-state.ts +7 -0
  63. package/src/github-tool-handlers.ts +252 -0
  64. package/src/index.ts +48 -431
  65. package/src/oauth-users.ts +47 -0
  66. package/src/protocol.ts +425 -0
  67. package/src/types.ts +10 -4
  68. package/src/webhook.ts +130 -0
  69. package/src/workspace-manager.ts +168 -0
  70. package/lib/adapter.d.ts +0 -63
  71. package/lib/adapter.d.ts.map +0 -1
  72. package/lib/adapter.js +0 -415
  73. package/lib/adapter.js.map +0 -1
  74. package/lib/agent-prompt.d.ts +0 -3
  75. package/lib/agent-prompt.d.ts.map +0 -1
  76. package/lib/agent-prompt.js +0 -82
  77. package/lib/agent-prompt.js.map +0 -1
  78. package/lib/bot.d.ts +0 -26
  79. package/lib/bot.d.ts.map +0 -1
  80. package/lib/bot.js +0 -160
  81. package/lib/bot.js.map +0 -1
  82. package/lib/gh-client.d.ts.map +0 -1
  83. package/lib/gh-client.js.map +0 -1
  84. package/lib/index.d.ts.map +0 -1
  85. package/lib/index.js.map +0 -1
  86. package/lib/register-github-mcp.d.ts +0 -6
  87. package/lib/register-github-mcp.d.ts.map +0 -1
  88. package/lib/register-github-mcp.js +0 -35
  89. package/lib/register-github-mcp.js.map +0 -1
  90. package/lib/types.d.ts.map +0 -1
  91. package/lib/types.js.map +0 -1
  92. package/plugin.yml +0 -3
  93. package/src/adapter.ts +0 -446
  94. package/src/agent-prompt.ts +0 -99
  95. package/src/bot.ts +0 -174
  96. package/src/register-github-mcp.ts +0 -60
package/README.md CHANGED
@@ -1,19 +1,14 @@
1
1
  # @zhin.js/adapter-github
2
2
 
3
- GitHub 当聊天通道 — Issue/PR 评论区即群聊,通过 GitHub App 认证,纯 REST API 对接,零 CLI 依赖。
4
-
5
- 查询 · 管理 · 通知 · OAuth 用户绑定 四合一。
3
+ GitHub Plugin Runtime 适配器 — Issue/PR 评论区即聊天通道,GitHub App 认证,Webhook 入站经 `httpHostToken`。
6
4
 
7
5
  ## 功能特性
8
6
 
9
- - **聊天通道**:Issue/PR 评论区映射为群聊,支持收发消息
10
- - **仓库管理**:PR 合并/创建/Review/关闭、Issue 创建/关闭/评论
11
- - **信息查询**:Star、Branch、Release、CI Workflow
12
- - **事件通知**:Webhook 订阅,跨平台推送到任意聊天
13
- - **GitHub App 认证**:JWT Installation Token,自动刷新
14
- - ✅ **OAuth 用户绑定**:用户可绑定自己的 GitHub 账号,star/fork 以个人身份执行
15
- - ✅ **AI Skill**:所有工具自动暴露给 AI 调用
16
- - ✅ **无 router 也能运行**:核心功能不依赖 HTTP 服务,有 router 时自动注册 Webhook 和 OAuth 路由
7
+ - **聊天通道**:Issue/PR 评论区映射为群聊,支持收发消息
8
+ - **Webhook 入站**:HMAC-SHA256 验签 → `Endpoint.emit(...)`
9
+ - **出站**:`send({ conversation, payload })` → Issue/PR comment(`conversation.id` 为 channel ID)
10
+ - **GitHub App 认证**:JWT → Installation Token
11
+ - **Agent 工具**:`agent/` star/bind/subscribe/workspace 等保留
17
12
 
18
13
  ## 安装
19
14
 
@@ -21,66 +16,59 @@
21
16
  pnpm add @zhin.js/adapter-github
22
17
  ```
23
18
 
24
- ## 依赖
25
-
26
- - `@zhin.js/host-router`(可选)— 提供 Webhook 路由,用于接收 GitHub 事件推送
27
-
28
- ## GitHub App 创建
29
-
30
- 1. 访问 [GitHub Developer Settings](https://github.com/settings/apps)
31
- 2. 点击 **New GitHub App**
32
- 3. 填写基本信息:
33
- - **App name**: 你的 bot 名称
34
- - **Homepage URL**: 任意
35
- - **Webhook URL**: `http://your-server:port/pub/github/webhook`(有 HTTP 服务时)
36
- - **Webhook secret**: 自定义密钥
37
- 4. 权限设置(Permissions):
38
- - **Repository → Issues**: Read & Write
39
- - **Repository → Pull requests**: Read & Write
40
- - **Repository → Contents**: Read
41
- - **Repository → Metadata**: Read
42
- - **Repository → Actions**: Read(查看 CI)
43
- 5. 订阅事件(Subscribe to events):
44
- - Issue comment、Pull request、Pull request review、Pull request review comment
45
- - Push、Star、Fork(用于通知)
46
- 6. 创建后记录 **App ID**,点击 **Generate a private key** 下载 `.pem` 文件
47
- 7. 安装 App 到目标仓库/组织
48
-
49
- ## 配置
19
+ Webhook 需要 Root 提供 `@zhin.js/host-http`(`zhin runtime start` 默认装配)。
20
+
21
+ ## 前置条件
22
+
23
+ 1. 创建 GitHub App,记录 App ID、私钥与 Webhook Secret。
24
+ 2. 授予目标仓库所需的 Issues、Pull requests 与 Contents 权限。
25
+ 3. Webhook 指向公网 HTTPS 的 `/github/webhook`,并订阅 Issue、PR 与评论事件。
26
+ 4. App 安装到目标仓库;仓库 Workroom 使用稳定的 `owner/repo` 地址匹配。
27
+
28
+ ## 配置(Plugin Runtime)
50
29
 
51
30
  ```yaml
52
31
  # zhin.config.yml
53
- bots:
54
- - context: github
55
- name: my-github-bot
56
- app_id: 123456
57
- private_key: ./data/github-app.pem # PEM 文件路径或直接粘贴内容
58
- webhook_secret: your-secret # 可选;配置后启用 Webhook
59
- webhook_path: /pub/github/webhook # 可选;默认 /github/webhook,/pub/* 可绕过 Bearer
60
-
61
32
  plugins:
62
- - database
63
- - "@zhin.js/adapter-github"
64
- - "@zhin.js/host-router" # Webhook 需要
33
+ github:
34
+ webhook_path: /github/webhook
35
+ auto_reply_repos:
36
+ - zhinjs/zhin
37
+ workspace_root: ./data/github-workspaces
38
+ endpoints:
39
+ - name: my-github-bot
40
+ app_id: 123456
41
+ private_key: ./data/github-app.pem
42
+ webhook_secret: your-secret
65
43
  ```
66
44
 
67
45
  ```env
68
46
  GITHUB_APP_ID=123456
69
47
  GITHUB_WEBHOOK_SECRET=your-secret
70
- # MCP server-github(适配器自动 addMcp,与 App 认证独立)
71
- GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxxxxxxxxxxx
72
- # 或 ai.githubMcp.token / ai.mcpServers
73
48
  ```
74
49
 
75
- 或在 `zhin.config.yml` 中设置 `ai.githubMcp.token`(优先于环境变量)。
50
+ `private_key` 支持文件路径或 PEM 内容。未配置 `webhook_secret` 时仅 API 出站 / agent 工具可用(无入站)。
51
+
52
+ 多 App:一个插件实例挂多个 endpoint(`endpoints` 数组逐项覆盖顶层字段,`name` 必填):
76
53
 
77
- `private_key` 支持两种写法:
78
- - 文件路径:`./data/github-app.pem`
79
- - 直接内容:`"-----BEGIN RSA PRIVATE KEY-----\n..."`
54
+ ```yaml
55
+ plugins:
56
+ github:
57
+ endpoints:
58
+ - name: app-a
59
+ app_id: 123456
60
+ private_key: ./data/app-a.pem
61
+ - name: app-b
62
+ app_id: 234567
63
+ private_key: ./data/app-b.pem
64
+ ```
80
65
 
81
- ## Channel ID 格式
66
+ ## 已移除的配置
82
67
 
83
- GitHub adapter Issue/PR 映射为聊天频道:
68
+ - **`ai.githubMcp.enabled` / `ai.githubMcp.token`**:Plugin Runtime 迁移后 `register-github-mcp`(stdio `@modelcontextprotocol/server-github`,PAT 人身份)已移除,该配置不再生效。如需 MCP 工具,请按新运行时 `mcp/<name>.ts`(`@zhin.js/mcp-feature`)约定自行装配。
69
+ - **`poll_interval`**:轮询降级已删除,仅 webhook 入站;该字段目前解析但不生效(deferred)。
70
+
71
+ ## Channel ID
84
72
 
85
73
  | 类型 | Channel ID | 示例 |
86
74
  |------|-----------|------|
@@ -89,141 +77,32 @@ GitHub adapter 将 Issue/PR 映射为聊天频道:
89
77
 
90
78
  ## AI 工具
91
79
 
92
- ### 适配器内置(Zhin 专有)
93
-
94
- | 工具 | 说明 |
95
- |------|------|
96
- | `github_star` | Star / Unstar / 检查(per-user OAuth 或 Bot 默认) |
97
- | `github_bind` / `github_unbind` / `github_whoami` | 用户 GitHub 账号绑定 |
98
- | `github_install` | GitHub App 安装链接 |
99
- | `github_subscribe` / `github_unsubscribe` / `github_subscriptions` | 频道级 Webhook 订阅 |
100
-
101
- ### MCP(`@modelcontextprotocol/server-github`)
102
-
103
- 配置 `GITHUB_PERSONAL_ACCESS_TOKEN`(或 `ai.githubMcp.token`)后,适配器通过 `orchestrator.addMcp` 注册 `github` server;AI 侧工具名为 `mcp_github_*`(如 `mcp_github_fork_repository`、`mcp_github_create_issue`)。
104
-
105
- **BREAKING**:`github_fork` 已移除,请改用 `mcp_github_fork_repository`。
106
-
107
- ### 使用示例
108
-
109
- ```
110
- AI: 列出 zhinjs/zhin 的 PR
111
- AI: 合并 zhinjs/zhin 的 PR #108
112
- AI: 查看 zhinjs/zhin 的 star 数
113
- AI: 订阅 zhinjs/zhin 的 push 和 pr 事件
114
- AI: 搜索 zhinjs 相关的仓库
115
- AI: 给 zhinjs/zhin 的 issue #42 加上 bug 标签
116
- AI: 查看 zhinjs/zhin 的 README.md 文件
117
- AI: 对比 zhinjs/zhin 的 main 和 dev 分支
118
- AI: 编辑 zhinjs/zhin 的 issue #42 标题
119
- AI: 绑定我的 GitHub 账号
120
- AI: star zhinjs/zhin
121
- AI: fork zhinjs/zhin # 使用 mcp_github_fork_repository
122
- ```
123
-
124
- ## Webhook 事件通知
125
-
126
- 配置好 Webhook 后,支持以下事件的跨平台推送:
127
-
128
- | 事件 | 参数 | 说明 |
129
- |------|------|------|
130
- | Push | `push` | 代码推送 |
131
- | Issue | `issue` | Issue 创建/更新/关闭 |
132
- | Star | `star` | 仓库被 star |
133
- | Unstar | `unstar` | 仓库被 unstar |
134
- | Fork | `fork` | 仓库被 fork |
135
- | Pull Request | `pr` / `pull_request` | PR 创建/更新/合并 |
136
-
137
- ### Webhook 端点
138
-
139
- ```
140
- POST /pub/github/webhook
141
- ```
142
-
143
- Headers:
144
- - `X-GitHub-Event`: 事件类型
145
- - `X-Hub-Signature-256`: 签名(配置了 secret 时)
146
-
147
- ## OAuth 用户绑定(Device Flow)
148
-
149
- 用户通过工具 **`github_bind`** 绑定 GitHub 账号([OAuth Device Flow](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow)),**不是**浏览器 OAuth 回调页面。
150
-
151
- ### 认证策略
152
-
153
- | 操作类型 | 使用的 Token | 原因 |
154
- |---------|------------|------|
155
- | 读取 issue/PR/repo 信息 | App JWT | 不涉及用户身份 |
156
- | 评论(bot 发言) | App JWT | 以机器人身份发言 |
157
- | star / unstar | User OAuth | 个人行为 |
158
- | fork | User OAuth | 个人行为 |
159
-
160
- ### 绑定流程
161
-
162
- 1. 用户在聊天中触发 `github_bind`(或说「绑定 GitHub」)
163
- 2. Bot 返回 **verification URI** 与 **user code**(GitHub Device Flow)
164
- 3. 用户在浏览器打开链接并输入 code 完成授权
165
- 4. Token 写入 `github_oauth_users` 表;可用 `github_whoami` / `github_unbind` 管理
166
-
167
- **Client ID**:从 GitHub App 的 `/app` API 自动获取(`GhClient.getClientId()`),**无需**在 bot 配置里写 `client_id` / `client_secret`。
168
-
169
- ### 前置条件
170
-
171
- - 需要 **`database`** 插件(`github_oauth_users` 模型)
172
- - Device Flow 在 IM 内完成,**不依赖** `/pub/github/oauth` HTTP 路由
80
+ `agent/tools/`:`github_star`、`github_bind`、`github_subscribe`、`github_prepare_workspace` 等。
173
81
 
174
- ## 数据库表
82
+ ## 架构
175
83
 
176
- ### github_subscriptions
177
-
178
- | 字段 | 类型 | 说明 |
179
- |------|------|------|
180
- | id | integer | 主键 |
181
- | repo | text | 仓库名 (owner/repo) |
182
- | events | json | 订阅的事件列表 |
183
- | target_id | text | 目标频道 ID |
184
- | target_type | text | 类型 (private/group/channel) |
185
- | adapter | text | 适配器名称 |
186
- | bot | text | 机器人名称 |
187
-
188
- ### github_events
189
-
190
- | 字段 | 类型 | 说明 |
191
- |------|------|------|
192
- | id | integer | 主键 |
193
- | repo | text | 仓库名 |
194
- | event_type | text | 事件类型 |
195
- | payload | json | 事件载荷 |
196
-
197
- ### github_oauth_users
198
-
199
- | 字段 | 类型 | 说明 |
200
- |------|------|------|
201
- | id | integer | 主键 |
202
- | platform | text | 聊天平台 |
203
- | platform_uid | text | 平台用户 ID |
204
- | github_login | text | GitHub 用户名 |
205
- | access_token | text | Device Flow 获得的 token |
206
- | created_at | integer | 创建时间戳 |
207
-
208
- ## 架构说明
209
-
210
- ```
211
- adapter-github/
212
- ├── src/
213
- │ ├── index.ts # 插件入口:provide、useContext、模型表
214
- │ ├── adapter.ts # GitHubAdapter
215
- │ ├── bot.ts # GitHubBot(Issue/PR 频道)
216
- │ ├── gh-client.ts # GitHub REST(App JWT / Installation Token)
217
- │ ├── register-github-mcp.ts # orchestrator.addMcp(server-github)
218
- │ ├── agent-prompt.ts # 平台 prompt / deferred 工具筛选
219
- │ └── types.ts # BotConfig、Webhook payload、Channel ID
220
- ├── package.json
221
- └── README.md
222
- ```
223
-
224
- - **无 `@zhin.js/host-router` 时**:REST 工具与轮询仍可用,但无法注册 Webhook
225
- - **有 `@zhin.js/host-router` 时**:注册 Webhook;MCP 通过 `orchestrator.addMcp`(需 PAT 或 `ai.githubMcp.token`)
226
-
227
- ## 许可证
84
+ | 路径 | 职责 |
85
+ |------|------|
86
+ | `plugin.ts` | 插件元数据;有 DatabaseHost 时定义 `github_oauth_users` |
87
+ | `adapters/github.ts` | 薄 `defineAdapter` 入口(发现约定) |
88
+ | `src/endpoint.ts` | Endpoint 生命周期、出站、admit |
89
+ | `src/webhook.ts` | HMAC 验签与事件分发 |
90
+ | `src/oauth-users.ts` | OAuth SSOT + token 查找 |
91
+ | `src/protocol.ts` | 协议纯函数(channel / payload) |
92
+ | `src/gh-client.ts` | GitHub API 客户端 |
93
+
94
+ - 入站:`httpHostToken` POST `Endpoint.emit(...)`
95
+ - 出站:`send({ conversation, payload })`
96
+
97
+ ## 故障排查
98
+
99
+ | 现象 | 排查 |
100
+ | --- | --- |
101
+ | Webhook 401 | 检查 Secret、`X-Hub-Signature-256` 与原始请求体 |
102
+ | App 鉴权失败 | 检查 App ID、私钥 PEM/文件路径与服务器时钟 |
103
+ | 评论没有进入 Workroom | 先查 Endpoint 收件箱,再核对 Catalog 的 Endpoint 与 `owner/repo` |
104
+ | 能收事件但不能回复 | 检查 installation 与仓库权限;PAT MCP 不替代 App 出站 |
105
+
106
+ ## License
228
107
 
229
108
  MIT
@@ -0,0 +1,51 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ /**
3
+ * Convention entry: discover `adapters/github.ts` → defineAdapter.
4
+ * Implementation lives under `src/` (endpoint / webhook / oauth / protocol).
5
+ */
6
+ import { defineAdapter } from 'zhin.js/adapter';
7
+ import { httpHostToken } from '@zhin.js/host-http';
8
+ import { databaseHostToken, } from 'zhin.js';
9
+ import { GithubEndpoint } from "../lib/endpoint.js";
10
+ import { githubRuntimeStateToken } from "../lib/github-runtime-state.js";
11
+ import { resolveGithubConfig, } from "../lib/protocol.js";
12
+ export { GithubEndpoint } from "../lib/endpoint.js";
13
+ function optionalDatabase(context) {
14
+ try {
15
+ return context.use(databaseHostToken);
16
+ }
17
+ catch {
18
+ return undefined;
19
+ }
20
+ }
21
+ export default defineAdapter({
22
+ capabilities: ['inbound', 'outbound'],
23
+ // Issue/PR 评论以 markdown 图片链接消费远程 URL;无交互面,交互段降级纯文本。
24
+ segments: {
25
+ outboundMedia: ['url'],
26
+ interactive: 'text',
27
+ },
28
+ create(context) {
29
+ const config = resolveGithubConfig(context.config);
30
+ const database = optionalDatabase(context);
31
+ // 注册到插件运行时状态(github.endpoint list 的"运行中"数据源)
32
+ context.use(githubRuntimeStateToken).endpoints.set(config.id, {
33
+ id: config.id,
34
+ mode: config.webhookSecret ? 'webhook' : 'api',
35
+ });
36
+ if (config.webhookSecret) {
37
+ return new GithubEndpoint({
38
+ id: context.id,
39
+ http: context.use(httpHostToken),
40
+ database,
41
+ config,
42
+ });
43
+ }
44
+ // API-only: Issue/PR send + agent tools without webhook.
45
+ return new GithubEndpoint({
46
+ id: context.id,
47
+ database,
48
+ config,
49
+ });
50
+ },
51
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Convention entry: discover `adapters/github.ts` → defineAdapter.
3
+ * Implementation lives under `src/` (endpoint / webhook / oauth / protocol).
4
+ */
5
+ import { defineAdapter, type AdapterContext } from 'zhin.js/adapter';
6
+ import { httpHostToken } from '@zhin.js/host-http';
7
+ import {
8
+ databaseHostToken,
9
+ type PluginDatabaseHost,
10
+ } from 'zhin.js';
11
+ import { GithubEndpoint } from '../src/endpoint.js';
12
+ import { githubRuntimeStateToken } from '../src/github-runtime-state.js';
13
+ import {
14
+ resolveGithubConfig,
15
+ type GithubAdapterConfig,
16
+ } from '../src/protocol.js';
17
+
18
+ export { GithubEndpoint } from '../src/endpoint.js';
19
+ export type { GithubEndpointOptions } from '../src/endpoint.js';
20
+
21
+ function optionalDatabase(context: AdapterContext): PluginDatabaseHost | undefined {
22
+ try {
23
+ return context.use(databaseHostToken);
24
+ } catch {
25
+ return undefined;
26
+ }
27
+ }
28
+
29
+ export default defineAdapter<GithubAdapterConfig>({
30
+ capabilities: ['inbound', 'outbound'],
31
+ // Issue/PR 评论以 markdown 图片链接消费远程 URL;无交互面,交互段降级纯文本。
32
+ segments: {
33
+ outboundMedia: ['url'],
34
+ interactive: 'text',
35
+ },
36
+ create(context) {
37
+ const config = resolveGithubConfig(context.config);
38
+ const database = optionalDatabase(context);
39
+ // 注册到插件运行时状态(github.endpoint list 的"运行中"数据源)
40
+ context.use(githubRuntimeStateToken).endpoints.set(config.id, {
41
+ id: config.id,
42
+ mode: config.webhookSecret ? 'webhook' : 'api',
43
+ });
44
+ if (config.webhookSecret) {
45
+ return new GithubEndpoint({
46
+ id: context.id,
47
+ http: context.use(httpHostToken),
48
+ database,
49
+ config,
50
+ });
51
+ }
52
+ // API-only: Issue/PR send + agent tools without webhook.
53
+ return new GithubEndpoint({
54
+ id: context.id,
55
+ database,
56
+ config,
57
+ });
58
+ },
59
+ });
@@ -0,0 +1,16 @@
1
+ import { defineAgentPromptSection } from '@zhin.js/prompt-section';
2
+
3
+ export default defineAgentPromptSection({
4
+ title: 'GitHub',
5
+ content: [
6
+ 'On GitHub, discuss Issues and Pull Requests in their current conversation context.',
7
+ 'Use github_* tools for Bot write operations; do not use mcp_github_* writes that act as a human PAT.',
8
+ 'Use a workspace and branch for multi-file changes, then report the resulting Pull Request or branch.',
9
+ ].join('\n'),
10
+ layer: 'tools',
11
+ order: 70,
12
+ retention: 'preferred',
13
+ maxChars: 1200,
14
+ profiles: ['interactive'],
15
+ platforms: ['github'],
16
+ });
@@ -5,7 +5,7 @@ platforms:
5
5
  description: >-
6
6
  GitHub 全功能适配器技能:内置工具处理 Star/绑定/订阅;MCP server-github 处理 Fork/PR/Issue 等 API;
7
7
  bash + gh CLI 覆盖其余仓库自动化。
8
- Bot 操作使用 GitHub App 身份;Star 等可使用用户 OAuth 绑定。
8
+ Endpoint 操作使用 GitHub App 身份;Star 等可使用用户 OAuth 绑定。
9
9
  每个 Zhin 实例通过 GH_TOKEN 环境变量注入身份,支持多实例协同。
10
10
  channel ID 格式:owner/repo/issues/N 或 owner/repo/pull/N。
11
11
  keywords:
@@ -60,6 +60,10 @@ tools:
60
60
  - github_subscribe
61
61
  - github_unsubscribe
62
62
  - github_subscriptions
63
+ - github_prepare_workspace
64
+ - github_patch_file
65
+ - github_push_branch
66
+ - github_create_pr
63
67
  always: false
64
68
  requires:
65
69
  bins:
@@ -72,7 +76,8 @@ requires:
72
76
 
73
77
  本技能提供三种操作方式:
74
78
  - **适配器内置工具**(`github_*`):用户交互类操作,具备账号绑定、Device Flow 授权、频道级订阅等适配器专有逻辑
75
- - **MCP server-github**(`mcp_github_*`):Issue/PR/搜索/Fork GitHub API(需 `GITHUB_PERSONAL_ACCESS_TOKEN` `ai.githubMcp.token`)
79
+ - **Bot 写仓库工具**(`github_prepare_workspace` / `github_patch_file` / `github_push_branch` / `github_create_pr`):Installation Token,UI 显示 **Bot** 身份;push/开 PR 需 HITL
80
+ - **MCP server-github**(`mcp_github_*`,可选):`ai.githubMcp.*` 配置已随 Plugin Runtime 迁移移除;如需 MCP 工具,按 `mcp/<name>.ts` 约定自行装配(PAT 为**人身份**,勿用于 Bot 写仓库)
76
81
  - **bash + gh CLI**:仓库自动化操作,灵活覆盖 GitHub API 全场景
77
82
 
78
83
  ## 一、适配器内置工具
@@ -86,15 +91,26 @@ requires:
86
91
  | `github_bind` | 绑定用户的 GitHub 账号(Device Flow 授权,无需输入密码)。用户想 star/fork 或操作自己的账号时,先引导使用此工具 |
87
92
  | `github_unbind` | 解除用户绑定的 GitHub 账号 |
88
93
  | `github_whoami` | 查看用户已绑定的 GitHub 账号信息 |
89
- | `github_install` | 获取安装 GitHub App 的链接,安装后 Bot 可访问用户的仓库 |
94
+ | `github_install` | 获取安装 GitHub App 的链接,安装后 Endpoint 可访问用户的仓库 |
90
95
 
91
96
  ### 用户操作(使用绑定账号)
92
97
 
93
98
  | 工具 | 说明 |
94
99
  |------|------|
95
- | `github_star` | Star 或取消 Star 一个仓库。优先使用用户绑定的 GitHub 账号,未绑定则降级为 Bot 默认账号 |
100
+ | `github_star` | Star 或取消 Star 一个仓库。优先使用用户绑定的 GitHub 账号,未绑定则降级为 Endpoint 默认账号 |
96
101
 
97
- ### MCP(server-github,单一 PAT)
102
+ ### Bot 开发工作流(App 身份)
103
+
104
+ | 工具 | 说明 |
105
+ |------|------|
106
+ | `github_prepare_workspace` | Clone/fetch 托管工作区并 checkout Issue/PR 对应分支 |
107
+ | `github_patch_file` | Contents API 单文件更新(小改) |
108
+ | `github_push_branch` | git commit + push(**需 HITL**) |
109
+ | `github_create_pr` | 创建 PR(**需 HITL**;Issue 线程常用) |
110
+
111
+ Issue 线程:新分支 → 开发 → push → 开 PR。PR 线程:push 到现有 head 分支。
112
+
113
+ ### MCP(server-github,可选 PAT)
98
114
 
99
115
  | 工具 | 说明 |
100
116
  |------|------|
@@ -111,10 +127,11 @@ requires:
111
127
 
112
128
  ### 内置工具执行规则
113
129
 
114
- 1. `github_star` 优先使用用户绑定的 GitHub 账号,未绑定则降级为 Bot 默认账号
115
- 2. Fork 与通用 API 使用 `mcp_github_*`(Bot PAT,非 per-user OAuth)
116
- 3. 当用户想操作自己的 GitHub 账号进行 Star 时,先引导用户使用 `github_bind` 绑定
117
- 4. Webhook 订阅关联到当前聊天通道,仅在该通道接收事件通知
130
+ 1. `github_star` 优先使用用户绑定的 GitHub 账号,未绑定则降级为 Endpoint 默认账号
131
+ 2. Bot 写仓库用 `github_*` 工具,不用 `mcp_github_*` 写操作
132
+ 3. MCP(`mcp_github_*`)仅在你按 `mcp/<name>.ts` 约定装配后可用(旧 `ai.githubMcp.enabled` 已移除),PAT 为人身份
133
+ 4. 当用户想操作自己的 GitHub 账号进行 Star 时,先引导用户使用 `github_bind` 绑定
134
+ 5. Webhook 订阅关联到当前聊天通道,仅在该通道接收事件通知
118
135
 
119
136
  ---
120
137
 
@@ -0,0 +1,13 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubBind } from '../../src/github-tool-handlers.js';
4
+
5
+ export default defineAgentTool<{}>({
6
+ description: '绑定你的 GitHub 账号 — 使用 Device Flow 授权,无需输入密码',
7
+ adapter: 'github',
8
+ inputSchema: z.object({}),
9
+ tags: ['github'],
10
+ async execute(input, context) {
11
+ return executeGithubBind({}, context.$client, context.message);
12
+ },
13
+ });
@@ -0,0 +1,20 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubCreatePr } from '../../src/github-bot-handlers.js';
4
+
5
+ export default defineAgentTool<{ repo?: string; title: string; body?: string; head?: string; base?: string }>({
6
+ description: '以 GitHub App Bot 身份创建 Pull Request(需 HITL 确认;Issue 场景常用)',
7
+ adapter: 'github',
8
+ inputSchema: z.object({
9
+ repo: z.string().optional().describe('owner/repo'),
10
+ title: z.string().describe('PR 标题'),
11
+ body: z.string().optional().describe('PR 正文'),
12
+ head: z.string().optional().describe('head 分支,缺省为工作区分支'),
13
+ base: z.string().optional().describe('base 分支,缺省为仓库默认分支'),
14
+ }),
15
+ tags: ['github'],
16
+ approval: 'always',
17
+ async execute(input, context) {
18
+ return executeGithubCreatePr(input, context.$client, context.message);
19
+ },
20
+ });
@@ -0,0 +1,13 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubInstall } from '../../src/github-tool-handlers.js';
4
+
5
+ export default defineAgentTool<{}>({
6
+ description: '获取安装 GitHub App 的链接 — 安装后 Endpoint 可以访问你的仓库,你也可以使用更多功能',
7
+ adapter: 'github',
8
+ inputSchema: z.object({}),
9
+ tags: ['github'],
10
+ async execute(input, context) {
11
+ return executeGithubInstall(context.$client);
12
+ },
13
+ });
@@ -0,0 +1,19 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubPatchFile } from '../../src/github-bot-handlers.js';
4
+
5
+ export default defineAgentTool<{ repo?: string; path: string; content: string; message: string; branch?: string }>({
6
+ description: '通过 Contents API 单文件更新(小改;Bot Installation Token 身份)',
7
+ adapter: 'github',
8
+ inputSchema: z.object({
9
+ repo: z.string().optional().describe('owner/repo'),
10
+ path: z.string().describe('仓库内文件路径'),
11
+ content: z.string().describe('新文件内容'),
12
+ message: z.string().describe('commit message'),
13
+ branch: z.string().optional().describe('目标分支,缺省从 Issue/PR 上下文推断'),
14
+ }),
15
+ tags: ['github'],
16
+ async execute(input, context) {
17
+ return executeGithubPatchFile(input, context.$client, context.message);
18
+ },
19
+ });
@@ -0,0 +1,15 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubPrepareWorkspace } from '../../src/github-bot-handlers.js';
4
+
5
+ export default defineAgentTool<{ repo?: string }>({
6
+ description: 'Clone/fetch 托管工作区并 checkout 到 Issue/PR 对应分支(GitHub App Bot 身份)',
7
+ adapter: 'github',
8
+ inputSchema: z.object({
9
+ repo: z.string().optional().describe('owner/repo,缺省从当前 Issue/PR 频道推断'),
10
+ }),
11
+ tags: ['github'],
12
+ async execute(input, context) {
13
+ return executeGithubPrepareWorkspace(input, context.$client, context.message);
14
+ },
15
+ });
@@ -0,0 +1,18 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubPushBranch } from '../../src/github-bot-handlers.js';
4
+
5
+ export default defineAgentTool<{ repo?: string; branch?: string; message: string }>({
6
+ description: '在托管工作区 git commit 并 push 到远程分支(需 HITL 确认;Bot 身份)',
7
+ adapter: 'github',
8
+ inputSchema: z.object({
9
+ repo: z.string().optional().describe('owner/repo'),
10
+ branch: z.string().optional().describe('分支名,缺省从上下文推断'),
11
+ message: z.string().describe('commit message'),
12
+ }),
13
+ tags: ['github'],
14
+ approval: 'always',
15
+ async execute(input, context) {
16
+ return executeGithubPushBranch(input, context.$client, context.message);
17
+ },
18
+ });
@@ -0,0 +1,16 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubStar } from '../../src/github-tool-handlers.js';
4
+
5
+ export default defineAgentTool<{ action: 'star' | 'unstar' | 'check'; repo: string }>({
6
+ description: 'Star 或取消 Star 一个 GitHub 仓库(使用你绑定的 GitHub 账号,未绑定则用 Endpoint 默认账号)',
7
+ adapter: 'github',
8
+ inputSchema: z.object({
9
+ action: z.enum(['star', 'unstar', 'check']),
10
+ repo: z.string().min(1),
11
+ }),
12
+ tags: ['github'],
13
+ async execute(input, context) {
14
+ return executeGithubStar(input, context.$client, context.message);
15
+ },
16
+ });
@@ -0,0 +1,16 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubSubscribe } from '../../src/github-tool-handlers.js';
4
+
5
+ export default defineAgentTool<{ repo: string; events?: string }>({
6
+ description: '订阅 GitHub 仓库的 Webhook 事件,事件将推送到当前聊天通道',
7
+ inputSchema: z.object({
8
+ repo: z.string().min(1),
9
+ events: z.string().optional(),
10
+ }),
11
+ adapter: 'github',
12
+ tags: ['github'],
13
+ async execute(input, context) {
14
+ return executeGithubSubscribe(input, context.$client, context.message);
15
+ },
16
+ });
@@ -0,0 +1,13 @@
1
+ import { defineAgentTool } from '@zhin.js/agent/tools';
2
+ import { z } from 'zod';
3
+ import { executeGithubSubscriptions } from '../../src/github-tool-handlers.js';
4
+
5
+ export default defineAgentTool<{}>({
6
+ description: '查看当前聊天通道的 GitHub 仓库订阅列表',
7
+ inputSchema: z.object({}),
8
+ adapter: 'github',
9
+ tags: ['github'],
10
+ async execute(input, context) {
11
+ return executeGithubSubscriptions({}, context.$client, context.message);
12
+ },
13
+ });