@trim21/personal-pi-extensions 0.1.685 → 0.1.688
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/README.md +2 -2
- package/package.json +1 -1
- package/src/gh/base.ts +115 -60
- package/src/gh/render.ts +65 -65
- package/src/gh/schemas.ts +102 -129
- package/src/gh/tools/download-release-assets.ts +58 -80
- package/src/gh/tools/list-issues.ts +10 -6
- package/src/gh/tools/list-prs.ts +10 -6
- package/src/gh/tools/list-releases.ts +14 -13
- package/src/gh/tools/list-workflow-runs.ts +7 -19
- package/src/gh/tools/read-ci-logs.ts +6 -19
- package/src/gh/tools/read-issue-comments.ts +10 -7
- package/src/gh/tools/read-issue.ts +10 -14
- package/src/gh/tools/read-pr-comments.ts +19 -38
- package/src/gh/tools/read-pr-diff.ts +9 -8
- package/src/gh/tools/read-pr.ts +7 -15
- package/src/gh/tools/read-release.ts +7 -23
- package/src/gh/tools/read-repo.ts +7 -32
- package/src/gh/tools/wait-pr-checks.ts +6 -7
- package/src/gh/tools/watch-run.ts +35 -25
- package/src/lib/github-reads.ts +405 -0
- package/src/lib/github.ts +74 -57
|
@@ -4,8 +4,8 @@ import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
|
4
4
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
5
|
import {
|
|
6
6
|
type GhClient,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
9
9
|
subtitlePendant,
|
|
10
10
|
toToolResult,
|
|
11
11
|
withStructuredResult,
|
|
@@ -13,10 +13,7 @@ import {
|
|
|
13
13
|
import { renderReleaseList } from "../render.js";
|
|
14
14
|
import { ghReleaseListPayloadSchema, ghReleaseSummarySchema } from "../schemas.js";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const RELEASE_FIELDS = "tagName,name,isLatest,isPrerelease,isDraft,publishedAt,createdAt";
|
|
18
|
-
|
|
19
|
-
export function addListReleasesTool(_gh: GhClient, bus: ToolBus) {
|
|
16
|
+
export function addListReleasesTool(gh: GhClient, bus: ToolBus) {
|
|
20
17
|
bus.register(
|
|
21
18
|
defineStructuredTool({
|
|
22
19
|
name: "list-github-releases",
|
|
@@ -31,13 +28,17 @@ export function addListReleasesTool(_gh: GhClient, bus: ToolBus) {
|
|
|
31
28
|
structuredSchema: ghReleaseListPayloadSchema,
|
|
32
29
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
33
30
|
const { repo, limit } = params;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
31
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
32
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
33
|
+
const items = await gh.reads.listReleases(owner, repoName, limit, signal);
|
|
34
|
+
const releases = parseWithSchema(Type.Array(ghReleaseSummarySchema), items);
|
|
35
|
+
// REST 没有 isLatest:按列表顺序取第一个非 draft / prerelease 的条目
|
|
36
|
+
const latestIndex = releases.findIndex(
|
|
37
|
+
(release) => release.draft !== true && release.prerelease !== true,
|
|
38
|
+
);
|
|
39
|
+
const text = renderReleaseList(
|
|
40
|
+
releases.map((release, index) => ({ ...release, latest: index === latestIndex })),
|
|
41
|
+
);
|
|
41
42
|
const result = toToolResult(text, params);
|
|
42
43
|
result.details.pendant = subtitlePendant(params);
|
|
43
44
|
return withStructuredResult(result, { text, releases });
|
|
@@ -4,8 +4,8 @@ import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
|
4
4
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
5
|
import {
|
|
6
6
|
type GhClient,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
9
9
|
subtitlePendant,
|
|
10
10
|
toToolResult,
|
|
11
11
|
withStructuredResult,
|
|
@@ -13,11 +13,7 @@ import {
|
|
|
13
13
|
import { renderRunList } from "../render.js";
|
|
14
14
|
import { ghRunListPayloadSchema, ghRunSummarySchema } from "../schemas.js";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const RUN_FIELDS =
|
|
18
|
-
"databaseId,displayTitle,status,conclusion,workflowName,headBranch,event,createdAt,url";
|
|
19
|
-
|
|
20
|
-
export function addListWorkflowRunsTool(_gh: GhClient, bus: ToolBus) {
|
|
16
|
+
export function addListWorkflowRunsTool(gh: GhClient, bus: ToolBus) {
|
|
21
17
|
bus.register(
|
|
22
18
|
defineStructuredTool({
|
|
23
19
|
name: "list-github-workflow-runs",
|
|
@@ -36,18 +32,10 @@ export function addListWorkflowRunsTool(_gh: GhClient, bus: ToolBus) {
|
|
|
36
32
|
structuredSchema: ghRunListPayloadSchema,
|
|
37
33
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
38
34
|
const { repo, limit, status, workflow } = params;
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (status) {
|
|
44
|
-
args.push("--status", status);
|
|
45
|
-
}
|
|
46
|
-
if (workflow) {
|
|
47
|
-
args.push("--workflow", workflow);
|
|
48
|
-
}
|
|
49
|
-
const stdout = await ghExec(args, { cwd: ctx.cwd, signal, input: params });
|
|
50
|
-
const runs = parseWithSchema(Type.Array(ghRunSummarySchema), JSON.parse(stdout));
|
|
35
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
36
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
37
|
+
const items = await gh.reads.listRuns(owner, repoName, { workflow, status, limit }, signal);
|
|
38
|
+
const runs = parseWithSchema(Type.Array(ghRunSummarySchema), items);
|
|
51
39
|
const text = renderRunList(runs);
|
|
52
40
|
const result = toToolResult(text, params);
|
|
53
41
|
result.details.pendant = subtitlePendant(params);
|
|
@@ -14,7 +14,6 @@ import { createSeqState } from "../../lib/seq-state.js";
|
|
|
14
14
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
15
15
|
import {
|
|
16
16
|
type GhClient,
|
|
17
|
-
ghExec,
|
|
18
17
|
resolveRepo,
|
|
19
18
|
splitRepo,
|
|
20
19
|
structuredFailure,
|
|
@@ -55,10 +54,9 @@ export function jobLogPath(repo: string, runId: string, jobId: number): string {
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
async function getJobLog(
|
|
57
|
+
gh: GhClient,
|
|
58
58
|
job: RunJob,
|
|
59
59
|
signal: AbortSignal | undefined,
|
|
60
|
-
cwd: string | undefined,
|
|
61
|
-
input?: unknown,
|
|
62
60
|
): Promise<string> {
|
|
63
61
|
// The log download only accepts a job id, and the cache is keyed on the
|
|
64
62
|
// canonical repo/run from the job itself, not on the caller's `repo` string.
|
|
@@ -76,21 +74,10 @@ async function getJobLog(
|
|
|
76
74
|
// Not cached, fetch from GitHub
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// --allow-escape-sequences to output it anyway". The raw bytes are kept
|
|
84
|
-
// as-is (the file is the log exactly as GitHub delivers it); the tool never
|
|
85
|
-
// echoes them, and the TUI strips ANSI when rendering tool results.
|
|
86
|
-
const log = await ghExec(
|
|
87
|
-
["api", "--allow-escape-sequences", `/repos/${repo}/actions/jobs/${job.id}/logs`],
|
|
88
|
-
{
|
|
89
|
-
cwd,
|
|
90
|
-
signal,
|
|
91
|
-
input,
|
|
92
|
-
},
|
|
93
|
-
);
|
|
77
|
+
// 日志原样落盘(GitHub 返回什么就是什么,含 ANSI 转义与 runner 时间戳);工具从不回显
|
|
78
|
+
// 它,模型自己读文件,TUI 渲染工具结果时会自己剥 ANSI。
|
|
79
|
+
const { owner, repo: name } = splitRepo(repo);
|
|
80
|
+
const log = await gh.reads.jobLogs(owner, name, job.id, signal);
|
|
94
81
|
|
|
95
82
|
// Write to cache
|
|
96
83
|
await mkdir(cacheDir, { recursive: true });
|
|
@@ -420,7 +407,7 @@ async function ciLogs(gh: GhClient, call: ToolCall<JobIdParams>): Promise<CiLogs
|
|
|
420
407
|
details: {},
|
|
421
408
|
});
|
|
422
409
|
|
|
423
|
-
const rawLog = await getJobLog(target, signal
|
|
410
|
+
const rawLog = await getJobLog(gh, target, signal);
|
|
424
411
|
const index = jobLogIndex(target, rawLog);
|
|
425
412
|
|
|
426
413
|
return withStructuredResult(
|
|
@@ -3,14 +3,14 @@ import { Type } from "typebox";
|
|
|
3
3
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
4
4
|
import {
|
|
5
5
|
type GhClient,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
resolveRepo,
|
|
7
|
+
splitRepo,
|
|
8
8
|
subtitlePendant,
|
|
9
9
|
toStructuredJsonResult,
|
|
10
10
|
} from "../base.js";
|
|
11
11
|
import { issueCommentsSchema } from "../schemas.js";
|
|
12
12
|
|
|
13
|
-
export function addReadIssueCommentsTool(
|
|
13
|
+
export function addReadIssueCommentsTool(gh: GhClient, bus: ToolBus) {
|
|
14
14
|
bus.register(
|
|
15
15
|
defineStructuredTool({
|
|
16
16
|
name: "read-github-issue-comments",
|
|
@@ -24,11 +24,14 @@ export function addReadIssueCommentsTool(_gh: GhClient, bus: ToolBus) {
|
|
|
24
24
|
structuredSchema: issueCommentsSchema,
|
|
25
25
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
26
26
|
const { number, repo } = params;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
28
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
29
|
+
const comments = await gh.reads.issueComments(owner, repoName, Number(number), signal);
|
|
30
|
+
const result = toStructuredJsonResult(
|
|
31
|
+
JSON.stringify({ comments }, null, 2),
|
|
32
|
+
params,
|
|
33
|
+
issueCommentsSchema,
|
|
30
34
|
);
|
|
31
|
-
const result = toStructuredJsonResult(out, params, issueCommentsSchema);
|
|
32
35
|
result.details.pendant = subtitlePendant(params, "number");
|
|
33
36
|
return result;
|
|
34
37
|
},
|
|
@@ -3,14 +3,14 @@ import { Type } from "typebox";
|
|
|
3
3
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
4
4
|
import {
|
|
5
5
|
type GhClient,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
resolveRepo,
|
|
7
|
+
splitRepo,
|
|
8
8
|
subtitlePendant,
|
|
9
9
|
toStructuredJsonResult,
|
|
10
10
|
} from "../base.js";
|
|
11
11
|
import { issueViewSchema } from "../schemas.js";
|
|
12
12
|
|
|
13
|
-
export function addReadIssueTool(
|
|
13
|
+
export function addReadIssueTool(gh: GhClient, bus: ToolBus) {
|
|
14
14
|
bus.register(
|
|
15
15
|
defineStructuredTool({
|
|
16
16
|
name: "read-github-issue",
|
|
@@ -24,18 +24,14 @@ export function addReadIssueTool(_gh: GhClient, bus: ToolBus) {
|
|
|
24
24
|
structuredSchema: issueViewSchema,
|
|
25
25
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
26
26
|
const { number, repo } = params;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"title,state,body,author,createdAt,updatedAt,closedAt,url,labels,assignees,comments,milestone,number",
|
|
35
|
-
],
|
|
36
|
-
{ cwd: ctx.cwd, signal, input: params },
|
|
27
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
28
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
29
|
+
const data = await gh.reads.issue(owner, repoName, Number(number), signal);
|
|
30
|
+
const result = toStructuredJsonResult(
|
|
31
|
+
JSON.stringify(data, null, 2),
|
|
32
|
+
params,
|
|
33
|
+
issueViewSchema,
|
|
37
34
|
);
|
|
38
|
-
const result = toStructuredJsonResult(out, params, issueViewSchema);
|
|
39
35
|
result.details.pendant = subtitlePendant(params, "number");
|
|
40
36
|
return result;
|
|
41
37
|
},
|
|
@@ -2,17 +2,15 @@ import { Type } from "typebox";
|
|
|
2
2
|
|
|
3
3
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
4
4
|
import {
|
|
5
|
-
ghApiList,
|
|
6
5
|
type GhClient,
|
|
7
|
-
ghExec,
|
|
8
|
-
repoArgs,
|
|
9
6
|
resolveRepo,
|
|
7
|
+
splitRepo,
|
|
10
8
|
subtitlePendant,
|
|
11
9
|
toStructuredJsonResult,
|
|
12
10
|
} from "../base.js";
|
|
13
11
|
import { prCommentsSchema } from "../schemas.js";
|
|
14
12
|
|
|
15
|
-
export function addReadPrCommentsTool(
|
|
13
|
+
export function addReadPrCommentsTool(gh: GhClient, bus: ToolBus) {
|
|
16
14
|
bus.register(
|
|
17
15
|
defineStructuredTool({
|
|
18
16
|
name: "read-github-pr-comments",
|
|
@@ -33,42 +31,25 @@ export function addReadPrCommentsTool(_gh: GhClient, bus: ToolBus) {
|
|
|
33
31
|
structuredSchema: prCommentsSchema,
|
|
34
32
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
35
33
|
const { number, repo, reviews } = params;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
35
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
36
|
+
const pullNumber = Number(number);
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
signal,
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
input: params,
|
|
50
|
-
}),
|
|
51
|
-
]);
|
|
38
|
+
// reviews=true 给行内评审评论 + 评审摘要;缺省给 PR 上的普通(issue)评论
|
|
39
|
+
const payload = reviews
|
|
40
|
+
? {
|
|
41
|
+
reviews: await gh.reads.pullReviews(owner, repoName, pullNumber, signal),
|
|
42
|
+
comments: await gh.reads.pullReviewComments(owner, repoName, pullNumber, signal),
|
|
43
|
+
}
|
|
44
|
+
: {
|
|
45
|
+
comments: await gh.reads.issueComments(owner, repoName, pullNumber, signal),
|
|
46
|
+
};
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
null,
|
|
59
|
-
2,
|
|
60
|
-
);
|
|
61
|
-
} else {
|
|
62
|
-
out = await ghExec(
|
|
63
|
-
["pr", "view", String(number), ...repoArgs(repo), "--json", "comments"],
|
|
64
|
-
{
|
|
65
|
-
cwd: ctx.cwd,
|
|
66
|
-
signal,
|
|
67
|
-
input: params,
|
|
68
|
-
},
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
const result = toStructuredJsonResult(out, params, prCommentsSchema);
|
|
48
|
+
const result = toStructuredJsonResult(
|
|
49
|
+
JSON.stringify(payload, null, 2),
|
|
50
|
+
params,
|
|
51
|
+
prCommentsSchema,
|
|
52
|
+
);
|
|
72
53
|
result.details.pendant = subtitlePendant(params, "number");
|
|
73
54
|
return result;
|
|
74
55
|
},
|
|
@@ -3,8 +3,8 @@ import { Type } from "typebox";
|
|
|
3
3
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
4
4
|
import {
|
|
5
5
|
type GhClient,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
resolveRepo,
|
|
7
|
+
splitRepo,
|
|
8
8
|
subtitlePendant,
|
|
9
9
|
toToolResult,
|
|
10
10
|
withStructuredResult,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { parseDiffStats } from "../render.js";
|
|
13
13
|
import { ghDiffPayloadSchema } from "../schemas.js";
|
|
14
14
|
|
|
15
|
-
export function addReadPrDiffTool(
|
|
15
|
+
export function addReadPrDiffTool(gh: GhClient, bus: ToolBus) {
|
|
16
16
|
bus.register(
|
|
17
17
|
defineStructuredTool({
|
|
18
18
|
name: "read-github-pr-diff",
|
|
@@ -26,12 +26,13 @@ export function addReadPrDiffTool(_gh: GhClient, bus: ToolBus) {
|
|
|
26
26
|
structuredSchema: ghDiffPayloadSchema,
|
|
27
27
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
28
28
|
const { number, repo } = params;
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
29
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
30
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
31
|
+
const diff = await gh.reads.pullDiff(owner, repoName, Number(number), signal);
|
|
32
|
+
const result = toToolResult(diff, params);
|
|
32
33
|
result.details.pendant = subtitlePendant(params, "number");
|
|
33
|
-
//
|
|
34
|
-
return withStructuredResult(result, { text:
|
|
34
|
+
// 文本是原始 diff(没有 JSON 形式),载荷从同一份 diff 解析出变更统计
|
|
35
|
+
return withStructuredResult(result, { text: diff, ...parseDiffStats(diff) });
|
|
35
36
|
},
|
|
36
37
|
}),
|
|
37
38
|
);
|
package/src/gh/tools/read-pr.ts
CHANGED
|
@@ -3,14 +3,14 @@ import { Type } from "typebox";
|
|
|
3
3
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
4
4
|
import {
|
|
5
5
|
type GhClient,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
resolveRepo,
|
|
7
|
+
splitRepo,
|
|
8
8
|
subtitlePendant,
|
|
9
9
|
toStructuredJsonResult,
|
|
10
10
|
} from "../base.js";
|
|
11
11
|
import { prViewSchema } from "../schemas.js";
|
|
12
12
|
|
|
13
|
-
export function addReadPrTool(
|
|
13
|
+
export function addReadPrTool(gh: GhClient, bus: ToolBus) {
|
|
14
14
|
bus.register(
|
|
15
15
|
defineStructuredTool({
|
|
16
16
|
name: "read-github-pr",
|
|
@@ -24,18 +24,10 @@ export function addReadPrTool(_gh: GhClient, bus: ToolBus) {
|
|
|
24
24
|
structuredSchema: prViewSchema,
|
|
25
25
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
26
26
|
const { number, repo } = params;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
String(number),
|
|
32
|
-
...repoArgs(repo),
|
|
33
|
-
"--json",
|
|
34
|
-
"title,state,body,author,createdAt,updatedAt,mergedAt,mergedBy,headRefName,baseRefName,url,additions,deletions,changedFiles,labels,assignees,reviewRequests,reviews,comments,number",
|
|
35
|
-
],
|
|
36
|
-
{ cwd: ctx.cwd, signal, input: params },
|
|
37
|
-
);
|
|
38
|
-
const result = toStructuredJsonResult(out, params, prViewSchema);
|
|
27
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
28
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
29
|
+
const data = await gh.reads.pull(owner, repoName, Number(number), signal);
|
|
30
|
+
const result = toStructuredJsonResult(JSON.stringify(data, null, 2), params, prViewSchema);
|
|
39
31
|
result.details.pendant = subtitlePendant(params, "number");
|
|
40
32
|
return result;
|
|
41
33
|
},
|
|
@@ -4,8 +4,8 @@ import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
|
4
4
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
5
|
import {
|
|
6
6
|
type GhClient,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
9
9
|
subtitlePendant,
|
|
10
10
|
toToolResult,
|
|
11
11
|
withStructuredResult,
|
|
@@ -13,22 +13,7 @@ import {
|
|
|
13
13
|
import { renderReleaseView } from "../render.js";
|
|
14
14
|
import { ghReleaseViewPayloadSchema, ghReleaseViewSchema } from "../schemas.js";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const RELEASE_FIELDS = [
|
|
18
|
-
"tagName",
|
|
19
|
-
"name",
|
|
20
|
-
"body",
|
|
21
|
-
"url",
|
|
22
|
-
"isDraft",
|
|
23
|
-
"isPrerelease",
|
|
24
|
-
"createdAt",
|
|
25
|
-
"publishedAt",
|
|
26
|
-
"targetCommitish",
|
|
27
|
-
"author",
|
|
28
|
-
"assets",
|
|
29
|
-
].join(",");
|
|
30
|
-
|
|
31
|
-
export function addReadReleaseTool(_gh: GhClient, bus: ToolBus) {
|
|
16
|
+
export function addReadReleaseTool(gh: GhClient, bus: ToolBus) {
|
|
32
17
|
bus.register(
|
|
33
18
|
defineStructuredTool({
|
|
34
19
|
name: "read-github-release",
|
|
@@ -43,11 +28,10 @@ export function addReadReleaseTool(_gh: GhClient, bus: ToolBus) {
|
|
|
43
28
|
structuredSchema: ghReleaseViewPayloadSchema,
|
|
44
29
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
45
30
|
const { tag, repo } = params;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
50
|
-
const view = parseWithSchema(ghReleaseViewSchema, JSON.parse(stdout));
|
|
31
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
32
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
33
|
+
const data = await gh.reads.release(owner, repoName, tag, signal);
|
|
34
|
+
const view = parseWithSchema(ghReleaseViewSchema, data);
|
|
51
35
|
const text = renderReleaseView(view);
|
|
52
36
|
const result = toToolResult(text, params);
|
|
53
37
|
result.details.pendant = subtitlePendant(params, "tag");
|
|
@@ -4,7 +4,8 @@ import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
|
4
4
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
5
|
import {
|
|
6
6
|
type GhClient,
|
|
7
|
-
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
8
9
|
subtitlePendant,
|
|
9
10
|
toToolResult,
|
|
10
11
|
withStructuredResult,
|
|
@@ -12,30 +13,7 @@ import {
|
|
|
12
13
|
import { renderRepoView } from "../render.js";
|
|
13
14
|
import { ghRepoPayloadSchema, ghRepoViewSchema } from "../schemas.js";
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
const REPO_FIELDS = [
|
|
17
|
-
"name",
|
|
18
|
-
"nameWithOwner",
|
|
19
|
-
"description",
|
|
20
|
-
"url",
|
|
21
|
-
"homepageUrl",
|
|
22
|
-
"visibility",
|
|
23
|
-
"isPrivate",
|
|
24
|
-
"isFork",
|
|
25
|
-
"isArchived",
|
|
26
|
-
"stargazerCount",
|
|
27
|
-
"forkCount",
|
|
28
|
-
"primaryLanguage",
|
|
29
|
-
"defaultBranchRef",
|
|
30
|
-
"licenseInfo",
|
|
31
|
-
"issues",
|
|
32
|
-
"pullRequests",
|
|
33
|
-
"pushedAt",
|
|
34
|
-
"createdAt",
|
|
35
|
-
"updatedAt",
|
|
36
|
-
].join(",");
|
|
37
|
-
|
|
38
|
-
export function addReadRepoTool(_gh: GhClient, bus: ToolBus) {
|
|
16
|
+
export function addReadRepoTool(gh: GhClient, bus: ToolBus) {
|
|
39
17
|
bus.register(
|
|
40
18
|
defineStructuredTool({
|
|
41
19
|
name: "read-github-repo",
|
|
@@ -48,13 +26,10 @@ export function addReadRepoTool(_gh: GhClient, bus: ToolBus) {
|
|
|
48
26
|
structuredSchema: ghRepoPayloadSchema,
|
|
49
27
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
50
28
|
const { repo } = params;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
args.push("--json", REPO_FIELDS);
|
|
56
|
-
const stdout = await ghExec(args, { cwd: ctx.cwd, signal, input: params });
|
|
57
|
-
const view = parseWithSchema(ghRepoViewSchema, JSON.parse(stdout));
|
|
29
|
+
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
30
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
31
|
+
const data = await gh.reads.repository(owner, repoName, signal);
|
|
32
|
+
const view = parseWithSchema(ghRepoViewSchema, data);
|
|
58
33
|
const text = renderRepoView(view);
|
|
59
34
|
const result = toToolResult(text, params);
|
|
60
35
|
result.details.pendant = subtitlePendant(params);
|
|
@@ -4,7 +4,6 @@ import { Value } from "typebox/value";
|
|
|
4
4
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
5
|
import {
|
|
6
6
|
type GhClient,
|
|
7
|
-
ghExec,
|
|
8
7
|
resolveRepo,
|
|
9
8
|
splitRepo,
|
|
10
9
|
type StructuredResultOf,
|
|
@@ -20,7 +19,8 @@ interface PrChecksWaitParams {
|
|
|
20
19
|
fail_fast?: boolean;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
/** pulls.get 里我们只需要 head commit 的 SHA(它决定查哪个 commit 的 checks)。 */
|
|
23
|
+
const pullHeadSchema = Type.Object({ head: Type.Object({ sha: Type.String() }) });
|
|
24
24
|
|
|
25
25
|
/** The toolcall handler behind `wait-github-pr-checks`. */
|
|
26
26
|
async function waitPrChecks(
|
|
@@ -39,18 +39,17 @@ async function waitPrChecks(
|
|
|
39
39
|
const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
|
|
40
40
|
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
41
41
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const pull = Value.Parse(
|
|
43
|
+
pullHeadSchema,
|
|
44
|
+
await gh.reads.pull(owner, repoName, Number(number), signal),
|
|
45
45
|
);
|
|
46
|
-
const { headRefOid } = Value.Parse(prHeadSchema, JSON.parse(prOut));
|
|
47
46
|
|
|
48
47
|
return waitChecksReport({
|
|
49
48
|
checks: gh.checks,
|
|
50
49
|
subject: `PR #${number}`,
|
|
51
50
|
owner,
|
|
52
51
|
repo: repoName,
|
|
53
|
-
headSha:
|
|
52
|
+
headSha: pull.head.sha,
|
|
54
53
|
failFast: fail_fast === true,
|
|
55
54
|
signal,
|
|
56
55
|
onUpdate,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
import { runGh } from "../../lib/gh-process.js";
|
|
4
|
-
import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
5
3
|
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
type GhClient,
|
|
6
|
+
renderRunStatus,
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
9
|
+
subtitlePendant,
|
|
10
|
+
type ToolResult,
|
|
11
|
+
watchRun,
|
|
12
|
+
} from "../base.js";
|
|
13
|
+
import { ghRunPayloadSchema } from "../schemas.js";
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
const RUN_FIELDS =
|
|
11
|
-
"databaseId,displayTitle,status,conclusion,workflowName,headBranch,event,createdAt,updatedAt,startedAt,url";
|
|
12
|
-
|
|
13
|
-
export function addWatchRunTool(_gh: GhClient, bus: ToolBus) {
|
|
15
|
+
export function addWatchRunTool(gh: GhClient, bus: ToolBus) {
|
|
14
16
|
bus.register(
|
|
15
17
|
defineStructuredTool({
|
|
16
18
|
name: "watch-github-run",
|
|
@@ -28,33 +30,41 @@ export function addWatchRunTool(_gh: GhClient, bus: ToolBus) {
|
|
|
28
30
|
const { run_id, repo } = params;
|
|
29
31
|
|
|
30
32
|
const pendant = subtitlePendant(params, "run_id");
|
|
31
|
-
onUpdate?.(
|
|
33
|
+
const publish = (message: ToolResult) => onUpdate?.(message);
|
|
34
|
+
publish({
|
|
32
35
|
content: [{ type: "text", text: `Watching workflow run ${run_id}...` }],
|
|
33
36
|
details: {},
|
|
34
37
|
});
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
// 轮询循环要求非空 signal(与两个 wait 工具一致:没有就自建一个)
|
|
40
|
+
const pollSignal = signal ?? new AbortController().signal;
|
|
41
|
+
const effectiveRepo = await resolveRepo(repo, pollSignal, ctx.cwd, params);
|
|
42
|
+
const { owner, repo: repoName } = splitRepo(effectiveRepo);
|
|
43
|
+
const outcome = await watchRun({
|
|
44
|
+
owner,
|
|
45
|
+
repo: repoName,
|
|
46
|
+
runId: Number(run_id),
|
|
47
|
+
reads: gh.reads,
|
|
48
|
+
signal: pollSignal,
|
|
49
|
+
onUpdate: publish,
|
|
40
50
|
});
|
|
41
51
|
|
|
42
|
-
if (
|
|
43
|
-
throw new Error(
|
|
52
|
+
if (outcome.outcome === "timeout") {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`workflow run ${run_id} did not finish within ${Math.round(outcome.elapsedMs / 1000)}s; last status: ${renderRunStatus(outcome.run)}`,
|
|
55
|
+
);
|
|
44
56
|
}
|
|
45
57
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
52
|
-
const run = parseWithSchema(ghRunSummarySchema, JSON.parse(stdout));
|
|
58
|
+
const heading =
|
|
59
|
+
outcome.run.conclusion === "success"
|
|
60
|
+
? `## Workflow Run ${run_id} Completed`
|
|
61
|
+
: `## Workflow Run ${run_id} Finished (${outcome.run.conclusion ?? "unknown"})`;
|
|
62
|
+
const text = `${heading}\n\n${renderRunStatus(outcome.run)}`;
|
|
53
63
|
|
|
54
64
|
return {
|
|
55
65
|
content: [{ type: "text" as const, text }],
|
|
56
|
-
details: {
|
|
57
|
-
structuredResult: { ok: true as const, value: { text, run } },
|
|
66
|
+
details: { input: params, ...(pendant && { pendant }) },
|
|
67
|
+
structuredResult: { ok: true as const, value: { text, run: outcome.run } },
|
|
58
68
|
};
|
|
59
69
|
},
|
|
60
70
|
}),
|