task-while 0.0.2 → 0.0.3

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.
Files changed (41) hide show
  1. package/README.md +32 -34
  2. package/package.json +2 -2
  3. package/src/adapters/fs/harness-store.ts +84 -0
  4. package/src/agents/claude.ts +159 -9
  5. package/src/agents/codex.ts +68 -4
  6. package/src/agents/event-log.ts +160 -15
  7. package/src/batch/discovery.ts +1 -1
  8. package/src/commands/batch.ts +63 -164
  9. package/src/commands/run-branch-helpers.ts +81 -0
  10. package/src/commands/run-providers.ts +77 -0
  11. package/src/commands/run.ts +121 -177
  12. package/src/core/create-runtime-ports.ts +118 -0
  13. package/src/core/runtime.ts +15 -36
  14. package/src/harness/in-memory-store.ts +45 -0
  15. package/src/harness/kernel.ts +226 -0
  16. package/src/harness/state.ts +47 -0
  17. package/src/harness/store.ts +26 -0
  18. package/src/harness/workflow-builders.ts +87 -0
  19. package/src/harness/workflow-program.ts +86 -0
  20. package/src/ports/agent.ts +17 -0
  21. package/src/ports/code-host.ts +23 -0
  22. package/src/programs/batch.ts +139 -0
  23. package/src/programs/run-direct.ts +209 -0
  24. package/src/programs/run-pr-transitions.ts +81 -0
  25. package/src/programs/run-pr.ts +290 -0
  26. package/src/programs/shared-steps.ts +252 -0
  27. package/src/schedulers/scheduler.ts +208 -0
  28. package/src/session/session.ts +127 -0
  29. package/src/workflow/config.ts +15 -0
  30. package/src/core/engine-helpers.ts +0 -114
  31. package/src/core/engine-outcomes.ts +0 -166
  32. package/src/core/engine.ts +0 -223
  33. package/src/core/orchestrator-helpers.ts +0 -52
  34. package/src/core/orchestrator-integrate-resume.ts +0 -149
  35. package/src/core/orchestrator-review-resume.ts +0 -228
  36. package/src/core/orchestrator-task-attempt.ts +0 -257
  37. package/src/core/orchestrator.ts +0 -99
  38. package/src/runtime/fs-runtime.ts +0 -209
  39. package/src/workflow/direct-preset.ts +0 -44
  40. package/src/workflow/preset.ts +0 -86
  41. package/src/workflow/pull-request-preset.ts +0 -312
