@blogic-cz/agent-tools 0.14.32 → 0.14.34

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blogic-cz/agent-tools",
3
- "version": "0.14.32",
3
+ "version": "0.14.34",
4
4
  "description": "CLI tools for AI coding agent workflows — GitHub, database, Kubernetes, Azure DevOps, logs, sessions, and audit",
5
5
  "keywords": [
6
6
  "agent",
@@ -36,6 +36,7 @@ import {
36
36
  prChecksFailedCommand,
37
37
  prRerunChecksCommand,
38
38
  prReplyAndResolveCommand,
39
+ prReviewTriageBatchCommand,
39
40
  prReviewTriageCommand,
40
41
  } from "./pr/index";
41
42
  import { branchRenameCommand } from "./branch";
@@ -84,6 +85,7 @@ const prCommand = Command.make("pr", {}).pipe(
84
85
  prRerunChecksCommand,
85
86
  prReplyAndResolveCommand,
86
87
  prReviewTriageCommand,
88
+ prReviewTriageBatchCommand,
87
89
  ]),
88
90
  );
89
91
 
@@ -1,7 +1,7 @@
1
1
  import { Command, Flag } from "effect/unstable/cli";
2
2
  import { Effect, Option } from "effect";
3
3
 
4
- import type { PRStatusResult } from "#gh/types";
4
+ import type { CheckResult, PRStatusResult } from "#gh/types";
5
5
 
6
6
  import { formatOption, logFormatted } from "#shared";
7
7
  import { GitHubService } from "#gh/service";
@@ -56,6 +56,50 @@ const withRepo = <A, E, R>(repo: Option.Option<string>, effect: Effect.Effect<A,
56
56
  return yield* gh.withRepoTarget(Option.getOrNull(repo), effect);
57
57
  });
58
58
 
59
+ type ReviewTriageSummary = {
60
+ readonly visibleOpenReviewThreadsCount: number;
61
+ readonly unrepliedReviewThreadsCount: number;
62
+ readonly unresolvedReviewThreadsCount: number;
63
+ };
64
+
65
+ type ReviewTriageClassification = {
66
+ readonly status: "clear" | "needs_investigation";
67
+ readonly reasons: readonly string[];
68
+ };
69
+
70
+ export const classifyReviewTriage = (
71
+ summary: ReviewTriageSummary,
72
+ checks: readonly CheckResult[],
73
+ ): ReviewTriageClassification => {
74
+ const reasons = [
75
+ ...(checks.some((check) => check.bucket === "fail") ? ["failed_checks"] : []),
76
+ ...(summary.visibleOpenReviewThreadsCount > 0 ? ["visible_open_review_threads"] : []),
77
+ ...(summary.unrepliedReviewThreadsCount > 0 ? ["unreplied_review_threads"] : []),
78
+ ...(summary.unresolvedReviewThreadsCount > 0 ? ["unresolved_review_threads"] : []),
79
+ ];
80
+ return { status: reasons.length > 0 ? "needs_investigation" : "clear", reasons };
81
+ };
82
+
83
+ export const parsePrNumbers = (input: string): readonly number[] =>
84
+ input
85
+ .split(",")
86
+ .map((part) => Number.parseInt(part.trim(), 10))
87
+ .filter((number) => Number.isInteger(number) && number > 0);
88
+
89
+ export const fetchReviewTriage = Effect.fn("pr.fetchReviewTriage")(function* (
90
+ prNumber: number | null,
91
+ ) {
92
+ const [info, unresolvedThreads, visibleOpenThreads, summary, checks] = yield* Effect.all([
93
+ viewPR(prNumber),
94
+ fetchThreads(prNumber, true),
95
+ fetchThreads(prNumber, false, true),
96
+ fetchDiscussionSummary(prNumber),
97
+ fetchChecks(prNumber, false, false, 0),
98
+ ]);
99
+ const classification = classifyReviewTriage(summary, checks);
100
+ return { classification, info, unresolvedThreads, visibleOpenThreads, summary, checks };
101
+ });
102
+
59
103
  export const prViewCommand = Command.make(
60
104
  "view",
61
105
  {
@@ -663,17 +707,8 @@ export const prReviewTriageCommand = Command.make(
663
707
  repo,
664
708
  Effect.gen(function* () {
665
709
  const prNumber = Option.getOrNull(pr);
666
- const [info, unresolvedThreads, visibleOpenThreads, summary, checks] = yield* Effect.all([
667
- viewPR(prNumber),
668
- fetchThreads(prNumber, true),
669
- fetchThreads(prNumber, false, true),
670
- fetchDiscussionSummary(prNumber),
671
- fetchChecks(prNumber, false, false, 0),
672
- ]);
673
- yield* logFormatted(
674
- { info, unresolvedThreads, visibleOpenThreads, summary, checks },
675
- format,
676
- );
710
+ const result = yield* fetchReviewTriage(prNumber);
711
+ yield* logFormatted(result, format);
677
712
  }),
678
713
  ),
679
714
  ).pipe(
@@ -682,6 +717,30 @@ export const prReviewTriageCommand = Command.make(
682
717
  ),
683
718
  );
684
719
 
720
+ export const prReviewTriageBatchCommand = Command.make(
721
+ "review-triage-batch",
722
+ {
723
+ format: formatOption,
724
+ prs: Flag.string("prs").pipe(Flag.withDescription("Comma-separated PR numbers")),
725
+ repo: repoOption,
726
+ },
727
+ ({ format, prs, repo }) =>
728
+ withRepo(
729
+ repo,
730
+ Effect.gen(function* () {
731
+ const results = yield* Effect.all(
732
+ parsePrNumbers(prs).map((prNumber) => fetchReviewTriage(prNumber)),
733
+ { concurrency: "unbounded" },
734
+ );
735
+ yield* logFormatted(results, format);
736
+ }),
737
+ ),
738
+ ).pipe(
739
+ Command.withDescription(
740
+ "Composite: fetch review-triage output for multiple PRs in one gh-tool invocation",
741
+ ),
742
+ );
743
+
685
744
  export const prReplyAndResolveCommand = Command.make(
686
745
  "reply-and-resolve",
687
746
  {
@@ -18,5 +18,6 @@ export {
18
18
  prSubmitReviewCommand,
19
19
  prThreadsCommand,
20
20
  prReviewTriageCommand,
21
+ prReviewTriageBatchCommand,
21
22
  prViewCommand,
22
23
  } from "./commands";