@h-rig/bundle-default-lifecycle 0.0.6-alpha.135 → 0.0.6-alpha.136
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/defaultPipeline.d.ts +17 -1
- package/dist/src/defaultPipeline.js +48 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +267 -101
- package/dist/src/pipelineCloseout.d.ts +17 -0
- package/dist/src/pipelineCloseout.js +465 -0
- package/dist/src/plugin.js +20 -1
- package/dist/src/stages/merge-gate.d.ts +23 -0
- package/dist/src/stages/merge-gate.js +21 -0
- package/package.json +8 -8
- package/dist/src/stagedCloseout.d.ts +0 -7
- package/dist/src/stagedCloseout.js +0 -325
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/bundle-default-lifecycle/src/pipelineCloseout.ts
|
|
3
|
+
import { resolve } from "path";
|
|
4
|
+
import { loadConfig } from "@rig/core/load-config";
|
|
5
|
+
import { createPluginHost } from "@rig/core";
|
|
6
|
+
import { createDefaultKernel } from "@rig/kernel/default-kernel";
|
|
7
|
+
import { buildPluginHostContext } from "@rig/runtime/control-plane/plugin-host-context";
|
|
8
|
+
import {
|
|
9
|
+
CloseoutValidationError
|
|
10
|
+
} from "@rig/runtime/control-plane/native/in-process-closeout";
|
|
11
|
+
import { taskValidate } from "@rig/runtime/control-plane/native/task-ops";
|
|
12
|
+
|
|
13
|
+
// packages/bundle-default-lifecycle/src/defaultPipeline.ts
|
|
14
|
+
import { resolveKernelStages } from "@rig/kernel/resolver";
|
|
15
|
+
import { createDefaultKernelPlugin } from "@rig/kernel/default-kernel";
|
|
16
|
+
|
|
17
|
+
// packages/bundle-default-lifecycle/src/stages/auto-merge.ts
|
|
18
|
+
import { runRepoDefaultMerge } from "@rig/runtime/control-plane/native/pr-automation";
|
|
19
|
+
|
|
20
|
+
// packages/bundle-default-lifecycle/src/stages/types.ts
|
|
21
|
+
function defineDefaultLifecycleStage(input) {
|
|
22
|
+
return {
|
|
23
|
+
...input,
|
|
24
|
+
protected: input.protected ?? false,
|
|
25
|
+
priority: input.priority ?? 0
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// packages/bundle-default-lifecycle/src/stages/auto-merge.ts
|
|
30
|
+
var autoMergeStage = defineDefaultLifecycleStage({
|
|
31
|
+
id: "auto-merge",
|
|
32
|
+
kind: "transform",
|
|
33
|
+
description: "Merge an approved PR using the repository default merge method through the runtime helper.",
|
|
34
|
+
calls: ["runRepoDefaultMerge"]
|
|
35
|
+
});
|
|
36
|
+
async function runAutoMergeStage(input) {
|
|
37
|
+
await runRepoDefaultMerge(input);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// packages/bundle-default-lifecycle/src/stages/commit.ts
|
|
41
|
+
import { commitRunChanges } from "@rig/runtime/control-plane/native/pr-automation";
|
|
42
|
+
var commitStage = defineDefaultLifecycleStage({
|
|
43
|
+
id: "commit",
|
|
44
|
+
kind: "transform",
|
|
45
|
+
description: "Commit the agent worktree changes using the runtime git closeout helper.",
|
|
46
|
+
calls: ["commitRunChanges"]
|
|
47
|
+
});
|
|
48
|
+
async function runCommitStage(input) {
|
|
49
|
+
return await commitRunChanges(input);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// packages/bundle-default-lifecycle/src/stages/isolation.ts
|
|
53
|
+
import { ensureAgentRuntime } from "@rig/runtime/control-plane/runtime/isolation";
|
|
54
|
+
var isolationStage = defineDefaultLifecycleStage({
|
|
55
|
+
id: "isolation",
|
|
56
|
+
kind: "transform",
|
|
57
|
+
description: "Provision the isolated runtime worktree through the runtime isolation subsystem.",
|
|
58
|
+
calls: ["ensureAgentRuntime"],
|
|
59
|
+
protected: true
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// packages/bundle-default-lifecycle/src/stages/journal-append.ts
|
|
63
|
+
var journalAppendStage = defineDefaultLifecycleStage({
|
|
64
|
+
id: "journal-append",
|
|
65
|
+
kind: "observe",
|
|
66
|
+
description: "Record resolved pipeline and per-stage outcome entries through the kernel journal capability.",
|
|
67
|
+
calls: ["journalCapability.append"],
|
|
68
|
+
protected: true
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// packages/bundle-default-lifecycle/src/stages/merge-gate.ts
|
|
72
|
+
import {
|
|
73
|
+
runStrictPrMergeGate
|
|
74
|
+
} from "@rig/runtime/control-plane/native/pr-review-gate";
|
|
75
|
+
var mergeGateStage = defineDefaultLifecycleStage({
|
|
76
|
+
id: "merge-gate",
|
|
77
|
+
kind: "gate",
|
|
78
|
+
description: "Enforce GitHub review state, required checks, and configured review gates through runtime PR automation.",
|
|
79
|
+
calls: ["runStrictPrMergeGate"],
|
|
80
|
+
protected: true
|
|
81
|
+
});
|
|
82
|
+
async function runMergeGateStage(input) {
|
|
83
|
+
return await runStrictPrMergeGate({
|
|
84
|
+
projectRoot: input.projectRoot,
|
|
85
|
+
prUrl: input.prUrl,
|
|
86
|
+
taskId: input.taskId,
|
|
87
|
+
runId: input.runId,
|
|
88
|
+
cycle: input.cycle,
|
|
89
|
+
command: input.command,
|
|
90
|
+
...input.artifactRoot !== undefined ? { artifactRoot: input.artifactRoot } : {},
|
|
91
|
+
...input.allowedFailures !== undefined ? { allowedFailures: input.allowedFailures } : {},
|
|
92
|
+
...input.greptileApi !== undefined ? { greptileApi: input.greptileApi } : {},
|
|
93
|
+
...input.final !== undefined ? { final: input.final } : {},
|
|
94
|
+
...input.requireGreptile !== undefined ? { requireGreptile: input.requireGreptile } : {}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// packages/bundle-default-lifecycle/src/stages/open-pr.ts
|
|
99
|
+
import { runPrAutomation } from "@rig/runtime/control-plane/native/pr-automation";
|
|
100
|
+
var openPrStage = defineDefaultLifecycleStage({
|
|
101
|
+
id: "open-pr",
|
|
102
|
+
kind: "transform",
|
|
103
|
+
description: "Open or reuse the closeout PR through the existing runtime PR automation seam.",
|
|
104
|
+
calls: ["runPrAutomation"]
|
|
105
|
+
});
|
|
106
|
+
async function runOpenPrStage(input) {
|
|
107
|
+
return await runPrAutomation({
|
|
108
|
+
projectRoot: input.workspace,
|
|
109
|
+
taskId: input.taskId,
|
|
110
|
+
runId: input.runId,
|
|
111
|
+
branch: input.branch,
|
|
112
|
+
sourceTask: input.sourceTask ? { title: typeof input.sourceTask.title === "string" ? input.sourceTask.title : null } : null,
|
|
113
|
+
command: input.command,
|
|
114
|
+
gitCommand: input.gitCommand,
|
|
115
|
+
steerPi: input.steerPi,
|
|
116
|
+
...input.config ? { config: input.config } : {},
|
|
117
|
+
...input.artifactRoot !== undefined ? { artifactRoot: input.artifactRoot } : {},
|
|
118
|
+
...input.greptileApi !== undefined ? { greptileApi: input.greptileApi } : {},
|
|
119
|
+
...input.lifecycle !== undefined ? { lifecycle: input.lifecycle } : {},
|
|
120
|
+
...input.uploadedSnapshot !== undefined ? { uploadedSnapshot: input.uploadedSnapshot } : {}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// packages/bundle-default-lifecycle/src/stages/push.ts
|
|
125
|
+
import { pushBranchSyncedWithOrigin } from "@rig/runtime/control-plane/native/pr-automation";
|
|
126
|
+
var pushStage = defineDefaultLifecycleStage({
|
|
127
|
+
id: "push",
|
|
128
|
+
kind: "transform",
|
|
129
|
+
description: "Synchronize and push the task branch using the runtime closeout git helper.",
|
|
130
|
+
calls: ["pushBranchSyncedWithOrigin"]
|
|
131
|
+
});
|
|
132
|
+
async function runPushStage(input) {
|
|
133
|
+
await pushBranchSyncedWithOrigin(input);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// packages/bundle-default-lifecycle/src/stages/source-closeout.ts
|
|
137
|
+
import { closeIssueAfterMergedPr } from "@rig/runtime/control-plane/native/pr-automation";
|
|
138
|
+
var sourceCloseoutStage = defineDefaultLifecycleStage({
|
|
139
|
+
id: "source-closeout",
|
|
140
|
+
kind: "transform",
|
|
141
|
+
description: "Reflect the merged PR into the task source using the existing runtime closeout helper.",
|
|
142
|
+
calls: ["closeIssueAfterMergedPr"]
|
|
143
|
+
});
|
|
144
|
+
async function runSourceCloseoutStage(input) {
|
|
145
|
+
if (input.pr.status !== "merged" || !input.pr.prUrl)
|
|
146
|
+
return;
|
|
147
|
+
await closeIssueAfterMergedPr({
|
|
148
|
+
projectRoot: input.projectRoot,
|
|
149
|
+
taskId: input.taskId,
|
|
150
|
+
runId: input.runId,
|
|
151
|
+
prUrl: input.pr.prUrl,
|
|
152
|
+
updateTaskSource: input.updateTaskSource,
|
|
153
|
+
...input.sourceTask !== undefined ? { sourceTask: input.sourceTask } : {}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// packages/bundle-default-lifecycle/src/stages/validate.ts
|
|
158
|
+
var validateStage = defineDefaultLifecycleStage({
|
|
159
|
+
id: "validate",
|
|
160
|
+
kind: "transform",
|
|
161
|
+
description: "Run plugin-host validators against the isolated worktree before closeout side effects.",
|
|
162
|
+
calls: ["taskValidate"]
|
|
163
|
+
});
|
|
164
|
+
async function runValidateStage(input, runner) {
|
|
165
|
+
return await runner(input);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// packages/bundle-default-lifecycle/src/stages/verify.ts
|
|
169
|
+
var verifyStage = defineDefaultLifecycleStage({
|
|
170
|
+
id: "verify",
|
|
171
|
+
kind: "gate",
|
|
172
|
+
description: "Run the local verifier preflight and block closeout when it rejects the worktree.",
|
|
173
|
+
calls: ["verifierPreflight"]
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// packages/bundle-default-lifecycle/src/defaultPipeline.ts
|
|
177
|
+
var DEFAULT_STAGE_AFTER = {
|
|
178
|
+
verify: ["validate"],
|
|
179
|
+
commit: ["verify"],
|
|
180
|
+
push: ["commit"],
|
|
181
|
+
"open-pr": ["push"],
|
|
182
|
+
"merge-gate": ["open-pr"],
|
|
183
|
+
"auto-merge": ["merge-gate"],
|
|
184
|
+
"source-closeout": ["auto-merge"],
|
|
185
|
+
isolation: ["source-closeout"],
|
|
186
|
+
"journal-append": ["isolation"]
|
|
187
|
+
};
|
|
188
|
+
function withDefaultAnchors(stage) {
|
|
189
|
+
const after = DEFAULT_STAGE_AFTER[stage.id];
|
|
190
|
+
return after ? { ...stage, after } : stage;
|
|
191
|
+
}
|
|
192
|
+
var defaultLifecycleStages = [
|
|
193
|
+
validateStage,
|
|
194
|
+
verifyStage,
|
|
195
|
+
commitStage,
|
|
196
|
+
pushStage,
|
|
197
|
+
openPrStage,
|
|
198
|
+
mergeGateStage,
|
|
199
|
+
autoMergeStage,
|
|
200
|
+
sourceCloseoutStage,
|
|
201
|
+
isolationStage,
|
|
202
|
+
journalAppendStage
|
|
203
|
+
].map(withDefaultAnchors);
|
|
204
|
+
function resolveDefaultLifecycle(input = {}) {
|
|
205
|
+
const grants = { protectedStageGrants: input.protectedStageGrants ?? [] };
|
|
206
|
+
return resolveKernelStages(defaultLifecycleStages, input.mutations ?? [], grants);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// packages/bundle-default-lifecycle/src/pipelineCloseout.ts
|
|
210
|
+
function cleanString(value) {
|
|
211
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
212
|
+
}
|
|
213
|
+
function closeoutOutcome(status) {
|
|
214
|
+
switch (status) {
|
|
215
|
+
case "completed":
|
|
216
|
+
return "completed";
|
|
217
|
+
case "failed":
|
|
218
|
+
case "needs-attention":
|
|
219
|
+
return "failed";
|
|
220
|
+
case "pending":
|
|
221
|
+
case "running":
|
|
222
|
+
return "started";
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async function loadRigAutomationConfig(projectRoot) {
|
|
226
|
+
try {
|
|
227
|
+
return await loadConfig(projectRoot);
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function runRigProjectValidation({ projectRoot, taskId }) {
|
|
233
|
+
const pluginHostCtx = await buildPluginHostContext(projectRoot);
|
|
234
|
+
return taskValidate(projectRoot, taskId, pluginHostCtx?.validatorRegistry ?? undefined);
|
|
235
|
+
}
|
|
236
|
+
function shouldAttemptRigMerge(config) {
|
|
237
|
+
const mode = config.merge?.mode;
|
|
238
|
+
return mode !== "off" && mode !== "pr-ready";
|
|
239
|
+
}
|
|
240
|
+
async function loadPluginStageContributions(projectRoot) {
|
|
241
|
+
try {
|
|
242
|
+
const config = await loadConfig(projectRoot);
|
|
243
|
+
const host = createPluginHost(config.plugins ?? []);
|
|
244
|
+
return { executors: host.listStageExecutors(), mutations: host.listStageMutations() };
|
|
245
|
+
} catch {
|
|
246
|
+
return { executors: {}, mutations: [] };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async function runPipelineCloseout(input) {
|
|
250
|
+
const taskId = cleanString(input.taskId);
|
|
251
|
+
if (!taskId) {
|
|
252
|
+
throw new Error("Pipeline closeout requires a task id.");
|
|
253
|
+
}
|
|
254
|
+
const loadedConfig = input.config ?? await loadRigAutomationConfig(input.projectRoot);
|
|
255
|
+
const prMode = loadedConfig?.pr?.mode ?? "off";
|
|
256
|
+
const reviewProvider = loadedConfig?.review?.provider ?? "github";
|
|
257
|
+
const effectiveConfig = {
|
|
258
|
+
...loadedConfig ?? {},
|
|
259
|
+
pr: { ...loadedConfig?.pr ?? {}, mode: prMode },
|
|
260
|
+
review: { ...loadedConfig?.review ?? {}, provider: reviewProvider }
|
|
261
|
+
};
|
|
262
|
+
const openOnlyConfig = {
|
|
263
|
+
...effectiveConfig,
|
|
264
|
+
merge: { ...effectiveConfig.merge ?? {}, mode: "pr-ready" }
|
|
265
|
+
};
|
|
266
|
+
const shouldMerge = shouldAttemptRigMerge(effectiveConfig);
|
|
267
|
+
const workspace = input.workspace;
|
|
268
|
+
const artifactRoot = input.artifactRoot ?? resolve(input.projectRoot, "artifacts", taskId);
|
|
269
|
+
const journal = async (phase, status, detail) => {
|
|
270
|
+
await input.journalPhase(phase, closeoutOutcome(status), detail ?? null);
|
|
271
|
+
};
|
|
272
|
+
if (prMode === "off" || prMode === "ask") {
|
|
273
|
+
const reason = prMode === "ask" ? "PR creation awaits operator approval." : "PR automation disabled.";
|
|
274
|
+
await input.reflect("under_review", reason);
|
|
275
|
+
await journal("completed", "completed", reason);
|
|
276
|
+
return {
|
|
277
|
+
mode: "pipeline",
|
|
278
|
+
pipelineStageIds: [...resolveDefaultLifecycle().order],
|
|
279
|
+
result: { status: "skipped", iterations: 0, feedback: [] }
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const state = {
|
|
283
|
+
branch: input.branch,
|
|
284
|
+
validationPassed: false,
|
|
285
|
+
committed: false,
|
|
286
|
+
pushed: false,
|
|
287
|
+
prUrl: null,
|
|
288
|
+
prReady: false,
|
|
289
|
+
pr: null,
|
|
290
|
+
gate: null,
|
|
291
|
+
mergeGate: null,
|
|
292
|
+
merged: false,
|
|
293
|
+
iterations: 0,
|
|
294
|
+
feedback: [],
|
|
295
|
+
blockedDetail: null
|
|
296
|
+
};
|
|
297
|
+
const cont = (ctx2) => ({ kind: "continue", ctx: ctx2 });
|
|
298
|
+
const executors = {
|
|
299
|
+
isolation: (ctx2) => cont(ctx2),
|
|
300
|
+
validate: async (ctx2) => {
|
|
301
|
+
await input.onValidationStart?.();
|
|
302
|
+
await journal("queued", "running", `Validating task ${taskId} before closeout.`);
|
|
303
|
+
let passed = false;
|
|
304
|
+
try {
|
|
305
|
+
passed = await runValidateStage({ projectRoot: input.projectRoot, taskId }, input.runValidation ?? runRigProjectValidation);
|
|
306
|
+
} catch (error) {
|
|
307
|
+
const detail = `Rig validation failed before closeout: ${error instanceof Error ? error.message : String(error)}`;
|
|
308
|
+
await input.reflect("needs_attention", "Rig validation failed before closeout; commit/push/PR automation is blocked.", { errorText: detail });
|
|
309
|
+
throw new CloseoutValidationError(detail);
|
|
310
|
+
}
|
|
311
|
+
if (!passed) {
|
|
312
|
+
const detail = `Rig validation failed for task ${taskId}; closeout blocked before commit.`;
|
|
313
|
+
await input.reflect("needs_attention", "Rig validation failed before closeout; commit/push/PR automation is blocked.", { errorText: detail });
|
|
314
|
+
throw new CloseoutValidationError(detail);
|
|
315
|
+
}
|
|
316
|
+
state.validationPassed = true;
|
|
317
|
+
await journal("queued", "completed", `Validation passed for task ${taskId}.`);
|
|
318
|
+
const workspaceBranch = await input.gitCommand(["rev-parse", "--abbrev-ref", "HEAD"], { cwd: workspace });
|
|
319
|
+
const currentWorkspaceBranch = workspaceBranch.exitCode === 0 ? cleanString(workspaceBranch.stdout) : null;
|
|
320
|
+
if (currentWorkspaceBranch && currentWorkspaceBranch !== "HEAD" && currentWorkspaceBranch !== state.branch) {
|
|
321
|
+
state.branch = currentWorkspaceBranch;
|
|
322
|
+
}
|
|
323
|
+
return cont(ctx2);
|
|
324
|
+
},
|
|
325
|
+
verify: () => state.validationPassed ? { kind: "allow" } : { kind: "block", reason: "validation did not pass" },
|
|
326
|
+
commit: async (ctx2) => {
|
|
327
|
+
await journal("commit", "running", `Committing changes in ${workspace}.`);
|
|
328
|
+
const committed = await runCommitStage({ cwd: workspace, message: `rig: complete task ${taskId}`, command: input.gitCommand });
|
|
329
|
+
state.committed = committed.committed;
|
|
330
|
+
return cont(ctx2);
|
|
331
|
+
},
|
|
332
|
+
push: async (ctx2) => {
|
|
333
|
+
await journal("push", "running", `Pushing branch ${state.branch}.`);
|
|
334
|
+
await runPushStage({ projectRoot: workspace, branch: state.branch, gitCommand: input.gitCommand });
|
|
335
|
+
state.pushed = true;
|
|
336
|
+
return cont(ctx2);
|
|
337
|
+
},
|
|
338
|
+
"open-pr": async (ctx2) => {
|
|
339
|
+
await journal("pr-review-merge", "running", `Opening a pull request for ${state.branch}.`);
|
|
340
|
+
const pr = await runOpenPrStage({
|
|
341
|
+
...input,
|
|
342
|
+
taskId,
|
|
343
|
+
branch: state.branch,
|
|
344
|
+
artifactRoot,
|
|
345
|
+
config: openOnlyConfig,
|
|
346
|
+
sourceTask: { title: cleanString(input.sourceTask?.title) },
|
|
347
|
+
lifecycle: {
|
|
348
|
+
onPrOpened: async ({ prUrl }) => {
|
|
349
|
+
await journal("pr-opened", "running", prUrl);
|
|
350
|
+
await input.reflect("under_review", "Rig opened a pull request for this task.");
|
|
351
|
+
},
|
|
352
|
+
onFeedback: async ({ feedback }) => {
|
|
353
|
+
await input.reflect("ci_fixing", "Rig is fixing CI/review feedback for this task.", { errorText: feedback.join(`
|
|
354
|
+
`) || null });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
state.pr = pr;
|
|
359
|
+
state.prUrl = pr.prUrl ?? null;
|
|
360
|
+
state.prReady = pr.status === "opened" || pr.status === "merged";
|
|
361
|
+
state.iterations = pr.iterations;
|
|
362
|
+
state.feedback = [...pr.actionableFeedback];
|
|
363
|
+
if (pr.status === "needs_attention") {
|
|
364
|
+
state.blockedDetail = pr.actionableFeedback.join(`
|
|
365
|
+
`) || "PR automation did not produce a mergeable PR.";
|
|
366
|
+
}
|
|
367
|
+
return cont(ctx2);
|
|
368
|
+
},
|
|
369
|
+
"merge-gate": async (ctx2) => {
|
|
370
|
+
if (!shouldMerge || !state.prReady || !state.prUrl) {
|
|
371
|
+
state.mergeGate = state.prReady ? "skipped" : null;
|
|
372
|
+
return state.prReady ? cont(ctx2) : { kind: "block", reason: state.blockedDetail ?? "no mergeable PR to gate" };
|
|
373
|
+
}
|
|
374
|
+
const gate = await runMergeGateStage({
|
|
375
|
+
projectRoot: workspace,
|
|
376
|
+
prUrl: state.prUrl,
|
|
377
|
+
taskId,
|
|
378
|
+
runId: input.runId,
|
|
379
|
+
cycle: 1,
|
|
380
|
+
command: input.command,
|
|
381
|
+
artifactRoot,
|
|
382
|
+
final: true,
|
|
383
|
+
...effectiveConfig.merge?.allowedFailures ? { allowedFailures: effectiveConfig.merge.allowedFailures } : {},
|
|
384
|
+
...input.greptileApi !== undefined ? { greptileApi: input.greptileApi } : {},
|
|
385
|
+
requireGreptile: reviewProvider === "greptile"
|
|
386
|
+
});
|
|
387
|
+
state.gate = gate;
|
|
388
|
+
if (gate.approved) {
|
|
389
|
+
state.mergeGate = "passed";
|
|
390
|
+
return cont(ctx2);
|
|
391
|
+
}
|
|
392
|
+
state.mergeGate = "blocked";
|
|
393
|
+
const detail = gate.actionableFeedback.join(`
|
|
394
|
+
`) || gate.reasons.join("; ") || "merge gate blocked the PR.";
|
|
395
|
+
state.blockedDetail = detail;
|
|
396
|
+
await input.reflect("needs_attention", "Rig needs operator attention before this task can merge.", { errorText: detail });
|
|
397
|
+
await journal("pr-review-merge", "needs-attention", detail);
|
|
398
|
+
return { kind: "block", reason: detail };
|
|
399
|
+
},
|
|
400
|
+
"auto-merge": async (ctx2) => {
|
|
401
|
+
if (!shouldMerge || state.mergeGate !== "passed" || !state.prUrl || !state.gate) {
|
|
402
|
+
return cont(ctx2);
|
|
403
|
+
}
|
|
404
|
+
await journal("merge", "running", state.prUrl);
|
|
405
|
+
await input.reflect("merging", "Rig is merging the pull request for this task.");
|
|
406
|
+
await runAutoMergeStage({ prUrl: state.prUrl, config: effectiveConfig, command: input.command, cwd: workspace, strictGate: state.gate });
|
|
407
|
+
state.merged = true;
|
|
408
|
+
return cont(ctx2);
|
|
409
|
+
},
|
|
410
|
+
"source-closeout": async (ctx2) => {
|
|
411
|
+
if (!state.merged || !state.prUrl)
|
|
412
|
+
return cont(ctx2);
|
|
413
|
+
await journal("close-source", "running", state.prUrl);
|
|
414
|
+
const mergedPr = { ...state.pr ?? { iterations: state.iterations, actionableFeedback: state.feedback }, status: "merged", prUrl: state.prUrl, merged: true };
|
|
415
|
+
await runSourceCloseoutStage({
|
|
416
|
+
projectRoot: input.projectRoot,
|
|
417
|
+
taskId,
|
|
418
|
+
runId: input.runId,
|
|
419
|
+
pr: mergedPr,
|
|
420
|
+
...input.sourceTask !== undefined ? { sourceTask: input.sourceTask } : {},
|
|
421
|
+
updateTaskSource: async () => {
|
|
422
|
+
await input.reflect("closed", "Rig merged the pull request and closed this task source.");
|
|
423
|
+
return { updated: true, taskId, status: "closed", source: "runtime", sourceKind: "runtime" };
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
return cont(ctx2);
|
|
427
|
+
},
|
|
428
|
+
"journal-append": (ctx2) => cont(ctx2)
|
|
429
|
+
};
|
|
430
|
+
const pluginStages = await loadPluginStageContributions(input.projectRoot);
|
|
431
|
+
const kernel = createDefaultKernel({ stageExecutors: { ...executors, ...pluginStages.executors } });
|
|
432
|
+
const resolved = kernel.stageRunner.resolve(defaultLifecycleStages, pluginStages.mutations);
|
|
433
|
+
const ctx = {
|
|
434
|
+
runId: input.runId,
|
|
435
|
+
taskId,
|
|
436
|
+
state,
|
|
437
|
+
metadata: { projectRoot: input.projectRoot, workspace }
|
|
438
|
+
};
|
|
439
|
+
await kernel.stageRunner.runPipeline(input.runId, resolved, ctx);
|
|
440
|
+
const result = mapStateToResult(state);
|
|
441
|
+
if (result.status === "merged" || result.status === "opened") {
|
|
442
|
+
await journal("completed", "completed", result.prUrl ? `${result.status === "merged" ? "PR merged and issue closed" : "PR ready without merge"}: ${result.prUrl}` : result.status);
|
|
443
|
+
}
|
|
444
|
+
return { mode: "pipeline", pipelineStageIds: [...resolved.order], result };
|
|
445
|
+
}
|
|
446
|
+
function mapStateToResult(state) {
|
|
447
|
+
if (state.merged && state.prUrl) {
|
|
448
|
+
return { status: "merged", prUrl: state.prUrl, iterations: state.iterations, feedback: state.feedback };
|
|
449
|
+
}
|
|
450
|
+
if (state.mergeGate === "blocked" || state.blockedDetail) {
|
|
451
|
+
return {
|
|
452
|
+
status: "needs-attention",
|
|
453
|
+
...state.prUrl ? { prUrl: state.prUrl } : {},
|
|
454
|
+
iterations: state.iterations,
|
|
455
|
+
feedback: state.feedback
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
if (state.prReady && state.prUrl) {
|
|
459
|
+
return { status: "opened", prUrl: state.prUrl, iterations: state.iterations, feedback: state.feedback };
|
|
460
|
+
}
|
|
461
|
+
return { status: "needs-attention", ...state.prUrl ? { prUrl: state.prUrl } : {}, iterations: state.iterations, feedback: state.feedback };
|
|
462
|
+
}
|
|
463
|
+
export {
|
|
464
|
+
runPipelineCloseout
|
|
465
|
+
};
|
package/dist/src/plugin.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/bundle-default-lifecycle/src/defaultPipeline.ts
|
|
3
3
|
import { resolveKernelStages } from "@rig/kernel/resolver";
|
|
4
|
+
import { createDefaultKernelPlugin } from "@rig/kernel/default-kernel";
|
|
4
5
|
|
|
5
6
|
// packages/bundle-default-lifecycle/src/stages/auto-merge.ts
|
|
6
7
|
import { runRepoDefaultMerge } from "@rig/runtime/control-plane/native/pr-automation";
|
|
@@ -51,6 +52,9 @@ var journalAppendStage = defineDefaultLifecycleStage({
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
// packages/bundle-default-lifecycle/src/stages/merge-gate.ts
|
|
55
|
+
import {
|
|
56
|
+
runStrictPrMergeGate
|
|
57
|
+
} from "@rig/runtime/control-plane/native/pr-review-gate";
|
|
54
58
|
var mergeGateStage = defineDefaultLifecycleStage({
|
|
55
59
|
id: "merge-gate",
|
|
56
60
|
kind: "gate",
|
|
@@ -103,6 +107,21 @@ var verifyStage = defineDefaultLifecycleStage({
|
|
|
103
107
|
});
|
|
104
108
|
|
|
105
109
|
// packages/bundle-default-lifecycle/src/defaultPipeline.ts
|
|
110
|
+
var DEFAULT_STAGE_AFTER = {
|
|
111
|
+
verify: ["validate"],
|
|
112
|
+
commit: ["verify"],
|
|
113
|
+
push: ["commit"],
|
|
114
|
+
"open-pr": ["push"],
|
|
115
|
+
"merge-gate": ["open-pr"],
|
|
116
|
+
"auto-merge": ["merge-gate"],
|
|
117
|
+
"source-closeout": ["auto-merge"],
|
|
118
|
+
isolation: ["source-closeout"],
|
|
119
|
+
"journal-append": ["isolation"]
|
|
120
|
+
};
|
|
121
|
+
function withDefaultAnchors(stage) {
|
|
122
|
+
const after = DEFAULT_STAGE_AFTER[stage.id];
|
|
123
|
+
return after ? { ...stage, after } : stage;
|
|
124
|
+
}
|
|
106
125
|
var defaultLifecycleStages = [
|
|
107
126
|
validateStage,
|
|
108
127
|
verifyStage,
|
|
@@ -114,7 +133,7 @@ var defaultLifecycleStages = [
|
|
|
114
133
|
sourceCloseoutStage,
|
|
115
134
|
isolationStage,
|
|
116
135
|
journalAppendStage
|
|
117
|
-
];
|
|
136
|
+
].map(withDefaultAnchors);
|
|
118
137
|
|
|
119
138
|
// packages/bundle-default-lifecycle/src/plugin.ts
|
|
120
139
|
var DEFAULT_LIFECYCLE_PLUGIN_ID = "@rig/bundle-default-lifecycle";
|
|
@@ -1 +1,24 @@
|
|
|
1
|
+
import { type StrictPrGreptileApiOptions, type StrictPrMergeGateResult } from "@rig/runtime/control-plane/native/pr-review-gate";
|
|
2
|
+
import type { GitHubCommandRunner } from "@rig/runtime/control-plane/native/pr-automation";
|
|
3
|
+
export type MergeGateStageInput = {
|
|
4
|
+
readonly projectRoot: string;
|
|
5
|
+
readonly prUrl: string;
|
|
6
|
+
readonly taskId: string;
|
|
7
|
+
readonly runId: string;
|
|
8
|
+
readonly cycle: number;
|
|
9
|
+
readonly command: GitHubCommandRunner;
|
|
10
|
+
readonly artifactRoot?: string | null;
|
|
11
|
+
readonly allowedFailures?: readonly string[];
|
|
12
|
+
readonly greptileApi?: StrictPrGreptileApiOptions;
|
|
13
|
+
readonly final?: boolean;
|
|
14
|
+
readonly requireGreptile?: boolean;
|
|
15
|
+
};
|
|
1
16
|
export declare const mergeGateStage: import("./types").DefaultLifecycleStageDescriptor;
|
|
17
|
+
/**
|
|
18
|
+
* Executable for the protected `merge-gate` stage. Wraps the runtime's strict
|
|
19
|
+
* merge gate (`runStrictPrMergeGate`) so the gate runs as a discrete resolved
|
|
20
|
+
* pipeline stage rather than only as logic embedded inside `runPrAutomation`.
|
|
21
|
+
* Returns the full {@link StrictPrMergeGateResult}; the caller maps it to a
|
|
22
|
+
* gate allow/block from `result.approved` / `result.pending`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runMergeGateStage(input: MergeGateStageInput): Promise<StrictPrMergeGateResult>;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// packages/bundle-default-lifecycle/src/stages/merge-gate.ts
|
|
3
|
+
import {
|
|
4
|
+
runStrictPrMergeGate
|
|
5
|
+
} from "@rig/runtime/control-plane/native/pr-review-gate";
|
|
6
|
+
|
|
2
7
|
// packages/bundle-default-lifecycle/src/stages/types.ts
|
|
3
8
|
function defineDefaultLifecycleStage(input) {
|
|
4
9
|
return {
|
|
@@ -16,6 +21,22 @@ var mergeGateStage = defineDefaultLifecycleStage({
|
|
|
16
21
|
calls: ["runStrictPrMergeGate"],
|
|
17
22
|
protected: true
|
|
18
23
|
});
|
|
24
|
+
async function runMergeGateStage(input) {
|
|
25
|
+
return await runStrictPrMergeGate({
|
|
26
|
+
projectRoot: input.projectRoot,
|
|
27
|
+
prUrl: input.prUrl,
|
|
28
|
+
taskId: input.taskId,
|
|
29
|
+
runId: input.runId,
|
|
30
|
+
cycle: input.cycle,
|
|
31
|
+
command: input.command,
|
|
32
|
+
...input.artifactRoot !== undefined ? { artifactRoot: input.artifactRoot } : {},
|
|
33
|
+
...input.allowedFailures !== undefined ? { allowedFailures: input.allowedFailures } : {},
|
|
34
|
+
...input.greptileApi !== undefined ? { greptileApi: input.greptileApi } : {},
|
|
35
|
+
...input.final !== undefined ? { final: input.final } : {},
|
|
36
|
+
...input.requireGreptile !== undefined ? { requireGreptile: input.requireGreptile } : {}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
19
39
|
export {
|
|
40
|
+
runMergeGateStage,
|
|
20
41
|
mergeGateStage
|
|
21
42
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/bundle-default-lifecycle",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.136",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Default Rig run lifecycle stage bundle wrapping the existing closeout runtime.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"types": "./dist/src/defaultPipeline.d.ts",
|
|
26
26
|
"import": "./dist/src/defaultPipeline.js"
|
|
27
27
|
},
|
|
28
|
-
"./
|
|
29
|
-
"types": "./dist/src/
|
|
30
|
-
"import": "./dist/src/
|
|
28
|
+
"./pipeline-closeout": {
|
|
29
|
+
"types": "./dist/src/pipelineCloseout.d.ts",
|
|
30
|
+
"import": "./dist/src/pipelineCloseout.js"
|
|
31
31
|
},
|
|
32
32
|
"./plugin": {
|
|
33
33
|
"types": "./dist/src/plugin.d.ts",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"module": "./dist/src/index.js",
|
|
42
42
|
"types": "./dist/src/index.d.ts",
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.
|
|
45
|
-
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.
|
|
46
|
-
"@rig/kernel": "npm:@h-rig/kernel@0.0.6-alpha.
|
|
47
|
-
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.
|
|
44
|
+
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.136",
|
|
45
|
+
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.136",
|
|
46
|
+
"@rig/kernel": "npm:@h-rig/kernel@0.0.6-alpha.136",
|
|
47
|
+
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.136"
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type InProcessCloseoutInput, type InProcessCloseoutResult } from "@rig/runtime/control-plane/native/in-process-closeout";
|
|
2
|
-
export type StagedCloseoutResult = {
|
|
3
|
-
readonly mode: "staged";
|
|
4
|
-
readonly pipelineStageIds: readonly string[];
|
|
5
|
-
readonly result: InProcessCloseoutResult;
|
|
6
|
-
};
|
|
7
|
-
export declare function runStagedCloseout(input: InProcessCloseoutInput): Promise<StagedCloseoutResult>;
|