@trim21/personal-pi-extensions 0.1.557 → 0.1.558

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.
@@ -0,0 +1,36 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+
4
+ import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
5
+
6
+ export function addReadPrTool(_gh: GhClient, pi: ExtensionAPI) {
7
+ pi.registerTool({
8
+ name: "read-github-pr",
9
+ label: "GitHub PR",
10
+ description: "Get details of a GitHub pull request by number.",
11
+ promptSnippet: "Read a GitHub PR",
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
+ }),
16
+ async execute(_id, params, signal, _onUpdate, ctx) {
17
+ const { number, repo } = params;
18
+ const result = toToolResult(
19
+ await ghExec(
20
+ [
21
+ "pr",
22
+ "view",
23
+ String(number),
24
+ ...repoArgs(repo),
25
+ "--json",
26
+ "title,state,body,author,createdAt,updatedAt,mergedAt,mergedBy,headRefName,baseRefName,url,additions,deletions,changedFiles,labels,assignees,reviewRequests,reviews,comments,number",
27
+ ],
28
+ { cwd: ctx.cwd, signal, input: params },
29
+ ),
30
+ params,
31
+ );
32
+ result.details.pendant = subtitlePendant(params, "number");
33
+ return result;
34
+ },
35
+ });
36
+ }
@@ -0,0 +1,30 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+
4
+ import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
5
+
6
+ export function addReadReleaseTool(_gh: GhClient, pi: ExtensionAPI) {
7
+ pi.registerTool({
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" })),
15
+ }),
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
+ });
30
+ }
@@ -0,0 +1,27 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+
4
+ import { type GhClient, ghExec, subtitlePendant, toToolResult } from "../base.js";
5
+
6
+ export function addReadRepoTool(_gh: GhClient, pi: ExtensionAPI) {
7
+ pi.registerTool({
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" })),
14
+ }),
15
+ async execute(_id, params, signal, _onUpdate, ctx) {
16
+ const { repo } = params;
17
+ const args = ["repo", "view"];
18
+ if (repo) args.push(repo);
19
+ const result = toToolResult(
20
+ await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
21
+ params,
22
+ );
23
+ result.details.pendant = subtitlePendant(params);
24
+ return result;
25
+ },
26
+ });
27
+ }
@@ -0,0 +1,88 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+
4
+ import {
5
+ type GhClient,
6
+ resolveRepo,
7
+ splitRepo,
8
+ subtitlePendant,
9
+ type ToolCall,
10
+ type ToolResult,
11
+ waitChecksReport,
12
+ } from "../base.js";
13
+
14
+ interface CommitChecksWaitParams {
15
+ commit: number | string;
16
+ repo?: string;
17
+ event?: string;
18
+ fail_fast?: boolean;
19
+ }
20
+
21
+ /** The toolcall handler behind `wait-github-commit-checks`. */
22
+ async function waitCommitChecks(
23
+ gh: GhClient,
24
+ call: ToolCall<CommitChecksWaitParams>,
25
+ ): Promise<ToolResult> {
26
+ const { params, ctx, signal, onUpdate } = call;
27
+ const { commit, repo, event, fail_fast } = params;
28
+
29
+ const pendant = subtitlePendant(params, "commit");
30
+ onUpdate?.({
31
+ content: [{ type: "text", text: `Watching CI checks for commit ${commit}...` }],
32
+ details: {},
33
+ });
34
+
35
+ const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
36
+ const { owner, repo: repoName } = splitRepo(effectiveRepo);
37
+
38
+ const pollSignal = signal ?? new AbortController().signal;
39
+ const sha = await gh.checks.headSha(owner, repoName, String(commit), pollSignal);
40
+
41
+ return waitChecksReport({
42
+ checks: gh.checks,
43
+ subject: `commit ${sha.slice(0, 7)}`,
44
+ owner,
45
+ repo: repoName,
46
+ headSha: sha,
47
+ failFast: fail_fast === true,
48
+ event,
49
+ signal,
50
+ onUpdate,
51
+ params,
52
+ pendant,
53
+ });
54
+ }
55
+
56
+ export function addWaitCommitChecksTool(gh: GhClient, pi: ExtensionAPI) {
57
+ pi.registerTool({
58
+ name: "wait-github-commit-checks",
59
+ label: "Watch GitHub Commit Checks",
60
+ description:
61
+ "Watch CI status checks for a commit until they complete — no pull request required. " +
62
+ "Same semantics as wait-github-pr-checks: returns when any check fails (immediately under fail_fast) " +
63
+ "or all checks pass/skip; on timeout the still-in-flight snapshot is returned. " +
64
+ "With `event`, only check runs triggered by that workflow event (e.g. push) are judged; " +
65
+ "commit statuses have an unknown trigger event and are excluded under a filter. " +
66
+ "Use this to wait for the runs a commit's push triggered, or for checks on an arbitrary ref.",
67
+ promptSnippet: "Watch and wait for GitHub commit CI checks to complete",
68
+ parameters: Type.Object({
69
+ commit: Type.Union([Type.Number(), Type.String()], {
70
+ description:
71
+ "Commit to wait for: full or partial SHA, branch name, or tag name (resolved to the commit's SHA)",
72
+ }),
73
+ repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
74
+ event: Type.Optional(
75
+ Type.String({
76
+ description:
77
+ "Only judge check runs triggered by this workflow event (e.g. push, pull_request)",
78
+ }),
79
+ ),
80
+ fail_fast: Type.Optional(
81
+ Type.Boolean({ description: "Exit immediately when any check fails (default: false)" }),
82
+ ),
83
+ }),
84
+ async execute(_id, params, signal, onUpdate, ctx) {
85
+ return waitCommitChecks(gh, { params, ctx, signal, onUpdate });
86
+ },
87
+ });
88
+ }
@@ -0,0 +1,80 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+ import { Value } from "typebox/value";
4
+
5
+ import {
6
+ type GhClient,
7
+ ghExec,
8
+ resolveRepo,
9
+ splitRepo,
10
+ subtitlePendant,
11
+ type ToolCall,
12
+ type ToolResult,
13
+ waitChecksReport,
14
+ } from "../base.js";
15
+
16
+ interface PrChecksWaitParams {
17
+ number: number | string;
18
+ repo?: string;
19
+ fail_fast?: boolean;
20
+ }
21
+
22
+ const prHeadSchema = Type.Object({ headRefOid: Type.String() });
23
+
24
+ /** The toolcall handler behind `wait-github-pr-checks`. */
25
+ async function waitPrChecks(gh: GhClient, call: ToolCall<PrChecksWaitParams>): Promise<ToolResult> {
26
+ const { params, ctx, signal, onUpdate } = call;
27
+ const { number, repo, fail_fast } = params;
28
+
29
+ const pendant = subtitlePendant(params, "number");
30
+ onUpdate?.({
31
+ content: [{ type: "text", text: `Watching CI checks for PR #${number}...` }],
32
+ details: {},
33
+ });
34
+
35
+ const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
36
+ const { owner, repo: repoName } = splitRepo(effectiveRepo);
37
+
38
+ const prOut = await ghExec(
39
+ ["pr", "view", String(number), "--repo", effectiveRepo, "--json", "headRefOid"],
40
+ { cwd: ctx.cwd, signal, input: params },
41
+ );
42
+ const { headRefOid } = Value.Parse(prHeadSchema, JSON.parse(prOut));
43
+
44
+ return waitChecksReport({
45
+ checks: gh.checks,
46
+ subject: `PR #${number}`,
47
+ owner,
48
+ repo: repoName,
49
+ headSha: headRefOid,
50
+ failFast: fail_fast === true,
51
+ signal,
52
+ onUpdate,
53
+ params,
54
+ pendant,
55
+ });
56
+ }
57
+
58
+ export function addWaitPrChecksTool(gh: GhClient, pi: ExtensionAPI) {
59
+ pi.registerTool({
60
+ name: "wait-github-pr-checks",
61
+ label: "Watch GitHub PR Checks",
62
+ description:
63
+ "Watch CI status checks for a PR until they complete. Blocks until all checks pass (or are skipped) or one fails. " +
64
+ "Covers both commit statuses (Azure DevOps, Jenkins, ...) and GitHub Actions check runs. " +
65
+ "Each polling round streams a compact bullet list of the checks still in flight via onUpdate; " +
66
+ "on timeout the still-in-flight snapshot is returned instead of a verdict. " +
67
+ "Use this when you need to wait for CI to complete and see the final result.",
68
+ promptSnippet: "Watch and wait for GitHub PR CI checks to complete",
69
+ parameters: Type.Object({
70
+ number: Type.Union([Type.Number(), Type.String()], { description: "PR number" }),
71
+ repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
72
+ fail_fast: Type.Optional(
73
+ Type.Boolean({ description: "Exit immediately when any check fails (default: false)" }),
74
+ ),
75
+ }),
76
+ async execute(_id, params, signal, onUpdate, ctx) {
77
+ return waitPrChecks(gh, { params, ctx, signal, onUpdate });
78
+ },
79
+ });
80
+ }
@@ -0,0 +1,45 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+
4
+ import { type GhClient, repoArgs, runGh, subtitlePendant } from "../base.js";
5
+
6
+ export function addWatchRunTool(_gh: GhClient, pi: ExtensionAPI) {
7
+ pi.registerTool({
8
+ name: "watch-github-run",
9
+ label: "Watch GitHub Workflow Run",
10
+ description:
11
+ "Watch a GitHub Actions workflow run until it completes. " +
12
+ "Blocks until the run finishes and shows the final status.",
13
+ promptSnippet: "Watch and wait for a GitHub Actions run to complete",
14
+ parameters: Type.Object({
15
+ run_id: Type.Union([Type.Number(), Type.String()], { description: "Workflow run ID" }),
16
+ repo: Type.Optional(Type.String({ description: "OWNER/REPO" })),
17
+ }),
18
+ async execute(_id, params, signal, onUpdate, ctx) {
19
+ const { run_id, repo } = params;
20
+
21
+ const pendant = subtitlePendant(params, "run_id");
22
+ onUpdate?.({
23
+ content: [{ type: "text", text: `Watching workflow run ${run_id}...` }],
24
+ details: {},
25
+ });
26
+
27
+ const result = await runGh(["run", "watch", String(run_id), ...repoArgs(repo)], {
28
+ cwd: ctx.cwd,
29
+ signal,
30
+ timeout: 600_000,
31
+ });
32
+
33
+ if (result.code !== 0) {
34
+ throw new Error(`gh run watch failed: ${result.stderr || `exit code ${result.code}`}`);
35
+ }
36
+
37
+ return {
38
+ content: [
39
+ { type: "text", text: `## Workflow Run ${run_id} Completed\n\n${result.stdout}` },
40
+ ],
41
+ details: { exitCode: 0, input: params, ...(pendant && { pendant }) },
42
+ };
43
+ },
44
+ });
45
+ }