@github-tools/sdk 0.0.1
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/LICENSE +201 -0
- package/README.md +175 -0
- package/dist/index.d.mts +689 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +626 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import { Octokit } from "@octokit/rest";
|
|
2
|
+
import { tool } from "ai";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
//#region src/client.ts
|
|
6
|
+
function createOctokit(token) {
|
|
7
|
+
return new Octokit({ auth: token });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/tools/repository.ts
|
|
12
|
+
const getRepository = (octokit) => tool({
|
|
13
|
+
description: "Get information about a GitHub repository including description, stars, forks, language, and default branch",
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
owner: z.string().describe("Repository owner (user or organization)"),
|
|
16
|
+
repo: z.string().describe("Repository name")
|
|
17
|
+
}),
|
|
18
|
+
execute: async ({ owner, repo }) => {
|
|
19
|
+
const { data } = await octokit.repos.get({
|
|
20
|
+
owner,
|
|
21
|
+
repo
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
name: data.name,
|
|
25
|
+
fullName: data.full_name,
|
|
26
|
+
description: data.description,
|
|
27
|
+
url: data.html_url,
|
|
28
|
+
defaultBranch: data.default_branch,
|
|
29
|
+
stars: data.stargazers_count,
|
|
30
|
+
forks: data.forks_count,
|
|
31
|
+
openIssues: data.open_issues_count,
|
|
32
|
+
language: data.language,
|
|
33
|
+
private: data.private,
|
|
34
|
+
createdAt: data.created_at,
|
|
35
|
+
updatedAt: data.updated_at
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const listBranches = (octokit) => tool({
|
|
40
|
+
description: "List branches in a GitHub repository",
|
|
41
|
+
inputSchema: z.object({
|
|
42
|
+
owner: z.string().describe("Repository owner"),
|
|
43
|
+
repo: z.string().describe("Repository name"),
|
|
44
|
+
perPage: z.number().optional().default(30).describe("Number of branches to return (max 100)")
|
|
45
|
+
}),
|
|
46
|
+
execute: async ({ owner, repo, perPage }) => {
|
|
47
|
+
const { data } = await octokit.repos.listBranches({
|
|
48
|
+
owner,
|
|
49
|
+
repo,
|
|
50
|
+
per_page: perPage
|
|
51
|
+
});
|
|
52
|
+
return data.map((branch) => ({
|
|
53
|
+
name: branch.name,
|
|
54
|
+
sha: branch.commit.sha,
|
|
55
|
+
protected: branch.protected
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const getFileContent = (octokit) => tool({
|
|
60
|
+
description: "Get the content of a file from a GitHub repository",
|
|
61
|
+
inputSchema: z.object({
|
|
62
|
+
owner: z.string().describe("Repository owner"),
|
|
63
|
+
repo: z.string().describe("Repository name"),
|
|
64
|
+
path: z.string().describe("Path to the file in the repository"),
|
|
65
|
+
ref: z.string().optional().describe("Branch, tag, or commit SHA (defaults to the default branch)")
|
|
66
|
+
}),
|
|
67
|
+
execute: async ({ owner, repo, path, ref }) => {
|
|
68
|
+
const { data } = await octokit.repos.getContent({
|
|
69
|
+
owner,
|
|
70
|
+
repo,
|
|
71
|
+
path,
|
|
72
|
+
ref
|
|
73
|
+
});
|
|
74
|
+
if (Array.isArray(data)) return {
|
|
75
|
+
type: "directory",
|
|
76
|
+
entries: data.map((e) => ({
|
|
77
|
+
name: e.name,
|
|
78
|
+
type: e.type,
|
|
79
|
+
path: e.path
|
|
80
|
+
}))
|
|
81
|
+
};
|
|
82
|
+
if (data.type !== "file") return {
|
|
83
|
+
type: data.type,
|
|
84
|
+
path: data.path
|
|
85
|
+
};
|
|
86
|
+
const content = Buffer.from(data.content, "base64").toString("utf-8");
|
|
87
|
+
return {
|
|
88
|
+
type: "file",
|
|
89
|
+
path: data.path,
|
|
90
|
+
sha: data.sha,
|
|
91
|
+
size: data.size,
|
|
92
|
+
content
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const createOrUpdateFile = (octokit, { needsApproval = true } = {}) => tool({
|
|
97
|
+
description: "Create or update a file in a GitHub repository. Provide the SHA when updating an existing file.",
|
|
98
|
+
needsApproval,
|
|
99
|
+
inputSchema: z.object({
|
|
100
|
+
owner: z.string().describe("Repository owner"),
|
|
101
|
+
repo: z.string().describe("Repository name"),
|
|
102
|
+
path: z.string().describe("Path to the file in the repository"),
|
|
103
|
+
message: z.string().describe("Commit message"),
|
|
104
|
+
content: z.string().describe("File content (plain text, will be base64-encoded automatically)"),
|
|
105
|
+
branch: z.string().optional().describe("Branch to commit to (defaults to the default branch)"),
|
|
106
|
+
sha: z.string().optional().describe("SHA of the file being replaced (required when updating an existing file)")
|
|
107
|
+
}),
|
|
108
|
+
execute: async ({ owner, repo, path, message, content, branch, sha }) => {
|
|
109
|
+
const encoded = Buffer.from(content).toString("base64");
|
|
110
|
+
const { data } = await octokit.repos.createOrUpdateFileContents({
|
|
111
|
+
owner,
|
|
112
|
+
repo,
|
|
113
|
+
path,
|
|
114
|
+
message,
|
|
115
|
+
content: encoded,
|
|
116
|
+
branch,
|
|
117
|
+
sha
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
path: data.content?.path,
|
|
121
|
+
sha: data.content?.sha,
|
|
122
|
+
commitSha: data.commit.sha,
|
|
123
|
+
commitUrl: data.commit.html_url
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/tools/pull-requests.ts
|
|
130
|
+
const listPullRequests = (octokit) => tool({
|
|
131
|
+
description: "List pull requests for a GitHub repository",
|
|
132
|
+
inputSchema: z.object({
|
|
133
|
+
owner: z.string().describe("Repository owner"),
|
|
134
|
+
repo: z.string().describe("Repository name"),
|
|
135
|
+
state: z.enum([
|
|
136
|
+
"open",
|
|
137
|
+
"closed",
|
|
138
|
+
"all"
|
|
139
|
+
]).optional().default("open").describe("Filter by state"),
|
|
140
|
+
perPage: z.number().optional().default(30).describe("Number of results to return (max 100)")
|
|
141
|
+
}),
|
|
142
|
+
execute: async ({ owner, repo, state, perPage }) => {
|
|
143
|
+
const { data } = await octokit.pulls.list({
|
|
144
|
+
owner,
|
|
145
|
+
repo,
|
|
146
|
+
state,
|
|
147
|
+
per_page: perPage
|
|
148
|
+
});
|
|
149
|
+
return data.map((pr) => ({
|
|
150
|
+
number: pr.number,
|
|
151
|
+
title: pr.title,
|
|
152
|
+
state: pr.state,
|
|
153
|
+
url: pr.html_url,
|
|
154
|
+
author: pr.user?.login,
|
|
155
|
+
branch: pr.head.ref,
|
|
156
|
+
base: pr.base.ref,
|
|
157
|
+
draft: pr.draft,
|
|
158
|
+
createdAt: pr.created_at,
|
|
159
|
+
updatedAt: pr.updated_at
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const getPullRequest = (octokit) => tool({
|
|
164
|
+
description: "Get detailed information about a specific pull request",
|
|
165
|
+
inputSchema: z.object({
|
|
166
|
+
owner: z.string().describe("Repository owner"),
|
|
167
|
+
repo: z.string().describe("Repository name"),
|
|
168
|
+
pullNumber: z.number().describe("Pull request number")
|
|
169
|
+
}),
|
|
170
|
+
execute: async ({ owner, repo, pullNumber }) => {
|
|
171
|
+
const { data } = await octokit.pulls.get({
|
|
172
|
+
owner,
|
|
173
|
+
repo,
|
|
174
|
+
pull_number: pullNumber
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
number: data.number,
|
|
178
|
+
title: data.title,
|
|
179
|
+
body: data.body,
|
|
180
|
+
state: data.state,
|
|
181
|
+
url: data.html_url,
|
|
182
|
+
author: data.user?.login,
|
|
183
|
+
branch: data.head.ref,
|
|
184
|
+
base: data.base.ref,
|
|
185
|
+
draft: data.draft,
|
|
186
|
+
merged: data.merged,
|
|
187
|
+
mergeable: data.mergeable,
|
|
188
|
+
additions: data.additions,
|
|
189
|
+
deletions: data.deletions,
|
|
190
|
+
changedFiles: data.changed_files,
|
|
191
|
+
createdAt: data.created_at,
|
|
192
|
+
updatedAt: data.updated_at,
|
|
193
|
+
mergedAt: data.merged_at
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
const createPullRequest = (octokit, { needsApproval = true } = {}) => tool({
|
|
198
|
+
description: "Create a new pull request in a GitHub repository",
|
|
199
|
+
needsApproval,
|
|
200
|
+
inputSchema: z.object({
|
|
201
|
+
owner: z.string().describe("Repository owner"),
|
|
202
|
+
repo: z.string().describe("Repository name"),
|
|
203
|
+
title: z.string().describe("Pull request title"),
|
|
204
|
+
body: z.string().optional().describe("Pull request description (supports Markdown)"),
|
|
205
|
+
head: z.string().describe("Branch containing the changes (format: branch or username:branch)"),
|
|
206
|
+
base: z.string().describe("Branch to merge into"),
|
|
207
|
+
draft: z.boolean().optional().default(false).describe("Create as draft pull request")
|
|
208
|
+
}),
|
|
209
|
+
execute: async ({ owner, repo, title, body, head, base, draft }) => {
|
|
210
|
+
const { data } = await octokit.pulls.create({
|
|
211
|
+
owner,
|
|
212
|
+
repo,
|
|
213
|
+
title,
|
|
214
|
+
body,
|
|
215
|
+
head,
|
|
216
|
+
base,
|
|
217
|
+
draft
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
number: data.number,
|
|
221
|
+
title: data.title,
|
|
222
|
+
url: data.html_url,
|
|
223
|
+
state: data.state,
|
|
224
|
+
draft: data.draft,
|
|
225
|
+
branch: data.head.ref,
|
|
226
|
+
base: data.base.ref
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const mergePullRequest = (octokit, { needsApproval = true } = {}) => tool({
|
|
231
|
+
description: "Merge a pull request",
|
|
232
|
+
needsApproval,
|
|
233
|
+
inputSchema: z.object({
|
|
234
|
+
owner: z.string().describe("Repository owner"),
|
|
235
|
+
repo: z.string().describe("Repository name"),
|
|
236
|
+
pullNumber: z.number().describe("Pull request number"),
|
|
237
|
+
commitTitle: z.string().optional().describe("Title for the automatic merge commit"),
|
|
238
|
+
commitMessage: z.string().optional().describe("Extra detail to append to automatic commit message"),
|
|
239
|
+
mergeMethod: z.enum([
|
|
240
|
+
"merge",
|
|
241
|
+
"squash",
|
|
242
|
+
"rebase"
|
|
243
|
+
]).optional().default("merge").describe("Merge strategy")
|
|
244
|
+
}),
|
|
245
|
+
execute: async ({ owner, repo, pullNumber, commitTitle, commitMessage, mergeMethod }) => {
|
|
246
|
+
const { data } = await octokit.pulls.merge({
|
|
247
|
+
owner,
|
|
248
|
+
repo,
|
|
249
|
+
pull_number: pullNumber,
|
|
250
|
+
commit_title: commitTitle,
|
|
251
|
+
commit_message: commitMessage,
|
|
252
|
+
merge_method: mergeMethod
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
merged: data.merged,
|
|
256
|
+
message: data.message,
|
|
257
|
+
sha: data.sha
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
const addPullRequestComment = (octokit, { needsApproval = true } = {}) => tool({
|
|
262
|
+
description: "Add a comment to a pull request",
|
|
263
|
+
needsApproval,
|
|
264
|
+
inputSchema: z.object({
|
|
265
|
+
owner: z.string().describe("Repository owner"),
|
|
266
|
+
repo: z.string().describe("Repository name"),
|
|
267
|
+
pullNumber: z.number().describe("Pull request number"),
|
|
268
|
+
body: z.string().describe("Comment text (supports Markdown)")
|
|
269
|
+
}),
|
|
270
|
+
execute: async ({ owner, repo, pullNumber, body }) => {
|
|
271
|
+
const { data } = await octokit.issues.createComment({
|
|
272
|
+
owner,
|
|
273
|
+
repo,
|
|
274
|
+
issue_number: pullNumber,
|
|
275
|
+
body
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
id: data.id,
|
|
279
|
+
url: data.html_url,
|
|
280
|
+
body: data.body,
|
|
281
|
+
author: data.user?.login,
|
|
282
|
+
createdAt: data.created_at
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/tools/issues.ts
|
|
289
|
+
const listIssues = (octokit) => tool({
|
|
290
|
+
description: "List issues for a GitHub repository (excludes pull requests)",
|
|
291
|
+
inputSchema: z.object({
|
|
292
|
+
owner: z.string().describe("Repository owner"),
|
|
293
|
+
repo: z.string().describe("Repository name"),
|
|
294
|
+
state: z.enum([
|
|
295
|
+
"open",
|
|
296
|
+
"closed",
|
|
297
|
+
"all"
|
|
298
|
+
]).optional().default("open").describe("Filter by state"),
|
|
299
|
+
labels: z.string().optional().describe("Comma-separated list of label names to filter by"),
|
|
300
|
+
perPage: z.number().optional().default(30).describe("Number of results to return (max 100)")
|
|
301
|
+
}),
|
|
302
|
+
execute: async ({ owner, repo, state, labels, perPage }) => {
|
|
303
|
+
const { data } = await octokit.issues.listForRepo({
|
|
304
|
+
owner,
|
|
305
|
+
repo,
|
|
306
|
+
state,
|
|
307
|
+
labels,
|
|
308
|
+
per_page: perPage
|
|
309
|
+
});
|
|
310
|
+
return data.filter((issue) => !issue.pull_request).map((issue) => ({
|
|
311
|
+
number: issue.number,
|
|
312
|
+
title: issue.title,
|
|
313
|
+
state: issue.state,
|
|
314
|
+
url: issue.html_url,
|
|
315
|
+
author: issue.user?.login,
|
|
316
|
+
labels: issue.labels.map((l) => typeof l === "string" ? l : l.name),
|
|
317
|
+
createdAt: issue.created_at,
|
|
318
|
+
updatedAt: issue.updated_at
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
const getIssue = (octokit) => tool({
|
|
323
|
+
description: "Get detailed information about a specific issue",
|
|
324
|
+
inputSchema: z.object({
|
|
325
|
+
owner: z.string().describe("Repository owner"),
|
|
326
|
+
repo: z.string().describe("Repository name"),
|
|
327
|
+
issueNumber: z.number().describe("Issue number")
|
|
328
|
+
}),
|
|
329
|
+
execute: async ({ owner, repo, issueNumber }) => {
|
|
330
|
+
const { data } = await octokit.issues.get({
|
|
331
|
+
owner,
|
|
332
|
+
repo,
|
|
333
|
+
issue_number: issueNumber
|
|
334
|
+
});
|
|
335
|
+
return {
|
|
336
|
+
number: data.number,
|
|
337
|
+
title: data.title,
|
|
338
|
+
body: data.body,
|
|
339
|
+
state: data.state,
|
|
340
|
+
url: data.html_url,
|
|
341
|
+
author: data.user?.login,
|
|
342
|
+
assignees: data.assignees?.map((a) => a.login),
|
|
343
|
+
labels: data.labels.map((l) => typeof l === "string" ? l : l.name),
|
|
344
|
+
comments: data.comments,
|
|
345
|
+
createdAt: data.created_at,
|
|
346
|
+
updatedAt: data.updated_at,
|
|
347
|
+
closedAt: data.closed_at
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
const createIssue = (octokit, { needsApproval = true } = {}) => tool({
|
|
352
|
+
description: "Create a new issue in a GitHub repository",
|
|
353
|
+
needsApproval,
|
|
354
|
+
inputSchema: z.object({
|
|
355
|
+
owner: z.string().describe("Repository owner"),
|
|
356
|
+
repo: z.string().describe("Repository name"),
|
|
357
|
+
title: z.string().describe("Issue title"),
|
|
358
|
+
body: z.string().optional().describe("Issue description (supports Markdown)"),
|
|
359
|
+
labels: z.array(z.string()).optional().describe("Labels to apply to the issue"),
|
|
360
|
+
assignees: z.array(z.string()).optional().describe("GitHub usernames to assign to the issue")
|
|
361
|
+
}),
|
|
362
|
+
execute: async ({ owner, repo, title, body, labels, assignees }) => {
|
|
363
|
+
const { data } = await octokit.issues.create({
|
|
364
|
+
owner,
|
|
365
|
+
repo,
|
|
366
|
+
title,
|
|
367
|
+
body,
|
|
368
|
+
labels,
|
|
369
|
+
assignees
|
|
370
|
+
});
|
|
371
|
+
return {
|
|
372
|
+
number: data.number,
|
|
373
|
+
title: data.title,
|
|
374
|
+
url: data.html_url,
|
|
375
|
+
state: data.state,
|
|
376
|
+
labels: data.labels.map((l) => typeof l === "string" ? l : l.name)
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
const addIssueComment = (octokit, { needsApproval = true } = {}) => tool({
|
|
381
|
+
description: "Add a comment to a GitHub issue",
|
|
382
|
+
needsApproval,
|
|
383
|
+
inputSchema: z.object({
|
|
384
|
+
owner: z.string().describe("Repository owner"),
|
|
385
|
+
repo: z.string().describe("Repository name"),
|
|
386
|
+
issueNumber: z.number().describe("Issue number"),
|
|
387
|
+
body: z.string().describe("Comment text (supports Markdown)")
|
|
388
|
+
}),
|
|
389
|
+
execute: async ({ owner, repo, issueNumber, body }) => {
|
|
390
|
+
const { data } = await octokit.issues.createComment({
|
|
391
|
+
owner,
|
|
392
|
+
repo,
|
|
393
|
+
issue_number: issueNumber,
|
|
394
|
+
body
|
|
395
|
+
});
|
|
396
|
+
return {
|
|
397
|
+
id: data.id,
|
|
398
|
+
url: data.html_url,
|
|
399
|
+
body: data.body,
|
|
400
|
+
author: data.user?.login,
|
|
401
|
+
createdAt: data.created_at
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
const closeIssue = (octokit, { needsApproval = true } = {}) => tool({
|
|
406
|
+
description: "Close an open GitHub issue",
|
|
407
|
+
needsApproval,
|
|
408
|
+
inputSchema: z.object({
|
|
409
|
+
owner: z.string().describe("Repository owner"),
|
|
410
|
+
repo: z.string().describe("Repository name"),
|
|
411
|
+
issueNumber: z.number().describe("Issue number to close"),
|
|
412
|
+
stateReason: z.enum(["completed", "not_planned"]).optional().default("completed").describe("Reason for closing")
|
|
413
|
+
}),
|
|
414
|
+
execute: async ({ owner, repo, issueNumber, stateReason }) => {
|
|
415
|
+
const { data } = await octokit.issues.update({
|
|
416
|
+
owner,
|
|
417
|
+
repo,
|
|
418
|
+
issue_number: issueNumber,
|
|
419
|
+
state: "closed",
|
|
420
|
+
state_reason: stateReason
|
|
421
|
+
});
|
|
422
|
+
return {
|
|
423
|
+
number: data.number,
|
|
424
|
+
title: data.title,
|
|
425
|
+
state: data.state,
|
|
426
|
+
url: data.html_url,
|
|
427
|
+
closedAt: data.closed_at
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/tools/search.ts
|
|
434
|
+
const searchCode = (octokit) => tool({
|
|
435
|
+
description: "Search for code in GitHub repositories. Use qualifiers like \"repo:owner/name\" to scope the search.",
|
|
436
|
+
inputSchema: z.object({
|
|
437
|
+
query: z.string().describe("Search query. Supports GitHub search qualifiers, e.g. \"useState repo:facebook/react\""),
|
|
438
|
+
perPage: z.number().optional().default(10).describe("Number of results to return (max 30)")
|
|
439
|
+
}),
|
|
440
|
+
execute: async ({ query, perPage }) => {
|
|
441
|
+
const { data } = await octokit.search.code({
|
|
442
|
+
q: query,
|
|
443
|
+
per_page: perPage
|
|
444
|
+
});
|
|
445
|
+
return {
|
|
446
|
+
totalCount: data.total_count,
|
|
447
|
+
items: data.items.map((item) => ({
|
|
448
|
+
name: item.name,
|
|
449
|
+
path: item.path,
|
|
450
|
+
url: item.html_url,
|
|
451
|
+
repository: item.repository.full_name,
|
|
452
|
+
sha: item.sha
|
|
453
|
+
}))
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
const searchRepositories = (octokit) => tool({
|
|
458
|
+
description: "Search for GitHub repositories by keyword, topic, language, or other qualifiers",
|
|
459
|
+
inputSchema: z.object({
|
|
460
|
+
query: z.string().describe("Search query. Supports GitHub search qualifiers, e.g. \"nuxt language:typescript stars:>1000\""),
|
|
461
|
+
perPage: z.number().optional().default(10).describe("Number of results to return (max 30)"),
|
|
462
|
+
sort: z.enum([
|
|
463
|
+
"stars",
|
|
464
|
+
"forks",
|
|
465
|
+
"help-wanted-issues",
|
|
466
|
+
"updated"
|
|
467
|
+
]).optional().describe("Sort field"),
|
|
468
|
+
order: z.enum(["asc", "desc"]).optional().default("desc").describe("Sort order")
|
|
469
|
+
}),
|
|
470
|
+
execute: async ({ query, perPage, sort, order }) => {
|
|
471
|
+
const { data } = await octokit.search.repos({
|
|
472
|
+
q: query,
|
|
473
|
+
per_page: perPage,
|
|
474
|
+
sort,
|
|
475
|
+
order
|
|
476
|
+
});
|
|
477
|
+
return {
|
|
478
|
+
totalCount: data.total_count,
|
|
479
|
+
items: data.items.map((repo) => ({
|
|
480
|
+
name: repo.name,
|
|
481
|
+
fullName: repo.full_name,
|
|
482
|
+
description: repo.description,
|
|
483
|
+
url: repo.html_url,
|
|
484
|
+
stars: repo.stargazers_count,
|
|
485
|
+
forks: repo.forks_count,
|
|
486
|
+
language: repo.language,
|
|
487
|
+
topics: repo.topics
|
|
488
|
+
}))
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
//#endregion
|
|
494
|
+
//#region src/tools/commits.ts
|
|
495
|
+
const listCommits = (octokit) => tool({
|
|
496
|
+
description: "List commits for a GitHub repository. Filter by file path to see who changed a specific file and when (git blame alternative). Filter by author, branch, or date range.",
|
|
497
|
+
inputSchema: z.object({
|
|
498
|
+
owner: z.string().describe("Repository owner"),
|
|
499
|
+
repo: z.string().describe("Repository name"),
|
|
500
|
+
path: z.string().optional().describe("Only commits containing this file path"),
|
|
501
|
+
sha: z.string().optional().describe("Branch name or commit SHA to start listing from"),
|
|
502
|
+
author: z.string().optional().describe("GitHub username or email to filter commits by"),
|
|
503
|
+
since: z.string().optional().describe("Only commits after this date (ISO 8601 format)"),
|
|
504
|
+
until: z.string().optional().describe("Only commits before this date (ISO 8601 format)"),
|
|
505
|
+
perPage: z.number().optional().default(30).describe("Number of results to return (max 100)")
|
|
506
|
+
}),
|
|
507
|
+
execute: async ({ owner, repo, path, sha, author, since, until, perPage }) => {
|
|
508
|
+
const { data } = await octokit.repos.listCommits({
|
|
509
|
+
owner,
|
|
510
|
+
repo,
|
|
511
|
+
path,
|
|
512
|
+
sha,
|
|
513
|
+
author,
|
|
514
|
+
since,
|
|
515
|
+
until,
|
|
516
|
+
per_page: perPage
|
|
517
|
+
});
|
|
518
|
+
return data.map((commit) => ({
|
|
519
|
+
sha: commit.sha,
|
|
520
|
+
message: commit.commit.message,
|
|
521
|
+
author: commit.commit.author?.name,
|
|
522
|
+
authorLogin: commit.author?.login,
|
|
523
|
+
date: commit.commit.author?.date,
|
|
524
|
+
url: commit.html_url
|
|
525
|
+
}));
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
const getCommit = (octokit) => tool({
|
|
529
|
+
description: "Get detailed information about a specific commit, including the list of files changed with additions and deletions",
|
|
530
|
+
inputSchema: z.object({
|
|
531
|
+
owner: z.string().describe("Repository owner"),
|
|
532
|
+
repo: z.string().describe("Repository name"),
|
|
533
|
+
ref: z.string().describe("Commit SHA, branch name, or tag")
|
|
534
|
+
}),
|
|
535
|
+
execute: async ({ owner, repo, ref }) => {
|
|
536
|
+
const { data } = await octokit.repos.getCommit({
|
|
537
|
+
owner,
|
|
538
|
+
repo,
|
|
539
|
+
ref
|
|
540
|
+
});
|
|
541
|
+
return {
|
|
542
|
+
sha: data.sha,
|
|
543
|
+
message: data.commit.message,
|
|
544
|
+
author: data.commit.author?.name,
|
|
545
|
+
authorLogin: data.author?.login,
|
|
546
|
+
date: data.commit.author?.date,
|
|
547
|
+
url: data.html_url,
|
|
548
|
+
stats: data.stats ? {
|
|
549
|
+
additions: data.stats.additions,
|
|
550
|
+
deletions: data.stats.deletions,
|
|
551
|
+
total: data.stats.total
|
|
552
|
+
} : null,
|
|
553
|
+
files: data.files?.map((file) => ({
|
|
554
|
+
filename: file.filename,
|
|
555
|
+
status: file.status,
|
|
556
|
+
additions: file.additions,
|
|
557
|
+
deletions: file.deletions,
|
|
558
|
+
patch: file.patch
|
|
559
|
+
}))
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/index.ts
|
|
566
|
+
function resolveApproval(toolName, config) {
|
|
567
|
+
if (typeof config === "boolean") return config;
|
|
568
|
+
return config[toolName] ?? true;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Create a set of GitHub tools for the Vercel AI SDK.
|
|
572
|
+
*
|
|
573
|
+
* Write operations require user approval by default.
|
|
574
|
+
* Control this globally or per-tool via `requireApproval`.
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```ts
|
|
578
|
+
* // All writes need approval (default)
|
|
579
|
+
* createGithubTools({ token })
|
|
580
|
+
*
|
|
581
|
+
* // No approval at all
|
|
582
|
+
* createGithubTools({ token, requireApproval: false })
|
|
583
|
+
*
|
|
584
|
+
* // Granular: only destructive actions need approval
|
|
585
|
+
* createGithubTools({
|
|
586
|
+
* token,
|
|
587
|
+
* requireApproval: {
|
|
588
|
+
* mergePullRequest: true,
|
|
589
|
+
* createOrUpdateFile: true,
|
|
590
|
+
* closeIssue: true,
|
|
591
|
+
* createPullRequest: false,
|
|
592
|
+
* addPullRequestComment: false,
|
|
593
|
+
* createIssue: false,
|
|
594
|
+
* addIssueComment: false,
|
|
595
|
+
* }
|
|
596
|
+
* })
|
|
597
|
+
* ```
|
|
598
|
+
*/
|
|
599
|
+
function createGithubTools({ token, requireApproval = true }) {
|
|
600
|
+
const octokit = createOctokit(token);
|
|
601
|
+
const approval = (name) => ({ needsApproval: resolveApproval(name, requireApproval) });
|
|
602
|
+
return {
|
|
603
|
+
getRepository: getRepository(octokit),
|
|
604
|
+
listBranches: listBranches(octokit),
|
|
605
|
+
getFileContent: getFileContent(octokit),
|
|
606
|
+
listPullRequests: listPullRequests(octokit),
|
|
607
|
+
getPullRequest: getPullRequest(octokit),
|
|
608
|
+
listIssues: listIssues(octokit),
|
|
609
|
+
getIssue: getIssue(octokit),
|
|
610
|
+
searchCode: searchCode(octokit),
|
|
611
|
+
searchRepositories: searchRepositories(octokit),
|
|
612
|
+
listCommits: listCommits(octokit),
|
|
613
|
+
getCommit: getCommit(octokit),
|
|
614
|
+
createOrUpdateFile: createOrUpdateFile(octokit, approval("createOrUpdateFile")),
|
|
615
|
+
createPullRequest: createPullRequest(octokit, approval("createPullRequest")),
|
|
616
|
+
mergePullRequest: mergePullRequest(octokit, approval("mergePullRequest")),
|
|
617
|
+
addPullRequestComment: addPullRequestComment(octokit, approval("addPullRequestComment")),
|
|
618
|
+
createIssue: createIssue(octokit, approval("createIssue")),
|
|
619
|
+
addIssueComment: addIssueComment(octokit, approval("addIssueComment")),
|
|
620
|
+
closeIssue: closeIssue(octokit, approval("closeIssue"))
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
//#endregion
|
|
625
|
+
export { addIssueComment, addPullRequestComment, closeIssue, createGithubTools, createIssue, createOctokit, createOrUpdateFile, createPullRequest, getCommit, getFileContent, getIssue, getPullRequest, getRepository, listBranches, listCommits, listIssues, listPullRequests, mergePullRequest, searchCode, searchRepositories };
|
|
626
|
+
//# sourceMappingURL=index.mjs.map
|