@blogic-cz/agent-tools 0.14.58 → 0.14.60
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 +19 -0
- package/package.json +1 -1
- package/src/gh-tool/index.ts +2 -0
- package/src/gh-tool/issue/core.ts +2 -0
- package/src/gh-tool/pr/commands.ts +199 -39
- package/src/gh-tool/pr/core.ts +557 -89
- package/src/gh-tool/pr/index.ts +1 -0
- package/src/gh-tool/pr/review.ts +178 -11
- package/src/gh-tool/types.ts +91 -0
- package/src/gh-tool/workflow.ts +68 -9
package/README.md
CHANGED
|
@@ -225,6 +225,7 @@ bun audit-tool list --limit 20
|
|
|
225
225
|
|
|
226
226
|
```bash
|
|
227
227
|
bun gh-tool pr review-triage # interactive summary of PR feedback
|
|
228
|
+
bun gh-tool pr watch --prs 12,34 --format jsonl # transition-only multi-PR CI stream
|
|
228
229
|
bun k8s-tool pods --env test # list pods (structured command)
|
|
229
230
|
```
|
|
230
231
|
|
|
@@ -251,6 +252,24 @@ export default { handleToolExecuteBefore };
|
|
|
251
252
|
|
|
252
253
|
All tools support `--help` for full usage documentation. Legacy `agent-tools-*` binary names (e.g. `agent-tools-gh`) still work for backwards compatibility.
|
|
253
254
|
|
|
255
|
+
### gh-tool machine contracts
|
|
256
|
+
|
|
257
|
+
`pr view` adds `headSha` and `baseSha`; failed-check evidence adds the same SHA pair. Review summaries, inline comments, and threads add `commitSha` plus `feedbackOrigin`: `current_head` only for an exact `commitSha === headSha`, `pre_existing` for a different known SHA (not an obsolescence verdict), and `unknown` when either SHA is absent. Issue comments always use `commitSha: null` and `feedbackOrigin: unknown`. `review-triage` preserves existing fields and adds `inlineComments` plus per-kind `feedbackOriginCounts`; batch triage returns the same object per PR.
|
|
258
|
+
|
|
259
|
+
`pr watch --prs 12,34 --until terminal --format jsonl` accepts at most 50 unique, digits-only PR numbers and emits only JSONL state transitions. Identity uses `repo/pr/headSha/runId/attempt/jobId`; `checkId` is nullable and reserved for actual check-run IDs. State/bucket revisions emit even when identity stays stable; `supersedes` appears only when identity changes. Open PRs with no checks become terminal only after three stable empty snapshots, allowing bounded GitHub eventual consistency. `pr checks`, batch checks, triage, and batch triage keep stderr silent with `--format json`; JSONL watch is also informationally silent. Failures still return structured nonzero errors on stderr.
|
|
260
|
+
|
|
261
|
+
Useful flows:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
bun gh-tool pr checks-failed --pr 123 --with-logs --format json # includes diagnosis
|
|
265
|
+
bun gh-tool pr rerun-checks --pr 123 --failed-only --watch --timeout 600
|
|
266
|
+
bun gh-tool pr watch --prs 123,124 --format jsonl --timeout 600
|
|
267
|
+
bun gh-tool pr reply-and-resolve --comment-id 456 --body "Done" # infers PR and thread
|
|
268
|
+
# Optional --pr/--thread-id retain legacy flow and are validated before either mutation.
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Reruns preflight every target before mutation and fail closed with `evidence_unavailable` when attempt jobs or logs cannot be read. Failed jobs use one `gh run rerun RUN --failed` mutation per workflow run. Without `--watch`, output returns current attempt metadata immediately; with `--watch`, discovery and watching share one absolute `--timeout` deadline and report `discovery_timeout` or `watch_timeout` with latest attempt state. Repeated matching pre-test infrastructure failures return `escalation_required` without mutation. See [`skills/gh-tool/SKILL.md`](skills/gh-tool/SKILL.md) for operating guidance; this section is canonical for added output fields.
|
|
272
|
+
|
|
254
273
|
`audit-tool` reads the same SQLite file the wrappers write to. By default that file lives at `~/.agent-tools/audit.sqlite`, and you can override both path and retention per repo with the global `audit` config section.
|
|
255
274
|
|
|
256
275
|
## Audit Logging
|
package/package.json
CHANGED
package/src/gh-tool/index.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
prReviewTriageBatchCommand,
|
|
45
45
|
prReviewTriageCommand,
|
|
46
46
|
prWaitMergeableCommand,
|
|
47
|
+
prWatchCommand,
|
|
47
48
|
} from "./pr/index";
|
|
48
49
|
import { branchRenameCommand } from "./branch";
|
|
49
50
|
import {
|
|
@@ -94,6 +95,7 @@ const prCommand = Command.make("pr", {}).pipe(
|
|
|
94
95
|
prSubmitReviewCommand,
|
|
95
96
|
prChecksCommand,
|
|
96
97
|
prChecksFailedCommand,
|
|
98
|
+
prWatchCommand,
|
|
97
99
|
prRerunChecksCommand,
|
|
98
100
|
prReplyAndResolveCommand,
|
|
99
101
|
prReviewTriageCommand,
|
|
@@ -82,6 +82,8 @@ const fetchAllRestPages = Effect.fn("issue.fetchAllRestPages")(function* <T>(
|
|
|
82
82
|
|
|
83
83
|
const mapRawIssueComment = (comment: RawIssueComment): IssueComment => ({
|
|
84
84
|
id: comment.id as IssueCommentId,
|
|
85
|
+
commitSha: null,
|
|
86
|
+
feedbackOrigin: "unknown",
|
|
85
87
|
author: comment.user.login,
|
|
86
88
|
body: comment.body,
|
|
87
89
|
createdAt: comment.created_at as IsoTimestamp,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
|
|
30
30
|
import {
|
|
31
31
|
closePR,
|
|
32
|
+
collectWithStableState,
|
|
32
33
|
createPR,
|
|
33
34
|
detectPRStatus,
|
|
34
35
|
editPR,
|
|
@@ -38,6 +39,7 @@ import {
|
|
|
38
39
|
listPRs,
|
|
39
40
|
mergePR,
|
|
40
41
|
rerunChecks,
|
|
42
|
+
watchPRs,
|
|
41
43
|
viewPR,
|
|
42
44
|
waitForMergeable,
|
|
43
45
|
} from "./core";
|
|
@@ -52,6 +54,7 @@ import {
|
|
|
52
54
|
fetchThreads,
|
|
53
55
|
postIssueComment,
|
|
54
56
|
replyToComment,
|
|
57
|
+
replyAndResolveComment,
|
|
55
58
|
resolveThread,
|
|
56
59
|
submitPendingReview,
|
|
57
60
|
} from "./review";
|
|
@@ -95,25 +98,115 @@ export const classifyReviewTriage = (
|
|
|
95
98
|
return { status: reasons.length > 0 ? "needs_investigation" : "clear", reasons };
|
|
96
99
|
};
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
const MAX_BATCH_PRS = 50;
|
|
102
|
+
|
|
103
|
+
export const parsePrNumbers = (
|
|
104
|
+
input: string,
|
|
105
|
+
): Effect.Effect<readonly number[], GitHubCommandError> => {
|
|
106
|
+
const tokens = input.split(",").map((part) => part.trim());
|
|
107
|
+
if (tokens.some((token) => !/^\d+$/.test(token) || Number(token) < 1)) {
|
|
108
|
+
return Effect.fail(emptyBatchError(input));
|
|
109
|
+
}
|
|
110
|
+
const numbers = [...new Set(tokens.map(Number))];
|
|
111
|
+
if (numbers.length > MAX_BATCH_PRS) {
|
|
112
|
+
return Effect.fail(
|
|
113
|
+
new GitHubCommandError({
|
|
114
|
+
message: `--prs supports at most ${MAX_BATCH_PRS} unique PRs`,
|
|
115
|
+
command: "gh pr --prs",
|
|
116
|
+
exitCode: 1,
|
|
117
|
+
stderr: "",
|
|
118
|
+
hint: `Split the request into batches of at most ${MAX_BATCH_PRS} PRs.`,
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return Effect.succeed(numbers);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const withStableHead = Effect.fn("pr.withStableHead")(function* <A, E, R>(
|
|
126
|
+
pr: number | null,
|
|
127
|
+
collect: (pr: number, headSha: string | null) => Effect.Effect<A, E, R>,
|
|
128
|
+
context: { operation: string; command: string },
|
|
129
|
+
) {
|
|
130
|
+
const initial = yield* viewPR(pr);
|
|
131
|
+
const snapshot = yield* collectWithStableState(
|
|
132
|
+
initial,
|
|
133
|
+
(info) => collect(info.number, info.headSha),
|
|
134
|
+
(info) => viewPR(info.number),
|
|
135
|
+
(before, after) => after.headSha === before.headSha,
|
|
136
|
+
);
|
|
137
|
+
if (snapshot !== null) return { info: snapshot.state, value: snapshot.value };
|
|
138
|
+
return yield* Effect.fail(
|
|
139
|
+
new GitHubCommandError({
|
|
140
|
+
message: `PR head changed repeatedly while collecting ${context.operation}`,
|
|
141
|
+
command: context.command,
|
|
142
|
+
exitCode: 1,
|
|
143
|
+
stderr: "",
|
|
144
|
+
nextCommand: context.command,
|
|
145
|
+
retryable: true,
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
export const fetchCurrentThreads = (
|
|
151
|
+
pr: number | null,
|
|
152
|
+
unresolvedOnly: boolean,
|
|
153
|
+
visibleOpenOnly: boolean,
|
|
154
|
+
) =>
|
|
155
|
+
withStableHead(
|
|
156
|
+
pr,
|
|
157
|
+
(number, headSha) => fetchThreads(number, unresolvedOnly, visibleOpenOnly, headSha),
|
|
158
|
+
{ operation: "review threads", command: "gh-tool pr threads" },
|
|
159
|
+
).pipe(Effect.map(({ value }) => value));
|
|
160
|
+
|
|
161
|
+
export const fetchCurrentComments = (pr: number | null, since: string | null) =>
|
|
162
|
+
withStableHead(pr, (number, headSha) => fetchComments(number, since, headSha), {
|
|
163
|
+
operation: "review comments",
|
|
164
|
+
command: "gh-tool pr comments",
|
|
165
|
+
}).pipe(Effect.map(({ value }) => value));
|
|
166
|
+
|
|
167
|
+
export const fetchCurrentReviews = (
|
|
168
|
+
pr: number | null,
|
|
169
|
+
author: string | null,
|
|
170
|
+
bodyContains: string | null,
|
|
171
|
+
state: string | null,
|
|
172
|
+
) =>
|
|
173
|
+
withStableHead(
|
|
174
|
+
pr,
|
|
175
|
+
(number, headSha) => fetchReviews(number, author, bodyContains, state, headSha),
|
|
176
|
+
{ operation: "reviews", command: "gh-tool pr reviews" },
|
|
177
|
+
).pipe(Effect.map(({ value }) => value));
|
|
178
|
+
|
|
179
|
+
export const fetchCurrentFeedback = (pr: number | null) =>
|
|
180
|
+
withStableHead(pr, (number, headSha) => fetchFeedback(number, headSha), {
|
|
181
|
+
operation: "feedback",
|
|
182
|
+
command: "gh-tool pr feedback",
|
|
183
|
+
}).pipe(Effect.map(({ value }) => value));
|
|
184
|
+
|
|
185
|
+
const countFeedbackOrigins = (items: ReadonlyArray<{ feedbackOrigin: string }>) => ({
|
|
186
|
+
current_head: items.filter((item) => item.feedbackOrigin === "current_head").length,
|
|
187
|
+
pre_existing: items.filter((item) => item.feedbackOrigin === "pre_existing").length,
|
|
188
|
+
unknown: items.filter((item) => item.feedbackOrigin === "unknown").length,
|
|
189
|
+
});
|
|
103
190
|
|
|
104
191
|
export const fetchReviewTriage = Effect.fn("pr.fetchReviewTriage")(function* (
|
|
105
192
|
prNumber: number | null,
|
|
193
|
+
format: "toon" | "json" = "toon",
|
|
106
194
|
) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
195
|
+
const { info, value } = yield* withStableHead(
|
|
196
|
+
prNumber,
|
|
197
|
+
(number, headSha) =>
|
|
198
|
+
Effect.all([
|
|
199
|
+
fetchThreads(number, false, false, headSha),
|
|
200
|
+
fetchDiscussionSummary(number),
|
|
201
|
+
fetchChecks(number, false, false, 0, format === "json"),
|
|
202
|
+
fetchReviews(number, null, null, null, headSha),
|
|
203
|
+
fetchComments(number, null, headSha),
|
|
204
|
+
]),
|
|
205
|
+
{ operation: "review triage", command: "gh-tool pr review-triage" },
|
|
116
206
|
);
|
|
207
|
+
const [allThreads, summary, checks, reviews, inlineComments] = value;
|
|
208
|
+
const unresolvedThreads = allThreads.filter((thread) => !thread.isResolved);
|
|
209
|
+
const visibleOpenThreads = allThreads.filter((thread) => thread.isVisibleOpen);
|
|
117
210
|
const classification = classifyReviewTriage(summary, checks);
|
|
118
211
|
|
|
119
212
|
// Single merge-readiness verdict so agents stop re-stitching mergeable + checks + threads +
|
|
@@ -142,6 +235,12 @@ export const fetchReviewTriage = Effect.fn("pr.fetchReviewTriage")(function* (
|
|
|
142
235
|
summary,
|
|
143
236
|
checks,
|
|
144
237
|
reviews,
|
|
238
|
+
inlineComments,
|
|
239
|
+
feedbackOriginCounts: {
|
|
240
|
+
reviews: countFeedbackOrigins(reviews),
|
|
241
|
+
inlineComments: countFeedbackOrigins(inlineComments),
|
|
242
|
+
threads: countFeedbackOrigins(allThreads),
|
|
243
|
+
},
|
|
145
244
|
};
|
|
146
245
|
});
|
|
147
246
|
|
|
@@ -165,8 +264,7 @@ export const prViewCommand = Command.make(
|
|
|
165
264
|
Effect.gen(function* () {
|
|
166
265
|
const batch = Option.getOrNull(prs);
|
|
167
266
|
if (batch !== null) {
|
|
168
|
-
const numbers = parsePrNumbers(batch);
|
|
169
|
-
if (numbers.length === 0) return yield* emptyBatchError(batch);
|
|
267
|
+
const numbers = yield* parsePrNumbers(batch);
|
|
170
268
|
const results = yield* Effect.all(
|
|
171
269
|
numbers.map((n) => viewPR(n).pipe(Effect.map((info) => ({ pr: n, info })))),
|
|
172
270
|
{ concurrency: 5 },
|
|
@@ -422,7 +520,9 @@ export const prMergeCommand = Command.make(
|
|
|
422
520
|
Flag.withDefault(false),
|
|
423
521
|
),
|
|
424
522
|
deleteBranch: Flag.boolean("delete-branch").pipe(
|
|
425
|
-
Flag.withDescription(
|
|
523
|
+
Flag.withDescription(
|
|
524
|
+
"Delete the remote branch after merge (local/worktree cleanup is separate)",
|
|
525
|
+
),
|
|
426
526
|
Flag.withDefault(DEFAULT_DELETE_BRANCH),
|
|
427
527
|
),
|
|
428
528
|
format: formatOption,
|
|
@@ -485,15 +585,16 @@ export const prChecksCommand = Command.make(
|
|
|
485
585
|
const batch = Option.getOrNull(prs);
|
|
486
586
|
if (batch !== null) {
|
|
487
587
|
if (watch) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
588
|
+
if (format !== "json") {
|
|
589
|
+
yield* Console.warn(
|
|
590
|
+
"ℹ️ --watch is ignored with --prs; batch mode returns a one-shot snapshot per PR.",
|
|
591
|
+
);
|
|
592
|
+
}
|
|
491
593
|
}
|
|
492
|
-
const numbers = parsePrNumbers(batch);
|
|
493
|
-
if (numbers.length === 0) return yield* emptyBatchError(batch);
|
|
594
|
+
const numbers = yield* parsePrNumbers(batch);
|
|
494
595
|
const results = yield* Effect.all(
|
|
495
596
|
numbers.map((n) =>
|
|
496
|
-
fetchChecks(n, false, failFast, timeout).pipe(
|
|
597
|
+
fetchChecks(n, false, failFast, timeout, format === "json").pipe(
|
|
497
598
|
Effect.map((checks) => ({ pr: n, checks })),
|
|
498
599
|
),
|
|
499
600
|
),
|
|
@@ -502,7 +603,13 @@ export const prChecksCommand = Command.make(
|
|
|
502
603
|
yield* logFormatted({ count: results.length, prs: results }, format);
|
|
503
604
|
return;
|
|
504
605
|
}
|
|
505
|
-
const checks = yield* fetchChecksForCommand(
|
|
606
|
+
const checks = yield* fetchChecksForCommand(
|
|
607
|
+
Option.getOrNull(pr),
|
|
608
|
+
watch,
|
|
609
|
+
failFast,
|
|
610
|
+
timeout,
|
|
611
|
+
format === "json",
|
|
612
|
+
);
|
|
506
613
|
yield* logFormatted(checks, format);
|
|
507
614
|
}),
|
|
508
615
|
),
|
|
@@ -539,6 +646,42 @@ export const prChecksFailedCommand = Command.make(
|
|
|
539
646
|
),
|
|
540
647
|
).pipe(Command.withDescription("Fetch only failed CI checks for a PR"));
|
|
541
648
|
|
|
649
|
+
export const prWatchCommand = Command.make(
|
|
650
|
+
"watch",
|
|
651
|
+
{
|
|
652
|
+
prs: Flag.string("prs").pipe(Flag.withDescription("Comma-separated PR numbers")),
|
|
653
|
+
until: Flag.choice("until", ["terminal"]).pipe(Flag.withDefault("terminal")),
|
|
654
|
+
format: Flag.choice("format", ["jsonl"]).pipe(Flag.withDefault("jsonl")),
|
|
655
|
+
interval: Flag.integer("interval").pipe(
|
|
656
|
+
Flag.withDefault(5),
|
|
657
|
+
Flag.filter(
|
|
658
|
+
(n) => n >= 1 && n <= 60,
|
|
659
|
+
() => "--interval must be 1..60 seconds",
|
|
660
|
+
),
|
|
661
|
+
),
|
|
662
|
+
timeout: Flag.integer("timeout").pipe(
|
|
663
|
+
Flag.withDefault(CI_CHECK_WATCH_TIMEOUT_MS / 1000),
|
|
664
|
+
Flag.filter(
|
|
665
|
+
(n) => n >= 1,
|
|
666
|
+
() => "--timeout must be at least 1 second",
|
|
667
|
+
),
|
|
668
|
+
),
|
|
669
|
+
repo: repoOption,
|
|
670
|
+
},
|
|
671
|
+
({ prs, until, interval, timeout, repo }) =>
|
|
672
|
+
withRepo(
|
|
673
|
+
repo,
|
|
674
|
+
Effect.gen(function* () {
|
|
675
|
+
const numbers = yield* parsePrNumbers(prs);
|
|
676
|
+
yield* watchPRs(
|
|
677
|
+
numbers,
|
|
678
|
+
{ intervalSeconds: interval, timeoutSeconds: timeout, until },
|
|
679
|
+
(event) => Console.log(JSON.stringify(event)),
|
|
680
|
+
);
|
|
681
|
+
}),
|
|
682
|
+
),
|
|
683
|
+
).pipe(Command.withDescription("Watch several PRs; emits JSONL state transitions only"));
|
|
684
|
+
|
|
542
685
|
export const prRerunChecksCommand = Command.make(
|
|
543
686
|
"rerun-checks",
|
|
544
687
|
{
|
|
@@ -552,13 +695,24 @@ export const prRerunChecksCommand = Command.make(
|
|
|
552
695
|
Flag.withDefault(true),
|
|
553
696
|
Flag.withDescription("Only rerun failed checks (default: true)"),
|
|
554
697
|
),
|
|
698
|
+
watch: Flag.boolean("watch").pipe(Flag.withDefault(false)),
|
|
699
|
+
timeout: Flag.integer("timeout").pipe(
|
|
700
|
+
Flag.withDefault(60),
|
|
701
|
+
Flag.filter(
|
|
702
|
+
(n) => n >= 1,
|
|
703
|
+
() => "--timeout must be at least 1 second",
|
|
704
|
+
),
|
|
705
|
+
),
|
|
555
706
|
},
|
|
556
|
-
({ failedOnly, format, pr, repo }) =>
|
|
707
|
+
({ failedOnly, format, pr, repo, watch, timeout }) =>
|
|
557
708
|
withRepo(
|
|
558
709
|
repo,
|
|
559
710
|
Effect.gen(function* () {
|
|
560
711
|
const prNumber = Option.getOrNull(pr);
|
|
561
|
-
const result = yield* rerunChecks(prNumber, failedOnly
|
|
712
|
+
const result = yield* rerunChecks(prNumber, failedOnly, {
|
|
713
|
+
watch,
|
|
714
|
+
timeoutSeconds: timeout,
|
|
715
|
+
});
|
|
562
716
|
yield* logFormatted(result, format);
|
|
563
717
|
}),
|
|
564
718
|
),
|
|
@@ -591,7 +745,7 @@ export const prThreadsCommand = Command.make(
|
|
|
591
745
|
repo,
|
|
592
746
|
Effect.gen(function* () {
|
|
593
747
|
const prNumber = Option.getOrNull(pr);
|
|
594
|
-
const threads = yield*
|
|
748
|
+
const threads = yield* fetchCurrentThreads(prNumber, unresolvedOnly, visibleOpenOnly);
|
|
595
749
|
yield* logFormatted(threads, format);
|
|
596
750
|
}),
|
|
597
751
|
),
|
|
@@ -621,7 +775,7 @@ export const prCommentsCommand = Command.make(
|
|
|
621
775
|
Effect.gen(function* () {
|
|
622
776
|
const prNumber = Option.getOrNull(pr);
|
|
623
777
|
const sinceValue = Option.getOrNull(since);
|
|
624
|
-
const comments = yield*
|
|
778
|
+
const comments = yield* fetchCurrentComments(prNumber, sinceValue);
|
|
625
779
|
yield* logFormatted(comments, format);
|
|
626
780
|
}),
|
|
627
781
|
),
|
|
@@ -679,7 +833,7 @@ export const prReviewsCommand = Command.make(
|
|
|
679
833
|
withRepo(
|
|
680
834
|
repo,
|
|
681
835
|
Effect.gen(function* () {
|
|
682
|
-
const reviews = yield*
|
|
836
|
+
const reviews = yield* fetchCurrentReviews(
|
|
683
837
|
Option.getOrNull(pr),
|
|
684
838
|
Option.getOrNull(author),
|
|
685
839
|
Option.getOrNull(bodyContains),
|
|
@@ -708,7 +862,7 @@ export const prFeedbackCommand = Command.make(
|
|
|
708
862
|
withRepo(
|
|
709
863
|
repo,
|
|
710
864
|
Effect.gen(function* () {
|
|
711
|
-
const feedback = yield*
|
|
865
|
+
const feedback = yield* fetchCurrentFeedback(Option.getOrNull(pr));
|
|
712
866
|
yield* logFormatted(feedback, format);
|
|
713
867
|
}),
|
|
714
868
|
),
|
|
@@ -971,7 +1125,7 @@ export const prReviewTriageCommand = Command.make(
|
|
|
971
1125
|
repo,
|
|
972
1126
|
Effect.gen(function* () {
|
|
973
1127
|
const prNumber = Option.getOrNull(pr);
|
|
974
|
-
const result = yield* fetchReviewTriage(prNumber);
|
|
1128
|
+
const result = yield* fetchReviewTriage(prNumber, format);
|
|
975
1129
|
yield* logFormatted(result, format);
|
|
976
1130
|
}),
|
|
977
1131
|
),
|
|
@@ -992,10 +1146,9 @@ export const prReviewTriageBatchCommand = Command.make(
|
|
|
992
1146
|
withRepo(
|
|
993
1147
|
repo,
|
|
994
1148
|
Effect.gen(function* () {
|
|
995
|
-
const numbers = parsePrNumbers(prs);
|
|
996
|
-
if (numbers.length === 0) return yield* emptyBatchError(prs);
|
|
1149
|
+
const numbers = yield* parsePrNumbers(prs);
|
|
997
1150
|
const results = yield* Effect.all(
|
|
998
|
-
numbers.map((prNumber) => fetchReviewTriage(prNumber)),
|
|
1151
|
+
numbers.map((prNumber) => fetchReviewTriage(prNumber, format)),
|
|
999
1152
|
{ concurrency: "unbounded" },
|
|
1000
1153
|
);
|
|
1001
1154
|
yield* logFormatted(results, format);
|
|
@@ -1025,7 +1178,10 @@ export const prReplyAndResolveCommand = Command.make(
|
|
|
1025
1178
|
),
|
|
1026
1179
|
repo: repoOption,
|
|
1027
1180
|
threadId: Flag.string("thread-id").pipe(
|
|
1028
|
-
Flag.withDescription(
|
|
1181
|
+
Flag.withDescription(
|
|
1182
|
+
"GraphQL node ID of the thread to resolve (inferred from comment when omitted)",
|
|
1183
|
+
),
|
|
1184
|
+
Flag.optional,
|
|
1029
1185
|
),
|
|
1030
1186
|
},
|
|
1031
1187
|
({ body, bodyFile, commentId, format, pr, repo, threadId }) =>
|
|
@@ -1041,13 +1197,17 @@ export const prReplyAndResolveCommand = Command.make(
|
|
|
1041
1197
|
fileFlag: "--body-file",
|
|
1042
1198
|
label: "body",
|
|
1043
1199
|
});
|
|
1044
|
-
const
|
|
1045
|
-
|
|
1046
|
-
|
|
1200
|
+
const result = yield* replyAndResolveComment(
|
|
1201
|
+
prNumber,
|
|
1202
|
+
commentId,
|
|
1203
|
+
Option.getOrNull(threadId),
|
|
1204
|
+
resolvedBody,
|
|
1205
|
+
);
|
|
1206
|
+
yield* logFormatted(result, format);
|
|
1047
1207
|
}),
|
|
1048
1208
|
),
|
|
1049
1209
|
).pipe(
|
|
1050
1210
|
Command.withDescription(
|
|
1051
|
-
"Composite: reply to a review comment and resolve its thread
|
|
1211
|
+
"Composite: reply to a review comment and resolve its thread (PR/thread inferred from comment)",
|
|
1052
1212
|
),
|
|
1053
1213
|
);
|