@trim21/personal-pi-extensions 0.1.684 → 0.1.687
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 +10 -8
- package/package.json +1 -1
- package/src/codemode/declarations.ts +3 -3
- package/src/codemode/tool.ts +13 -26
- package/src/gh/base.ts +125 -60
- package/src/gh/render.ts +259 -0
- package/src/gh/schemas.ts +233 -47
- package/src/gh/tools/download-release-assets.ts +58 -80
- package/src/gh/tools/list-issues.ts +66 -47
- package/src/gh/tools/list-prs.ts +66 -47
- package/src/gh/tools/list-releases.ts +43 -25
- package/src/gh/tools/list-workflow-runs.ts +41 -35
- 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 +34 -22
- package/src/gh/tools/read-pr.ts +7 -15
- package/src/gh/tools/read-release.ts +37 -25
- package/src/gh/tools/read-repo.ts +35 -24
- package/src/gh/tools/wait-pr-checks.ts +6 -7
- package/src/gh/tools/watch-run.ts +64 -38
- package/src/lib/github-reads.ts +405 -0
- package/src/lib/github.ts +95 -3
- package/src/lib/lsp/inspect-schemas.ts +44 -0
- package/src/lib/lsp/inspect-tool.ts +188 -137
|
@@ -1,27 +1,39 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
import type
|
|
4
|
-
import {
|
|
3
|
+
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
4
|
+
import {
|
|
5
|
+
type GhClient,
|
|
6
|
+
resolveRepo,
|
|
7
|
+
splitRepo,
|
|
8
|
+
subtitlePendant,
|
|
9
|
+
toToolResult,
|
|
10
|
+
withStructuredResult,
|
|
11
|
+
} from "../base.js";
|
|
12
|
+
import { parseDiffStats } from "../render.js";
|
|
13
|
+
import { ghDiffPayloadSchema } from "../schemas.js";
|
|
5
14
|
|
|
6
|
-
export function addReadPrDiffTool(
|
|
7
|
-
bus.register(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
export function addReadPrDiffTool(gh: GhClient, bus: ToolBus) {
|
|
16
|
+
bus.register(
|
|
17
|
+
defineStructuredTool({
|
|
18
|
+
name: "read-github-pr-diff",
|
|
19
|
+
label: "GitHub PR Diff",
|
|
20
|
+
description: "Get the diff of a GitHub pull request.",
|
|
21
|
+
promptSnippet: "Read a GitHub PR diff",
|
|
22
|
+
parameters: Type.Object({
|
|
23
|
+
number: Type.Union([Type.Number(), Type.String()], { description: "PR number" }),
|
|
24
|
+
repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
|
|
25
|
+
}),
|
|
26
|
+
structuredSchema: ghDiffPayloadSchema,
|
|
27
|
+
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
28
|
+
const { number, repo } = params;
|
|
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);
|
|
33
|
+
result.details.pendant = subtitlePendant(params, "number");
|
|
34
|
+
// 文本是原始 diff(没有 JSON 形式),载荷从同一份 diff 解析出变更统计
|
|
35
|
+
return withStructuredResult(result, { text: diff, ...parseDiffStats(diff) });
|
|
36
|
+
},
|
|
15
37
|
}),
|
|
16
|
-
|
|
17
|
-
const { number, repo } = params;
|
|
18
|
-
const args = ["pr", "diff", String(number), ...repoArgs(repo)];
|
|
19
|
-
const result = toToolResult(
|
|
20
|
-
await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
|
|
21
|
-
params,
|
|
22
|
-
);
|
|
23
|
-
result.details.pendant = subtitlePendant(params, "number");
|
|
24
|
-
return result;
|
|
25
|
-
},
|
|
26
|
-
});
|
|
38
|
+
);
|
|
27
39
|
}
|
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
|
},
|
|
@@ -1,30 +1,42 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
4
|
+
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
|
+
import {
|
|
6
|
+
type GhClient,
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
9
|
+
subtitlePendant,
|
|
10
|
+
toToolResult,
|
|
11
|
+
withStructuredResult,
|
|
12
|
+
} from "../base.js";
|
|
13
|
+
import { renderReleaseView } from "../render.js";
|
|
14
|
+
import { ghReleaseViewPayloadSchema, ghReleaseViewSchema } from "../schemas.js";
|
|
5
15
|
|
|
6
|
-
export function addReadReleaseTool(
|
|
7
|
-
bus.register(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
export function addReadReleaseTool(gh: GhClient, bus: ToolBus) {
|
|
17
|
+
bus.register(
|
|
18
|
+
defineStructuredTool({
|
|
19
|
+
name: "read-github-release",
|
|
20
|
+
label: "GitHub Release",
|
|
21
|
+
description:
|
|
22
|
+
"Get details of a specific GitHub release by tag: metadata, asset list and release notes.",
|
|
23
|
+
promptSnippet: "Read a GitHub release",
|
|
24
|
+
parameters: Type.Object({
|
|
25
|
+
tag: Type.String({ description: "Release tag name" }),
|
|
26
|
+
repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
|
|
27
|
+
}),
|
|
28
|
+
structuredSchema: ghReleaseViewPayloadSchema,
|
|
29
|
+
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
30
|
+
const { tag, repo } = params;
|
|
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);
|
|
35
|
+
const text = renderReleaseView(view);
|
|
36
|
+
const result = toToolResult(text, params);
|
|
37
|
+
result.details.pendant = subtitlePendant(params, "tag");
|
|
38
|
+
return withStructuredResult(result, { text, release: view });
|
|
39
|
+
},
|
|
15
40
|
}),
|
|
16
|
-
|
|
17
|
-
const { tag, repo } = params;
|
|
18
|
-
const result = toToolResult(
|
|
19
|
-
await ghExec(["release", "view", tag, ...repoArgs(repo)], {
|
|
20
|
-
cwd: ctx.cwd,
|
|
21
|
-
signal,
|
|
22
|
-
input: params,
|
|
23
|
-
}),
|
|
24
|
-
params,
|
|
25
|
-
);
|
|
26
|
-
result.details.pendant = subtitlePendant(params, "tag");
|
|
27
|
-
return result;
|
|
28
|
-
},
|
|
29
|
-
});
|
|
41
|
+
);
|
|
30
42
|
}
|
|
@@ -1,29 +1,40 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { parseWithSchema } from "../../lib/parse-with-schema.js";
|
|
4
|
+
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
5
|
+
import {
|
|
6
|
+
type GhClient,
|
|
7
|
+
resolveRepo,
|
|
8
|
+
splitRepo,
|
|
9
|
+
subtitlePendant,
|
|
10
|
+
toToolResult,
|
|
11
|
+
withStructuredResult,
|
|
12
|
+
} from "../base.js";
|
|
13
|
+
import { renderRepoView } from "../render.js";
|
|
14
|
+
import { ghRepoPayloadSchema, ghRepoViewSchema } from "../schemas.js";
|
|
5
15
|
|
|
6
|
-
export function addReadRepoTool(
|
|
7
|
-
bus.register(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
export function addReadRepoTool(gh: GhClient, bus: ToolBus) {
|
|
17
|
+
bus.register(
|
|
18
|
+
defineStructuredTool({
|
|
19
|
+
name: "read-github-repo",
|
|
20
|
+
label: "GitHub Repo",
|
|
21
|
+
description: "Get repository information.",
|
|
22
|
+
promptSnippet: "Read GitHub repo info",
|
|
23
|
+
parameters: Type.Object({
|
|
24
|
+
repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
|
|
25
|
+
}),
|
|
26
|
+
structuredSchema: ghRepoPayloadSchema,
|
|
27
|
+
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
28
|
+
const { repo } = params;
|
|
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);
|
|
33
|
+
const text = renderRepoView(view);
|
|
34
|
+
const result = toToolResult(text, params);
|
|
35
|
+
result.details.pendant = subtitlePendant(params);
|
|
36
|
+
return withStructuredResult(result, { text, repo: view });
|
|
37
|
+
},
|
|
14
38
|
}),
|
|
15
|
-
|
|
16
|
-
const { repo } = params;
|
|
17
|
-
const args = ["repo", "view"];
|
|
18
|
-
if (repo) {
|
|
19
|
-
args.push(repo);
|
|
20
|
-
}
|
|
21
|
-
const result = toToolResult(
|
|
22
|
-
await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
|
|
23
|
-
params,
|
|
24
|
-
);
|
|
25
|
-
result.details.pendant = subtitlePendant(params);
|
|
26
|
-
return result;
|
|
27
|
-
},
|
|
28
|
-
});
|
|
39
|
+
);
|
|
29
40
|
}
|
|
@@ -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,46 +1,72 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
3
|
+
import { defineStructuredTool, type ToolBus } from "../../lib/tool-bus.js";
|
|
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";
|
|
6
14
|
|
|
7
|
-
export function addWatchRunTool(
|
|
8
|
-
bus.register(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
export function addWatchRunTool(gh: GhClient, bus: ToolBus) {
|
|
16
|
+
bus.register(
|
|
17
|
+
defineStructuredTool({
|
|
18
|
+
name: "watch-github-run",
|
|
19
|
+
label: "Watch GitHub Workflow Run",
|
|
20
|
+
description:
|
|
21
|
+
"Watch a GitHub Actions workflow run until it completes. " +
|
|
22
|
+
"Blocks until the run finishes and shows the final status.",
|
|
23
|
+
promptSnippet: "Watch and wait for a GitHub Actions run to complete",
|
|
24
|
+
parameters: Type.Object({
|
|
25
|
+
run_id: Type.Union([Type.Number(), Type.String()], { description: "Workflow run ID" }),
|
|
26
|
+
repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
|
|
27
|
+
}),
|
|
28
|
+
structuredSchema: ghRunPayloadSchema,
|
|
29
|
+
async execute(_id, params, signal, onUpdate, ctx) {
|
|
30
|
+
const { run_id, repo } = params;
|
|
31
|
+
|
|
32
|
+
const pendant = subtitlePendant(params, "run_id");
|
|
33
|
+
const publish = (message: ToolResult) => onUpdate?.(message);
|
|
34
|
+
publish({
|
|
35
|
+
content: [{ type: "text", text: `Watching workflow run ${run_id}...` }],
|
|
36
|
+
details: {},
|
|
37
|
+
});
|
|
21
38
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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,
|
|
50
|
+
});
|
|
27
51
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
);
|
|
56
|
+
}
|
|
33
57
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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)}`;
|
|
37
63
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text" as const, text }],
|
|
66
|
+
details: { input: params, ...(pendant && { pendant }) },
|
|
67
|
+
structuredResult: { ok: true as const, value: { text, run: outcome.run } },
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
46
72
|
}
|