@h-rig/bundle-default-lifecycle 0.0.6-alpha.157 → 0.0.6-alpha.158
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/src/cli.d.ts +1 -7
- package/dist/src/cli.js +5 -2
- package/dist/src/control-plane/completion-verification.js +1591 -118
- package/dist/src/control-plane/hooks/inject-context.d.ts +2 -0
- package/dist/src/control-plane/hooks/inject-context.js +175 -0
- package/dist/src/control-plane/hooks/shared.d.ts +11 -0
- package/dist/src/control-plane/hooks/shared.js +44 -0
- package/dist/src/control-plane/hooks/submodule-branch.d.ts +2 -0
- package/dist/src/control-plane/hooks/submodule-branch.js +432 -0
- package/dist/src/control-plane/hooks/task-runtime-start.d.ts +2 -0
- package/dist/src/control-plane/hooks/task-runtime-start.js +429 -0
- package/dist/src/control-plane/materialize-task-config.d.ts +29 -0
- package/dist/src/control-plane/materialize-task-config.js +95 -0
- package/dist/src/control-plane/native/git-ops.d.ts +67 -0
- package/dist/src/control-plane/native/git-ops.js +1390 -0
- package/dist/src/control-plane/policy.d.ts +3 -0
- package/dist/src/control-plane/policy.js +226 -0
- package/dist/src/control-plane/pr-automation.d.ts +2 -0
- package/dist/src/control-plane/pr-automation.js +26 -16
- package/dist/src/control-plane/pr-merge-gate-cap.d.ts +10 -0
- package/dist/src/control-plane/pr-merge-gate-cap.js +13 -0
- package/dist/src/control-plane/task-data.d.ts +13 -0
- package/dist/src/control-plane/task-data.js +12 -0
- package/dist/src/control-plane/task-verify.js +131 -59
- package/dist/src/control-plane/verifier.d.ts +1 -3
- package/dist/src/control-plane/verifier.js +133 -57
- package/dist/src/defaultPipeline.d.ts +1 -1
- package/dist/src/defaultPipeline.js +5 -2
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.js +1908 -290
- package/dist/src/native/closeout-runners.js +22 -2
- package/dist/src/native/github-auth-env.d.ts +2 -0
- package/dist/src/native/github-auth-env.js +25 -0
- package/dist/src/native/host-git.d.ts +6 -0
- package/dist/src/native/host-git.js +62 -0
- package/dist/src/native/in-process-closeout.d.ts +1 -3
- package/dist/src/native/in-process-closeout.js +0 -794
- package/dist/src/pipelineCloseout.js +1905 -185
- package/dist/src/plugin.js +2843 -145
- package/dist/src/stages/auto-merge.js +28 -16
- package/dist/src/stages/commit.js +28 -16
- package/dist/src/stages/isolation.d.ts +1 -1
- package/dist/src/stages/isolation.js +5 -3
- package/dist/src/stages/merge-gate.js +35 -3
- package/dist/src/stages/open-pr.js +28 -16
- package/dist/src/stages/push.js +28 -16
- package/dist/src/stages/source-closeout.js +28 -16
- package/package.json +29 -16
- package/dist/src/branch-naming.d.ts +0 -15
- package/dist/src/branch-naming.js +0 -33
- package/dist/src/closeoutEquivalence.d.ts +0 -37
- package/dist/src/closeoutEquivalence.js +0 -78
- package/dist/src/closeoutShadowHarness.d.ts +0 -27
- package/dist/src/closeoutShadowHarness.js +0 -29
|
@@ -1,32 +1,101 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// packages/bundle-default-lifecycle/src/control-plane/task-
|
|
3
|
-
import {
|
|
2
|
+
// packages/bundle-default-lifecycle/src/control-plane/task-data.ts
|
|
3
|
+
import { TASK_DATA_SERVICE_CAPABILITY } from "@rig/contracts";
|
|
4
|
+
import { defineCapability } from "@rig/core/capability";
|
|
5
|
+
import { requireInstalledCapability } from "@rig/core/capability-loaders";
|
|
6
|
+
var TaskDataCap = defineCapability(TASK_DATA_SERVICE_CAPABILITY);
|
|
7
|
+
function taskData() {
|
|
8
|
+
return requireInstalledCapability(TaskDataCap, "task-data capability unavailable: load @rig/task-sources-plugin (default bundle) before running the lifecycle.");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// packages/bundle-default-lifecycle/src/control-plane/verifier.ts
|
|
12
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
13
|
+
import { resolve as resolve2 } from "path";
|
|
14
|
+
import { resolveRuntimeSecrets as resolveRuntimeSecrets2 } from "@rig/core/baked-secrets";
|
|
15
|
+
|
|
16
|
+
// packages/bundle-default-lifecycle/src/control-plane/native/git-ops.ts
|
|
17
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
18
|
+
import { dirname, isAbsolute, resolve } from "path";
|
|
19
|
+
import { loadDotEnvSecrets, resolveRuntimeSecrets } from "@rig/core/baked-secrets";
|
|
20
|
+
import { loadRuntimeContext, loadRuntimeContextFromEnv } from "@rig/core/runtime-context";
|
|
21
|
+
import { nowIso, runCapture as baseRunCapture } from "@rig/core/exec";
|
|
22
|
+
import { resolveCheckoutRoot as resolveMonorepoRoot } from "@rig/core/checkout-root";
|
|
23
|
+
import { getScopeRules } from "@rig/core/scope-rules";
|
|
24
|
+
import { safePathSegment } from "@rig/core/safe-identifiers";
|
|
25
|
+
var TASK_ARTIFACT_STAGE_FALLBACK = new Set([
|
|
26
|
+
"changed-files.txt",
|
|
27
|
+
"contract-changes.md",
|
|
28
|
+
"decision-log.md",
|
|
29
|
+
"git-state.txt",
|
|
30
|
+
"next-actions.md",
|
|
31
|
+
"pr-state.json",
|
|
32
|
+
"task-result.json",
|
|
33
|
+
"validation-summary.json"
|
|
34
|
+
]);
|
|
35
|
+
function readPrMetadata(projectRoot, taskId) {
|
|
36
|
+
const path = resolve(taskData().artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
37
|
+
if (!existsSync(path)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
42
|
+
if (!parsed || typeof parsed !== "object") {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
if (parsed.prs && typeof parsed.prs === "object") {
|
|
46
|
+
return Object.values(parsed.prs).filter(isGitOpenPrResult);
|
|
47
|
+
}
|
|
48
|
+
return isGitOpenPrResult(parsed) ? [parsed] : [];
|
|
49
|
+
} catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function isGitOpenPrResult(value) {
|
|
54
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const record = value;
|
|
58
|
+
return typeof record.url === "string" && typeof record.branch === "string" && typeof record.base === "string" && (record.target === "project" || record.target === "monorepo") && typeof record.repoLabel === "string";
|
|
59
|
+
}
|
|
4
60
|
|
|
5
61
|
// packages/bundle-default-lifecycle/src/control-plane/verifier.ts
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
62
|
+
import { loadRuntimeContextFromEnv as loadRuntimeContextFromEnv2 } from "@rig/core/runtime-context";
|
|
63
|
+
import { nowIso as nowIso2, runCapture } from "@rig/core/exec";
|
|
64
|
+
import { resolveHarnessPaths } from "@rig/core/harness-paths";
|
|
65
|
+
|
|
66
|
+
// packages/bundle-default-lifecycle/src/control-plane/pr-merge-gate-cap.ts
|
|
67
|
+
import { PR_MERGE_GATE } from "@rig/contracts";
|
|
68
|
+
import { defineCapability as defineCapability2 } from "@rig/core/capability";
|
|
69
|
+
import { resolvePluginHost } from "@rig/core/project-plugins";
|
|
70
|
+
var PrMergeGateCap = defineCapability2(PR_MERGE_GATE);
|
|
71
|
+
async function resolvePrMergeGateService(projectRoot) {
|
|
72
|
+
const { host } = await resolvePluginHost(projectRoot);
|
|
73
|
+
return PrMergeGateCap.require(host);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// packages/bundle-default-lifecycle/src/control-plane/verifier.ts
|
|
77
|
+
var mergeGateHolder = null;
|
|
78
|
+
async function ensureMergeGate(projectRoot) {
|
|
79
|
+
mergeGateHolder = await resolvePrMergeGateService(projectRoot);
|
|
80
|
+
return mergeGateHolder;
|
|
81
|
+
}
|
|
82
|
+
function mg() {
|
|
83
|
+
if (!mergeGateHolder) {
|
|
84
|
+
throw new Error("PR merge-gate capability not resolved (verifyTask must run first).");
|
|
85
|
+
}
|
|
86
|
+
return mergeGateHolder;
|
|
87
|
+
}
|
|
20
88
|
async function verifyTask(options) {
|
|
89
|
+
await ensureMergeGate(options.projectRoot);
|
|
21
90
|
const paths = resolveHarnessPaths(options.projectRoot);
|
|
22
91
|
const taskId = options.taskId;
|
|
23
|
-
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
24
|
-
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
25
|
-
|
|
26
|
-
const validationSummaryPath =
|
|
27
|
-
const reviewFeedbackPath =
|
|
28
|
-
const reviewStatePath =
|
|
29
|
-
const greptileRawPath =
|
|
92
|
+
const normalizedTaskId = taskData().lookupTask(options.projectRoot, taskId);
|
|
93
|
+
const artifactDir = taskData().artifactDirForId(options.projectRoot, taskId);
|
|
94
|
+
mkdirSync2(artifactDir, { recursive: true });
|
|
95
|
+
const validationSummaryPath = resolve2(artifactDir, "validation-summary.json");
|
|
96
|
+
const reviewFeedbackPath = resolve2(artifactDir, "review-feedback.md");
|
|
97
|
+
const reviewStatePath = resolve2(artifactDir, "review-state.json");
|
|
98
|
+
const greptileRawPath = resolve2(artifactDir, "review-greptile-raw.json");
|
|
30
99
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
31
100
|
const prState = prStates[0] || null;
|
|
32
101
|
const localReasons = [];
|
|
@@ -38,7 +107,7 @@ async function verifyTask(options) {
|
|
|
38
107
|
if (!normalizedTaskId && !await hasConfiguredSourceTask(options.projectRoot, taskId)) {
|
|
39
108
|
localReasons.push(`[Task Config] Unknown task id '${taskId}' in task-config or configured task source.`);
|
|
40
109
|
}
|
|
41
|
-
if (!
|
|
110
|
+
if (!existsSync2(validationSummaryPath)) {
|
|
42
111
|
localReasons.push(`[Artifact Quality] validation-summary.json not found at ${validationSummaryPath}.`);
|
|
43
112
|
} else {
|
|
44
113
|
const summary = await parseValidationSummary(validationSummaryPath);
|
|
@@ -47,13 +116,13 @@ async function verifyTask(options) {
|
|
|
47
116
|
}
|
|
48
117
|
}
|
|
49
118
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
50
|
-
const requiredPath =
|
|
51
|
-
if (!
|
|
119
|
+
const requiredPath = resolve2(artifactDir, file);
|
|
120
|
+
if (!existsSync2(requiredPath)) {
|
|
52
121
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
53
122
|
}
|
|
54
123
|
}
|
|
55
|
-
const taskResultPath =
|
|
56
|
-
if (
|
|
124
|
+
const taskResultPath = resolve2(artifactDir, "task-result.json");
|
|
125
|
+
if (existsSync2(taskResultPath)) {
|
|
57
126
|
const taskResult = await readJsonFile(taskResultPath);
|
|
58
127
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
59
128
|
if (artifactStatus === "partial") {
|
|
@@ -66,8 +135,8 @@ async function verifyTask(options) {
|
|
|
66
135
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
67
136
|
}
|
|
68
137
|
}
|
|
69
|
-
const nextActionsPath =
|
|
70
|
-
if (
|
|
138
|
+
const nextActionsPath = resolve2(artifactDir, "next-actions.md");
|
|
139
|
+
if (existsSync2(nextActionsPath)) {
|
|
71
140
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
72
141
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
73
142
|
localReasons.push("[Artifact Quality] next-actions.md still contains scaffold placeholder text. Replace with real recommendations.");
|
|
@@ -98,7 +167,7 @@ async function verifyTask(options) {
|
|
|
98
167
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
99
168
|
}
|
|
100
169
|
if (persistArtifacts && ai.rawResponse) {
|
|
101
|
-
|
|
170
|
+
writeFileSync2(greptileRawPath, `${ai.rawResponse}
|
|
102
171
|
`, "utf-8");
|
|
103
172
|
}
|
|
104
173
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -220,15 +289,15 @@ function nextActionsIndicateRemainingScope(content) {
|
|
|
220
289
|
return /^\s*- \[ \]/m.test(normalized) || /\b(remaining scope|still need|needs? to be implemented|not yet implemented|not implemented|follow[- ]?up required|blocked by|blocker:)\b/i.test(lower);
|
|
221
290
|
}
|
|
222
291
|
async function hasConfiguredSourceTask(projectRoot, taskId) {
|
|
223
|
-
return readConfiguredTaskSourceTask(projectRoot, taskId).then((result) => result.task !== null).catch(() => false);
|
|
292
|
+
return taskData().readConfiguredTaskSourceTask(projectRoot, taskId).then((result) => result.task !== null).catch(() => false);
|
|
224
293
|
}
|
|
225
294
|
function resolveGithubSourceIssueId(projectRoot, taskId) {
|
|
226
|
-
const fromRuntime =
|
|
295
|
+
const fromRuntime = loadRuntimeContextFromEnv2()?.sourceTask?.sourceIssueId;
|
|
227
296
|
if (typeof fromRuntime === "string" && isGithubSourceIssueId(fromRuntime)) {
|
|
228
297
|
return fromRuntime;
|
|
229
298
|
}
|
|
230
299
|
try {
|
|
231
|
-
const taskConfig = readTaskConfig(projectRoot);
|
|
300
|
+
const taskConfig = taskData().readTaskConfig(projectRoot);
|
|
232
301
|
const entry = taskConfig[taskId];
|
|
233
302
|
const sourceIssueId = typeof entry?.sourceIssueId === "string" ? entry.sourceIssueId : typeof entry?.source_issue_id === "string" ? entry.source_issue_id : null;
|
|
234
303
|
if (sourceIssueId && isGithubSourceIssueId(sourceIssueId)) {
|
|
@@ -299,14 +368,15 @@ function loadGithubPullRequestCloseoutSnapshot(projectRoot, prState) {
|
|
|
299
368
|
"--json",
|
|
300
369
|
"state,isDraft,mergeable,mergeStateStatus,reviewDecision,title,body,statusCheckRollup"
|
|
301
370
|
]);
|
|
371
|
+
const isDraft = booleanField(view, "isDraft");
|
|
302
372
|
return {
|
|
303
|
-
state
|
|
304
|
-
isDraft
|
|
305
|
-
mergeable
|
|
306
|
-
mergeStateStatus
|
|
307
|
-
reviewDecision
|
|
308
|
-
title
|
|
309
|
-
body
|
|
373
|
+
...objectField("state", stringField(view, "state")),
|
|
374
|
+
...isDraft !== undefined ? { isDraft } : {},
|
|
375
|
+
...objectField("mergeable", stringField(view, "mergeable")),
|
|
376
|
+
...objectField("mergeStateStatus", stringField(view, "mergeStateStatus")),
|
|
377
|
+
...objectField("reviewDecision", stringField(view, "reviewDecision")),
|
|
378
|
+
...objectField("title", stringField(view, "title")),
|
|
379
|
+
...objectField("body", stringField(view, "body")),
|
|
310
380
|
statusCheckRollup: statusCheckRollupField(view, "statusCheckRollup"),
|
|
311
381
|
reviewThreads: loadGithubReviewThreads(projectRoot, repoName, prNumber)
|
|
312
382
|
};
|
|
@@ -381,6 +451,9 @@ function stringField(record, key) {
|
|
|
381
451
|
const value = record[key];
|
|
382
452
|
return typeof value === "string" ? value : undefined;
|
|
383
453
|
}
|
|
454
|
+
function objectField(key, value) {
|
|
455
|
+
return value === undefined ? {} : { [key]: value };
|
|
456
|
+
}
|
|
384
457
|
function booleanField(record, key) {
|
|
385
458
|
const value = record[key];
|
|
386
459
|
return typeof value === "boolean" ? value : undefined;
|
|
@@ -437,7 +510,7 @@ function isAcceptedValidationSummary(summary) {
|
|
|
437
510
|
return summary.status === "skipped" && summary.total === 0 && summary.failed === 0;
|
|
438
511
|
}
|
|
439
512
|
async function loadReviewMode(reviewProfilePath, fallback) {
|
|
440
|
-
const parsed =
|
|
513
|
+
const parsed = existsSync2(reviewProfilePath) ? await readJsonFile(reviewProfilePath) : null;
|
|
441
514
|
const mode = parsed?.mode;
|
|
442
515
|
if (mode === "off" || mode === "advisory" || mode === "required") {
|
|
443
516
|
return mode;
|
|
@@ -448,7 +521,7 @@ async function loadReviewMode(reviewProfilePath, fallback) {
|
|
|
448
521
|
return "advisory";
|
|
449
522
|
}
|
|
450
523
|
async function loadReviewProvider(reviewProfilePath, fallback) {
|
|
451
|
-
const parsed =
|
|
524
|
+
const parsed = existsSync2(reviewProfilePath) ? await readJsonFile(reviewProfilePath) : null;
|
|
452
525
|
const provider = parsed?.provider;
|
|
453
526
|
if (typeof provider === "string" && provider.trim().length > 0) {
|
|
454
527
|
return provider;
|
|
@@ -471,7 +544,7 @@ function resolveRepoSlug(projectRoot) {
|
|
|
471
544
|
async function runGreptileReview(options) {
|
|
472
545
|
const reasons = [];
|
|
473
546
|
const warnings = [];
|
|
474
|
-
const secrets =
|
|
547
|
+
const secrets = resolveRuntimeSecrets2(process.env);
|
|
475
548
|
const apiKey = secrets.GREPTILE_API_KEY || "";
|
|
476
549
|
const apiBase = secrets.GREPTILE_API_BASE || "https://api.greptile.com/mcp";
|
|
477
550
|
const remote = secrets.GREPTILE_REMOTE || "github";
|
|
@@ -607,7 +680,7 @@ function writeFeedbackFile(options) {
|
|
|
607
680
|
if (options.aiRawFeedback) {
|
|
608
681
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
609
682
|
}
|
|
610
|
-
|
|
683
|
+
writeFileSync2(options.output, `${lines.join(`
|
|
611
684
|
`)}
|
|
612
685
|
`, "utf-8");
|
|
613
686
|
}
|
|
@@ -622,9 +695,9 @@ function writeReviewStateFile(options) {
|
|
|
622
695
|
local_reasons: options.localReasons,
|
|
623
696
|
ai_reasons: options.aiReasons,
|
|
624
697
|
ai_warnings: options.aiWarnings,
|
|
625
|
-
updated_at:
|
|
698
|
+
updated_at: nowIso2()
|
|
626
699
|
};
|
|
627
|
-
|
|
700
|
+
writeFileSync2(options.output, `${JSON.stringify(payload, null, 2)}
|
|
628
701
|
`, "utf-8");
|
|
629
702
|
}
|
|
630
703
|
async function runGreptileReviewForPr(options) {
|
|
@@ -649,7 +722,6 @@ async function runGreptileReviewForPr(options) {
|
|
|
649
722
|
taskId: options.taskId,
|
|
650
723
|
prState: options.prState,
|
|
651
724
|
reviewMode: options.reviewMode,
|
|
652
|
-
infrastructureError: undefined,
|
|
653
725
|
pollAttempts: options.pollAttempts,
|
|
654
726
|
pollIntervalMs: options.pollIntervalMs
|
|
655
727
|
});
|
|
@@ -777,7 +849,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
777
849
|
});
|
|
778
850
|
const actionableComments = filterActionableGreptileComments(commentsPayload.comments || []);
|
|
779
851
|
const reviewBody = reviewDetails.codeReview?.body || "";
|
|
780
|
-
const score = parseGreptileScore(reviewBody);
|
|
852
|
+
const score = mg().parseGreptileScore(reviewBody);
|
|
781
853
|
const feedback = [
|
|
782
854
|
`## ${options.prState.repoLabel || repoName} PR Review`,
|
|
783
855
|
"",
|
|
@@ -785,7 +857,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
785
857
|
`- Review ID: ${selectedReview.id}`,
|
|
786
858
|
`- Status: ${selectedReview.status}`,
|
|
787
859
|
"",
|
|
788
|
-
reviewBody ? stripHtml(reviewBody).trim() : "Greptile completed without summary body."
|
|
860
|
+
reviewBody ? mg().stripHtml(reviewBody).trim() : "Greptile completed without summary body."
|
|
789
861
|
].filter(Boolean).join(`
|
|
790
862
|
`);
|
|
791
863
|
if (actionableComments.length > 0) {
|
|
@@ -806,7 +878,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
806
878
|
}
|
|
807
879
|
};
|
|
808
880
|
}
|
|
809
|
-
const blockerScanBody = stripHtml(reviewBody).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
|
|
881
|
+
const blockerScanBody = mg().stripHtml(reviewBody).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
|
|
810
882
|
if (/not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this|\breject(?:ed|ion)?\b|\bskip(?:ped)?\b|status\s*:\s*(?:reject(?:ed)?|skip(?:ped)?|failed)/i.test(blockerScanBody)) {
|
|
811
883
|
reasons.push(`[AI Review] ${repoName}#${prNumber} summary indicates the PR is not safe to merge.`);
|
|
812
884
|
return {
|
|
@@ -854,7 +926,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
854
926
|
status: selectedReview.status
|
|
855
927
|
}]
|
|
856
928
|
});
|
|
857
|
-
strictGate =
|
|
929
|
+
strictGate = mg().evaluateGate(strictEvidence);
|
|
858
930
|
} catch (error) {
|
|
859
931
|
reasons.push(`[AI Review] Strict Greptile evidence collection failed for ${repoName}#${prNumber}: ${error instanceof Error ? error.message : String(error)}`);
|
|
860
932
|
return {
|
|
@@ -981,7 +1053,7 @@ async function runGithubGreptileFallbackReviewForPr(options) {
|
|
|
981
1053
|
fallbackReview?.html_url ? `- Review: ${fallbackReview.html_url}` : "",
|
|
982
1054
|
fallbackReview?.state ? `- Status: ${fallbackReview.state}` : "",
|
|
983
1055
|
"",
|
|
984
|
-
fallbackReview?.body?.trim() ? stripHtml(fallbackReview.body).trim() : "Greptile MCP was unavailable, so verification used GitHub review threads instead."
|
|
1056
|
+
fallbackReview?.body?.trim() ? mg().stripHtml(fallbackReview.body).trim() : "Greptile MCP was unavailable, so verification used GitHub review threads instead."
|
|
985
1057
|
].filter(Boolean).join(`
|
|
986
1058
|
`);
|
|
987
1059
|
const warnings = buildGithubGreptileFallbackWarnings(options);
|
|
@@ -1004,7 +1076,7 @@ async function runGithubGreptileFallbackReviewForPr(options) {
|
|
|
1004
1076
|
taskId: options.taskId,
|
|
1005
1077
|
prUrl
|
|
1006
1078
|
});
|
|
1007
|
-
strictGate =
|
|
1079
|
+
strictGate = mg().evaluateGate(strictEvidence);
|
|
1008
1080
|
} catch (error) {
|
|
1009
1081
|
return {
|
|
1010
1082
|
verdict: "REJECT",
|
|
@@ -1229,7 +1301,7 @@ function loadGithubPullRequestState(projectRoot, repoName, prNumber) {
|
|
|
1229
1301
|
]);
|
|
1230
1302
|
return {
|
|
1231
1303
|
state: response.state || "",
|
|
1232
|
-
merged: response.merged,
|
|
1304
|
+
...response.merged !== undefined ? { merged: response.merged } : {},
|
|
1233
1305
|
merged_at: response.merged_at ?? null
|
|
1234
1306
|
};
|
|
1235
1307
|
}
|
|
@@ -1258,7 +1330,7 @@ function runGhJson(projectRoot, args) {
|
|
|
1258
1330
|
}
|
|
1259
1331
|
}
|
|
1260
1332
|
async function collectStrictPrEvidenceForVerifier(input) {
|
|
1261
|
-
return
|
|
1333
|
+
return mg().collectEvidence({
|
|
1262
1334
|
projectRoot: input.projectRoot,
|
|
1263
1335
|
prUrl: input.prUrl,
|
|
1264
1336
|
taskId: input.taskId,
|
|
@@ -1423,7 +1495,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
1423
1495
|
}
|
|
1424
1496
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
1425
1497
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
1426
|
-
if (prState.target === "monorepo" && runtimeWorkspace &&
|
|
1498
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync2(resolve2(runtimeWorkspace, ".git"))) {
|
|
1427
1499
|
return runtimeWorkspace;
|
|
1428
1500
|
}
|
|
1429
1501
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -1437,7 +1509,7 @@ function isCommitAncestorOfPrHead(projectRoot, prState, reviewedCommit, headComm
|
|
|
1437
1509
|
return runCapture(["git", "-C", repoRoot, "merge-base", "--is-ancestor", reviewedCommit, headCommit], projectRoot).exitCode === 0;
|
|
1438
1510
|
}
|
|
1439
1511
|
function summarizeComment(input) {
|
|
1440
|
-
const text = stripHtml(input).replace(/\s+/g, " ").trim();
|
|
1512
|
+
const text = mg().stripHtml(input).replace(/\s+/g, " ").trim();
|
|
1441
1513
|
return text.length > 160 ? `${text.slice(0, 157)}...` : text;
|
|
1442
1514
|
}
|
|
1443
1515
|
function asGreptileInfrastructureWarning(reason) {
|
|
@@ -1455,7 +1527,7 @@ function isAiReviewApproved(input) {
|
|
|
1455
1527
|
|
|
1456
1528
|
// packages/bundle-default-lifecycle/src/control-plane/task-verify.ts
|
|
1457
1529
|
async function taskVerify(projectRoot, taskId) {
|
|
1458
|
-
const activeTask = taskId || currentTaskId(projectRoot);
|
|
1530
|
+
const activeTask = taskId || taskData().currentTaskId(projectRoot);
|
|
1459
1531
|
if (!activeTask) {
|
|
1460
1532
|
throw new Error("No active task.");
|
|
1461
1533
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { parseGreptileScore } from "@rig/pr-review-plugin";
|
|
2
1
|
export type VerifyOutcome = {
|
|
3
2
|
approved: boolean;
|
|
4
3
|
localReasons: string[];
|
|
@@ -104,7 +103,7 @@ declare function shouldPreferGithubGreptileFallback(prState: {
|
|
|
104
103
|
declare function pickRelevantGithubGreptileReview(reviews: GithubPullRequestReview[], expectedHeadSha: string): GithubPullRequestReview | null;
|
|
105
104
|
declare function pickLatestGithubGreptileReview(reviews: GithubPullRequestReview[]): GithubPullRequestReview | null;
|
|
106
105
|
export declare function evaluatePullRequestCiChecks(checks: GithubStatusCheckRollupItem[], repoName: string, prNumber: number, options?: {
|
|
107
|
-
mergeStateStatus?: string;
|
|
106
|
+
mergeStateStatus?: string | undefined;
|
|
108
107
|
}): {
|
|
109
108
|
verdict: "APPROVE" | "REJECT" | "SKIP";
|
|
110
109
|
reasons: string[];
|
|
@@ -125,7 +124,6 @@ export declare const __testOnly: {
|
|
|
125
124
|
filterActionableGithubGreptileThreads: typeof filterActionableGithubGreptileThreads;
|
|
126
125
|
isGithubGreptileCheckApproved: typeof isGithubGreptileCheckApproved;
|
|
127
126
|
isAiReviewApproved: typeof isAiReviewApproved;
|
|
128
|
-
parseGreptileScore: typeof parseGreptileScore;
|
|
129
127
|
pickLatestGithubGreptileReview: typeof pickLatestGithubGreptileReview;
|
|
130
128
|
pickRelevantGithubGreptileReview: typeof pickRelevantGithubGreptileReview;
|
|
131
129
|
resolveGreptileRequestTimeoutMs: typeof resolveGreptileRequestTimeoutMs;
|