@@ -0,0 +1,209 @@
1
+ import {
2
+ errorRetry,
3
+ KernelResultKind,
4
+ retryBudgetReached,
5
+ } from '../harness/kernel'
6
+ import { TaskStatus } from '../harness/state'
7
+ import { action, sequence } from '../harness/workflow-builders'
8
+ import {
9
+ createSharedSteps,
10
+ type ContractPayload,
11
+ type ImplementPayload,
12
+ type ReviewPayload,
13
+ type RuntimePorts,
14
+ type SharedSteps,
15
+ } from './shared-steps'
16
+
17
+ import type { WorkflowProgram } from '../harness/workflow-program'
18
+ import type { AgentPort } from '../ports/agent'
19
+
20
+ export enum RunPhase {
21
+ Checkpoint = 'checkpoint',
22
+ Contract = 'contract',
23
+ Implement = 'implement',
24
+ Integrate = 'integrate',
25
+ Review = 'review',
26
+ Verify = 'verify',
27
+ }
28
+
29
+ export enum RunResult {
30
+ CheckpointCreated = 'checkpoint.created',
31
+ ContractGenerated = 'contract.generated',
32
+ ImplementationGenerated = 'implementation.generated',
33
+ IntegrateAlreadyIntegrated = 'integrate.already_integrated',
34
+ IntegrateCompleted = 'integrate.completed',
35
+ ReviewApproved = 'review.approved',
36
+ ReviewPending = 'review.pending',
37
+ ReviewRejected = 'review.rejected',
38
+ ReviewReplanRequired = 'review.replan_required',
39
+ VerifyFailed = 'verify.failed',
40
+ VerifyPassed = 'verify.passed',
41
+ }
42
+
43
+ export enum RunArtifactKind {
44
+ CheckpointResult = 'checkpoint_result',
45
+ Contract = 'contract',
46
+ Implementation = 'implementation',
47
+ IntegrateResult = 'integrate_result',
48
+ ReviewResult = 'review_result',
49
+ VerifyResult = 'verify_result',
50
+ }
51
+
52
+ export function createRunDirectProgram(deps: {
53
+ implementer: AgentPort
54
+ maxIterations: number
55
+ ports: RuntimePorts
56
+ reviewer: AgentPort
57
+ verifyCommands: string[]
58
+ workspaceRoot: string
59
+ }): WorkflowProgram {
60
+ const { maxIterations } = deps
61
+ const onError = errorRetry(maxIterations)
62
+ const steps: SharedSteps = createSharedSteps({
63
+ implementer: deps.implementer,
64
+ ports: deps.ports,
65
+ reviewer: deps.reviewer,
66
+ verifyCommands: deps.verifyCommands,
67
+ workspaceRoot: deps.workspaceRoot,
68
+ artifactKinds: {
69
+ contract: RunArtifactKind.Contract,
70
+ implementation: RunArtifactKind.Implementation,
71
+ integrateResult: RunArtifactKind.IntegrateResult,
72
+ reviewResult: RunArtifactKind.ReviewResult,
73
+ verifyResult: RunArtifactKind.VerifyResult,
74
+ },
75
+ })
76
+
77
+ return sequence(
78
+ [
79
+ action(RunPhase.Contract, {
80
+ async run(ctx) {
81
+ const artifact = await steps.contract(ctx.subjectId, {
82
+ attempt: ctx.state.iteration,
83
+ lastFindings: [],
84
+ })
85
+ return {
86
+ artifact,
87
+ result: { kind: RunResult.ContractGenerated },
88
+ }
89
+ },
90
+ }),
91
+ action(RunPhase.Implement, {
92
+ async run(ctx) {
93
+ const contractArtifact = ctx.artifacts.get<ContractPayload>(
94
+ RunArtifactKind.Contract,
95
+ )
96
+ const reviewArtifact = ctx.artifacts.get<ReviewPayload>(
97
+ RunArtifactKind.ReviewResult,
98
+ )
99
+ const lastFindings = reviewArtifact?.payload.findings ?? []
100
+ const artifact = await steps.implement(ctx.subjectId, {
101
+ attempt: ctx.state.iteration,
102
+ lastFindings,
103
+ prompt: contractArtifact!.payload.prompt,
104
+ })
105
+ return {
106
+ artifact,
107
+ result: { kind: RunResult.ImplementationGenerated },
108
+ }
109
+ },
110
+ }),
111
+ action(RunPhase.Verify, {
112
+ async run(ctx) {
113
+ const artifact = await steps.verify(ctx.subjectId)
114
+ const allPassed = artifact.payload.checks.every(
115
+ (c) => c.exitCode === 0,
116
+ )
117
+ return {
118
+ artifact,
119
+ result: {
120
+ kind: allPassed ? RunResult.VerifyPassed : RunResult.VerifyFailed,
121
+ },
122
+ }
123
+ },
124
+ }),
125
+ action(RunPhase.Review, {
126
+ async run(ctx) {
127
+ const implArtifact = ctx.artifacts.get<ImplementPayload>(
128
+ RunArtifactKind.Implementation,
129
+ )
130
+ const reviewArtifact = ctx.artifacts.get<ReviewPayload>(
131
+ RunArtifactKind.ReviewResult,
132
+ )
133
+ const lastFindings = reviewArtifact?.payload.findings ?? []
134
+ const artifact = await steps.review(ctx.subjectId, {
135
+ attempt: ctx.state.iteration,
136
+ implement: implArtifact!.payload,
137
+ lastFindings,
138
+ })
139
+ const verdict = artifact.payload.verdict
140
+ const kind =
141
+ verdict === 'approved'
142
+ ? RunResult.ReviewApproved
143
+ : verdict === 'replan_required'
144
+ ? RunResult.ReviewReplanRequired
145
+ : RunResult.ReviewRejected
146
+ return { artifact, result: { kind } }
147
+ },
148
+ }),
149
+ action(RunPhase.Integrate, {
150
+ async run(ctx) {
151
+ const artifact = await steps.integrate(ctx.subjectId)
152
+ return {
153
+ artifact,
154
+ result: { kind: RunResult.IntegrateCompleted },
155
+ }
156
+ },
157
+ }),
158
+ ],
159
+ {
160
+ [RunPhase.Contract]: {
161
+ [KernelResultKind.Error]: onError(RunPhase.Contract),
162
+ [RunResult.ContractGenerated]: {
163
+ nextPhase: RunPhase.Implement,
164
+ status: TaskStatus.Running,
165
+ },
166
+ },
167
+ [RunPhase.Implement]: {
168
+ [KernelResultKind.Error]: onError(RunPhase.Implement),
169
+ [RunResult.ImplementationGenerated]: {
170
+ nextPhase: RunPhase.Verify,
171
+ status: TaskStatus.Running,
172
+ },
173
+ },
174
+ [RunPhase.Integrate]: {
175
+ [KernelResultKind.Error]: onError(RunPhase.Integrate),
176
+ [RunResult.IntegrateCompleted]: {
177
+ nextPhase: null,
178
+ status: TaskStatus.Done,
179
+ },
180
+ },
181
+ [RunPhase.Review]: {
182
+ [KernelResultKind.Error]: onError(RunPhase.Implement),
183
+ [RunResult.ReviewApproved]: {
184
+ nextPhase: RunPhase.Integrate,
185
+ status: TaskStatus.Running,
186
+ },
187
+ [RunResult.ReviewReplanRequired]: {
188
+ nextPhase: null,
189
+ status: TaskStatus.Replan,
190
+ },
191
+ [RunResult.ReviewRejected]: (input) =>
192
+ retryBudgetReached(input.state, maxIterations)
193
+ ? { nextPhase: null, status: TaskStatus.Blocked }
194
+ : { nextPhase: RunPhase.Implement, status: TaskStatus.Running },
195
+ },
196
+ [RunPhase.Verify]: {
197
+ [KernelResultKind.Error]: onError(RunPhase.Implement),
198
+ [RunResult.VerifyPassed]: {
199
+ nextPhase: RunPhase.Review,
200
+ status: TaskStatus.Running,
201
+ },
202
+ [RunResult.VerifyFailed]: (input) =>
203
+ retryBudgetReached(input.state, maxIterations)
204
+ ? { nextPhase: null, status: TaskStatus.Blocked }
205
+ : { nextPhase: RunPhase.Implement, status: TaskStatus.Running },
206
+ },
207
+ },
208
+ )
209
+ }
@@ -0,0 +1,81 @@
1
+ import {
2
+ errorRetry,
3
+ KernelResultKind,
4
+ retryBudgetReached,
5
+ } from '../harness/kernel'
6
+ import { TaskStatus } from '../harness/state'
7
+ import { RunPhase, RunResult } from './run-direct'
8
+
9
+ import type {
10
+ TransitionRule,
11
+ WorkflowProgram,
12
+ } from '../harness/workflow-program'
13
+
14
+ function retryImplement(maxIterations: number): TransitionRule {
15
+ return (input) =>
16
+ retryBudgetReached(input.state, maxIterations)
17
+ ? { nextPhase: null, status: TaskStatus.Blocked }
18
+ : { nextPhase: RunPhase.Implement, status: TaskStatus.Running }
19
+ }
20
+
21
+ export function createRunPrTransitions(
22
+ maxIterations: number,
23
+ ): WorkflowProgram['transitions'] {
24
+ const onError = errorRetry(maxIterations)
25
+ const retryImplementRule = retryImplement(maxIterations)
26
+
27
+ return {
28
+ [RunPhase.Checkpoint]: {
29
+ [KernelResultKind.Error]: onError(RunPhase.Checkpoint),
30
+ [RunResult.CheckpointCreated]: {
31
+ nextPhase: RunPhase.Review,
32
+ status: TaskStatus.Running,
33
+ },
34
+ },
35
+ [RunPhase.Contract]: {
36
+ [KernelResultKind.Error]: onError(RunPhase.Contract),
37
+ [RunResult.ContractGenerated]: {
38
+ nextPhase: RunPhase.Implement,
39
+ status: TaskStatus.Running,
40
+ },
41
+ },
42
+ [RunPhase.Implement]: {
43
+ [KernelResultKind.Error]: onError(RunPhase.Implement),
44
+ [RunResult.ImplementationGenerated]: {
45
+ nextPhase: RunPhase.Verify,
46
+ status: TaskStatus.Running,
47
+ },
48
+ },
49
+ [RunPhase.Integrate]: {
50
+ [KernelResultKind.Error]: onError(RunPhase.Integrate),
51
+ [RunResult.IntegrateAlreadyIntegrated]: {
52
+ nextPhase: null,
53
+ status: TaskStatus.Done,
54
+ },
55
+ [RunResult.IntegrateCompleted]: {
56
+ nextPhase: null,
57
+ status: TaskStatus.Done,
58
+ },
59
+ },
60
+ [RunPhase.Review]: {
61
+ [KernelResultKind.Error]: onError(RunPhase.Implement),
62
+ [RunResult.ReviewRejected]: retryImplementRule,
63
+ [RunResult.ReviewApproved]: {
64
+ nextPhase: RunPhase.Integrate,
65
+ status: TaskStatus.Running,
66
+ },
67
+ [RunResult.ReviewReplanRequired]: {
68
+ nextPhase: null,
69
+ status: TaskStatus.Replan,
70
+ },
71
+ },
72
+ [RunPhase.Verify]: {
73
+ [KernelResultKind.Error]: onError(RunPhase.Implement),
74
+ [RunResult.VerifyFailed]: retryImplementRule,
75
+ [RunResult.VerifyPassed]: {
76
+ nextPhase: RunPhase.Checkpoint,
77
+ status: TaskStatus.Running,
78
+ },
79
+ },
80
+ }
81
+ }
@@ -0,0 +1,290 @@
1
+ import {
2
+ cleanupBranch,
3
+ ensureTaskBranch,
4
+ runPrCheckpoint,
5
+ sleep,
6
+ toTaskBranchName,
7
+ } from '../commands/run-branch-helpers'
8
+ import { action, sequence } from '../harness/workflow-builders'
9
+ import { finalizeTaskCheckbox } from '../workflow/finalize-task-checkbox'
10
+ import { createCodexRemoteReviewerProvider } from '../workflow/remote-reviewer'
11
+ import { RunArtifactKind, RunPhase, RunResult } from './run-direct'
12
+ import { createRunPrTransitions } from './run-pr-transitions'
13
+ import {
14
+ createSharedSteps,
15
+ type ContractPayload,
16
+ type ReviewPayload,
17
+ type RuntimePorts,
18
+ type SharedSteps,
19
+ } from './shared-steps'
20
+
21
+ import type { OrchestratorRuntime } from '../core/runtime'
22
+ import type { WorkflowProgram } from '../harness/workflow-program'
23
+ import type { AgentPort } from '../ports/agent'
24
+ import type { CodeHostPort } from '../ports/code-host'
25
+
26
+ export interface CheckpointPayload {
27
+ checkpointStartedAt: string
28
+ prNumber: number
29
+ }
30
+
31
+ export interface IntegratePrPayload {
32
+ commitSha: string
33
+ prNumber: number
34
+ }
35
+
36
+ export function createRunPrProgram(deps: {
37
+ implementer: AgentPort
38
+ maxIterations: number
39
+ ports: RuntimePorts & { codeHost: CodeHostPort }
40
+ reviewer: AgentPort
41
+ reviewPollIntervalMs?: number
42
+ verifyCommands: string[]
43
+ workspaceRoot: string
44
+ }): WorkflowProgram {
45
+ const { maxIterations } = deps
46
+ const reviewPollIntervalMs = deps.reviewPollIntervalMs ?? 60_000
47
+ const steps: SharedSteps = createSharedSteps({
48
+ implementer: deps.implementer,
49
+ ports: deps.ports,
50
+ reviewer: deps.reviewer,
51
+ verifyCommands: deps.verifyCommands,
52
+ workspaceRoot: deps.workspaceRoot,
53
+ artifactKinds: {
54
+ contract: RunArtifactKind.Contract,
55
+ implementation: RunArtifactKind.Implementation,
56
+ integrateResult: RunArtifactKind.IntegrateResult,
57
+ reviewResult: RunArtifactKind.ReviewResult,
58
+ verifyResult: RunArtifactKind.VerifyResult,
59
+ },
60
+ })
61
+
62
+ const remoteReviewer = createCodexRemoteReviewerProvider()
63
+
64
+ return sequence(
65
+ [
66
+ action(RunPhase.Contract, {
67
+ async run(ctx) {
68
+ const artifact = await steps.contract(ctx.subjectId, {
69
+ attempt: ctx.state.iteration,
70
+ lastFindings: [],
71
+ })
72
+ return {
73
+ artifact,
74
+ result: { kind: RunResult.ContractGenerated },
75
+ }
76
+ },
77
+ }),
78
+ action(RunPhase.Implement, {
79
+ async run(ctx) {
80
+ const contractArtifact = ctx.artifacts.get<ContractPayload>(
81
+ RunArtifactKind.Contract,
82
+ )
83
+ const reviewArtifact = ctx.artifacts.get<ReviewPayload>(
84
+ RunArtifactKind.ReviewResult,
85
+ )
86
+ const lastFindings = reviewArtifact?.payload.findings ?? []
87
+ const artifact = await steps.implement(ctx.subjectId, {
88
+ attempt: ctx.state.iteration,
89
+ lastFindings,
90
+ prompt: contractArtifact!.payload.prompt,
91
+ })
92
+ return {
93
+ artifact,
94
+ result: { kind: RunResult.ImplementationGenerated },
95
+ }
96
+ },
97
+ }),
98
+ action(RunPhase.Verify, {
99
+ async run(ctx) {
100
+ const artifact = await steps.verify(ctx.subjectId)
101
+ const allPassed = artifact.payload.checks.every(
102
+ (c) => c.exitCode === 0,
103
+ )
104
+ return {
105
+ artifact,
106
+ result: {
107
+ kind: allPassed ? RunResult.VerifyPassed : RunResult.VerifyFailed,
108
+ },
109
+ }
110
+ },
111
+ }),
112
+ action(RunPhase.Checkpoint, {
113
+ async run(ctx) {
114
+ const result = await runPrCheckpoint(
115
+ { codeHost: deps.ports.codeHost, git: deps.ports.git },
116
+ deps.ports.taskSource,
117
+ { iteration: ctx.state.iteration, subjectId: ctx.subjectId },
118
+ )
119
+ const payload: CheckpointPayload = {
120
+ checkpointStartedAt: result.checkpointStartedAt,
121
+ prNumber: result.prNumber,
122
+ }
123
+ return {
124
+ result: { kind: RunResult.CheckpointCreated },
125
+ artifact: {
126
+ id: `${RunArtifactKind.CheckpointResult}-${ctx.subjectId}-${Date.now()}`,
127
+ kind: RunArtifactKind.CheckpointResult,
128
+ payload,
129
+ subjectId: ctx.subjectId,
130
+ timestamp: new Date().toISOString(),
131
+ },
132
+ }
133
+ },
134
+ }),
135
+ action(RunPhase.Review, {
136
+ async run(ctx) {
137
+ const checkpointArtifact = ctx.artifacts.get<CheckpointPayload>(
138
+ RunArtifactKind.CheckpointResult,
139
+ )
140
+ const contractArtifact = ctx.artifacts.get<ContractPayload>(
141
+ RunArtifactKind.Contract,
142
+ )
143
+ let reviewResult: Awaited<
144
+ ReturnType<typeof remoteReviewer.evaluatePullRequestReview>
145
+ >
146
+ for (;;) {
147
+ const snapshot = await deps.ports.codeHost.getPullRequestSnapshot({
148
+ pullRequestNumber: checkpointArtifact!.payload.prNumber,
149
+ })
150
+ reviewResult = await remoteReviewer.evaluatePullRequestReview({
151
+ pullRequest: snapshot,
152
+ taskHandle: ctx.subjectId,
153
+ checkpointStartedAt:
154
+ checkpointArtifact!.payload.checkpointStartedAt,
155
+ completionCriteria:
156
+ contractArtifact?.payload.completionCriteria ?? [],
157
+ })
158
+ if (reviewResult.kind !== 'pending') {
159
+ break
160
+ }
161
+ if (reviewPollIntervalMs > 0) {
162
+ await sleep(reviewPollIntervalMs)
163
+ }
164
+ }
165
+
166
+ let verdict: string
167
+ let findings: ReviewPayload['findings'] = []
168
+ let summary: string
169
+
170
+ if (reviewResult.kind === 'approved') {
171
+ verdict = 'approved'
172
+ summary = reviewResult.review.summary
173
+ } else {
174
+ verdict = 'rejected'
175
+ summary = reviewResult.review.summary
176
+ findings = reviewResult.review.findings.map((f) => ({
177
+ fixHint: f.fixHint,
178
+ issue: f.issue,
179
+ severity: f.severity,
180
+ }))
181
+ }
182
+
183
+ const kind =
184
+ verdict === 'approved'
185
+ ? RunResult.ReviewApproved
186
+ : RunResult.ReviewRejected
187
+
188
+ const payload: ReviewPayload = {
189
+ findings,
190
+ summary,
191
+ verdict,
192
+ }
193
+
194
+ return {
195
+ result: { kind },
196
+ artifact: {
197
+ id: `${RunArtifactKind.ReviewResult}-${ctx.subjectId}-${Date.now()}`,
198
+ kind: RunArtifactKind.ReviewResult,
199
+ payload,
200
+ subjectId: ctx.subjectId,
201
+ timestamp: new Date().toISOString(),
202
+ },
203
+ }
204
+ },
205
+ }),
206
+ action(RunPhase.Integrate, {
207
+ async run(ctx) {
208
+ const commitSubject = deps.ports.taskSource.buildCommitSubject(
209
+ ctx.subjectId,
210
+ )
211
+ const branchName = toTaskBranchName(commitSubject)
212
+
213
+ const openPr =
214
+ await deps.ports.codeHost.findOpenPullRequestByHeadBranch({
215
+ headBranch: branchName,
216
+ })
217
+
218
+ if (openPr) {
219
+ await ensureTaskBranch(deps.ports.git, branchName, true)
220
+ const taskChecked = await deps.ports.taskSource.isTaskCompleted(
221
+ ctx.subjectId,
222
+ )
223
+ if (!taskChecked) {
224
+ await finalizeTaskCheckbox({
225
+ commitMessage: commitSubject,
226
+ taskHandle: ctx.subjectId,
227
+ runtime: {
228
+ git: deps.ports.git,
229
+ github: deps.ports.codeHost,
230
+ taskSource: deps.ports.taskSource,
231
+ } as OrchestratorRuntime,
232
+ })
233
+ }
234
+ await deps.ports.git.pushBranch(branchName)
235
+ const mergeResult =
236
+ await deps.ports.codeHost.squashMergePullRequest({
237
+ pullRequestNumber: openPr.number,
238
+ subject: commitSubject,
239
+ })
240
+
241
+ await cleanupBranch(deps.ports.git, branchName)
242
+
243
+ const payload: IntegratePrPayload = {
244
+ commitSha: mergeResult.commitSha,
245
+ prNumber: openPr.number,
246
+ }
247
+ return {
248
+ result: { kind: RunResult.IntegrateCompleted },
249
+ artifact: {
250
+ id: `${RunArtifactKind.IntegrateResult}-${ctx.subjectId}-${Date.now()}`,
251
+ kind: RunArtifactKind.IntegrateResult,
252
+ payload,
253
+ subjectId: ctx.subjectId,
254
+ timestamp: new Date().toISOString(),
255
+ },
256
+ }
257
+ }
258
+
259
+ const mergedPr =
260
+ await deps.ports.codeHost.findMergedPullRequestByHeadBranch({
261
+ headBranch: branchName,
262
+ })
263
+ if (!mergedPr) {
264
+ throw new Error(
265
+ `Missing open or merged pull request for branch ${branchName}`,
266
+ )
267
+ }
268
+
269
+ await cleanupBranch(deps.ports.git, branchName)
270
+
271
+ const payload: IntegratePrPayload = {
272
+ commitSha: mergedPr.mergeCommitSha,
273
+ prNumber: mergedPr.number,
274
+ }
275
+ return {
276
+ result: { kind: RunResult.IntegrateAlreadyIntegrated },
277
+ artifact: {
278
+ id: `${RunArtifactKind.IntegrateResult}-${ctx.subjectId}-${Date.now()}`,
279
+ kind: RunArtifactKind.IntegrateResult,
280
+ payload,
281
+ subjectId: ctx.subjectId,
282
+ timestamp: new Date().toISOString(),
283
+ },
284
+ }
285
+ },
286
+ }),
287
+ ],
288
+ createRunPrTransitions(maxIterations),
289
+ )
290
+ }