patchrelay 0.36.1 → 0.36.2

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,6 +1,6 @@
1
1
  {
2
2
  "service": "patchrelay",
3
- "version": "0.36.1",
4
- "commit": "ceada430ca0b",
5
- "builtAt": "2026-04-08T23:27:56.372Z"
3
+ "version": "0.36.2",
4
+ "commit": "45b497cfbf8e",
5
+ "builtAt": "2026-04-08T23:32:38.896Z"
6
6
  }
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
3
  import { summarizeIssueStatusNote } from "./issue-status-note.js";
4
4
  import { relativeTime, truncate } from "./format-utils.js";
5
- import { hasDisplayPrBlocker, isRereviewNeeded, prChecksFact } from "./pr-status.js";
5
+ import { hasDisplayPrBlocker, isApprovedReviewState, isAwaitingReviewState, isChangesRequestedReviewState, isRereviewNeeded, prChecksFact, } from "./pr-status.js";
6
6
  // ─── State display ──────────────────────────────────────────────
7
7
  const TERMINAL_STATES = new Set(["done", "failed", "escalated"]);
8
8
  function needsOperatorIntervention(issue) {
@@ -17,6 +17,8 @@ function effectiveState(issue) {
17
17
  return "blocked";
18
18
  if (issue.sessionState === "waiting_input")
19
19
  return "awaiting_input";
20
+ if (issue.prNumber !== undefined)
21
+ return issue.factoryState;
20
22
  if (issue.readyForExecution && !issue.activeRunType && !hasDisplayPrBlocker(issue))
21
23
  return "ready";
22
24
  return issue.factoryState;
@@ -80,18 +82,22 @@ function buildFacts(issue, selected) {
80
82
  facts.push({ text: "operator action needed", color: "red" });
81
83
  }
82
84
  // Review state — only show when it matters (not yet approved, or changes requested)
83
- if (issue.prReviewState === "approved") {
85
+ if (isApprovedReviewState(issue.prReviewState)) {
84
86
  facts.push({ text: "approved", color: "green" });
85
87
  }
86
88
  else if (rereviewNeeded) {
87
89
  facts.push({ text: "re-review needed", color: "yellow" });
88
90
  }
89
- else if (issue.prReviewState === "changes_requested") {
91
+ else if (isChangesRequestedReviewState(issue.prReviewState)) {
90
92
  facts.push({ text: "changes requested", color: "yellow" });
91
93
  }
92
- else if (issue.prNumber !== undefined && !issue.prReviewState && !TERMINAL_STATES.has(effectiveState(issue))) {
94
+ else if (issue.prNumber !== undefined
95
+ && (isAwaitingReviewState(issue.prReviewState) || (!issue.prReviewState && !TERMINAL_STATES.has(effectiveState(issue))))) {
93
96
  facts.push({ text: "awaiting review", color: "yellow" });
94
97
  }
98
+ if (issue.factoryState === "awaiting_queue") {
99
+ facts.push({ text: "merge queue", color: "cyan" });
100
+ }
95
101
  // Check status — compact
96
102
  const checksFact = prChecksFact(issue);
97
103
  if (checksFact) {
@@ -133,8 +139,10 @@ function blockerText(issue) {
133
139
  }
134
140
  if (rereviewNeeded)
135
141
  return "Awaiting re-review after requested changes";
136
- if (issue.prReviewState === "changes_requested")
142
+ if (isChangesRequestedReviewState(issue.prReviewState))
137
143
  return "Review changes requested";
144
+ if (issue.prNumber !== undefined && isAwaitingReviewState(issue.prReviewState))
145
+ return "Awaiting review";
138
146
  return null;
139
147
  }
140
148
  // ─── Render ─────────────────────────────────────────────────────
@@ -3,7 +3,7 @@ import { buildTimelineRows } from "./timeline-presentation.js";
3
3
  import { planStepColor, planStepSymbol } from "./plan-helpers.js";
4
4
  import { progressBar } from "./format-utils.js";
5
5
  import { describePatchRelayFreshness } from "./freshness.js";
6
- import { hasDisplayPrBlocker, isRereviewNeeded, prChecksFact } from "./pr-status.js";
6
+ import { hasDisplayPrBlocker, isApprovedReviewState, isAwaitingReviewState, isChangesRequestedReviewState, isRereviewNeeded, prChecksFact, } from "./pr-status.js";
7
7
  import { renderRichTextLines, renderTextLines } from "./render-rich-text.js";
8
8
  const SESSION_DISPLAY = {
9
9
  idle: { label: "idle", color: "blueBright" },
@@ -400,12 +400,17 @@ function buildFactSegments(issue, issueContext) {
400
400
  const rereviewNeeded = isRereviewNeeded(issue);
401
401
  if (issue.prNumber !== undefined)
402
402
  facts.push([{ text: `PR #${issue.prNumber}`, color: "cyan" }]);
403
- if (issue.prReviewState === "approved")
403
+ if (isApprovedReviewState(issue.prReviewState))
404
404
  facts.push([{ text: "approved", color: "green" }]);
405
405
  else if (rereviewNeeded)
406
406
  facts.push([{ text: "re-review needed", color: "yellow" }]);
407
- else if (issue.prReviewState === "changes_requested")
407
+ else if (isChangesRequestedReviewState(issue.prReviewState))
408
408
  facts.push([{ text: "changes requested", color: "yellow" }]);
409
+ else if (issue.prNumber !== undefined
410
+ && (isAwaitingReviewState(issue.prReviewState) || (!issue.prReviewState && issue.factoryState === "pr_open")))
411
+ facts.push([{ text: "awaiting review", color: "yellow" }]);
412
+ if (issue.factoryState === "awaiting_queue")
413
+ facts.push([{ text: "merge queue", color: "cyan" }]);
409
414
  if (issue.waitingReason && issue.sessionState === "waiting_input")
410
415
  facts.push([{ text: issue.waitingReason, color: "yellow" }]);
411
416
  const checks = prChecksFact({
@@ -512,6 +517,8 @@ function effectiveState(issue) {
512
517
  return "blocked";
513
518
  if (issue.sessionState === "waiting_input")
514
519
  return "awaiting_input";
520
+ if (issue.prNumber !== undefined)
521
+ return issue.factoryState;
515
522
  if (issue.readyForExecution && !issue.activeRunType && !hasDisplayPrBlocker(issue))
516
523
  return "ready";
517
524
  return issue.factoryState;
@@ -549,10 +556,11 @@ function blockerText(issue, issueContext) {
549
556
  }
550
557
  if (rereviewNeeded)
551
558
  return "Awaiting re-review after requested changes";
552
- if (issue.prReviewState === "changes_requested")
559
+ if (isChangesRequestedReviewState(issue.prReviewState))
553
560
  return "Review changes requested";
554
- if (issue.prNumber !== undefined && !issue.prReviewState && effectiveState(issue) !== "done")
561
+ if (issue.prNumber !== undefined && (isAwaitingReviewState(issue.prReviewState) || (!issue.prReviewState && effectiveState(issue) !== "done"))) {
555
562
  return "Awaiting review";
563
+ }
556
564
  return null;
557
565
  }
558
566
  function cleanCommand(raw) {
@@ -7,6 +7,20 @@ function isFailingCheckStatus(status) {
7
7
  function isPendingCheckStatus(status) {
8
8
  return status === "pending" || status === "in_progress";
9
9
  }
10
+ function normalizeReviewState(state) {
11
+ const normalized = state?.trim().toLowerCase();
12
+ return normalized && normalized.length > 0 ? normalized : undefined;
13
+ }
14
+ export function isApprovedReviewState(state) {
15
+ return normalizeReviewState(state) === "approved";
16
+ }
17
+ export function isChangesRequestedReviewState(state) {
18
+ return normalizeReviewState(state) === "changes_requested";
19
+ }
20
+ export function isAwaitingReviewState(state) {
21
+ const normalized = normalizeReviewState(state);
22
+ return normalized === "review_required" || normalized === "commented";
23
+ }
10
24
  export function hasPendingPrChecks(issue) {
11
25
  const summary = issue.prChecksSummary;
12
26
  if (summary?.total) {
@@ -29,7 +43,7 @@ export function arePrChecksCompleteAndGreen(issue) {
29
43
  return isPassingCheckStatus(issue.prCheckStatus);
30
44
  }
31
45
  export function isRereviewNeeded(issue) {
32
- return issue.prReviewState === "changes_requested"
46
+ return isChangesRequestedReviewState(issue.prReviewState)
33
47
  && arePrChecksCompleteAndGreen(issue)
34
48
  && !issue.activeRunType;
35
49
  }
@@ -61,10 +75,13 @@ export function hasDisplayPrBlocker(issue) {
61
75
  if (issue.prNumber === undefined || issue.activeRunType) {
62
76
  return false;
63
77
  }
78
+ if (issue.factoryState === "pr_open" || issue.factoryState === "awaiting_queue" || issue.factoryState === "repairing_queue") {
79
+ return true;
80
+ }
64
81
  if (hasPendingPrChecks(issue) || hasFailedPrChecks(issue)) {
65
82
  return true;
66
83
  }
67
- if (issue.prReviewState === "changes_requested" && !isRereviewNeeded(issue)) {
84
+ if (isChangesRequestedReviewState(issue.prReviewState) && !isRereviewNeeded(issue)) {
68
85
  return true;
69
86
  }
70
87
  if (!issue.prReviewState && issue.factoryState === "pr_open") {
@@ -67,7 +67,7 @@ export function computeAggregates(issues) {
67
67
  active++;
68
68
  if (!issue.activeRunType && issue.blockedByCount > 0)
69
69
  blocked++;
70
- if (!issue.activeRunType && issue.readyForExecution && !isDone && !isFailed)
70
+ if (!issue.activeRunType && issue.prNumber === undefined && issue.readyForExecution && !isDone && !isFailed)
71
71
  ready++;
72
72
  if (isDone)
73
73
  done++;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchrelay",
3
- "version": "0.36.1",
3
+ "version": "0.36.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {