patchrelay 0.35.11 → 0.35.13
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 +41 -9
- package/dist/build-info.json +3 -3
- package/dist/cli/args.js +19 -1
- package/dist/cli/commands/issues.js +18 -56
- package/dist/cli/commands/watch.js +5 -0
- package/dist/cli/data.js +160 -47
- package/dist/cli/formatters/text.js +51 -90
- package/dist/cli/help.js +15 -8
- package/dist/cli/index.js +3 -58
- package/dist/cli/operator-client.js +0 -82
- package/dist/cli/watch/App.js +21 -12
- package/dist/cli/watch/HelpBar.js +3 -3
- package/dist/cli/watch/IssueDetailView.js +63 -130
- package/dist/cli/watch/IssueRow.js +82 -27
- package/dist/cli/watch/StatusBar.js +8 -4
- package/dist/cli/watch/detail-rows.js +589 -0
- package/dist/cli/watch/render-rich-text.js +226 -0
- package/dist/cli/watch/state-visualization.js +48 -23
- package/dist/cli/watch/timeline-builder.js +2 -1
- package/dist/cli/watch/use-detail-stream.js +10 -104
- package/dist/cli/watch/use-watch-stream.js +11 -102
- package/dist/cli/watch/watch-state.js +129 -56
- package/dist/codex-thread-utils.js +3 -0
- package/dist/db/migrations.js +239 -2
- package/dist/db.js +628 -39
- package/dist/github-app-token.js +7 -0
- package/dist/github-failure-context.js +44 -1
- package/dist/github-rollup.js +47 -0
- package/dist/github-webhook-handler.js +423 -52
- package/dist/github-webhooks.js +7 -0
- package/dist/http.js +12 -264
- package/dist/idle-reconciliation.js +268 -76
- package/dist/issue-query-service.js +221 -129
- package/dist/issue-session-events.js +151 -0
- package/dist/issue-session.js +99 -0
- package/dist/linear-client.js +39 -25
- package/dist/linear-session-reporting.js +12 -0
- package/dist/linear-session-sync.js +253 -24
- package/dist/linear-workflow.js +33 -0
- package/dist/merge-queue-protocol.js +0 -51
- package/dist/preflight.js +1 -4
- package/dist/queue-health-monitor.js +11 -7
- package/dist/run-orchestrator.js +1364 -147
- package/dist/run-reporting.js +5 -3
- package/dist/service.js +279 -102
- package/dist/status-note.js +56 -0
- package/dist/waiting-reason.js +65 -0
- package/dist/webhook-handler.js +270 -79
- package/package.json +3 -2
- package/dist/cli/commands/feed.js +0 -60
- package/dist/cli/watch/FeedView.js +0 -28
- package/dist/cli/watch/use-feed-stream.js +0 -92
package/dist/github-app-token.js
CHANGED
|
@@ -57,6 +57,11 @@ fi
|
|
|
57
57
|
exec /usr/bin/gh "$@"
|
|
58
58
|
`;
|
|
59
59
|
await writeFile(ghWrapper, script, { mode: 0o755 });
|
|
60
|
+
const currentPath = process.env.PATH ?? "";
|
|
61
|
+
const pathEntries = currentPath.split(path.delimiter).filter(Boolean);
|
|
62
|
+
if (!pathEntries.includes(binDir)) {
|
|
63
|
+
process.env.PATH = [binDir, ...pathEntries].join(path.delimiter);
|
|
64
|
+
}
|
|
60
65
|
logger.debug({ path: ghWrapper }, "Wrote gh wrapper script");
|
|
61
66
|
}
|
|
62
67
|
/**
|
|
@@ -144,6 +149,8 @@ export function createGitHubAppTokenManager(credentials, logger) {
|
|
|
144
149
|
await mkdir(path.dirname(tokenFile), { recursive: true });
|
|
145
150
|
await writeFile(tokenFile, token, { mode: 0o600 });
|
|
146
151
|
cachedToken = token;
|
|
152
|
+
process.env.GH_TOKEN = token;
|
|
153
|
+
process.env.GITHUB_TOKEN = token;
|
|
147
154
|
logger.debug("Refreshed GitHub App installation token");
|
|
148
155
|
}
|
|
149
156
|
catch (error) {
|
|
@@ -33,7 +33,14 @@ export function createGitHubFailureContextResolver() {
|
|
|
33
33
|
const annotations = failedCheck?.id
|
|
34
34
|
? await resolveAnnotations(repoFullName, failedCheck.id)
|
|
35
35
|
: undefined;
|
|
36
|
-
const summary =
|
|
36
|
+
const summary = pickFailureSummary({
|
|
37
|
+
annotations,
|
|
38
|
+
failedCheckOutputTitle: failedCheck?.outputTitle,
|
|
39
|
+
failedCheckOutputSummary: failedCheck?.outputSummary,
|
|
40
|
+
eventCheckOutputTitle: event.checkOutputTitle,
|
|
41
|
+
eventCheckOutputSummary: event.checkOutputSummary,
|
|
42
|
+
workflowStepName: workflowJob?.stepName,
|
|
43
|
+
});
|
|
37
44
|
const checkName = firstNonEmpty(failedCheck?.name, event.checkName);
|
|
38
45
|
const checkUrl = firstNonEmpty(failedCheck?.htmlUrl, event.checkUrl);
|
|
39
46
|
const checkDetailsUrl = firstNonEmpty(failedCheck?.detailsUrl, event.checkDetailsUrl);
|
|
@@ -105,6 +112,12 @@ export function summarizeGitHubFailureContext(context) {
|
|
|
105
112
|
const step = context.stepName ? `${lead ?? "CI"} -> ${context.stepName}` : lead;
|
|
106
113
|
return firstNonEmpty(step && context.summary ? `${step}: ${context.summary}` : undefined, step, context.summary);
|
|
107
114
|
}
|
|
115
|
+
export function pickFailureSummary(params) {
|
|
116
|
+
const preferredAnnotation = pickPreferredFailureAnnotation(params.annotations);
|
|
117
|
+
const structuredSummary = firstNonEmpty(params.failedCheckOutputTitle, params.failedCheckOutputSummary, params.eventCheckOutputTitle, params.eventCheckOutputSummary);
|
|
118
|
+
const failedStepSummary = params.workflowStepName ? `Failed step: ${params.workflowStepName}` : undefined;
|
|
119
|
+
return firstNonEmpty(preferredAnnotation, structuredSummary, failedStepSummary, params.annotations?.[0]);
|
|
120
|
+
}
|
|
108
121
|
function buildFallbackFailureContext(source, repoFullName, event) {
|
|
109
122
|
const summary = firstNonEmpty(event.checkOutputTitle, event.checkOutputSummary, event.checkOutputText ? sanitizeDiagnosticText(event.checkOutputText, 240) : undefined);
|
|
110
123
|
return {
|
|
@@ -119,6 +132,36 @@ function buildFallbackFailureContext(source, repoFullName, event) {
|
|
|
119
132
|
...(summary ? { summary } : {}),
|
|
120
133
|
};
|
|
121
134
|
}
|
|
135
|
+
export function pickPreferredFailureAnnotation(annotations) {
|
|
136
|
+
if (!Array.isArray(annotations) || annotations.length === 0)
|
|
137
|
+
return undefined;
|
|
138
|
+
const ranked = annotations
|
|
139
|
+
.map((annotation) => ({ annotation, score: scoreFailureAnnotation(annotation) }))
|
|
140
|
+
.filter((entry) => entry.score > 0)
|
|
141
|
+
.sort((left, right) => right.score - left.score);
|
|
142
|
+
return ranked[0]?.annotation;
|
|
143
|
+
}
|
|
144
|
+
function scoreFailureAnnotation(annotation) {
|
|
145
|
+
const text = annotation.trim();
|
|
146
|
+
if (!text)
|
|
147
|
+
return 0;
|
|
148
|
+
const lower = text.toLowerCase();
|
|
149
|
+
if (lower.startsWith("process completed with exit code"))
|
|
150
|
+
return 0;
|
|
151
|
+
if (lower.includes("actions target node.js 20 but are being forced to run on node.js 24"))
|
|
152
|
+
return 0;
|
|
153
|
+
let score = 1;
|
|
154
|
+
if (!lower.includes("(.github)")) {
|
|
155
|
+
score += 2;
|
|
156
|
+
}
|
|
157
|
+
if (lower.includes("assertionerror") || lower.includes("expected values to be strictly equal")) {
|
|
158
|
+
score += 2;
|
|
159
|
+
}
|
|
160
|
+
if (lower.includes("error") || lower.includes("exception") || lower.includes("failed")) {
|
|
161
|
+
score += 1;
|
|
162
|
+
}
|
|
163
|
+
return score;
|
|
164
|
+
}
|
|
122
165
|
async function resolveFailedCheckRun(repoFullName, event) {
|
|
123
166
|
if (!event.headSha)
|
|
124
167
|
return undefined;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const FAILED_CONCLUSIONS = new Set([
|
|
2
|
+
"action_required",
|
|
3
|
+
"cancelled",
|
|
4
|
+
"failure",
|
|
5
|
+
"stale",
|
|
6
|
+
"startup_failure",
|
|
7
|
+
"timed_out",
|
|
8
|
+
]);
|
|
9
|
+
function normalizeGateStatus(entry) {
|
|
10
|
+
const status = entry.status?.trim().toLowerCase();
|
|
11
|
+
if (status === "queued" || status === "in_progress" || status === "requested" || status === "waiting" || status === "pending") {
|
|
12
|
+
return "pending";
|
|
13
|
+
}
|
|
14
|
+
const conclusion = entry.conclusion?.trim().toLowerCase();
|
|
15
|
+
if (conclusion === "success" || conclusion === "neutral" || conclusion === "skipped") {
|
|
16
|
+
return "success";
|
|
17
|
+
}
|
|
18
|
+
if (conclusion && FAILED_CONCLUSIONS.has(conclusion)) {
|
|
19
|
+
return "failure";
|
|
20
|
+
}
|
|
21
|
+
return status === "completed" ? "failure" : "pending";
|
|
22
|
+
}
|
|
23
|
+
export function deriveGateCheckStatusFromRollup(statusCheckRollup, gateCheckNames) {
|
|
24
|
+
if (!Array.isArray(statusCheckRollup) || statusCheckRollup.length === 0) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const expectedNames = gateCheckNames
|
|
28
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
if (expectedNames.length === 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const matches = statusCheckRollup.filter((entry) => {
|
|
34
|
+
if (typeof entry?.name !== "string" || !entry.name.trim())
|
|
35
|
+
return false;
|
|
36
|
+
return expectedNames.includes(entry.name.trim().toLowerCase());
|
|
37
|
+
});
|
|
38
|
+
if (matches.length === 0) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const normalized = matches.map((entry) => normalizeGateStatus(entry));
|
|
42
|
+
if (normalized.some((status) => status === "pending"))
|
|
43
|
+
return "pending";
|
|
44
|
+
if (normalized.some((status) => status === "failure"))
|
|
45
|
+
return "failure";
|
|
46
|
+
return "success";
|
|
47
|
+
}
|