patchrelay 0.35.13 → 0.35.15
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/dist/build-info.json
CHANGED
|
@@ -2,6 +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
6
|
// ─── State display ──────────────────────────────────────────────
|
|
6
7
|
const TERMINAL_STATES = new Set(["done", "failed", "escalated"]);
|
|
7
8
|
function needsOperatorIntervention(issue) {
|
|
@@ -14,10 +15,10 @@ function effectiveState(issue) {
|
|
|
14
15
|
return "failed";
|
|
15
16
|
if (issue.blockedByCount > 0 && !issue.activeRunType)
|
|
16
17
|
return "blocked";
|
|
17
|
-
if (issue.readyForExecution && !issue.activeRunType)
|
|
18
|
-
return "ready";
|
|
19
18
|
if (issue.sessionState === "waiting_input")
|
|
20
19
|
return "awaiting_input";
|
|
20
|
+
if (issue.readyForExecution && !issue.activeRunType && !hasDisplayPrBlocker(issue))
|
|
21
|
+
return "ready";
|
|
21
22
|
return issue.factoryState;
|
|
22
23
|
}
|
|
23
24
|
function sessionDisplay(issue) {
|
|
@@ -61,9 +62,7 @@ function stageLabel(issue) {
|
|
|
61
62
|
// ─── Context facts (what matters right now) ─────────────────────
|
|
62
63
|
function buildFacts(issue, selected) {
|
|
63
64
|
const facts = [];
|
|
64
|
-
const rereviewNeeded = issue
|
|
65
|
-
&& (issue.prCheckStatus === "passed" || issue.prCheckStatus === "success")
|
|
66
|
-
&& !issue.activeRunType;
|
|
65
|
+
const rereviewNeeded = isRereviewNeeded(issue);
|
|
67
66
|
// PR number
|
|
68
67
|
if (issue.prNumber !== undefined) {
|
|
69
68
|
facts.push({ text: `PR #${issue.prNumber}` });
|
|
@@ -94,23 +93,9 @@ function buildFacts(issue, selected) {
|
|
|
94
93
|
facts.push({ text: "awaiting review", color: "yellow" });
|
|
95
94
|
}
|
|
96
95
|
// Check status — compact
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
else if (issue.prCheckStatus === "failed" || issue.prCheckStatus === "failure") {
|
|
101
|
-
const failedNames = issue.prChecksSummary?.failedNames ?? [];
|
|
102
|
-
const checkInfo = issue.latestFailureCheckName
|
|
103
|
-
?? (failedNames.length > 0 ? failedNames.slice(0, 2).join(", ") : "checks");
|
|
104
|
-
facts.push({ text: `${checkInfo} failed`, color: "red" });
|
|
105
|
-
}
|
|
106
|
-
else if (issue.prCheckStatus === "pending" || issue.prCheckStatus === "in_progress") {
|
|
107
|
-
const summary = issue.prChecksSummary;
|
|
108
|
-
if (summary && summary.total > 0) {
|
|
109
|
-
facts.push({ text: `checks ${summary.completed}/${summary.total}`, color: "yellow" });
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
facts.push({ text: "checks running", color: "yellow" });
|
|
113
|
-
}
|
|
96
|
+
const checksFact = prChecksFact(issue);
|
|
97
|
+
if (checksFact) {
|
|
98
|
+
facts.push(checksFact);
|
|
114
99
|
}
|
|
115
100
|
// Blocker
|
|
116
101
|
if (issue.blockedByCount > 0) {
|
|
@@ -120,9 +105,7 @@ function buildFacts(issue, selected) {
|
|
|
120
105
|
}
|
|
121
106
|
// ─── What's blocking progress ───────────────────────────────────
|
|
122
107
|
function blockerText(issue) {
|
|
123
|
-
const rereviewNeeded = issue
|
|
124
|
-
&& (issue.prCheckStatus === "passed" || issue.prCheckStatus === "success")
|
|
125
|
-
&& !issue.activeRunType;
|
|
108
|
+
const rereviewNeeded = isRereviewNeeded(issue);
|
|
126
109
|
if (issue.sessionState === "waiting_input")
|
|
127
110
|
return issue.waitingReason ?? "Waiting for input";
|
|
128
111
|
if (needsOperatorIntervention(issue))
|
|
@@ -137,9 +120,12 @@ function blockerText(issue) {
|
|
|
137
120
|
const check = issue.latestFailureCheckName ?? "CI";
|
|
138
121
|
return `Repairing ${check}`;
|
|
139
122
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return
|
|
123
|
+
const checksFact = prChecksFact(issue);
|
|
124
|
+
if (checksFact?.color === "red") {
|
|
125
|
+
return checksFact.text;
|
|
126
|
+
}
|
|
127
|
+
if (checksFact?.color === "yellow" && checksFact.text.startsWith("checks ")) {
|
|
128
|
+
return `${checksFact.text} still running`;
|
|
143
129
|
}
|
|
144
130
|
if (rereviewNeeded)
|
|
145
131
|
return "Awaiting re-review after requested changes";
|
|
@@ -3,6 +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
7
|
import { renderRichTextLines, renderTextLines } from "./render-rich-text.js";
|
|
7
8
|
const SESSION_DISPLAY = {
|
|
8
9
|
idle: { label: "idle", color: "blueBright" },
|
|
@@ -117,10 +118,9 @@ function buildHeaderLines(input, width) {
|
|
|
117
118
|
}));
|
|
118
119
|
}
|
|
119
120
|
if (issue.statusNote && issue.statusNote !== blocker) {
|
|
120
|
-
lines.push(...
|
|
121
|
+
lines.push(...renderRichTextLines(issue.statusNote, {
|
|
121
122
|
key: "detail-note",
|
|
122
123
|
width,
|
|
123
|
-
style: { dimColor: true },
|
|
124
124
|
}));
|
|
125
125
|
}
|
|
126
126
|
if (input.issueContext?.latestFailureSummary) {
|
|
@@ -396,9 +396,7 @@ function renderSideTripLines(trip, runOffset, width) {
|
|
|
396
396
|
}
|
|
397
397
|
function buildFacts(issue, issueContext) {
|
|
398
398
|
const facts = [];
|
|
399
|
-
const rereviewNeeded = issue
|
|
400
|
-
&& (issue.prCheckStatus === "passed" || issue.prCheckStatus === "success")
|
|
401
|
-
&& !issue.activeRunType;
|
|
399
|
+
const rereviewNeeded = isRereviewNeeded(issue);
|
|
402
400
|
if (issue.prNumber !== undefined)
|
|
403
401
|
facts.push(`PR #${issue.prNumber}`);
|
|
404
402
|
if (issue.prReviewState === "approved")
|
|
@@ -409,14 +407,12 @@ function buildFacts(issue, issueContext) {
|
|
|
409
407
|
facts.push("changes requested");
|
|
410
408
|
if (issue.waitingReason && issue.sessionState === "waiting_input")
|
|
411
409
|
facts.push(issue.waitingReason);
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
else if (issue.prChecksSummary?.total) {
|
|
419
|
-
facts.push(`checks ${issue.prChecksSummary.completed}/${issue.prChecksSummary.total}`);
|
|
410
|
+
const checks = prChecksFact({
|
|
411
|
+
...issue,
|
|
412
|
+
latestFailureCheckName: issueContext?.latestFailureCheckName ?? issue.latestFailureCheckName,
|
|
413
|
+
});
|
|
414
|
+
if (checks) {
|
|
415
|
+
facts.push(checks.text);
|
|
420
416
|
}
|
|
421
417
|
return facts;
|
|
422
418
|
}
|
|
@@ -503,16 +499,14 @@ function effectiveState(issue) {
|
|
|
503
499
|
return "failed";
|
|
504
500
|
if (issue.blockedByCount > 0 && !issue.activeRunType)
|
|
505
501
|
return "blocked";
|
|
506
|
-
if (issue.readyForExecution && !issue.activeRunType)
|
|
507
|
-
return "ready";
|
|
508
502
|
if (issue.sessionState === "waiting_input")
|
|
509
503
|
return "awaiting_input";
|
|
504
|
+
if (issue.readyForExecution && !issue.activeRunType && !hasDisplayPrBlocker(issue))
|
|
505
|
+
return "ready";
|
|
510
506
|
return issue.factoryState;
|
|
511
507
|
}
|
|
512
508
|
function blockerText(issue, issueContext) {
|
|
513
|
-
const rereviewNeeded = issue
|
|
514
|
-
&& (issue.prCheckStatus === "passed" || issue.prCheckStatus === "success")
|
|
515
|
-
&& !issue.activeRunType;
|
|
509
|
+
const rereviewNeeded = isRereviewNeeded(issue);
|
|
516
510
|
if (issue.sessionState === "waiting_input")
|
|
517
511
|
return issue.waitingReason ?? "Waiting for input";
|
|
518
512
|
if (issue.sessionState === "failed" || issue.factoryState === "failed" || issue.factoryState === "escalated") {
|
|
@@ -528,9 +522,15 @@ function blockerText(issue, issueContext) {
|
|
|
528
522
|
const check = issueContext?.latestFailureCheckName ?? issue.latestFailureCheckName ?? "CI";
|
|
529
523
|
return `Repairing ${check}`;
|
|
530
524
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
525
|
+
const checks = prChecksFact({
|
|
526
|
+
...issue,
|
|
527
|
+
latestFailureCheckName: issueContext?.latestFailureCheckName ?? issue.latestFailureCheckName,
|
|
528
|
+
});
|
|
529
|
+
if (checks?.color === "red") {
|
|
530
|
+
return checks.text;
|
|
531
|
+
}
|
|
532
|
+
if (checks?.color === "yellow" && checks.text.startsWith("checks ")) {
|
|
533
|
+
return `${checks.text} still running`;
|
|
534
534
|
}
|
|
535
535
|
if (rereviewNeeded)
|
|
536
536
|
return "Awaiting re-review after requested changes";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function isPassingCheckStatus(status) {
|
|
2
|
+
return status === "passed" || status === "success";
|
|
3
|
+
}
|
|
4
|
+
function isFailingCheckStatus(status) {
|
|
5
|
+
return status === "failed" || status === "failure";
|
|
6
|
+
}
|
|
7
|
+
function isPendingCheckStatus(status) {
|
|
8
|
+
return status === "pending" || status === "in_progress";
|
|
9
|
+
}
|
|
10
|
+
export function hasPendingPrChecks(issue) {
|
|
11
|
+
const summary = issue.prChecksSummary;
|
|
12
|
+
if (summary?.total) {
|
|
13
|
+
return summary.pending > 0 || summary.completed < summary.total;
|
|
14
|
+
}
|
|
15
|
+
return isPendingCheckStatus(issue.prCheckStatus);
|
|
16
|
+
}
|
|
17
|
+
export function hasFailedPrChecks(issue) {
|
|
18
|
+
const summary = issue.prChecksSummary;
|
|
19
|
+
if (summary?.total) {
|
|
20
|
+
return summary.failed > 0 || summary.overall === "failure";
|
|
21
|
+
}
|
|
22
|
+
return isFailingCheckStatus(issue.prCheckStatus);
|
|
23
|
+
}
|
|
24
|
+
export function arePrChecksCompleteAndGreen(issue) {
|
|
25
|
+
const summary = issue.prChecksSummary;
|
|
26
|
+
if (summary?.total) {
|
|
27
|
+
return summary.pending === 0 && summary.failed === 0;
|
|
28
|
+
}
|
|
29
|
+
return isPassingCheckStatus(issue.prCheckStatus);
|
|
30
|
+
}
|
|
31
|
+
export function isRereviewNeeded(issue) {
|
|
32
|
+
return issue.prReviewState === "changes_requested"
|
|
33
|
+
&& arePrChecksCompleteAndGreen(issue)
|
|
34
|
+
&& !issue.activeRunType;
|
|
35
|
+
}
|
|
36
|
+
export function prChecksFact(issue) {
|
|
37
|
+
const summary = issue.prChecksSummary;
|
|
38
|
+
if (hasFailedPrChecks(issue)) {
|
|
39
|
+
const failedNames = summary?.failedNames ?? [];
|
|
40
|
+
const checkInfo = issue.latestFailureCheckName
|
|
41
|
+
?? (failedNames.length > 0 ? failedNames.slice(0, 2).join(", ") : "checks");
|
|
42
|
+
return { text: `${checkInfo} failed`, color: "red" };
|
|
43
|
+
}
|
|
44
|
+
if (summary?.total) {
|
|
45
|
+
if (summary.pending > 0 || summary.completed < summary.total) {
|
|
46
|
+
return { text: `checks ${summary.completed}/${summary.total}`, color: "yellow" };
|
|
47
|
+
}
|
|
48
|
+
if (summary.failed === 0) {
|
|
49
|
+
return { text: "checks passed", color: "green" };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (isPassingCheckStatus(issue.prCheckStatus)) {
|
|
53
|
+
return { text: "checks passed", color: "green" };
|
|
54
|
+
}
|
|
55
|
+
if (isPendingCheckStatus(issue.prCheckStatus)) {
|
|
56
|
+
return { text: "checks running", color: "yellow" };
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
export function hasDisplayPrBlocker(issue) {
|
|
61
|
+
if (issue.prNumber === undefined || issue.activeRunType) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (hasPendingPrChecks(issue) || hasFailedPrChecks(issue)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (issue.prReviewState === "changes_requested" && !isRereviewNeeded(issue)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
if (!issue.prReviewState && issue.factoryState === "pr_open") {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
@@ -113,11 +113,10 @@ function parseInlineMarkdown(text, style) {
|
|
|
113
113
|
segments.push({ text: text.slice(lastIndex, index), ...(style ?? {}) });
|
|
114
114
|
}
|
|
115
115
|
if (match[1] && match[2]) {
|
|
116
|
-
segments.push({ text: match[1], color: "cyan"
|
|
117
|
-
segments.push({ text: ` (${match[2]})`, dimColor: true });
|
|
116
|
+
segments.push({ text: match[1], color: "cyan" });
|
|
118
117
|
}
|
|
119
118
|
else if (match[3]) {
|
|
120
|
-
segments.push({ text: match[3], color: "yellow"
|
|
119
|
+
segments.push({ text: match[3], color: "yellow" });
|
|
121
120
|
}
|
|
122
121
|
else if (match[4]) {
|
|
123
122
|
segments.push({ text: match[4], ...(style ?? {}), bold: true });
|