agentweaver 0.1.3 → 0.1.4
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 +48 -14
- package/dist/artifacts.js +34 -0
- package/dist/executors/verify-build-executor.js +110 -9
- package/dist/index.js +82 -5
- package/dist/interactive-ui.js +100 -13
- package/dist/pipeline/checks.js +5 -0
- package/dist/pipeline/declarative-flow-runner.js +16 -0
- package/dist/pipeline/flow-specs/auto.json +17 -3
- package/dist/pipeline/flow-specs/bug-analyze.json +140 -0
- package/dist/pipeline/flow-specs/bug-fix.json +44 -0
- package/dist/pipeline/flow-specs/mr-description.json +61 -0
- package/dist/pipeline/flow-specs/run-linter-loop.json +149 -0
- package/dist/pipeline/flow-specs/run-tests-loop.json +149 -0
- package/dist/pipeline/flow-specs/task-describe.json +61 -0
- package/dist/pipeline/node-registry.js +3 -0
- package/dist/pipeline/nodes/flow-run-node.js +40 -0
- package/dist/pipeline/nodes/verify-build-node.js +1 -0
- package/dist/pipeline/prompt-registry.js +6 -1
- package/dist/pipeline/spec-compiler.js +13 -0
- package/dist/pipeline/spec-validator.js +12 -0
- package/dist/pipeline/value-resolver.js +19 -1
- package/dist/prompts.js +21 -0
- package/dist/structured-artifacts.js +178 -0
- package/package.json +1 -1
package/dist/interactive-ui.js
CHANGED
|
@@ -483,32 +483,62 @@ export class InteractiveUi {
|
|
|
483
483
|
const lines = [flow.label, ""];
|
|
484
484
|
for (const item of this.visiblePhaseItems(flow, flowState)) {
|
|
485
485
|
if (item.kind === "group") {
|
|
486
|
-
|
|
487
|
-
|
|
486
|
+
const visiblePhases = item.phases.filter((phase) => this.shouldDisplayPhase(flow, flowState, phase));
|
|
487
|
+
if (visiblePhases.length === 0) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
lines.push(`${this.symbolForGroup(flow.id, flow, visiblePhases, flowState)} ${item.label}`);
|
|
491
|
+
for (const phase of visiblePhases) {
|
|
488
492
|
const phaseState = flowState?.phases.find((candidate) => candidate.id === phase.id);
|
|
489
|
-
|
|
493
|
+
const phaseStatus = this.displayStatusForPhase(flowState, flow, phase, phaseState?.status ?? null);
|
|
494
|
+
lines.push(` ${this.symbolForStatus(flow.id, phaseStatus)} ${this.displayPhaseId(phase)}`);
|
|
490
495
|
for (const step of phase.steps) {
|
|
491
496
|
const stepState = phaseState?.steps.find((candidate) => candidate.id === step.id);
|
|
492
|
-
|
|
497
|
+
const stepStatus = this.displayStatusForStep(flowState, flow, phase, stepState?.status ?? null);
|
|
498
|
+
lines.push(` ${this.symbolForStatus(flow.id, stepStatus)} ${step.id}`);
|
|
493
499
|
}
|
|
494
500
|
}
|
|
495
501
|
lines.push("");
|
|
496
502
|
continue;
|
|
497
503
|
}
|
|
498
504
|
const phase = item.phase;
|
|
505
|
+
if (!this.shouldDisplayPhase(flow, flowState, phase)) {
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
499
508
|
const phaseState = flowState?.phases.find((candidate) => candidate.id === phase.id);
|
|
500
|
-
|
|
509
|
+
const phaseStatus = this.displayStatusForPhase(flowState, flow, phase, phaseState?.status ?? null);
|
|
510
|
+
lines.push(`${this.symbolForStatus(flow.id, phaseStatus)} ${this.displayPhaseId(phase)}`);
|
|
501
511
|
for (const step of phase.steps) {
|
|
502
512
|
const stepState = phaseState?.steps.find((candidate) => candidate.id === step.id);
|
|
503
|
-
|
|
513
|
+
const stepStatus = this.displayStatusForStep(flowState, flow, phase, stepState?.status ?? null);
|
|
514
|
+
lines.push(` ${this.symbolForStatus(flow.id, stepStatus)} ${step.id}`);
|
|
504
515
|
}
|
|
505
516
|
lines.push("");
|
|
506
517
|
}
|
|
507
518
|
if (flowState?.terminated) {
|
|
508
|
-
lines.push(
|
|
519
|
+
lines.push(`✓ Flow completed successfully`);
|
|
520
|
+
lines.push(`Reason: ${flowState.terminationReason ?? "flow terminated"}`);
|
|
509
521
|
}
|
|
510
522
|
this.progress.setContent(lines.join("\n").trimEnd());
|
|
511
523
|
}
|
|
524
|
+
displayStatusForPhase(flowState, flow, phase, actualStatus) {
|
|
525
|
+
if (actualStatus) {
|
|
526
|
+
return actualStatus;
|
|
527
|
+
}
|
|
528
|
+
if (!flowState?.terminated) {
|
|
529
|
+
return "pending";
|
|
530
|
+
}
|
|
531
|
+
return this.isAfterTermination(flowState, flow, phase) ? "skipped" : "pending";
|
|
532
|
+
}
|
|
533
|
+
displayStatusForStep(flowState, flow, phase, actualStatus) {
|
|
534
|
+
if (actualStatus) {
|
|
535
|
+
return actualStatus;
|
|
536
|
+
}
|
|
537
|
+
if (!flowState?.terminated) {
|
|
538
|
+
return "pending";
|
|
539
|
+
}
|
|
540
|
+
return this.isAfterTermination(flowState, flow, phase) ? "skipped" : "pending";
|
|
541
|
+
}
|
|
512
542
|
symbolForStatus(flowId, status) {
|
|
513
543
|
if (status === "done") {
|
|
514
544
|
return "✓";
|
|
@@ -522,8 +552,8 @@ export class InteractiveUi {
|
|
|
522
552
|
}
|
|
523
553
|
return "○";
|
|
524
554
|
}
|
|
525
|
-
symbolForGroup(flowId, phases, flowState) {
|
|
526
|
-
const statuses = phases.map((phase) => flowState?.phases.find((candidate) => candidate.id === phase.id)?.status ??
|
|
555
|
+
symbolForGroup(flowId, flow, phases, flowState) {
|
|
556
|
+
const statuses = phases.map((phase) => this.displayStatusForPhase(flowState, flow, phase, flowState?.phases.find((candidate) => candidate.id === phase.id)?.status ?? null));
|
|
527
557
|
if (statuses.some((status) => status === "running")) {
|
|
528
558
|
return this.symbolForStatus(flowId, "running");
|
|
529
559
|
}
|
|
@@ -568,9 +598,13 @@ export class InteractiveUi {
|
|
|
568
598
|
const pendingSeries = new Set();
|
|
569
599
|
return this.groupPhases(flow).filter((item) => {
|
|
570
600
|
if (item.kind === "phase") {
|
|
571
|
-
return
|
|
601
|
+
return this.shouldDisplayPhase(flow, flowState, item.phase);
|
|
602
|
+
}
|
|
603
|
+
const visiblePhases = item.phases.filter((phase) => this.shouldDisplayPhase(flow, flowState, phase));
|
|
604
|
+
const hasState = visiblePhases.some((phase) => flowState?.phases.some((candidate) => candidate.id === phase.id));
|
|
605
|
+
if (visiblePhases.length === 0) {
|
|
606
|
+
return false;
|
|
572
607
|
}
|
|
573
|
-
const hasState = item.phases.some((phase) => flowState?.phases.some((candidate) => candidate.id === phase.id));
|
|
574
608
|
if (hasState) {
|
|
575
609
|
return true;
|
|
576
610
|
}
|
|
@@ -585,6 +619,42 @@ export class InteractiveUi {
|
|
|
585
619
|
const entries = Object.entries(repeatVars).sort(([left], [right]) => left.localeCompare(right));
|
|
586
620
|
return JSON.stringify(entries);
|
|
587
621
|
}
|
|
622
|
+
shouldDisplayPhase(flow, flowState, phase) {
|
|
623
|
+
const phaseState = flowState?.phases.find((candidate) => candidate.id === phase.id) ?? null;
|
|
624
|
+
if (!flowState) {
|
|
625
|
+
if (Object.keys(phase.repeatVars).length > 0) {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
return !this.hasPreviousRepeatPhase(flow, phase);
|
|
629
|
+
}
|
|
630
|
+
if (Object.keys(phase.repeatVars).length === 0) {
|
|
631
|
+
if (!phaseState) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
if (phaseState?.status === "skipped" && flowState.terminated && this.isAfterTermination(flowState, flow, phase)) {
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
if (!phaseState) {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
if (phaseState.status === "skipped" && flowState.terminated && this.isAfterTermination(flowState, flow, phase)) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
hasPreviousRepeatPhase(flow, phase) {
|
|
648
|
+
for (const candidate of flow.phases) {
|
|
649
|
+
if (candidate.id === phase.id) {
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
if (Object.keys(candidate.repeatVars).length > 0) {
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return false;
|
|
657
|
+
}
|
|
588
658
|
repeatSeriesKey(phases) {
|
|
589
659
|
const repeatVarNames = Object.keys(phases[0]?.repeatVars ?? {}).sort();
|
|
590
660
|
const phaseNames = phases.map((phase) => this.displayPhaseId(phase));
|
|
@@ -594,7 +664,7 @@ export class InteractiveUi {
|
|
|
594
664
|
});
|
|
595
665
|
}
|
|
596
666
|
repeatLabel(repeatVars) {
|
|
597
|
-
const entries = Object.entries(repeatVars);
|
|
667
|
+
const entries = Object.entries(repeatVars).filter(([key]) => !key.endsWith("_minus_one"));
|
|
598
668
|
if (entries.length === 0) {
|
|
599
669
|
return null;
|
|
600
670
|
}
|
|
@@ -606,7 +676,10 @@ export class InteractiveUi {
|
|
|
606
676
|
}
|
|
607
677
|
displayPhaseId(phase) {
|
|
608
678
|
let result = phase.id;
|
|
609
|
-
|
|
679
|
+
const values = Object.entries(phase.repeatVars)
|
|
680
|
+
.filter(([key]) => !key.endsWith("_minus_one"))
|
|
681
|
+
.map(([, value]) => value);
|
|
682
|
+
for (const value of values) {
|
|
610
683
|
const suffix = `_${String(value)}`;
|
|
611
684
|
if (result.endsWith(suffix)) {
|
|
612
685
|
result = result.slice(0, -suffix.length);
|
|
@@ -614,6 +687,20 @@ export class InteractiveUi {
|
|
|
614
687
|
}
|
|
615
688
|
return result;
|
|
616
689
|
}
|
|
690
|
+
isAfterTermination(flowState, flow, phase) {
|
|
691
|
+
const terminationReason = flowState.terminationReason ?? "";
|
|
692
|
+
const match = /^Stopped by ([^:]+):/.exec(terminationReason);
|
|
693
|
+
if (!match) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
const stoppedPhaseId = match[1];
|
|
697
|
+
const stoppedIndex = flow.phases.findIndex((candidate) => candidate.id === stoppedPhaseId);
|
|
698
|
+
const currentIndex = flow.phases.findIndex((candidate) => candidate.id === phase.id);
|
|
699
|
+
if (stoppedIndex < 0 || currentIndex < 0) {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
return currentIndex > stoppedIndex;
|
|
703
|
+
}
|
|
617
704
|
openConfirm() {
|
|
618
705
|
const flow = this.flowMap.get(this.selectedFlowId);
|
|
619
706
|
if (!flow) {
|
package/dist/pipeline/checks.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { requireArtifacts } from "../artifacts.js";
|
|
2
2
|
import { TaskRunnerError } from "../errors.js";
|
|
3
|
+
import { validateStructuredArtifacts } from "../structured-artifacts.js";
|
|
3
4
|
export function runNodeChecks(checks) {
|
|
4
5
|
for (const check of checks) {
|
|
5
6
|
if (check.kind === "require-artifacts") {
|
|
@@ -10,6 +11,10 @@ export function runNodeChecks(checks) {
|
|
|
10
11
|
requireArtifacts([check.path], check.message);
|
|
11
12
|
continue;
|
|
12
13
|
}
|
|
14
|
+
if (check.kind === "require-structured-artifacts") {
|
|
15
|
+
validateStructuredArtifacts(check.items, check.message);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
13
18
|
throw new TaskRunnerError(`Unsupported node check: ${check.kind ?? "unknown"}`);
|
|
14
19
|
}
|
|
15
20
|
}
|
|
@@ -76,6 +76,22 @@ function resolveExpectation(expectation, context) {
|
|
|
76
76
|
message: expectation.message,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
+
if (expectation.kind === "require-structured-artifacts") {
|
|
80
|
+
return {
|
|
81
|
+
kind: "require-structured-artifacts",
|
|
82
|
+
items: expectation.items.map((item) => {
|
|
83
|
+
const value = resolveValue(item.path, context);
|
|
84
|
+
if (typeof value !== "string") {
|
|
85
|
+
throw new TaskRunnerError("Expectation 'require-structured-artifacts' item path must resolve to string");
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
path: value,
|
|
89
|
+
schemaId: item.schemaId,
|
|
90
|
+
};
|
|
91
|
+
}),
|
|
92
|
+
message: expectation.message,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
79
95
|
if (expectation.kind === "require-file") {
|
|
80
96
|
const value = resolveValue(expectation.path, context);
|
|
81
97
|
if (typeof value !== "string") {
|
|
@@ -123,11 +123,25 @@
|
|
|
123
123
|
"id": "test_after_implement",
|
|
124
124
|
"steps": [
|
|
125
125
|
{
|
|
126
|
-
"id": "
|
|
127
|
-
"node": "
|
|
126
|
+
"id": "run_linter_loop_after_implement",
|
|
127
|
+
"node": "flow-run",
|
|
128
128
|
"params": {
|
|
129
|
+
"fileName": { "const": "run-linter-loop.json" },
|
|
130
|
+
"labelText": { "const": "Running run-linter-loop after implement" },
|
|
131
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
129
132
|
"dockerComposeFile": { "ref": "params.dockerComposeFile" },
|
|
130
|
-
"
|
|
133
|
+
"extraPrompt": { "ref": "params.extraPrompt" }
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "run_tests_loop_after_implement",
|
|
138
|
+
"node": "flow-run",
|
|
139
|
+
"params": {
|
|
140
|
+
"fileName": { "const": "run-tests-loop.json" },
|
|
141
|
+
"labelText": { "const": "Running run-tests-loop after implement" },
|
|
142
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
143
|
+
"dockerComposeFile": { "ref": "params.dockerComposeFile" },
|
|
144
|
+
"extraPrompt": { "ref": "params.extraPrompt" }
|
|
131
145
|
}
|
|
132
146
|
}
|
|
133
147
|
]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "bug-analyze-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "bug_analyze",
|
|
7
|
+
"steps": [
|
|
8
|
+
{
|
|
9
|
+
"id": "fetch_jira",
|
|
10
|
+
"node": "jira-fetch",
|
|
11
|
+
"params": {
|
|
12
|
+
"jiraApiUrl": { "ref": "params.jiraApiUrl" },
|
|
13
|
+
"outputFile": {
|
|
14
|
+
"artifact": {
|
|
15
|
+
"kind": "jira-task-file",
|
|
16
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"expect": [
|
|
21
|
+
{
|
|
22
|
+
"kind": "require-file",
|
|
23
|
+
"path": {
|
|
24
|
+
"artifact": {
|
|
25
|
+
"kind": "jira-task-file",
|
|
26
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"message": "Jira fetch node did not produce the Jira task file."
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "run_codex_bug_analyze",
|
|
35
|
+
"node": "codex-local-prompt",
|
|
36
|
+
"prompt": {
|
|
37
|
+
"templateRef": "bug-analyze",
|
|
38
|
+
"vars": {
|
|
39
|
+
"jira_task_file": {
|
|
40
|
+
"artifact": {
|
|
41
|
+
"kind": "jira-task-file",
|
|
42
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"bug_analyze_file": {
|
|
46
|
+
"artifact": {
|
|
47
|
+
"kind": "bug-analyze-file",
|
|
48
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"bug_analyze_json_file": {
|
|
52
|
+
"artifact": {
|
|
53
|
+
"kind": "bug-analyze-json-file",
|
|
54
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"bug_fix_design_file": {
|
|
58
|
+
"artifact": {
|
|
59
|
+
"kind": "bug-fix-design-file",
|
|
60
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"bug_fix_design_json_file": {
|
|
64
|
+
"artifact": {
|
|
65
|
+
"kind": "bug-fix-design-json-file",
|
|
66
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"bug_fix_plan_file": {
|
|
70
|
+
"artifact": {
|
|
71
|
+
"kind": "bug-fix-plan-file",
|
|
72
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"bug_fix_plan_json_file": {
|
|
76
|
+
"artifact": {
|
|
77
|
+
"kind": "bug-fix-plan-json-file",
|
|
78
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"extraPrompt": { "ref": "params.extraPrompt" },
|
|
83
|
+
"format": "task-prompt"
|
|
84
|
+
},
|
|
85
|
+
"params": {
|
|
86
|
+
"labelText": { "const": "Running Codex bug analysis mode" },
|
|
87
|
+
"model": { "const": "gpt-5.4" }
|
|
88
|
+
},
|
|
89
|
+
"expect": [
|
|
90
|
+
{
|
|
91
|
+
"kind": "require-artifacts",
|
|
92
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
93
|
+
"paths": {
|
|
94
|
+
"artifactList": {
|
|
95
|
+
"kind": "bug-analyze-artifacts",
|
|
96
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"message": "Bug analyze mode did not produce the required artifacts."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"kind": "require-structured-artifacts",
|
|
103
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
104
|
+
"items": [
|
|
105
|
+
{
|
|
106
|
+
"path": {
|
|
107
|
+
"artifact": {
|
|
108
|
+
"kind": "bug-analyze-json-file",
|
|
109
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"schemaId": "bug-analysis/v1"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"path": {
|
|
116
|
+
"artifact": {
|
|
117
|
+
"kind": "bug-fix-design-json-file",
|
|
118
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"schemaId": "bug-fix-design/v1"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"path": {
|
|
125
|
+
"artifact": {
|
|
126
|
+
"kind": "bug-fix-plan-json-file",
|
|
127
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"schemaId": "bug-fix-plan/v1"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"message": "Bug analyze mode produced invalid structured artifacts."
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "bug-fix-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "bug_fix",
|
|
7
|
+
"steps": [
|
|
8
|
+
{
|
|
9
|
+
"id": "run_codex_bug_fix",
|
|
10
|
+
"node": "codex-local-prompt",
|
|
11
|
+
"prompt": {
|
|
12
|
+
"templateRef": "bug-fix",
|
|
13
|
+
"vars": {
|
|
14
|
+
"bug_analyze_json_file": {
|
|
15
|
+
"artifact": {
|
|
16
|
+
"kind": "bug-analyze-json-file",
|
|
17
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"bug_fix_design_json_file": {
|
|
21
|
+
"artifact": {
|
|
22
|
+
"kind": "bug-fix-design-json-file",
|
|
23
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"bug_fix_plan_json_file": {
|
|
27
|
+
"artifact": {
|
|
28
|
+
"kind": "bug-fix-plan-json-file",
|
|
29
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"extraPrompt": { "ref": "params.extraPrompt" },
|
|
34
|
+
"format": "task-prompt"
|
|
35
|
+
},
|
|
36
|
+
"params": {
|
|
37
|
+
"labelText": { "const": "Running Codex bug fix mode locally" },
|
|
38
|
+
"model": { "const": "gpt-5.4" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "mr-description-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "mr_description",
|
|
7
|
+
"steps": [
|
|
8
|
+
{
|
|
9
|
+
"id": "run_codex_mr_description",
|
|
10
|
+
"node": "codex-local-prompt",
|
|
11
|
+
"prompt": {
|
|
12
|
+
"templateRef": "mr-description",
|
|
13
|
+
"vars": {
|
|
14
|
+
"jira_task_file": {
|
|
15
|
+
"artifact": {
|
|
16
|
+
"kind": "jira-task-file",
|
|
17
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"mr_description_file": {
|
|
21
|
+
"artifact": {
|
|
22
|
+
"kind": "mr-description-file",
|
|
23
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"extraPrompt": { "ref": "params.extraPrompt" },
|
|
28
|
+
"format": "task-prompt"
|
|
29
|
+
},
|
|
30
|
+
"params": {
|
|
31
|
+
"labelText": { "const": "Running Codex MR description mode" },
|
|
32
|
+
"model": { "const": "gpt-5.4" },
|
|
33
|
+
"requiredArtifacts": {
|
|
34
|
+
"list": [
|
|
35
|
+
{
|
|
36
|
+
"artifact": {
|
|
37
|
+
"kind": "mr-description-file",
|
|
38
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"expect": [
|
|
45
|
+
{
|
|
46
|
+
"kind": "require-file",
|
|
47
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
48
|
+
"path": {
|
|
49
|
+
"artifact": {
|
|
50
|
+
"kind": "mr-description-file",
|
|
51
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"message": "MR description mode did not produce the MR description artifact."
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "run-linter-loop-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "run_linter_try_1",
|
|
7
|
+
"steps": [
|
|
8
|
+
{
|
|
9
|
+
"id": "run_linter",
|
|
10
|
+
"node": "verify-build",
|
|
11
|
+
"params": {
|
|
12
|
+
"dockerComposeFile": { "ref": "params.dockerComposeFile" },
|
|
13
|
+
"labelText": {
|
|
14
|
+
"const": "Running run_linter.sh in isolated Docker (attempt 1)"
|
|
15
|
+
},
|
|
16
|
+
"service": { "const": "run-linter" }
|
|
17
|
+
},
|
|
18
|
+
"stopFlowIf": {
|
|
19
|
+
"equals": [
|
|
20
|
+
{ "ref": "steps.run_linter_try_1.run_linter.outputs.parsed.ok" },
|
|
21
|
+
{ "const": true }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "fix_linter",
|
|
27
|
+
"when": {
|
|
28
|
+
"equals": [
|
|
29
|
+
{ "ref": "steps.run_linter_try_1.run_linter.outputs.parsed.ok" },
|
|
30
|
+
{ "const": false }
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"node": "codex-local-prompt",
|
|
34
|
+
"prompt": {
|
|
35
|
+
"templateRef": "run-linter-loop-fix",
|
|
36
|
+
"extraPrompt": {
|
|
37
|
+
"appendPrompt": {
|
|
38
|
+
"base": { "ref": "params.extraPrompt" },
|
|
39
|
+
"suffix": {
|
|
40
|
+
"template": "Последний результат run_linter.sh: exitCode={exit_code}, summary={summary}. Исправь только то, что мешает успешному прохождению проверки.",
|
|
41
|
+
"vars": {
|
|
42
|
+
"exit_code": { "ref": "steps.run_linter_try_1.run_linter.outputs.parsed.exitCode" },
|
|
43
|
+
"summary": { "ref": "steps.run_linter_try_1.run_linter.outputs.parsed.summary" }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"format": "task-prompt"
|
|
49
|
+
},
|
|
50
|
+
"params": {
|
|
51
|
+
"labelText": {
|
|
52
|
+
"const": "Running Codex linter loop fix (attempt 1)"
|
|
53
|
+
},
|
|
54
|
+
"model": { "const": "gpt-5.4" }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"repeat": {
|
|
61
|
+
"var": "attempt",
|
|
62
|
+
"from": 2,
|
|
63
|
+
"to": 5
|
|
64
|
+
},
|
|
65
|
+
"phases": [
|
|
66
|
+
{
|
|
67
|
+
"id": "run_linter_try_${attempt}",
|
|
68
|
+
"when": {
|
|
69
|
+
"equals": [
|
|
70
|
+
{ "ref": "steps.run_linter_try_${attempt_minus_one}.run_linter.outputs.parsed.ok" },
|
|
71
|
+
{ "const": false }
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"steps": [
|
|
75
|
+
{
|
|
76
|
+
"id": "run_linter",
|
|
77
|
+
"node": "verify-build",
|
|
78
|
+
"params": {
|
|
79
|
+
"dockerComposeFile": { "ref": "params.dockerComposeFile" },
|
|
80
|
+
"labelText": {
|
|
81
|
+
"template": "Running run_linter.sh in isolated Docker (attempt ${attempt})"
|
|
82
|
+
},
|
|
83
|
+
"service": { "const": "run-linter" }
|
|
84
|
+
},
|
|
85
|
+
"stopFlowIf": {
|
|
86
|
+
"equals": [
|
|
87
|
+
{ "ref": "steps.run_linter_try_${attempt}.run_linter.outputs.parsed.ok" },
|
|
88
|
+
{ "const": true }
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "fix_linter",
|
|
94
|
+
"when": {
|
|
95
|
+
"equals": [
|
|
96
|
+
{ "ref": "steps.run_linter_try_${attempt}.run_linter.outputs.parsed.ok" },
|
|
97
|
+
{ "const": false }
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
"node": "codex-local-prompt",
|
|
101
|
+
"prompt": {
|
|
102
|
+
"templateRef": "run-linter-loop-fix",
|
|
103
|
+
"extraPrompt": {
|
|
104
|
+
"appendPrompt": {
|
|
105
|
+
"base": { "ref": "params.extraPrompt" },
|
|
106
|
+
"suffix": {
|
|
107
|
+
"template": "Последний результат run_linter.sh: exitCode={exit_code}, summary={summary}. Исправь только то, что мешает успешному прохождению проверки.",
|
|
108
|
+
"vars": {
|
|
109
|
+
"exit_code": { "ref": "steps.run_linter_try_${attempt}.run_linter.outputs.parsed.exitCode" },
|
|
110
|
+
"summary": { "ref": "steps.run_linter_try_${attempt}.run_linter.outputs.parsed.summary" }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"format": "task-prompt"
|
|
116
|
+
},
|
|
117
|
+
"params": {
|
|
118
|
+
"labelText": {
|
|
119
|
+
"template": "Running Codex linter loop fix (attempt ${attempt})"
|
|
120
|
+
},
|
|
121
|
+
"model": { "const": "gpt-5.4" }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"id": "run_linter_failed",
|
|
130
|
+
"steps": [
|
|
131
|
+
{
|
|
132
|
+
"id": "assert_run_linter_success",
|
|
133
|
+
"node": "file-check",
|
|
134
|
+
"params": {
|
|
135
|
+
"path": { "ref": "params.dockerComposeFile" }
|
|
136
|
+
},
|
|
137
|
+
"expect": [
|
|
138
|
+
{
|
|
139
|
+
"kind": "step-output",
|
|
140
|
+
"value": { "ref": "steps.run_linter_try_5.run_linter.outputs.parsed.ok" },
|
|
141
|
+
"equals": { "const": true },
|
|
142
|
+
"message": "run-linter-loop exhausted all attempts without a successful run_linter.sh execution."
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|