@osolmaz/pi-workflows 0.13.0 → 0.13.2
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 +11 -9
- package/dist/builtins/autodoc.workflow.d.ts +191 -4
- package/dist/builtins/autodoc.workflow.js +156 -30
- package/dist/builtins/autodoc.workflow.js.map +1 -1
- package/dist/builtins/autoimplement-command-batches.d.ts +1 -0
- package/dist/builtins/autoimplement-command-batches.js +29 -31
- package/dist/builtins/autoimplement-command-batches.js.map +1 -1
- package/dist/builtins/autoimplement.workflow.d.ts +1259 -29
- package/dist/builtins/autoimplement.workflow.js +416 -153
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/autoplan.workflow.d.ts +6 -0
- package/dist/builtins/autoplan.workflow.js +68 -32
- package/dist/builtins/autoplan.workflow.js.map +1 -1
- package/dist/builtins/catalog.js +5 -5
- package/dist/builtins/catalog.js.map +1 -1
- package/dist/builtins/change-verification.workflow.d.ts +110 -0
- package/dist/builtins/change-verification.workflow.js +860 -0
- package/dist/builtins/change-verification.workflow.js.map +1 -0
- package/dist/builtins/monitor.workflow.js +4 -3
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/plain-summary.workflow.js +35 -24
- package/dist/builtins/plain-summary.workflow.js.map +1 -1
- package/dist/builtins/plan-change.workflow.d.ts +361 -6
- package/dist/builtins/plan-change.workflow.js +26 -0
- package/dist/builtins/plan-change.workflow.js.map +1 -1
- package/dist/builtins/sanity-check.workflow.js +19 -22
- package/dist/builtins/sanity-check.workflow.js.map +1 -1
- package/dist/builtins/workspace-preparation.workflow.d.ts +75 -0
- package/dist/builtins/workspace-preparation.workflow.js +498 -0
- package/dist/builtins/workspace-preparation.workflow.js.map +1 -0
- package/dist/controllers/sqlite.js +16 -51
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/extension/decision-channels.js +45 -7
- package/dist/extension/decision-channels.js.map +1 -1
- package/dist/extension/executor.js +1 -4
- package/dist/extension/executor.js.map +1 -1
- package/dist/extension/index.js +2 -15
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/recorder.d.ts +1 -1
- package/dist/extension/recorder.js +8 -8
- package/dist/extension/recorder.js.map +1 -1
- package/dist/state/schema.js +22 -3
- package/dist/state/schema.js.map +1 -1
- package/dist/viewer/session-reducer.d.ts +0 -1
- package/dist/viewer/session-reducer.js +2 -24
- package/dist/viewer/session-reducer.js.map +1 -1
- package/dist/workflows/engine.js +4 -3
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/store.d.ts +6 -1
- package/dist/workflows/store.js +286 -33
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +1 -1
- package/docs/SQLITE_STATE.md +20 -14
- package/docs/WORKFLOW_COMPOSITION.md +8 -0
- package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +1 -1
- package/docs/plans/2026-08-24-change-scoped-verification-plan.md +419 -0
- package/docs/plans/2026-08-25-autoplan-user-intent-capture-plan.md +107 -0
- package/docs/session-event-journal.md +2 -3
- package/docs/workflows.md +43 -21
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/skills/autodoc/SKILL.md +7 -0
- package/skills/autoimplement/SKILL.md +4 -0
- package/src/builtins/autodoc.workflow.ts +184 -33
- package/src/builtins/autoimplement-command-batches.ts +39 -33
- package/src/builtins/autoimplement.workflow.ts +483 -175
- package/src/builtins/autoplan.workflow.ts +80 -32
- package/src/builtins/catalog.ts +5 -5
- package/src/builtins/change-verification.workflow.ts +1143 -0
- package/src/builtins/monitor.workflow.ts +6 -3
- package/src/builtins/plain-summary.workflow.ts +38 -40
- package/src/builtins/plan-change.workflow.ts +35 -0
- package/src/builtins/sanity-check.workflow.ts +19 -22
- package/src/builtins/workspace-preparation.workflow.ts +668 -0
- package/src/controllers/sqlite.ts +19 -53
- package/src/extension/decision-channels.ts +47 -7
- package/src/extension/executor.ts +1 -4
- package/src/extension/index.ts +2 -15
- package/src/extension/recorder.ts +10 -8
- package/src/state/schema.ts +22 -3
- package/src/viewer/session-reducer.ts +2 -29
- package/src/workflows/engine.ts +4 -3
- package/src/workflows/store.ts +397 -43
- package/src/workflows/types.ts +0 -1
|
@@ -4,8 +4,10 @@ import { action, agent, compute, defineWorkflow, includeWorkflow, includedResult
|
|
|
4
4
|
import { digest } from "../workflows/human-decision.js";
|
|
5
5
|
import autodocWorkflow, {} from "./autodoc.workflow.js";
|
|
6
6
|
import { parseAutoimplementConcurrency, parseCiInspectionBatch, parsePublishedRepositories, parseVerificationCommandPlan, reviewerCommand, } from "./autoimplement-command-batches.js";
|
|
7
|
+
import changeVerificationWorkflow, {} from "./change-verification.workflow.js";
|
|
7
8
|
import { parsePlanApprovalPolicy } from "./plan-approval.workflow.js";
|
|
8
9
|
import planChangeWorkflow, {} from "./plan-change.workflow.js";
|
|
10
|
+
import workspacePreparationWorkflow, { parsePreparedWorkspace, } from "./workspace-preparation.workflow.js";
|
|
9
11
|
const MAX_BLOCKER_CHALLENGES = 3;
|
|
10
12
|
const MAX_CHALLENGE_ITEMS = 5;
|
|
11
13
|
const MAX_CHALLENGE_TEXT = 500;
|
|
@@ -22,6 +24,7 @@ const TIMEOUT_FALLBACK_SOURCES = [
|
|
|
22
24
|
"inspectComments",
|
|
23
25
|
"inspectCi",
|
|
24
26
|
"opportunisticTest",
|
|
27
|
+
"finalizeDefaultBranch",
|
|
25
28
|
"finalizeDelivery",
|
|
26
29
|
];
|
|
27
30
|
const WORK_ATTEMPT_NODES = ["implement", "fix", "addressP2"];
|
|
@@ -36,6 +39,7 @@ const TIMEOUT_FALLBACK_ROUTES = {
|
|
|
36
39
|
inspectComments: ["retry", "review", "ci", "replan", "blocked"],
|
|
37
40
|
inspectCi: ["retry", "ci", "deliver", "replan", "blocked"],
|
|
38
41
|
opportunisticTest: ["retry", "ci", "deliver", "replan", "blocked"],
|
|
42
|
+
finalizeDefaultBranch: ["retry", "replan", "blocked"],
|
|
39
43
|
finalizeDelivery: ["retry", "deliver", "replan", "blocked"],
|
|
40
44
|
};
|
|
41
45
|
function requireRecord(value, label) {
|
|
@@ -50,6 +54,12 @@ function requireString(value, label) {
|
|
|
50
54
|
}
|
|
51
55
|
return value.trim();
|
|
52
56
|
}
|
|
57
|
+
function requireAbsolutePath(value, label) {
|
|
58
|
+
const result = requireString(value, label);
|
|
59
|
+
if (!path.isAbsolute(result))
|
|
60
|
+
throw new Error(`${label} must be absolute`);
|
|
61
|
+
return path.resolve(result);
|
|
62
|
+
}
|
|
53
63
|
function requireStringArray(value, label) {
|
|
54
64
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
55
65
|
throw new Error(`${label} must be an array of strings`);
|
|
@@ -74,10 +84,12 @@ function isTimeoutFallbackSource(nodeId) {
|
|
|
74
84
|
function latestTimedOutStep(context) {
|
|
75
85
|
for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
|
|
76
86
|
const step = context.state.steps[index];
|
|
77
|
-
if (step?.outcome === "timed_out"
|
|
87
|
+
if ((step?.outcome === "timed_out" || step?.outcome === "failed") &&
|
|
88
|
+
isTimeoutFallbackSource(step.nodeId)) {
|
|
78
89
|
return step;
|
|
90
|
+
}
|
|
79
91
|
}
|
|
80
|
-
throw new Error("No supported
|
|
92
|
+
throw new Error("No supported failed Autoimplement step is available");
|
|
81
93
|
}
|
|
82
94
|
function latestStepIndex(context, predicate) {
|
|
83
95
|
for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
|
|
@@ -158,7 +170,7 @@ function timeoutFallbackTarget(context) {
|
|
|
158
170
|
const fallback = context.outputs.timeoutFallback;
|
|
159
171
|
if (fallback.route !== "retry") {
|
|
160
172
|
const routes = {
|
|
161
|
-
verify: "
|
|
173
|
+
verify: "selectVerificationPath",
|
|
162
174
|
review: "selectReviewCommands",
|
|
163
175
|
ci: "inspectCi",
|
|
164
176
|
deliver: "finalizeDelivery",
|
|
@@ -174,7 +186,8 @@ function timeoutFallbackGuard(context) {
|
|
|
174
186
|
const attempts = context.state.steps.filter((step) => step.nodeId === "timeoutFallback" && step.outcome === "ok").length;
|
|
175
187
|
if (attempts >= MAX_TIMEOUT_FALLBACKS) {
|
|
176
188
|
const timeouts = context.state.steps
|
|
177
|
-
.filter((step) => step.outcome === "timed_out"
|
|
189
|
+
.filter((step) => (step.outcome === "timed_out" || step.outcome === "failed") &&
|
|
190
|
+
isTimeoutFallbackSource(step.nodeId))
|
|
178
191
|
.map((step) => ({
|
|
179
192
|
nodeId: step.nodeId,
|
|
180
193
|
attemptId: step.attemptId,
|
|
@@ -201,15 +214,6 @@ function timeoutFallbackGuard(context) {
|
|
|
201
214
|
},
|
|
202
215
|
};
|
|
203
216
|
}
|
|
204
|
-
function throwLatestSupportedFailure(context) {
|
|
205
|
-
for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
|
|
206
|
-
const step = context.state.steps[index];
|
|
207
|
-
if (step?.outcome === "failed" && isTimeoutFallbackSource(step.nodeId)) {
|
|
208
|
-
throw new Error(step.error ?? `Autoimplement node failed: ${step.nodeId}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
throw new Error("No supported failed Autoimplement step is available");
|
|
212
|
-
}
|
|
213
217
|
function parseBlockerChallenge(value) {
|
|
214
218
|
const result = requireRecord(value, "blocker challenge");
|
|
215
219
|
if (result.route !== "continue" && result.route !== "blocked") {
|
|
@@ -234,6 +238,20 @@ function parseBlockerChallenge(value) {
|
|
|
234
238
|
if (nextAction.length > MAX_CHALLENGE_TEXT) {
|
|
235
239
|
throw new Error(`blocker challenge nextAction must be at most ${MAX_CHALLENGE_TEXT} characters`);
|
|
236
240
|
}
|
|
241
|
+
const stages = [
|
|
242
|
+
"planDiscovery",
|
|
243
|
+
"documentation",
|
|
244
|
+
"implementation",
|
|
245
|
+
"repair",
|
|
246
|
+
"review",
|
|
247
|
+
"ci",
|
|
248
|
+
"delivery",
|
|
249
|
+
"redesign",
|
|
250
|
+
];
|
|
251
|
+
const nextStage = result.nextStage === null ? null : result.nextStage;
|
|
252
|
+
if (nextStage !== null && !stages.includes(nextStage)) {
|
|
253
|
+
throw new Error(`blocker challenge nextStage must be one of ${stages.join(", ")} or null`);
|
|
254
|
+
}
|
|
237
255
|
const alternativesChecked = boundedChallengeItems(result.alternativesChecked, "blocker challenge alternativesChecked");
|
|
238
256
|
const evidence = boundedChallengeItems(result.evidence, "blocker challenge evidence");
|
|
239
257
|
if (result.route === "blocked") {
|
|
@@ -241,13 +259,14 @@ function parseBlockerChallenge(value) {
|
|
|
241
259
|
outsideAuthority !== true ||
|
|
242
260
|
canProceed !== false ||
|
|
243
261
|
nextAction.length > 0 ||
|
|
262
|
+
nextStage !== null ||
|
|
244
263
|
alternativesChecked.length === 0 ||
|
|
245
264
|
evidence.length === 0) {
|
|
246
265
|
throw new Error("blocked challenge requires blockingNow=true, outsideAuthority=true, canProceed=false, an empty nextAction, and concrete alternatives and evidence");
|
|
247
266
|
}
|
|
248
267
|
}
|
|
249
|
-
else if (canProceed !== true || nextAction.length === 0) {
|
|
250
|
-
throw new Error("continue challenge requires canProceed=true
|
|
268
|
+
else if (canProceed !== true || nextAction.length === 0 || nextStage === null) {
|
|
269
|
+
throw new Error("continue challenge requires canProceed=true, a practical nextAction, and nextStage");
|
|
251
270
|
}
|
|
252
271
|
return {
|
|
253
272
|
route: result.route,
|
|
@@ -256,6 +275,7 @@ function parseBlockerChallenge(value) {
|
|
|
256
275
|
canProceed,
|
|
257
276
|
reason,
|
|
258
277
|
nextAction,
|
|
278
|
+
nextStage: nextStage,
|
|
259
279
|
alternativesChecked,
|
|
260
280
|
evidence,
|
|
261
281
|
};
|
|
@@ -299,14 +319,31 @@ function parseInput(value) {
|
|
|
299
319
|
}
|
|
300
320
|
const concurrency = parseAutoimplementConcurrency(input.concurrency);
|
|
301
321
|
const approval = parsePlanApprovalPolicy(input.approval);
|
|
322
|
+
let workspaceMode;
|
|
323
|
+
if (input.workspaceMode !== undefined) {
|
|
324
|
+
if (input.workspaceMode !== "auto" &&
|
|
325
|
+
input.workspaceMode !== "branch" &&
|
|
326
|
+
input.workspaceMode !== "worktree" &&
|
|
327
|
+
input.workspaceMode !== "defaultBranch") {
|
|
328
|
+
throw new Error("autoimplement workspaceMode must be auto, branch, worktree, or defaultBranch");
|
|
329
|
+
}
|
|
330
|
+
workspaceMode = input.workspaceMode;
|
|
331
|
+
}
|
|
332
|
+
const preparedWorkspace = input.preparedWorkspace === undefined
|
|
333
|
+
? undefined
|
|
334
|
+
: parsePreparedWorkspace(input.preparedWorkspace);
|
|
335
|
+
if (input.verificationChecks !== undefined && !Array.isArray(input.verificationChecks)) {
|
|
336
|
+
throw new Error("autoimplement verificationChecks must be an array");
|
|
337
|
+
}
|
|
338
|
+
if (Array.isArray(input.verificationChecks) && input.verificationChecks.length === 0) {
|
|
339
|
+
throw new Error("autoimplement verificationChecks must be non-empty when supplied");
|
|
340
|
+
}
|
|
302
341
|
return {
|
|
303
342
|
task: requireString(input.task, "autoimplement task"),
|
|
304
343
|
...(input.plan !== undefined ? { plan: input.plan } : {}),
|
|
305
344
|
...(input.scope !== undefined ? { scope: requireString(input.scope, "scope") } : {}),
|
|
306
345
|
...(constraints !== undefined ? { constraints: [...constraints] } : {}),
|
|
307
|
-
|
|
308
|
-
? { repository: requireString(input.repository, "repository") }
|
|
309
|
-
: {}),
|
|
346
|
+
repository: requireAbsolutePath(input.repository, "repository"),
|
|
310
347
|
...(input.baseBranch !== undefined
|
|
311
348
|
? { baseBranch: requireString(input.baseBranch, "baseBranch") }
|
|
312
349
|
: {}),
|
|
@@ -315,6 +352,14 @@ function parseInput(value) {
|
|
|
315
352
|
...(documentation !== undefined ? { documentation } : {}),
|
|
316
353
|
approval,
|
|
317
354
|
concurrency,
|
|
355
|
+
...(workspaceMode === undefined ? {} : { workspaceMode }),
|
|
356
|
+
...(input.directDefaultBranchAuthorized === undefined
|
|
357
|
+
? {}
|
|
358
|
+
: { directDefaultBranchAuthorized: input.directDefaultBranchAuthorized === true }),
|
|
359
|
+
...(preparedWorkspace === undefined ? {} : { preparedWorkspace }),
|
|
360
|
+
...(input.verificationChecks === undefined
|
|
361
|
+
? {}
|
|
362
|
+
: { verificationChecks: input.verificationChecks }),
|
|
318
363
|
};
|
|
319
364
|
}
|
|
320
365
|
function parseExistingPlan(value) {
|
|
@@ -423,31 +468,96 @@ function currentPlan(context) {
|
|
|
423
468
|
return discovered.plan;
|
|
424
469
|
return context.input.plan;
|
|
425
470
|
}
|
|
471
|
+
function preparedWorkspace(context) {
|
|
472
|
+
const request = context.input;
|
|
473
|
+
if (request.preparedWorkspace !== undefined)
|
|
474
|
+
return request.preparedWorkspace;
|
|
475
|
+
const result = includedResult(workspacePreparationWorkflow, context.outputs.workspace);
|
|
476
|
+
if (result.exit !== "ready")
|
|
477
|
+
throw new Error("autoimplement workspace is not ready");
|
|
478
|
+
return result.output;
|
|
479
|
+
}
|
|
426
480
|
function blockerChallenges(context) {
|
|
427
481
|
return context.state.steps
|
|
428
482
|
.filter((step) => step.nodeId === "challengeBlocker" && step.outcome === "ok")
|
|
429
483
|
.map((step) => step.output);
|
|
430
484
|
}
|
|
431
485
|
function latestBlockerClaim(context) {
|
|
432
|
-
const ids = [
|
|
433
|
-
"classifyImplementation",
|
|
434
|
-
"classifyVerification",
|
|
435
|
-
"repairReviewCommand",
|
|
436
|
-
"inspectComments",
|
|
437
|
-
"inspectCi",
|
|
438
|
-
"repairCiCommand",
|
|
439
|
-
"assessTrackedCi",
|
|
440
|
-
"classifyCi",
|
|
441
|
-
"finalizeDelivery",
|
|
442
|
-
"timeoutFallback",
|
|
443
|
-
];
|
|
444
486
|
for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
|
|
445
487
|
const step = context.state.steps[index];
|
|
446
|
-
if (step &&
|
|
447
|
-
return
|
|
488
|
+
if (step?.nodeId === "createBlockerClaim" && step.outcome === "ok") {
|
|
489
|
+
return step.output;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
throw new Error("No durable blocker claim is available to challenge");
|
|
493
|
+
}
|
|
494
|
+
function unwrapResult(value) {
|
|
495
|
+
const record = requireRecord(value, "blocker source output");
|
|
496
|
+
const output = record.output;
|
|
497
|
+
return output !== null && typeof output === "object" && !Array.isArray(output)
|
|
498
|
+
? output
|
|
499
|
+
: record;
|
|
500
|
+
}
|
|
501
|
+
function createBlockerClaim(context) {
|
|
502
|
+
const source = [...context.state.steps].reverse().find((step) => {
|
|
503
|
+
if (step.nodeId === "createBlockerClaim")
|
|
504
|
+
return false;
|
|
505
|
+
if (step.error !== undefined)
|
|
506
|
+
return true;
|
|
507
|
+
if (step.output === null || typeof step.output !== "object" || Array.isArray(step.output)) {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
const result = unwrapResult(step.output);
|
|
511
|
+
return (typeof result.reason === "string" ||
|
|
512
|
+
typeof result.summary === "string" ||
|
|
513
|
+
typeof result.blocker === "string");
|
|
514
|
+
});
|
|
515
|
+
if (source === undefined)
|
|
516
|
+
throw new Error("No blocker source step is available");
|
|
517
|
+
const result = unwrapResult(source.output ?? { reason: source.error ?? "Step failed" });
|
|
518
|
+
const reasonValue = result.reason ?? result.summary ?? result.blocker ?? source.error;
|
|
519
|
+
const reason = typeof reasonValue === "string" && reasonValue.trim().length > 0
|
|
520
|
+
? reasonValue.trim()
|
|
521
|
+
: `Autoimplement could not continue after ${source.nodeId}.`;
|
|
522
|
+
const commands = result.candidateCommands ?? result.commands;
|
|
523
|
+
const failedCommands = commands !== null && typeof commands === "object" && !Array.isArray(commands)
|
|
524
|
+
? (commands.items ?? [])
|
|
525
|
+
: [];
|
|
526
|
+
return {
|
|
527
|
+
schema: "pi-workflows.blocker-claim.v1",
|
|
528
|
+
sourceNode: typeof result.sourceNode === "string" && result.sourceNode.length > 0
|
|
529
|
+
? result.sourceNode
|
|
530
|
+
: source.nodeId,
|
|
531
|
+
attemptId: source.attemptId,
|
|
532
|
+
route: typeof result.route === "string" ? result.route : source.outcome,
|
|
533
|
+
reason,
|
|
534
|
+
evidence: typeof result.sourceNode === "string"
|
|
535
|
+
? result
|
|
536
|
+
: (result.evidence ?? source.output ?? source.error),
|
|
537
|
+
failedCommands,
|
|
538
|
+
relatedFailures: Array.isArray(result.relatedFailures) ? result.relatedFailures : [],
|
|
539
|
+
unrelatedFailures: Array.isArray(result.unrelatedFailures) ? result.unrelatedFailures : [],
|
|
540
|
+
recoveryAttempts: Array.isArray(result.repairAttempts) ? result.repairAttempts : [],
|
|
541
|
+
alternativesChecked: [],
|
|
542
|
+
authorityFact: `scope=${context.input.scope ?? "unspecified"}; merge=${context.input.merge === true}`,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function challengeTarget(context) {
|
|
546
|
+
const challenge = context.outputs.challengeBlocker;
|
|
547
|
+
if (challenge.route === "blocked" || challenge.nextStage === null)
|
|
548
|
+
return { route: "blocked" };
|
|
549
|
+
if (challenge.nextStage !== "planDiscovery" && currentPlan(context) === undefined) {
|
|
550
|
+
return { route: "planDiscovery" };
|
|
551
|
+
}
|
|
552
|
+
if (["documentation", "implementation", "repair", "redesign"].includes(challenge.nextStage)) {
|
|
553
|
+
try {
|
|
554
|
+
preparedWorkspace(context);
|
|
555
|
+
}
|
|
556
|
+
catch {
|
|
557
|
+
return { route: "workspace" };
|
|
448
558
|
}
|
|
449
559
|
}
|
|
450
|
-
|
|
560
|
+
return { route: challenge.nextStage };
|
|
451
561
|
}
|
|
452
562
|
function recentWorkflowAttempts(context) {
|
|
453
563
|
return context.state.steps.slice(-12).map((step) => ({
|
|
@@ -487,23 +597,26 @@ function parseFinding(value, severity) {
|
|
|
487
597
|
}
|
|
488
598
|
function parseVerificationForContext(value, context) {
|
|
489
599
|
const plan = parseVerificationCommandPlan(value);
|
|
490
|
-
const
|
|
491
|
-
const reported = Array.isArray(implementation.repositories)
|
|
492
|
-
? implementation.repositories.filter((entry) => typeof entry === "string")
|
|
493
|
-
: [];
|
|
494
|
-
const request = context.input;
|
|
495
|
-
const roots = new Set((reported.length > 0 ? reported : [request.repository ?? process.cwd()]).map((entry) => path.resolve(entry)));
|
|
600
|
+
const root = preparedWorkspace(context).worktreePath ?? preparedWorkspace(context).repository;
|
|
496
601
|
for (const command of plan.commands) {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
throw new Error(`verification command cwd was not reported by implementation: ${command.cwd}`);
|
|
602
|
+
if (path.resolve(command.cwd) !== path.resolve(root)) {
|
|
603
|
+
throw new Error(`verification command cwd must match the prepared workspace: ${root}`);
|
|
500
604
|
}
|
|
501
605
|
}
|
|
502
|
-
if (roots.size > 0) {
|
|
503
|
-
throw new Error(`verification plan is missing reported repositories: ${[...roots].join(", ")}`);
|
|
504
|
-
}
|
|
505
606
|
return plan;
|
|
506
607
|
}
|
|
608
|
+
function parsePublishedForContext(value, context) {
|
|
609
|
+
const result = parsePublishedRepositories(value);
|
|
610
|
+
const workspace = preparedWorkspace(context);
|
|
611
|
+
const expected = path.resolve(workspace.worktreePath ?? workspace.repository);
|
|
612
|
+
if (result.repositories[0]?.repository !== expected) {
|
|
613
|
+
throw new Error(`publication repository must match the prepared workspace: ${expected}`);
|
|
614
|
+
}
|
|
615
|
+
if (result.repositories.some((repository) => repository.repository !== expected)) {
|
|
616
|
+
throw new Error("publication cannot include an unprepared repository");
|
|
617
|
+
}
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
507
620
|
function currentPublishedRepositories(context) {
|
|
508
621
|
return latestOutput(context, ["verifyP2", "publish"]);
|
|
509
622
|
}
|
|
@@ -807,7 +920,15 @@ function ciForOutput(context) {
|
|
|
807
920
|
return aggregate;
|
|
808
921
|
}
|
|
809
922
|
function latestBlockedReason(context) {
|
|
923
|
+
for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
|
|
924
|
+
const step = context.state.steps[index];
|
|
925
|
+
if (step?.nodeId === "createBlockerClaim" && step.outcome === "ok") {
|
|
926
|
+
const claim = step.output;
|
|
927
|
+
return { reason: claim.reason, evidence: claim };
|
|
928
|
+
}
|
|
929
|
+
}
|
|
810
930
|
const candidates = [
|
|
931
|
+
"createBlockerClaim",
|
|
811
932
|
"timeoutFallbackGuard",
|
|
812
933
|
"timeoutFallback",
|
|
813
934
|
"challengeBlockerGuard",
|
|
@@ -847,8 +968,28 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
847
968
|
title: ({ input }) => `autoimplement: ${input.task.slice(0, 60)}`,
|
|
848
969
|
presentationPrompt: "Summarize what was implemented, the review rounds by severity, the CI result, the PR or merge result, and any remaining limitation. Include exact validation commands.",
|
|
849
970
|
startAt: "prepare",
|
|
850
|
-
maxSteps:
|
|
971
|
+
maxSteps: 320,
|
|
851
972
|
includes: {
|
|
973
|
+
workspace: includeWorkflow(workspacePreparationWorkflow, {
|
|
974
|
+
input: (context) => {
|
|
975
|
+
const request = context.input;
|
|
976
|
+
if (request.repository === undefined) {
|
|
977
|
+
throw new Error("autoimplement workspace preparation requires an absolute repository");
|
|
978
|
+
}
|
|
979
|
+
return {
|
|
980
|
+
repository: request.repository,
|
|
981
|
+
...(request.baseBranch === undefined ? {} : { baseBranch: request.baseBranch }),
|
|
982
|
+
...(request.scope === undefined ? {} : { scope: request.scope }),
|
|
983
|
+
...(request.workspaceMode === undefined ? {} : { workspaceMode: request.workspaceMode }),
|
|
984
|
+
...(request.directDefaultBranchAuthorized === undefined
|
|
985
|
+
? {}
|
|
986
|
+
: { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
|
|
987
|
+
...(request.preparedWorkspace === undefined
|
|
988
|
+
? {}
|
|
989
|
+
: { preparedWorkspace: request.preparedWorkspace }),
|
|
990
|
+
};
|
|
991
|
+
},
|
|
992
|
+
}),
|
|
852
993
|
documentation: includeWorkflow(autodocWorkflow, {
|
|
853
994
|
input: (context) => {
|
|
854
995
|
const request = context.input;
|
|
@@ -860,11 +1001,48 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
860
1001
|
task: request.task,
|
|
861
1002
|
plan,
|
|
862
1003
|
...(request.repository !== undefined ? { repository: request.repository } : {}),
|
|
1004
|
+
...(request.baseBranch !== undefined ? { baseBranch: request.baseBranch } : {}),
|
|
1005
|
+
...(request.scope !== undefined ? { scope: request.scope } : {}),
|
|
1006
|
+
...(request.directDefaultBranchAuthorized === undefined
|
|
1007
|
+
? {}
|
|
1008
|
+
: { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
|
|
1009
|
+
preparedWorkspace: preparedWorkspace(context),
|
|
1010
|
+
...(request.verificationChecks === undefined
|
|
1011
|
+
? {}
|
|
1012
|
+
: { verificationChecks: request.verificationChecks }),
|
|
863
1013
|
documents: request.documents ?? request.documentation?.documents ?? discovery?.documents ?? [],
|
|
864
1014
|
evidence: latestIssue(context),
|
|
865
1015
|
};
|
|
866
1016
|
},
|
|
867
1017
|
}),
|
|
1018
|
+
localVerification: includeWorkflow(changeVerificationWorkflow, {
|
|
1019
|
+
input: (context) => {
|
|
1020
|
+
const request = context.input;
|
|
1021
|
+
const plan = request.verificationChecks === undefined
|
|
1022
|
+
? latestOutput(context, ["planVerification"])
|
|
1023
|
+
: { commands: [], untested: [] };
|
|
1024
|
+
const implementation = latestOutput(context, ["implement"]);
|
|
1025
|
+
return {
|
|
1026
|
+
originatingWorkflow: "autoimplement",
|
|
1027
|
+
qualifiedNode: "autoimplement/localVerification",
|
|
1028
|
+
workspace: preparedWorkspace(context),
|
|
1029
|
+
checks: request.verificationChecks ??
|
|
1030
|
+
plan.commands.map((command) => ({
|
|
1031
|
+
...command,
|
|
1032
|
+
readOnly: true,
|
|
1033
|
+
baseEligible: true,
|
|
1034
|
+
changedFileScope: false,
|
|
1035
|
+
findingFormat: "text",
|
|
1036
|
+
})),
|
|
1037
|
+
changedFiles: Array.isArray(implementation.files)
|
|
1038
|
+
? implementation.files.filter((file) => typeof file === "string")
|
|
1039
|
+
: [],
|
|
1040
|
+
untested: plan.untested,
|
|
1041
|
+
plan: currentPlan(context),
|
|
1042
|
+
maxConcurrency: concurrency(context).verification,
|
|
1043
|
+
};
|
|
1044
|
+
},
|
|
1045
|
+
}),
|
|
868
1046
|
redesign: includeWorkflow(planChangeWorkflow, {
|
|
869
1047
|
input: (context) => {
|
|
870
1048
|
const request = context.input;
|
|
@@ -872,7 +1050,14 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
872
1050
|
task: request.task,
|
|
873
1051
|
...(request.scope !== undefined ? { scope: request.scope } : {}),
|
|
874
1052
|
...(request.constraints !== undefined ? { constraints: request.constraints } : {}),
|
|
875
|
-
|
|
1053
|
+
repository: request.repository,
|
|
1054
|
+
preparedWorkspace: preparedWorkspace(context),
|
|
1055
|
+
...(request.directDefaultBranchAuthorized === undefined
|
|
1056
|
+
? {}
|
|
1057
|
+
: { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
|
|
1058
|
+
...(request.verificationChecks === undefined
|
|
1059
|
+
? {}
|
|
1060
|
+
: { verificationChecks: request.verificationChecks }),
|
|
876
1061
|
documents: request.documents ?? request.documentation?.documents ?? [],
|
|
877
1062
|
...(currentPlan(context) !== undefined ? { previousPlan: currentPlan(context) } : {}),
|
|
878
1063
|
newEvidence: latestIssue(context),
|
|
@@ -895,13 +1080,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
895
1080
|
prepare: compute({
|
|
896
1081
|
run: ({ input }) => {
|
|
897
1082
|
const request = input;
|
|
898
|
-
return {
|
|
899
|
-
route: request.plan === undefined
|
|
900
|
-
? "find"
|
|
901
|
-
: request.documentation?.status === "current"
|
|
902
|
-
? "ready"
|
|
903
|
-
: "document",
|
|
904
|
-
};
|
|
1083
|
+
return { route: request.plan === undefined ? "find" : "workspace" };
|
|
905
1084
|
},
|
|
906
1085
|
}),
|
|
907
1086
|
findPlan: agent({
|
|
@@ -929,13 +1108,26 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
929
1108
|
return { route: "blocked", reason: discovered.reason, evidence: discovered.evidence };
|
|
930
1109
|
}
|
|
931
1110
|
return {
|
|
932
|
-
route:
|
|
1111
|
+
route: "workspace",
|
|
933
1112
|
plan: discovered.plan,
|
|
1113
|
+
documentation: discovered.documentation,
|
|
934
1114
|
reason: discovered.reason,
|
|
935
1115
|
evidence: discovered.evidence,
|
|
936
1116
|
};
|
|
937
1117
|
},
|
|
938
1118
|
}),
|
|
1119
|
+
routeWorkspace: compute({
|
|
1120
|
+
run: ({ input, outputs }) => {
|
|
1121
|
+
const request = input;
|
|
1122
|
+
const discovered = outputs.findPlan;
|
|
1123
|
+
return {
|
|
1124
|
+
route: request.documentation?.status === "current" || discovered?.documentation === "current"
|
|
1125
|
+
? "implement"
|
|
1126
|
+
: "document",
|
|
1127
|
+
workspace: preparedWorkspace({ input, outputs }),
|
|
1128
|
+
};
|
|
1129
|
+
},
|
|
1130
|
+
}),
|
|
939
1131
|
adoptPlan: compute({
|
|
940
1132
|
run: ({ outputs }) => {
|
|
941
1133
|
const result = includedResult(planChangeWorkflow, outputs.redesign);
|
|
@@ -963,10 +1155,10 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
963
1155
|
.filter((step) => step.nodeId === "timeoutFallback" && step.outcome === "ok")
|
|
964
1156
|
.map((step) => step.output);
|
|
965
1157
|
return [
|
|
966
|
-
"A bounded Autoimplement
|
|
1158
|
+
"A bounded Autoimplement step failed or timed out. Choose the safest existing workflow stage to run next instead of ending the run blindly.",
|
|
967
1159
|
"This is a read-only fallback step. Inspect state, but do not edit files, run mutating commands, commit, push, open or update a pull request, post comments, merge, deploy, or release.",
|
|
968
1160
|
"Inspect the current repository worktree, branch, diff, and commits. Inspect the remote branch, pull request, review, CI, merge, and final report when they exist and affect the next route.",
|
|
969
|
-
"Do not assume that
|
|
1161
|
+
"Do not assume that a mutating step failed or completed. Observe durable repository or pull-request state first, adopt an effect that already completed, and retry only a missing effect.",
|
|
970
1162
|
"Before any forward route, confirm that its accepted output belongs to the current work attempt and that observed local and remote heads match the accepted publication. Otherwise retry, replan, or block.",
|
|
971
1163
|
"Choose retry only when the timed-out stage must run again. Choose verify when accepted implementation output exists and verification is next. Choose review when accepted publication output exists. Choose ci only after comment inspection routed to CI. Choose deliver only after CI is green or classified unrelated. Choose replan when evidence invalidates the approved plan. Choose blocked only when no safe route exists.",
|
|
972
1164
|
"Do not skip required implementation, verification, review, CI, authorization, or delivery checks.",
|
|
@@ -985,9 +1177,6 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
985
1177
|
routeTimeoutFallback: compute({
|
|
986
1178
|
run: timeoutFallbackTarget,
|
|
987
1179
|
}),
|
|
988
|
-
propagateSupportedFailure: compute({
|
|
989
|
-
run: throwLatestSupportedFailure,
|
|
990
|
-
}),
|
|
991
1180
|
routeVerifyP2Result: compute({
|
|
992
1181
|
run: ({ outputs }) => outputs.verifyP2,
|
|
993
1182
|
}),
|
|
@@ -1010,6 +1199,8 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1010
1199
|
`Plan: ${JSON.stringify(currentPlan(context))}`,
|
|
1011
1200
|
`Authorized scope: ${request.scope ?? request.repository ?? "the current repository and task"}`,
|
|
1012
1201
|
`Constraints: ${JSON.stringify(request.constraints ?? [])}`,
|
|
1202
|
+
`Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
|
|
1203
|
+
"Use the prepared absolute workspace path for every read, edit, command, and report. Do not fall back to the Pi process working directory.",
|
|
1013
1204
|
"Before changing files, inspect the current worktree, diff, commits, branch, remote state, and matching pull request. Continue existing work and do not repeat completed effects.",
|
|
1014
1205
|
"Follow repository instructions and use the most elegant long-term production-ready implementation without unnecessary work.",
|
|
1015
1206
|
"If implementation exposes a new design or scope problem, report it precisely instead of forcing the old plan.",
|
|
@@ -1033,6 +1224,17 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1033
1224
|
expectedOutput: `{ "route": "verify" | "redesign" | "fix" | "blocked", "summary": "reason", "evidence": "evidence" }`,
|
|
1034
1225
|
validate: (value) => parseRoute(value, ["verify", "redesign", "fix", "blocked"], "implementation assessment"),
|
|
1035
1226
|
}),
|
|
1227
|
+
createBlockerClaim: compute({
|
|
1228
|
+
run: createBlockerClaim,
|
|
1229
|
+
}),
|
|
1230
|
+
routeBlockerClaim: compute({
|
|
1231
|
+
run: ({ outputs }) => {
|
|
1232
|
+
const claim = outputs.createBlockerClaim;
|
|
1233
|
+
return {
|
|
1234
|
+
route: claim.sourceNode === "challengeBlockerGuard" ? "blocked" : "challenge",
|
|
1235
|
+
};
|
|
1236
|
+
},
|
|
1237
|
+
}),
|
|
1036
1238
|
challengeBlockerGuard: compute({
|
|
1037
1239
|
run: (context) => {
|
|
1038
1240
|
const challenges = blockerChallenges(context);
|
|
@@ -1064,7 +1266,8 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1064
1266
|
"A local test failure, stale package, packaging or artifact mismatch, rollback preparation, or deployment procedure is not by itself outside authority.",
|
|
1065
1267
|
"If a safe deployment and rollback path is already authorized, a supported cutover is work to do, not a blocker.",
|
|
1066
1268
|
"Confirm blocked only when the issue blocks progress now, is outside authority, and has no safe practical path forward.",
|
|
1067
|
-
"Return continue with the next practical action
|
|
1269
|
+
"Return continue with the next practical action and its exact nextStage: planDiscovery, documentation, implementation, repair, review, ci, delivery, or redesign.",
|
|
1270
|
+
"Keep text concise, with at most five alternatives and five evidence items.",
|
|
1068
1271
|
`Task: ${request.task}`,
|
|
1069
1272
|
`Approved plan: ${JSON.stringify(currentPlan(context))}`,
|
|
1070
1273
|
`Current result and claimed blocker: ${JSON.stringify(latestBlockerClaim(context))}`,
|
|
@@ -1075,58 +1278,62 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1075
1278
|
`Recent workflow attempts: ${JSON.stringify(recentWorkflowAttempts(context))}`,
|
|
1076
1279
|
].join("\n");
|
|
1077
1280
|
},
|
|
1078
|
-
expectedOutput: `{ "route": "continue" | "blocked", "blockingNow": true | false, "outsideAuthority": true | false, "canProceed": true | false, "reason": "concise reason", "nextAction": "practical action or empty when blocked", "alternativesChecked": ["checked alternative"], "evidence": ["concrete evidence"] }`,
|
|
1281
|
+
expectedOutput: `{ "route": "continue" | "blocked", "blockingNow": true | false, "outsideAuthority": true | false, "canProceed": true | false, "reason": "concise reason", "nextAction": "practical action or empty when blocked", "nextStage": "planDiscovery" | "documentation" | "implementation" | "repair" | "review" | "ci" | "delivery" | "redesign" | null, "alternativesChecked": ["checked alternative"], "evidence": ["concrete evidence"] }`,
|
|
1079
1282
|
validate: parseBlockerChallenge,
|
|
1080
1283
|
}),
|
|
1284
|
+
routeChallenge: compute({ run: challengeTarget }),
|
|
1285
|
+
selectVerificationPath: compute({
|
|
1286
|
+
run: ({ input }) => ({
|
|
1287
|
+
route: input.verificationChecks === undefined ? "plan" : "verify",
|
|
1288
|
+
}),
|
|
1289
|
+
}),
|
|
1081
1290
|
planVerification: agent({
|
|
1082
1291
|
timeoutMs: 15 * 60_000,
|
|
1083
1292
|
statusDetail: "planning independent verification commands",
|
|
1084
|
-
prompt: () => [
|
|
1085
|
-
"Select
|
|
1086
|
-
"Return one
|
|
1293
|
+
prompt: (context) => [
|
|
1294
|
+
"Select all required local verification commands for the implementation.",
|
|
1295
|
+
"Return one or more commands for the prepared repository workspace.",
|
|
1087
1296
|
"Use exact executables and argument arrays without shell wrappers, environment overrides, stdin, Git or GitHub mutations, package publication, deployment, merge, or release commands.",
|
|
1088
|
-
"Use absolute
|
|
1297
|
+
"Use the prepared absolute workspace path as cwd for every command, explicit timeouts no longer than 2700000ms, and maxOutputChars no larger than 1000000.",
|
|
1089
1298
|
"List checks that cannot run locally under untested.",
|
|
1299
|
+
`Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
|
|
1090
1300
|
].join("\n"),
|
|
1091
1301
|
expectedOutput: `{ "commands": [{ "id": "stable-id", "command": "npm", "args": ["run", "check"], "cwd": "/absolute/repository", "timeoutMs": 2700000, "maxOutputChars": 1000000 }], "untested": ["remaining check"] }`,
|
|
1092
1302
|
validate: parseVerificationForContext,
|
|
1093
1303
|
}),
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
},
|
|
1099
|
-
statusDetail: "running independent verification commands",
|
|
1100
|
-
run: async (context) => {
|
|
1101
|
-
const plan = latestOutput(context, ["planVerification"]);
|
|
1102
|
-
return await runAutoimplementBatch(context, "verification", plan.commands, concurrency(context).verification);
|
|
1103
|
-
},
|
|
1304
|
+
routeVerifiedWorkspace: compute({
|
|
1305
|
+
run: (context) => ({
|
|
1306
|
+
route: preparedWorkspace(context).mode === "defaultBranch" ? "defaultBranch" : "pullRequest",
|
|
1307
|
+
}),
|
|
1104
1308
|
}),
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
statusDetail: "assessing verification",
|
|
1108
|
-
prompt: (context) => [
|
|
1109
|
-
"Assess the completed local verification commands.",
|
|
1110
|
-
"Set passed true only when every required command succeeded without truncated output.",
|
|
1111
|
-
"Report exact command outcomes, failures, and checks that still need remote verification.",
|
|
1112
|
-
`Command plan: ${JSON.stringify(latestOutput(context, ["planVerification"]))}`,
|
|
1113
|
-
`Command results: ${JSON.stringify(latestOutput(context, ["runVerification"]))}`,
|
|
1114
|
-
].join("\n"),
|
|
1115
|
-
expectedOutput: `{ "passed": true | false, "commands": [{ "command": "exact command", "outcome": "result" }], "failures": ["failure"], "untested": ["remaining check"] }`,
|
|
1116
|
-
validate: (value) => requireRecord(value, "verification result"),
|
|
1309
|
+
routeFinalizeDefaultBranchResult: compute({
|
|
1310
|
+
run: ({ outputs }) => outputs.finalizeDefaultBranch,
|
|
1117
1311
|
}),
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1312
|
+
finalizeDefaultBranch: agent({
|
|
1313
|
+
timeoutMs: 30 * 60_000,
|
|
1314
|
+
statusDetail: "finalizing default-branch work",
|
|
1315
|
+
prompt: (context) => {
|
|
1316
|
+
const request = context.input;
|
|
1317
|
+
return [
|
|
1318
|
+
"Finalize verified work in the explicitly authorized default-branch workspace.",
|
|
1319
|
+
"Never open a pull request from the default branch to itself.",
|
|
1320
|
+
"Commit and push only when the authorized scope explicitly allows each action. Otherwise leave the verified local change and report it.",
|
|
1321
|
+
"Do not merge, release, or deploy.",
|
|
1322
|
+
`Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
|
|
1323
|
+
`Authorized scope: ${request.scope}`,
|
|
1324
|
+
].join("\n");
|
|
1325
|
+
},
|
|
1326
|
+
expectedOutput: `{ "status": "completed" | "blocked", "committed": true | false, "pushed": true | false, "merged": false, "pr": "none", "reportComment": "summary", "reason": "result" }`,
|
|
1327
|
+
validate: (value) => {
|
|
1328
|
+
const result = requireRecord(value, "default-branch delivery");
|
|
1329
|
+
if (result.status !== "completed" && result.status !== "blocked") {
|
|
1330
|
+
throw new Error("default-branch delivery status must be completed or blocked");
|
|
1331
|
+
}
|
|
1332
|
+
if (result.merged !== false || result.pr !== "none") {
|
|
1333
|
+
throw new Error("default-branch delivery cannot merge or open a pull request to itself");
|
|
1334
|
+
}
|
|
1335
|
+
return result;
|
|
1336
|
+
},
|
|
1130
1337
|
}),
|
|
1131
1338
|
fix: agent({
|
|
1132
1339
|
timeoutMs: 45 * 60_000,
|
|
@@ -1136,6 +1343,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1136
1343
|
"Inspect the current diff and commits first. Continue any partial fix and change only work that is still missing.",
|
|
1137
1344
|
`Issue: ${JSON.stringify(latestIssue(context))}`,
|
|
1138
1345
|
`Current plan: ${JSON.stringify(currentPlan(context))}`,
|
|
1346
|
+
`Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
|
|
1139
1347
|
"Stop after the fix so verification can run again.",
|
|
1140
1348
|
].join("\n"),
|
|
1141
1349
|
expectedOutput: `{ "fixed": "what changed", "files": ["changed file"] }`,
|
|
@@ -1144,8 +1352,8 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1144
1352
|
publish: agent({
|
|
1145
1353
|
timeoutMs: 30 * 60_000,
|
|
1146
1354
|
statusDetail: "committing and pushing",
|
|
1147
|
-
prompt: (
|
|
1148
|
-
const request = input;
|
|
1355
|
+
prompt: (context) => {
|
|
1356
|
+
const request = context.input;
|
|
1149
1357
|
return [
|
|
1150
1358
|
"Commit and push the verified implementation before review.",
|
|
1151
1359
|
"Inspect the branch, local and remote heads, and matching pull requests first. Do not push an already-pushed head or create a second pull request for the same branch and base.",
|
|
@@ -1154,11 +1362,12 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1154
1362
|
"Report every repository that received a pushed pull request with its absolute repository path, branch, base branch, pushed head revision, and PR URL.",
|
|
1155
1363
|
"Include dependencyFingerprint only when a declared dependency result is relevant to review reuse.",
|
|
1156
1364
|
`Requested base branch: ${request.baseBranch ?? "discover each repository default branch"}.`,
|
|
1365
|
+
`Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
|
|
1157
1366
|
"Do not merge yet.",
|
|
1158
1367
|
].join("\n");
|
|
1159
1368
|
},
|
|
1160
1369
|
expectedOutput: `{ "repositories": [{ "repository": "/absolute/repository", "branch": "branch", "baseBranch": "base", "headRevision": "revision", "pr": "URL", "pushed": true, "dependencyFingerprint": "optional digest" }] }`,
|
|
1161
|
-
validate:
|
|
1370
|
+
validate: parsePublishedForContext,
|
|
1162
1371
|
}),
|
|
1163
1372
|
selectReviewCommands: compute({
|
|
1164
1373
|
run: selectReviewCommands,
|
|
@@ -1374,10 +1583,20 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1374
1583
|
task: request.task,
|
|
1375
1584
|
plan: currentPlan(context),
|
|
1376
1585
|
implementation: latestOutput(context, ["implement"]),
|
|
1377
|
-
verification:
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1586
|
+
verification: context.outputs.localVerification === undefined
|
|
1587
|
+
? latestOutput(context, ["verifyP2"])
|
|
1588
|
+
: includedResult(changeVerificationWorkflow, context.outputs.localVerification)
|
|
1589
|
+
.output,
|
|
1590
|
+
reviewRounds: context.outputs.finalizeDefaultBranch === undefined
|
|
1591
|
+
? reviewRoundsForOutput(context)
|
|
1592
|
+
: [],
|
|
1593
|
+
ci: context.outputs.finalizeDefaultBranch === undefined
|
|
1594
|
+
? ciForOutput(context)
|
|
1595
|
+
: {
|
|
1596
|
+
route: "notApplicable",
|
|
1597
|
+
reason: "Direct default-branch work has no pull request.",
|
|
1598
|
+
},
|
|
1599
|
+
delivery: latestOutput(context, ["finalizeDefaultBranch", "finalizeDelivery"]),
|
|
1381
1600
|
};
|
|
1382
1601
|
},
|
|
1383
1602
|
}),
|
|
@@ -1385,33 +1604,41 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1385
1604
|
edges: [
|
|
1386
1605
|
{
|
|
1387
1606
|
from: "prepare",
|
|
1388
|
-
switch: {
|
|
1389
|
-
on: "$.route",
|
|
1390
|
-
cases: { find: "findPlan", document: "documentation", ready: "implement" },
|
|
1391
|
-
},
|
|
1607
|
+
switch: { on: "$.route", cases: { find: "findPlan", workspace: "workspace" } },
|
|
1392
1608
|
},
|
|
1393
1609
|
{
|
|
1394
1610
|
from: "findPlan",
|
|
1395
|
-
switch: {
|
|
1611
|
+
switch: {
|
|
1612
|
+
on: "$.route",
|
|
1613
|
+
cases: { found: "routeFoundPlan", blocked: "createBlockerClaim" },
|
|
1614
|
+
},
|
|
1396
1615
|
},
|
|
1397
1616
|
{
|
|
1398
1617
|
from: "routeFoundPlan",
|
|
1399
1618
|
switch: {
|
|
1400
1619
|
on: "$.route",
|
|
1401
|
-
cases: {
|
|
1620
|
+
cases: { workspace: "workspace", blocked: "createBlockerClaim" },
|
|
1402
1621
|
},
|
|
1403
1622
|
},
|
|
1623
|
+
{ from: "workspace.ready", to: "routeWorkspace" },
|
|
1624
|
+
{ from: "workspace.blocked", to: "createBlockerClaim" },
|
|
1625
|
+
{
|
|
1626
|
+
from: "routeWorkspace",
|
|
1627
|
+
switch: { on: "$.route", cases: { implement: "implement", document: "documentation" } },
|
|
1628
|
+
},
|
|
1404
1629
|
{ from: "redesign.ready", to: "adoptPlan" },
|
|
1405
1630
|
{ from: "redesign.blocked", to: "blocked" },
|
|
1406
1631
|
{ from: "adoptPlan", to: "implement" },
|
|
1407
1632
|
{ from: "documentation.ready", to: "implement" },
|
|
1408
|
-
{ from: "documentation.blocked", to: "
|
|
1633
|
+
{ from: "documentation.blocked", to: "createBlockerClaim" },
|
|
1409
1634
|
{
|
|
1410
1635
|
from: "timeoutFallbackGuard",
|
|
1411
|
-
switch: {
|
|
1636
|
+
switch: {
|
|
1637
|
+
on: "$.route",
|
|
1638
|
+
cases: { recover: "timeoutFallback", blocked: "createBlockerClaim" },
|
|
1639
|
+
},
|
|
1412
1640
|
},
|
|
1413
1641
|
{ from: "timeoutFallback", to: "routeTimeoutFallback" },
|
|
1414
|
-
{ from: "propagateSupportedFailure", to: "blocked" },
|
|
1415
1642
|
{
|
|
1416
1643
|
from: "routeTimeoutFallback",
|
|
1417
1644
|
switch: {
|
|
@@ -1419,7 +1646,6 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1419
1646
|
cases: {
|
|
1420
1647
|
implement: "implement",
|
|
1421
1648
|
planVerification: "planVerification",
|
|
1422
|
-
verify: "verify",
|
|
1423
1649
|
fix: "fix",
|
|
1424
1650
|
publish: "publish",
|
|
1425
1651
|
addressP2: "addressP2",
|
|
@@ -1427,10 +1653,11 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1427
1653
|
inspectComments: "inspectComments",
|
|
1428
1654
|
inspectCi: "inspectCi",
|
|
1429
1655
|
opportunisticTest: "opportunisticTest",
|
|
1656
|
+
finalizeDefaultBranch: "finalizeDefaultBranch",
|
|
1430
1657
|
finalizeDelivery: "finalizeDelivery",
|
|
1431
1658
|
selectReviewCommands: "selectReviewCommands",
|
|
1432
1659
|
redesign: "redesign",
|
|
1433
|
-
blocked: "
|
|
1660
|
+
blocked: "createBlockerClaim",
|
|
1434
1661
|
},
|
|
1435
1662
|
},
|
|
1436
1663
|
},
|
|
@@ -1441,7 +1668,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1441
1668
|
cases: {
|
|
1442
1669
|
ok: "classifyImplementation",
|
|
1443
1670
|
timed_out: "timeoutFallbackGuard",
|
|
1444
|
-
failed: "
|
|
1671
|
+
failed: "timeoutFallbackGuard",
|
|
1445
1672
|
},
|
|
1446
1673
|
},
|
|
1447
1674
|
},
|
|
@@ -1450,64 +1677,100 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1450
1677
|
switch: {
|
|
1451
1678
|
on: "$.route",
|
|
1452
1679
|
cases: {
|
|
1453
|
-
verify: "
|
|
1680
|
+
verify: "selectVerificationPath",
|
|
1454
1681
|
redesign: "redesign",
|
|
1455
1682
|
fix: "fix",
|
|
1456
|
-
blocked: "
|
|
1683
|
+
blocked: "createBlockerClaim",
|
|
1457
1684
|
},
|
|
1458
1685
|
},
|
|
1459
1686
|
},
|
|
1687
|
+
{ from: "createBlockerClaim", to: "routeBlockerClaim" },
|
|
1688
|
+
{
|
|
1689
|
+
from: "routeBlockerClaim",
|
|
1690
|
+
switch: {
|
|
1691
|
+
on: "$.route",
|
|
1692
|
+
cases: { challenge: "challengeBlockerGuard", blocked: "blocked" },
|
|
1693
|
+
},
|
|
1694
|
+
},
|
|
1460
1695
|
{
|
|
1461
1696
|
from: "challengeBlockerGuard",
|
|
1462
|
-
switch: {
|
|
1697
|
+
switch: {
|
|
1698
|
+
on: "$.route",
|
|
1699
|
+
cases: { challenge: "challengeBlocker", blocked: "createBlockerClaim" },
|
|
1700
|
+
},
|
|
1463
1701
|
},
|
|
1464
1702
|
{
|
|
1465
1703
|
from: "challengeBlocker",
|
|
1466
|
-
switch: { on: "$.route", cases: { continue: "
|
|
1704
|
+
switch: { on: "$.route", cases: { continue: "routeChallenge", blocked: "blocked" } },
|
|
1467
1705
|
},
|
|
1468
1706
|
{
|
|
1469
|
-
from: "
|
|
1707
|
+
from: "routeChallenge",
|
|
1470
1708
|
switch: {
|
|
1471
|
-
on: "
|
|
1709
|
+
on: "$.route",
|
|
1472
1710
|
cases: {
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1711
|
+
planDiscovery: "findPlan",
|
|
1712
|
+
workspace: "workspace",
|
|
1713
|
+
documentation: "documentation",
|
|
1714
|
+
implementation: "implement",
|
|
1715
|
+
repair: "fix",
|
|
1716
|
+
review: "selectReviewCommands",
|
|
1717
|
+
ci: "inspectCi",
|
|
1718
|
+
delivery: "finalizeDelivery",
|
|
1719
|
+
redesign: "redesign",
|
|
1720
|
+
blocked: "blocked",
|
|
1476
1721
|
},
|
|
1477
1722
|
},
|
|
1478
1723
|
},
|
|
1479
|
-
{ from: "runVerification", to: "verify" },
|
|
1480
1724
|
{
|
|
1481
|
-
from: "
|
|
1725
|
+
from: "selectVerificationPath",
|
|
1726
|
+
switch: { on: "$.route", cases: { plan: "planVerification", verify: "localVerification" } },
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
from: "planVerification",
|
|
1482
1730
|
switch: {
|
|
1483
1731
|
on: "$result.outcome",
|
|
1484
1732
|
cases: {
|
|
1485
|
-
ok: "
|
|
1733
|
+
ok: "localVerification",
|
|
1486
1734
|
timed_out: "timeoutFallbackGuard",
|
|
1487
|
-
failed: "
|
|
1735
|
+
failed: "timeoutFallbackGuard",
|
|
1488
1736
|
},
|
|
1489
1737
|
},
|
|
1490
1738
|
},
|
|
1739
|
+
{ from: "localVerification.ready", to: "routeVerifiedWorkspace" },
|
|
1740
|
+
{ from: "localVerification.blocked", to: "createBlockerClaim" },
|
|
1491
1741
|
{
|
|
1492
|
-
from: "
|
|
1742
|
+
from: "routeVerifiedWorkspace",
|
|
1493
1743
|
switch: {
|
|
1494
1744
|
on: "$.route",
|
|
1745
|
+
cases: { pullRequest: "publish", defaultBranch: "finalizeDefaultBranch" },
|
|
1746
|
+
},
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
from: "finalizeDefaultBranch",
|
|
1750
|
+
switch: {
|
|
1751
|
+
on: "$result.outcome",
|
|
1495
1752
|
cases: {
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
blocked: "challengeBlockerGuard",
|
|
1753
|
+
ok: "routeFinalizeDefaultBranchResult",
|
|
1754
|
+
timed_out: "timeoutFallbackGuard",
|
|
1755
|
+
failed: "timeoutFallbackGuard",
|
|
1500
1756
|
},
|
|
1501
1757
|
},
|
|
1502
1758
|
},
|
|
1759
|
+
{
|
|
1760
|
+
from: "routeFinalizeDefaultBranchResult",
|
|
1761
|
+
switch: {
|
|
1762
|
+
on: "$.status",
|
|
1763
|
+
cases: { completed: "finalize", blocked: "createBlockerClaim" },
|
|
1764
|
+
},
|
|
1765
|
+
},
|
|
1503
1766
|
{
|
|
1504
1767
|
from: "fix",
|
|
1505
1768
|
switch: {
|
|
1506
1769
|
on: "$result.outcome",
|
|
1507
1770
|
cases: {
|
|
1508
|
-
ok: "
|
|
1771
|
+
ok: "selectVerificationPath",
|
|
1509
1772
|
timed_out: "timeoutFallbackGuard",
|
|
1510
|
-
failed: "
|
|
1773
|
+
failed: "timeoutFallbackGuard",
|
|
1511
1774
|
},
|
|
1512
1775
|
},
|
|
1513
1776
|
},
|
|
@@ -1518,7 +1781,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1518
1781
|
cases: {
|
|
1519
1782
|
ok: "selectReviewCommands",
|
|
1520
1783
|
timed_out: "timeoutFallbackGuard",
|
|
1521
|
-
failed: "
|
|
1784
|
+
failed: "timeoutFallbackGuard",
|
|
1522
1785
|
},
|
|
1523
1786
|
},
|
|
1524
1787
|
},
|
|
@@ -1534,7 +1797,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1534
1797
|
from: "repairReviewCommand",
|
|
1535
1798
|
switch: {
|
|
1536
1799
|
on: "$.route",
|
|
1537
|
-
cases: { retry: "runReview", blocked: "
|
|
1800
|
+
cases: { retry: "runReview", blocked: "createBlockerClaim" },
|
|
1538
1801
|
},
|
|
1539
1802
|
},
|
|
1540
1803
|
{
|
|
@@ -1560,7 +1823,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1560
1823
|
cases: {
|
|
1561
1824
|
ok: "verifyP2",
|
|
1562
1825
|
timed_out: "timeoutFallbackGuard",
|
|
1563
|
-
failed: "
|
|
1826
|
+
failed: "timeoutFallbackGuard",
|
|
1564
1827
|
},
|
|
1565
1828
|
},
|
|
1566
1829
|
},
|
|
@@ -1571,7 +1834,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1571
1834
|
cases: {
|
|
1572
1835
|
ok: "routeVerifyP2Result",
|
|
1573
1836
|
timed_out: "timeoutFallbackGuard",
|
|
1574
|
-
failed: "
|
|
1837
|
+
failed: "timeoutFallbackGuard",
|
|
1575
1838
|
},
|
|
1576
1839
|
},
|
|
1577
1840
|
},
|
|
@@ -1586,7 +1849,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1586
1849
|
cases: {
|
|
1587
1850
|
ok: "routeInspectCommentsResult",
|
|
1588
1851
|
timed_out: "timeoutFallbackGuard",
|
|
1589
|
-
failed: "
|
|
1852
|
+
failed: "timeoutFallbackGuard",
|
|
1590
1853
|
},
|
|
1591
1854
|
},
|
|
1592
1855
|
},
|
|
@@ -1598,7 +1861,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1598
1861
|
redesign: "redesign",
|
|
1599
1862
|
fix: "fix",
|
|
1600
1863
|
ci: "inspectCi",
|
|
1601
|
-
blocked: "
|
|
1864
|
+
blocked: "createBlockerClaim",
|
|
1602
1865
|
},
|
|
1603
1866
|
},
|
|
1604
1867
|
},
|
|
@@ -1609,7 +1872,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1609
1872
|
cases: {
|
|
1610
1873
|
ok: "routeInspectCiResult",
|
|
1611
1874
|
timed_out: "timeoutFallbackGuard",
|
|
1612
|
-
failed: "
|
|
1875
|
+
failed: "timeoutFallbackGuard",
|
|
1613
1876
|
},
|
|
1614
1877
|
},
|
|
1615
1878
|
},
|
|
@@ -1621,7 +1884,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1621
1884
|
green: "finalizeDelivery",
|
|
1622
1885
|
failed: "classifyCi",
|
|
1623
1886
|
pending: "trackCi",
|
|
1624
|
-
unavailable: "
|
|
1887
|
+
unavailable: "createBlockerClaim",
|
|
1625
1888
|
},
|
|
1626
1889
|
},
|
|
1627
1890
|
},
|
|
@@ -1633,7 +1896,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1633
1896
|
from: "repairCiCommand",
|
|
1634
1897
|
switch: {
|
|
1635
1898
|
on: "$.route",
|
|
1636
|
-
cases: { retry: "trackCi", blocked: "
|
|
1899
|
+
cases: { retry: "trackCi", blocked: "createBlockerClaim" },
|
|
1637
1900
|
},
|
|
1638
1901
|
},
|
|
1639
1902
|
{
|
|
@@ -1644,7 +1907,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1644
1907
|
green: "finalizeDelivery",
|
|
1645
1908
|
failed: "classifyCi",
|
|
1646
1909
|
pending: "opportunisticTest",
|
|
1647
|
-
unavailable: "
|
|
1910
|
+
unavailable: "createBlockerClaim",
|
|
1648
1911
|
},
|
|
1649
1912
|
},
|
|
1650
1913
|
},
|
|
@@ -1655,7 +1918,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1655
1918
|
cases: {
|
|
1656
1919
|
ok: "inspectCi",
|
|
1657
1920
|
timed_out: "timeoutFallbackGuard",
|
|
1658
|
-
failed: "
|
|
1921
|
+
failed: "timeoutFallbackGuard",
|
|
1659
1922
|
},
|
|
1660
1923
|
},
|
|
1661
1924
|
},
|
|
@@ -1667,7 +1930,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1667
1930
|
redesign: "redesign",
|
|
1668
1931
|
fix: "fix",
|
|
1669
1932
|
unrelated: "finalizeDelivery",
|
|
1670
|
-
blocked: "
|
|
1933
|
+
blocked: "createBlockerClaim",
|
|
1671
1934
|
},
|
|
1672
1935
|
},
|
|
1673
1936
|
},
|
|
@@ -1678,7 +1941,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1678
1941
|
cases: {
|
|
1679
1942
|
ok: "routeFinalizeDeliveryResult",
|
|
1680
1943
|
timed_out: "timeoutFallbackGuard",
|
|
1681
|
-
failed: "
|
|
1944
|
+
failed: "timeoutFallbackGuard",
|
|
1682
1945
|
},
|
|
1683
1946
|
},
|
|
1684
1947
|
},
|
|
@@ -1686,7 +1949,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1686
1949
|
from: "routeFinalizeDeliveryResult",
|
|
1687
1950
|
switch: {
|
|
1688
1951
|
on: "$.status",
|
|
1689
|
-
cases: { completed: "finalize", blocked: "
|
|
1952
|
+
cases: { completed: "finalize", blocked: "createBlockerClaim" },
|
|
1690
1953
|
},
|
|
1691
1954
|
},
|
|
1692
1955
|
],
|