@blogic-cz/agent-tools 0.14.47 → 0.14.49
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/package.json +1 -1
- package/src/gh-tool/index.ts +16 -11
- package/src/gh-tool/pr/commands.ts +44 -0
- package/src/gh-tool/pr/index.ts +1 -0
- package/src/gh-tool/pr/review.ts +59 -0
- package/src/gh-tool/types.ts +9 -0
- package/src/gh-tool/workflow.ts +60 -1
package/package.json
CHANGED
package/src/gh-tool/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
prDiscussionSummaryCommand,
|
|
34
34
|
prReplyCommand,
|
|
35
35
|
prResolveCommand,
|
|
36
|
+
prReviewsCommand,
|
|
36
37
|
prSubmitReviewCommand,
|
|
37
38
|
prChecksCommand,
|
|
38
39
|
prChecksFailedCommand,
|
|
@@ -61,6 +62,7 @@ import {
|
|
|
61
62
|
workflowListCommand,
|
|
62
63
|
workflowLogsCommand,
|
|
63
64
|
workflowRerunCommand,
|
|
65
|
+
workflowRunCommand,
|
|
64
66
|
workflowViewCommand,
|
|
65
67
|
workflowWatchCommand,
|
|
66
68
|
} from "./workflow";
|
|
@@ -78,6 +80,7 @@ const prCommand = Command.make("pr", {}).pipe(
|
|
|
78
80
|
prWaitMergeableCommand,
|
|
79
81
|
prThreadsCommand,
|
|
80
82
|
prCommentsCommand,
|
|
83
|
+
prReviewsCommand,
|
|
81
84
|
prIssueCommentsCommand,
|
|
82
85
|
prIssueCommentsLatestCommand,
|
|
83
86
|
prCommentCommand,
|
|
@@ -123,9 +126,10 @@ const repoCommand = Command.make("repo", {}).pipe(
|
|
|
123
126
|
|
|
124
127
|
const workflowCommand = Command.make("workflow", {}).pipe(
|
|
125
128
|
Command.withDescription(
|
|
126
|
-
"GitHub Actions workflow operations (list
|
|
129
|
+
"GitHub Actions workflow operations (run, list, view, jobs, logs, job-logs, annotations, rerun, cancel, watch)",
|
|
127
130
|
),
|
|
128
131
|
Command.withSubcommands([
|
|
132
|
+
workflowRunCommand,
|
|
129
133
|
workflowListCommand,
|
|
130
134
|
workflowViewCommand,
|
|
131
135
|
workflowJobsCommand,
|
|
@@ -172,16 +176,17 @@ WORKFLOW FOR AI AGENTS:
|
|
|
172
176
|
10. Use 'issue close --issue N --comment "reason"' to close issues
|
|
173
177
|
11. Use 'issue comment --issue N --body "text"' to comment on issues
|
|
174
178
|
12. Use 'repo info' to get repository metadata
|
|
175
|
-
13. Use 'workflow
|
|
176
|
-
14. Use 'workflow
|
|
177
|
-
15. Use 'workflow
|
|
178
|
-
16. Use 'workflow
|
|
179
|
-
17. Use 'workflow
|
|
180
|
-
18. Use 'workflow
|
|
181
|
-
19. Use '
|
|
182
|
-
20. Use 'release
|
|
183
|
-
21. Use 'release
|
|
184
|
-
22. Use '
|
|
179
|
+
13. Use 'workflow run' to dispatch workflow_dispatch workflows
|
|
180
|
+
14. Use 'workflow list' to list recent workflow runs
|
|
181
|
+
15. Use 'workflow view --run N' to inspect a specific run with jobs/steps
|
|
182
|
+
16. Use 'workflow logs --run N' to get logs (failed jobs by default)
|
|
183
|
+
17. Use 'workflow job-logs --run N --job "build-web-app"' to get clean parsed logs for a specific job
|
|
184
|
+
18. Use 'workflow annotations --run N' to list CI annotations (errors, warnings, notices)
|
|
185
|
+
19. Use 'workflow watch --run N' to watch until completion
|
|
186
|
+
20. Use 'release status' to inspect latest release + repository context
|
|
187
|
+
21. Use 'release create --tag vX.Y.Z --generate-notes' to publish a release
|
|
188
|
+
22. Use 'release edit/view/list/delete' to maintain existing releases
|
|
189
|
+
23. Use 'branch rename --old-name X --new-name Y --confirm' to rename a branch`,
|
|
185
190
|
),
|
|
186
191
|
Command.withSubcommands([
|
|
187
192
|
prCommand,
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
fetchDiscussionSummary,
|
|
47
47
|
fetchIssueComments,
|
|
48
48
|
fetchLatestIssueComment,
|
|
49
|
+
fetchReviews,
|
|
49
50
|
fetchThreads,
|
|
50
51
|
postIssueComment,
|
|
51
52
|
replyToComment,
|
|
@@ -606,6 +607,49 @@ export const prCommentsCommand = Command.make(
|
|
|
606
607
|
),
|
|
607
608
|
).pipe(Command.withDescription("Fetch review comments for a PR (optionally filter by --since)"));
|
|
608
609
|
|
|
610
|
+
export const prReviewsCommand = Command.make(
|
|
611
|
+
"reviews",
|
|
612
|
+
{
|
|
613
|
+
author: Flag.string("author").pipe(
|
|
614
|
+
Flag.withDescription("Filter by author login substring"),
|
|
615
|
+
Flag.optional,
|
|
616
|
+
),
|
|
617
|
+
bodyContains: Flag.string("body-contains").pipe(
|
|
618
|
+
Flag.withDescription("Filter reviews by body substring"),
|
|
619
|
+
Flag.optional,
|
|
620
|
+
),
|
|
621
|
+
format: formatOption,
|
|
622
|
+
pr: Flag.integer("pr").pipe(
|
|
623
|
+
Flag.withDescription("PR number (default: current branch PR)"),
|
|
624
|
+
Flag.optional,
|
|
625
|
+
),
|
|
626
|
+
repo: repoOption,
|
|
627
|
+
state: Flag.string("state").pipe(
|
|
628
|
+
Flag.withDescription(
|
|
629
|
+
"Filter by review state (APPROVED, CHANGES_REQUESTED, COMMENTED, DISMISSED)",
|
|
630
|
+
),
|
|
631
|
+
Flag.optional,
|
|
632
|
+
),
|
|
633
|
+
},
|
|
634
|
+
({ author, bodyContains, format, pr, repo, state }) =>
|
|
635
|
+
withRepo(
|
|
636
|
+
repo,
|
|
637
|
+
Effect.gen(function* () {
|
|
638
|
+
const reviews = yield* fetchReviews(
|
|
639
|
+
Option.getOrNull(pr),
|
|
640
|
+
Option.getOrNull(author),
|
|
641
|
+
Option.getOrNull(bodyContains),
|
|
642
|
+
Option.getOrNull(state),
|
|
643
|
+
);
|
|
644
|
+
yield* logFormatted(reviews, format);
|
|
645
|
+
}),
|
|
646
|
+
),
|
|
647
|
+
).pipe(
|
|
648
|
+
Command.withDescription(
|
|
649
|
+
"Fetch submitted review summaries (state + body) for a PR — the review bodies that comments/issue-comments do not expose",
|
|
650
|
+
),
|
|
651
|
+
);
|
|
652
|
+
|
|
609
653
|
export const prIssueCommentsCommand = Command.make(
|
|
610
654
|
"issue-comments",
|
|
611
655
|
{
|
package/src/gh-tool/pr/index.ts
CHANGED
package/src/gh-tool/pr/review.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
IssueComment,
|
|
6
6
|
IssueCommentId,
|
|
7
7
|
IsoTimestamp,
|
|
8
|
+
PullRequestReview,
|
|
8
9
|
ReviewComment,
|
|
9
10
|
ReviewThread,
|
|
10
11
|
} from "#gh/types";
|
|
@@ -158,6 +159,15 @@ type RawIssueComment = {
|
|
|
158
159
|
html_url: string;
|
|
159
160
|
};
|
|
160
161
|
|
|
162
|
+
type RawPullRequestReview = {
|
|
163
|
+
id: number;
|
|
164
|
+
user: { login: string } | null;
|
|
165
|
+
state: string;
|
|
166
|
+
body: string | null;
|
|
167
|
+
submitted_at: string | null;
|
|
168
|
+
html_url: string;
|
|
169
|
+
};
|
|
170
|
+
|
|
161
171
|
type ReviewCommentById = {
|
|
162
172
|
id: number;
|
|
163
173
|
in_reply_to_id: number | null;
|
|
@@ -405,6 +415,55 @@ export const fetchIssueComments = Effect.fn("pr.fetchIssueComments")(function* (
|
|
|
405
415
|
return comments;
|
|
406
416
|
});
|
|
407
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Fetch submitted review summaries (state + top-level body) for a PR via REST API.
|
|
420
|
+
* Complements `comments` (inline review comments) and `issue-comments` (discussion),
|
|
421
|
+
* which never expose the submitted review body. Optional author/state/body filters.
|
|
422
|
+
*/
|
|
423
|
+
export const fetchReviews = Effect.fn("pr.fetchReviews")(function* (
|
|
424
|
+
pr: number | null,
|
|
425
|
+
author: string | null,
|
|
426
|
+
bodyContains: string | null,
|
|
427
|
+
state: string | null,
|
|
428
|
+
) {
|
|
429
|
+
const service = yield* GitHubService;
|
|
430
|
+
const repoInfo = yield* service.getRepoInfo();
|
|
431
|
+
|
|
432
|
+
const resolvedPr = pr ?? (yield* viewPR(null)).number;
|
|
433
|
+
|
|
434
|
+
const raw = yield* fetchAllRestPages<RawPullRequestReview>(
|
|
435
|
+
`repos/${repoInfo.owner}/${repoInfo.name}/pulls/${resolvedPr}/reviews`,
|
|
436
|
+
"gh-tool pr reviews",
|
|
437
|
+
"Failed to parse response",
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
let reviews: PullRequestReview[] = raw.map((review) => ({
|
|
441
|
+
id: review.id,
|
|
442
|
+
author: review.user?.login ?? "unknown",
|
|
443
|
+
state: review.state,
|
|
444
|
+
body: review.body ?? "",
|
|
445
|
+
submittedAt: (review.submitted_at ?? null) as IsoTimestamp | null,
|
|
446
|
+
url: review.html_url,
|
|
447
|
+
}));
|
|
448
|
+
|
|
449
|
+
if (author !== null) {
|
|
450
|
+
const authorFilter = author.toLowerCase();
|
|
451
|
+
reviews = reviews.filter((review) => review.author.toLowerCase().includes(authorFilter));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (state !== null) {
|
|
455
|
+
const stateFilter = state.toLowerCase();
|
|
456
|
+
reviews = reviews.filter((review) => review.state.toLowerCase() === stateFilter);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (bodyContains !== null) {
|
|
460
|
+
const bodyFilter = bodyContains.toLowerCase();
|
|
461
|
+
reviews = reviews.filter((review) => review.body.toLowerCase().includes(bodyFilter));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return reviews;
|
|
465
|
+
});
|
|
466
|
+
|
|
408
467
|
export const fetchLatestIssueComment = Effect.fn("pr.fetchLatestIssueComment")(function* (
|
|
409
468
|
pr: number | null,
|
|
410
469
|
author: string | null,
|
package/src/gh-tool/types.ts
CHANGED
|
@@ -66,6 +66,15 @@ export type IssueComment = {
|
|
|
66
66
|
url: GitHubIssueCommentUrl;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
export type PullRequestReview = {
|
|
70
|
+
id: number;
|
|
71
|
+
author: string;
|
|
72
|
+
state: string;
|
|
73
|
+
body: string;
|
|
74
|
+
submittedAt: IsoTimestamp | null;
|
|
75
|
+
url: string;
|
|
76
|
+
};
|
|
77
|
+
|
|
69
78
|
export type CheckResult = {
|
|
70
79
|
name: string;
|
|
71
80
|
state: string;
|
package/src/gh-tool/workflow.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
1
|
+
import { Command, Flag, Param } from "effect/unstable/cli";
|
|
2
2
|
import { Console, Effect, Option } from "effect";
|
|
3
3
|
|
|
4
4
|
import { formatOption, logFormatted } from "#shared";
|
|
@@ -213,6 +213,34 @@ const cancelRun = Effect.fn("workflow.cancelRun")(function* (runId: number, repo
|
|
|
213
213
|
};
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
+
export const dispatchWorkflow = Effect.fn("workflow.dispatchWorkflow")(function* (opts: {
|
|
217
|
+
workflow: string;
|
|
218
|
+
ref: string;
|
|
219
|
+
fields: ReadonlyArray<string>;
|
|
220
|
+
repo: string | null;
|
|
221
|
+
}) {
|
|
222
|
+
const gh = yield* GitHubService;
|
|
223
|
+
const args = ["workflow", "run", opts.workflow, "--ref", opts.ref];
|
|
224
|
+
|
|
225
|
+
if (opts.repo !== null) {
|
|
226
|
+
args.push("--repo", opts.repo);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const field of opts.fields) {
|
|
230
|
+
args.push("-f", field);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
yield* gh.runGh(args);
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
dispatched: true as const,
|
|
237
|
+
workflow: opts.workflow,
|
|
238
|
+
ref: opts.ref,
|
|
239
|
+
repo: opts.repo,
|
|
240
|
+
fields: opts.fields,
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
|
|
216
244
|
// `gh run watch` has no native timeout (observed hanging 36 min). Block for the caller's --timeout,
|
|
217
245
|
// then fall back to a one-shot snapshot so a timeout never returns nothing.
|
|
218
246
|
const DEFAULT_WATCH_RUN_TIMEOUT_SECONDS = CI_CHECK_WATCH_TIMEOUT_MS / 1000;
|
|
@@ -649,6 +677,37 @@ export const workflowCancelCommand = Command.make(
|
|
|
649
677
|
}),
|
|
650
678
|
).pipe(Command.withDescription("Cancel an in-progress workflow run"));
|
|
651
679
|
|
|
680
|
+
export const workflowRunCommand = Command.make(
|
|
681
|
+
"run",
|
|
682
|
+
{
|
|
683
|
+
field: Param.variadic(
|
|
684
|
+
Param.string(Param.flagKind, "field").pipe(
|
|
685
|
+
Param.withAlias("f"),
|
|
686
|
+
Param.withDescription("Workflow input as key=value; may be repeated"),
|
|
687
|
+
),
|
|
688
|
+
),
|
|
689
|
+
format: formatOption,
|
|
690
|
+
ref: Flag.string("ref").pipe(
|
|
691
|
+
Flag.withDescription("Git ref to run the workflow on (branch, tag, or SHA)"),
|
|
692
|
+
),
|
|
693
|
+
repo: repoOption,
|
|
694
|
+
workflow: Flag.string("workflow").pipe(
|
|
695
|
+
Flag.withDescription("Workflow file name (e.g., build.yml) or workflow ID"),
|
|
696
|
+
),
|
|
697
|
+
},
|
|
698
|
+
({ field, format, ref, repo, workflow }) =>
|
|
699
|
+
Effect.gen(function* () {
|
|
700
|
+
const resolvedRepo = yield* resolveRepoArg(repo);
|
|
701
|
+
const result = yield* dispatchWorkflow({
|
|
702
|
+
workflow,
|
|
703
|
+
ref,
|
|
704
|
+
fields: field,
|
|
705
|
+
repo: resolvedRepo,
|
|
706
|
+
});
|
|
707
|
+
yield* logFormatted(result, format);
|
|
708
|
+
}),
|
|
709
|
+
).pipe(Command.withDescription("Dispatch a workflow_dispatch workflow run"));
|
|
710
|
+
|
|
652
711
|
export const workflowWatchCommand = Command.make(
|
|
653
712
|
"watch",
|
|
654
713
|
{
|