@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.
@@ -1,27 +1,39 @@
1
1
  import { Type } from "typebox";
2
2
 
3
- import type { ToolBus } from "../../lib/tool-bus.js";
4
- import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
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(_gh: GhClient, bus: ToolBus) {
7
- bus.register({
8
- name: "read-github-pr-diff",
9
- label: "GitHub PR Diff",
10
- description: "Get the diff of a GitHub pull request.",
11
- promptSnippet: "Read a GitHub PR diff",
12
- parameters: Type.Object({
13
- number: Type.Union([Type.Number(), Type.String()], { description: "PR number" }),
14
- repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
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
- async execute(_id, params, signal, _onUpdate, ctx) {
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
  }
@@ -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
- ghExec,
7
- repoArgs,
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(_gh: GhClient, bus: ToolBus) {
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 out = await ghExec(
28
- [
29
- "pr",
30
- "view",
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 type { ToolBus } from "../../lib/tool-bus.js";
4
- import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
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(_gh: GhClient, bus: ToolBus) {
7
- bus.register({
8
- name: "read-github-release",
9
- label: "GitHub Release",
10
- description: "Get details of a specific GitHub release by tag.",
11
- promptSnippet: "Read a GitHub release",
12
- parameters: Type.Object({
13
- tag: Type.String({ description: "Release tag name" }),
14
- repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
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
- async execute(_id, params, signal, _onUpdate, ctx) {
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 type { ToolBus } from "../../lib/tool-bus.js";
4
- import { type GhClient, ghExec, subtitlePendant, toToolResult } from "../base.js";
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(_gh: GhClient, bus: ToolBus) {
7
- bus.register({
8
- name: "read-github-repo",
9
- label: "GitHub Repo",
10
- description: "Get repository information.",
11
- promptSnippet: "Read GitHub repo info",
12
- parameters: Type.Object({
13
- repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
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
- async execute(_id, params, signal, _onUpdate, ctx) {
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
- const prHeadSchema = Type.Object({ headRefOid: Type.String() });
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 prOut = await ghExec(
43
- ["pr", "view", String(number), "--repo", effectiveRepo, "--json", "headRefOid"],
44
- { cwd: ctx.cwd, signal, input: params },
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: headRefOid,
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 { runGh } from "../../lib/gh-process.js";
4
- import type { ToolBus } from "../../lib/tool-bus.js";
5
- import { type GhClient, repoArgs, subtitlePendant } from "../base.js";
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(_gh: GhClient, bus: ToolBus) {
8
- bus.register({
9
- name: "watch-github-run",
10
- label: "Watch GitHub Workflow Run",
11
- description:
12
- "Watch a GitHub Actions workflow run until it completes. " +
13
- "Blocks until the run finishes and shows the final status.",
14
- promptSnippet: "Watch and wait for a GitHub Actions run to complete",
15
- parameters: Type.Object({
16
- run_id: Type.Union([Type.Number(), Type.String()], { description: "Workflow run ID" }),
17
- repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
18
- }),
19
- async execute(_id, params, signal, onUpdate, ctx) {
20
- const { run_id, repo } = params;
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
- const pendant = subtitlePendant(params, "run_id");
23
- onUpdate?.({
24
- content: [{ type: "text", text: `Watching workflow run ${run_id}...` }],
25
- details: {},
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
- const result = await runGh(["run", "watch", String(run_id), ...repoArgs(repo)], {
29
- cwd: ctx.cwd,
30
- signal,
31
- timeout: 600_000,
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
- if (result.code !== 0) {
35
- throw new Error(`gh run watch failed: ${result.stderr || `exit code ${result.code}`}`);
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
- return {
39
- content: [
40
- { type: "text", text: `## Workflow Run ${run_id} Completed\n\n${result.stdout}` },
41
- ],
42
- details: { exitCode: 0, input: params, ...(pendant && { pendant }) },
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
  }