@zhin.js/adapter-github 0.1.39 → 0.1.41
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.
- package/lib/gh-client.d.ts +0 -162
- package/lib/gh-client.d.ts.map +1 -1
- package/lib/gh-client.js +0 -101
- package/lib/gh-client.js.map +1 -1
- package/lib/index.js +0 -508
- package/lib/index.js.map +1 -1
- package/package.json +4 -4
- package/skills/github/SKILL.md +205 -47
- package/src/gh-client.ts +0 -136
- package/src/index.ts +0 -463
- package/LICENSE +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-github",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "Zhin.js adapter for GitHub (gh CLI) — treat issues/PRs as chat channels, full repo management, webhook notifications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"typescript": "^6.0.0",
|
|
44
|
-
"zhin.js": "1.0.
|
|
44
|
+
"zhin.js": "1.0.71"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"
|
|
48
|
-
"zhin.js": "1.0.
|
|
47
|
+
"zhin.js": "1.0.71",
|
|
48
|
+
"@zhin.js/http": "1.0.64"
|
|
49
49
|
},
|
|
50
50
|
"peerDependenciesMeta": {
|
|
51
51
|
"@zhin.js/http": {
|
package/skills/github/SKILL.md
CHANGED
|
@@ -3,12 +3,15 @@ name: github
|
|
|
3
3
|
platforms:
|
|
4
4
|
- github
|
|
5
5
|
description: >-
|
|
6
|
-
GitHub
|
|
7
|
-
|
|
6
|
+
GitHub 全功能适配器技能:通过适配器内置工具完成用户交互操作(Star/Fork/账号绑定/Webhook 订阅/App 安装),
|
|
7
|
+
通过 bash + gh CLI 完成仓库自动化操作(Issue/PR/Release/CI/搜索/文件/Discussion)。
|
|
8
8
|
Bot 操作使用 GitHub App 身份,Star/Fork 等用户操作使用个人绑定的 OAuth Token。
|
|
9
|
+
每个 Zhin 实例通过 GH_TOKEN 环境变量注入身份,支持多实例协同。
|
|
9
10
|
channel ID 格式:owner/repo/issues/N 或 owner/repo/pull/N。
|
|
10
11
|
keywords:
|
|
11
12
|
- github
|
|
13
|
+
- gh
|
|
14
|
+
- cli
|
|
12
15
|
- adapter:github
|
|
13
16
|
- pr
|
|
14
17
|
- pull request
|
|
@@ -41,61 +44,216 @@ keywords:
|
|
|
41
44
|
- edit
|
|
42
45
|
- webhook
|
|
43
46
|
- subscribe
|
|
47
|
+
- discussion
|
|
44
48
|
tags:
|
|
45
49
|
- github
|
|
46
50
|
- development
|
|
47
51
|
- git
|
|
48
52
|
- ci-cd
|
|
49
53
|
tools:
|
|
50
|
-
-
|
|
51
|
-
- github_issue
|
|
52
|
-
- github_repo
|
|
53
|
-
- github_subscribe
|
|
54
|
-
- github_unsubscribe
|
|
55
|
-
- github_subscriptions
|
|
54
|
+
- bash
|
|
56
55
|
- github_star
|
|
57
56
|
- github_fork
|
|
58
|
-
- github_search
|
|
59
|
-
- github_label
|
|
60
|
-
- github_assign
|
|
61
|
-
- github_file
|
|
62
|
-
- github_commits
|
|
63
|
-
- github_edit
|
|
64
57
|
- github_bind
|
|
65
58
|
- github_unbind
|
|
66
59
|
- github_whoami
|
|
60
|
+
- github_install
|
|
61
|
+
- github_subscribe
|
|
62
|
+
- github_unsubscribe
|
|
63
|
+
- github_subscriptions
|
|
64
|
+
always: false
|
|
65
|
+
requires:
|
|
66
|
+
bins:
|
|
67
|
+
- gh
|
|
68
|
+
env:
|
|
69
|
+
- GH_TOKEN
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
# GitHub 全功能操作指南
|
|
73
|
+
|
|
74
|
+
本技能提供两种操作方式:
|
|
75
|
+
- **适配器内置工具**(`github_*`):用户交互类操作,具备账号绑定、Device Flow 授权、频道级订阅等适配器专有逻辑
|
|
76
|
+
- **bash + gh CLI**:仓库自动化操作,灵活覆盖 GitHub API 全场景
|
|
77
|
+
|
|
78
|
+
## 一、适配器内置工具
|
|
79
|
+
|
|
80
|
+
以下工具由 GitHub 适配器注册,具有特殊行为(用户 OAuth 绑定、频道绑定等),**不能用 gh CLI 替代**。
|
|
81
|
+
|
|
82
|
+
### 账号与身份
|
|
83
|
+
|
|
84
|
+
| 工具 | 说明 |
|
|
85
|
+
|------|------|
|
|
86
|
+
| `github_bind` | 绑定用户的 GitHub 账号(Device Flow 授权,无需输入密码)。用户想 star/fork 或操作自己的账号时,先引导使用此工具 |
|
|
87
|
+
| `github_unbind` | 解除用户绑定的 GitHub 账号 |
|
|
88
|
+
| `github_whoami` | 查看用户已绑定的 GitHub 账号信息 |
|
|
89
|
+
| `github_install` | 获取安装 GitHub App 的链接,安装后 Bot 可访问用户的仓库 |
|
|
90
|
+
|
|
91
|
+
### 用户操作(使用绑定账号)
|
|
92
|
+
|
|
93
|
+
| 工具 | 说明 |
|
|
94
|
+
|------|------|
|
|
95
|
+
| `github_star` | Star 或取消 Star 一个仓库。优先使用用户绑定的 GitHub 账号,未绑定则降级为 Bot 默认账号 |
|
|
96
|
+
| `github_fork` | Fork 一个仓库。优先使用用户绑定的 GitHub 账号,未绑定则降级为 Bot 默认账号 |
|
|
97
|
+
|
|
98
|
+
### Webhook 订阅(频道级)
|
|
99
|
+
|
|
100
|
+
| 工具 | 说明 |
|
|
101
|
+
|------|------|
|
|
102
|
+
| `github_subscribe` | 订阅仓库的 Webhook 事件,推送到**当前聊天通道** |
|
|
103
|
+
| `github_unsubscribe` | 取消订阅仓库的 Webhook 事件 |
|
|
104
|
+
| `github_subscriptions` | 查看当前聊天通道的订阅列表 |
|
|
105
|
+
|
|
106
|
+
### 内置工具执行规则
|
|
107
|
+
|
|
108
|
+
1. `github_star` 和 `github_fork` 优先使用用户绑定的 GitHub 账号,未绑定则降级为 Bot 默认账号
|
|
109
|
+
2. 当用户想操作自己的 GitHub 账号时,先引导用户使用 `github_bind` 绑定
|
|
110
|
+
3. Webhook 订阅关联到当前聊天通道,仅在该通道接收事件通知
|
|
111
|
+
|
|
67
112
|
---
|
|
68
113
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
114
|
+
## 二、gh CLI 全场景速查
|
|
115
|
+
|
|
116
|
+
当适配器内置工具不能满足需求(如 Release 管理、Workflow 触发、Discussion、gh api 万能调用),或需要更灵活的参数控制时,使用 `bash` 工具调用 `gh` CLI。当前进程已通过 `GH_TOKEN` 环境变量注入身份凭据。
|
|
117
|
+
|
|
118
|
+
### 0. 前提检查
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
gh --version
|
|
122
|
+
gh auth status
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 1. 仓库(gh repo)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
gh repo view owner/repo
|
|
129
|
+
gh repo list owner --limit 10 --json name,description
|
|
130
|
+
gh repo clone owner/repo
|
|
131
|
+
gh repo create owner/new-repo --public --description "描述"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 2. Issue(gh issue)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
gh issue list -R owner/repo --state open --limit 20 --json number,title,state,labels,assignees
|
|
138
|
+
gh issue view 123 -R owner/repo --json number,title,body,state,labels,assignees --jq '{number,title,state,labels,assignees,body: .body[:2000]}'
|
|
139
|
+
gh issue create -R owner/repo --title "标题" --body "正文" --label "bug" --assignee "user1"
|
|
140
|
+
gh issue close 123 -R owner/repo
|
|
141
|
+
gh issue reopen 123 -R owner/repo
|
|
142
|
+
gh issue comment 123 -R owner/repo --body "评论内容"
|
|
143
|
+
gh issue edit 123 -R owner/repo --title "新标题"
|
|
144
|
+
gh issue edit 123 -R owner/repo --add-label "enhancement" --remove-label "bug"
|
|
145
|
+
gh issue edit 123 -R owner/repo --add-assignee "user2" --remove-assignee "user1"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 3. Pull Request(gh pr)
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
gh pr list -R owner/repo --state open --limit 20 --json number,title,state,author,mergeable
|
|
152
|
+
gh pr view 456 -R owner/repo --json number,title,body,state,author,mergeable,reviewDecision --jq '{number,title,state,author,mergeable,reviewDecision,body: .body[:2000]}'
|
|
153
|
+
gh pr create -R owner/repo --title "标题" --body "描述" --base main --head feature-branch
|
|
154
|
+
gh pr merge 456 -R owner/repo --squash --delete-branch
|
|
155
|
+
gh pr close 456 -R owner/repo
|
|
156
|
+
gh pr reopen 456 -R owner/repo
|
|
157
|
+
gh pr comment 456 -R owner/repo --body "评论内容"
|
|
158
|
+
gh pr review 456 -R owner/repo --approve
|
|
159
|
+
gh pr review 456 -R owner/repo --request-changes --body "需要修改的内容"
|
|
160
|
+
gh pr review 456 -R owner/repo --comment --body "一般性建议"
|
|
161
|
+
gh pr checks 456 -R owner/repo
|
|
162
|
+
gh pr diff 456 -R owner/repo | head -n 200
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 4. Release(gh release)
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
gh release list -R owner/repo --limit 10
|
|
169
|
+
gh release view v1.0.0 -R owner/repo
|
|
170
|
+
gh release create v1.0.0 -R owner/repo --title "v1.0.0" --notes "发布说明" --target main
|
|
171
|
+
gh release delete v1.0.0 -R owner/repo --yes
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 5. Workflow / CI(gh run & gh workflow)
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
gh run list -R owner/repo --limit 10 --json databaseId,displayTitle,status,conclusion
|
|
178
|
+
gh run view 12345 -R owner/repo
|
|
179
|
+
gh run rerun 12345 -R owner/repo --failed
|
|
180
|
+
gh workflow list -R owner/repo
|
|
181
|
+
gh workflow run ci.yml -R owner/repo --ref main
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 6. 搜索(gh search)
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
gh search issues "关键词" --repo owner/repo --limit 10 --json number,title,state
|
|
188
|
+
gh search repos "关键词" --limit 10 --json fullName,description,stargazersCount
|
|
189
|
+
gh search code "函数名" --repo owner/repo --limit 10 --json path,textMatches
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 7. 标签与指派
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
gh label list -R owner/repo
|
|
196
|
+
gh label create "priority:high" -R owner/repo --color FF0000 --description "高优先级"
|
|
197
|
+
gh issue edit 123 -R owner/repo --add-label "priority:high"
|
|
198
|
+
gh issue edit 123 -R owner/repo --remove-label "priority:low"
|
|
199
|
+
gh issue edit 123 -R owner/repo --add-assignee "user1"
|
|
200
|
+
gh issue edit 123 -R owner/repo --remove-assignee "user2"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 8. 文件与提交
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
gh api /repos/owner/repo/contents/path/to/file --jq '.content' | base64 -d
|
|
207
|
+
gh api /repos/owner/repo/commits --jq '.[0:10] | .[] | {sha: .sha[:7], message: .commit.message[:80], author: .commit.author.name, date: .commit.author.date}'
|
|
208
|
+
gh api /repos/owner/repo/compare/main...feature --jq '{ahead_by, behind_by, files: [.files[:20][] | {filename, status, changes}]}'
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 9. Discussion
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
gh api /repos/owner/repo/discussions --jq '.[0:10] | .[] | {number, title, category: .category.name}'
|
|
215
|
+
gh api /repos/owner/repo/discussions/categories --jq '.[] | {id: .node_id, name, slug}'
|
|
216
|
+
gh api graphql -f query='mutation {
|
|
217
|
+
createDiscussion(input: {
|
|
218
|
+
repositoryId: "REPO_NODE_ID",
|
|
219
|
+
categoryId: "CATEGORY_NODE_ID",
|
|
220
|
+
title: "标题",
|
|
221
|
+
body: "正文"
|
|
222
|
+
}) { discussion { number url } }
|
|
223
|
+
}'
|
|
224
|
+
gh api -X POST /repos/owner/repo/discussions/{number}/comments -f body="评论内容"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 10. 万能 fallback:gh api
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
gh api /repos/owner/repo/xxx
|
|
231
|
+
gh api -X POST /repos/owner/repo/xxx -f key=value
|
|
232
|
+
gh api -X PATCH /repos/owner/repo/xxx -f key=value
|
|
233
|
+
gh api graphql -f query='{ repository(owner:"owner", name:"repo") { ... } }'
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 三、输出控制黄金规则
|
|
239
|
+
|
|
240
|
+
**所有 gh CLI 命令都必须控制输出大小**,防止 token 爆炸:
|
|
241
|
+
|
|
242
|
+
| 手段 | 示例 |
|
|
243
|
+
|------|------|
|
|
244
|
+
| `--json` + `--jq` | 精确控制返回字段和条数 |
|
|
245
|
+
| `--limit N` | 列表不超过 20 条 |
|
|
246
|
+
| `--jq '.body[:2000]'` | 截断长文本字段 |
|
|
247
|
+
| `\| head -n 200` | 截断 diff 等大文本 |
|
|
248
|
+
|
|
249
|
+
**目标:单次调用输出 < 15KB。**
|
|
250
|
+
|
|
251
|
+
## 四、常见错误与修复
|
|
252
|
+
|
|
253
|
+
| 错误 | 原因 | 修复 |
|
|
254
|
+
|------|------|------|
|
|
255
|
+
| `gh: command not found` | 未安装 gh CLI | 需管理员安装 |
|
|
256
|
+
| `HTTP 401` | Token 无效或过期 | 检查 GH_TOKEN 环境变量 |
|
|
257
|
+
| `HTTP 404` | 仓库/资源不存在或无权限 | 确认 owner/repo 和 Token scope |
|
|
258
|
+
| `HTTP 422` | 参数不合法 | 检查必填字段是否缺失 |
|
|
259
|
+
| `GraphQL: ...` | GraphQL 查询语法错误 | 检查 query 拼写与字段名 |
|
package/src/gh-client.ts
CHANGED
|
@@ -248,142 +248,6 @@ export class GhClient {
|
|
|
248
248
|
return this.del(`/repos/${repo}/pulls/comments/${commentId}`);
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
// ── Pull Requests ─────────────────────────────────────────────────
|
|
252
|
-
|
|
253
|
-
async listPRs(repo: string, state: string = 'open', limit: number = 15) {
|
|
254
|
-
return this.get<any[]>(`/repos/${repo}/pulls?state=${state}&per_page=${limit}`);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async getPR(repo: string, number: number) {
|
|
258
|
-
return this.get<any>(`/repos/${repo}/pulls/${number}`);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
async getPRDiff(repo: string, number: number): Promise<{ ok: boolean; data: string }> {
|
|
262
|
-
return this.request('GET', `/repos/${repo}/pulls/${number}`, undefined, {
|
|
263
|
-
Accept: 'application/vnd.github.diff',
|
|
264
|
-
}) as Promise<{ ok: boolean; data: string }>;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
async mergePR(repo: string, number: number, method: string = 'squash') {
|
|
268
|
-
return this.put<any>(`/repos/${repo}/pulls/${number}/merge`, { merge_method: method });
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async createPR(repo: string, title: string, body: string, head: string, base: string = 'main') {
|
|
272
|
-
return this.post<any>(`/repos/${repo}/pulls`, { title, body, head, base });
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
async createPRReview(repo: string, number: number, event: 'APPROVE' | 'REQUEST_CHANGES' | 'COMMENT', body?: string) {
|
|
276
|
-
return this.post<any>(`/repos/${repo}/pulls/${number}/reviews`, { event, body: body || '' });
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async closePR(repo: string, number: number) {
|
|
280
|
-
return this.patch<any>(`/repos/${repo}/pulls/${number}`, { state: 'closed' });
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// ── Issues ────────────────────────────────────────────────────────
|
|
284
|
-
|
|
285
|
-
async listIssues(repo: string, state: string = 'open', limit: number = 15) {
|
|
286
|
-
return this.get<any[]>(`/repos/${repo}/issues?state=${state}&per_page=${limit}&direction=desc`);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async getIssue(repo: string, number: number) {
|
|
290
|
-
return this.get<any>(`/repos/${repo}/issues/${number}`);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async createIssue(repo: string, title: string, body?: string, labels?: string[]) {
|
|
294
|
-
return this.post<any>(`/repos/${repo}/issues`, { title, body, labels });
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
async closeIssue(repo: string, number: number) {
|
|
298
|
-
return this.patch<any>(`/repos/${repo}/issues/${number}`, { state: 'closed', state_reason: 'completed' });
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// ── Repository ────────────────────────────────────────────────────
|
|
302
|
-
|
|
303
|
-
async getRepo(repo: string) {
|
|
304
|
-
return this.get<any>(`/repos/${repo}`);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async listBranches(repo: string, limit: number = 30) {
|
|
308
|
-
return this.get<any[]>(`/repos/${repo}/branches?per_page=${limit}`);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async listReleases(repo: string, limit: number = 10) {
|
|
312
|
-
return this.get<any[]>(`/repos/${repo}/releases?per_page=${limit}`);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
async listWorkflowRuns(repo: string, limit: number = 10) {
|
|
316
|
-
return this.get<{ total_count: number; workflow_runs: any[] }>(`/repos/${repo}/actions/runs?per_page=${limit}`);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// ── Search ───────────────────────────────────────────────────────
|
|
320
|
-
|
|
321
|
-
async searchIssues(query: string, limit: number = 15) {
|
|
322
|
-
return this.get<{ total_count: number; items: any[] }>(`/search/issues?q=${encodeURIComponent(query)}&per_page=${limit}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
async searchRepos(query: string, limit: number = 15) {
|
|
326
|
-
return this.get<{ total_count: number; items: any[] }>(`/search/repositories?q=${encodeURIComponent(query)}&per_page=${limit}`);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
async searchCode(query: string, limit: number = 15) {
|
|
330
|
-
return this.get<{ total_count: number; items: any[] }>(`/search/code?q=${encodeURIComponent(query)}&per_page=${limit}`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// ── Labels ───────────────────────────────────────────────────────
|
|
334
|
-
|
|
335
|
-
async listLabels(repo: string) {
|
|
336
|
-
return this.get<any[]>(`/repos/${repo}/labels?per_page=100`);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
async addLabels(repo: string, issueNumber: number, labels: string[]) {
|
|
340
|
-
return this.post<any[]>(`/repos/${repo}/issues/${issueNumber}/labels`, { labels });
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
async removeLabel(repo: string, issueNumber: number, label: string) {
|
|
344
|
-
return this.del(`/repos/${repo}/issues/${issueNumber}/labels/${encodeURIComponent(label)}`);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// ── Assignees ────────────────────────────────────────────────────
|
|
348
|
-
|
|
349
|
-
async addAssignees(repo: string, issueNumber: number, assignees: string[]) {
|
|
350
|
-
return this.post<any>(`/repos/${repo}/issues/${issueNumber}/assignees`, { assignees });
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
async removeAssignees(repo: string, issueNumber: number, assignees: string[]) {
|
|
354
|
-
return this.del<any>(`/repos/${repo}/issues/${issueNumber}/assignees`, { assignees });
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// ── File Content ─────────────────────────────────────────────────
|
|
358
|
-
|
|
359
|
-
async getFileContent(repo: string, filePath: string, ref?: string) {
|
|
360
|
-
const qs = ref ? `?ref=${encodeURIComponent(ref)}` : '';
|
|
361
|
-
return this.get<any>(`/repos/${repo}/contents/${filePath}${qs}`);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// ── Commits ──────────────────────────────────────────────────────
|
|
365
|
-
|
|
366
|
-
async listCommits(repo: string, sha?: string, filePath?: string, limit: number = 15) {
|
|
367
|
-
const params = new URLSearchParams({ per_page: String(limit) });
|
|
368
|
-
if (sha) params.set('sha', sha);
|
|
369
|
-
if (filePath) params.set('path', filePath);
|
|
370
|
-
return this.get<any[]>(`/repos/${repo}/commits?${params}`);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
async compareCommits(repo: string, base: string, head: string) {
|
|
374
|
-
return this.get<any>(`/repos/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// ── Update Issue / PR ────────────────────────────────────────────
|
|
378
|
-
|
|
379
|
-
async updateIssue(repo: string, number: number, data: { title?: string; body?: string; state?: string; labels?: string[]; assignees?: string[] }) {
|
|
380
|
-
return this.patch<any>(`/repos/${repo}/issues/${number}`, data);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
async updatePR(repo: string, number: number, data: { title?: string; body?: string; state?: string; base?: string }) {
|
|
384
|
-
return this.patch<any>(`/repos/${repo}/pulls/${number}`, data);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
251
|
// ── Star ─────────────────────────────────────────────────────────
|
|
388
252
|
|
|
389
253
|
async starRepo(repo: string) {
|