agentweaver 0.1.7 → 0.1.8
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/Dockerfile.codex +3 -3
- package/README.md +4 -4
- package/dist/artifacts.js +6 -0
- package/dist/index.js +7 -7
- package/dist/interactive-ui.js +24 -8
- package/dist/pipeline/flow-specs/bug-analyze.json +1 -1
- package/dist/pipeline/flow-specs/run-go-linter-loop.json +83 -7
- package/dist/pipeline/flow-specs/run-go-tests-loop.json +83 -7
- package/dist/pipeline/flow-specs/task-describe.json +1 -1
- package/dist/pipeline/nodes/local-script-check-node.js +50 -8
- package/dist/pipeline/prompt-registry.js +2 -1
- package/dist/pipeline/value-resolver.js +11 -1
- package/dist/prompts.js +7 -2
- package/dist/scope.js +24 -7
- package/dist/structured-artifact-schemas.json +407 -0
- package/dist/structured-artifacts.js +101 -262
- package/docker-compose.yml +2 -2
- package/package.json +3 -3
- package/run_go_linter.py +128 -0
- package/run_go_tests.py +120 -0
- package/verify_build.sh +3 -3
- package/run_go_linter.sh +0 -89
- package/run_go_tests.sh +0 -83
package/Dockerfile.codex
CHANGED
|
@@ -45,10 +45,10 @@ RUN GOBIN=/usr/local/bin go install github.com/golangci/golangci-lint/v2/cmd/gol
|
|
|
45
45
|
ENV PATH="/usr/local/go/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
46
46
|
|
|
47
47
|
COPY verify_build.sh /usr/local/bin/verify_build.sh
|
|
48
|
-
COPY run_go_tests.
|
|
49
|
-
COPY run_go_linter.
|
|
48
|
+
COPY run_go_tests.py /usr/local/bin/run_go_tests.py
|
|
49
|
+
COPY run_go_linter.py /usr/local/bin/run_go_linter.py
|
|
50
50
|
COPY run_go_coverage.sh /usr/local/bin/run_go_coverage.sh
|
|
51
|
-
RUN chmod +x /usr/local/bin/verify_build.sh /usr/local/bin/run_go_tests.
|
|
51
|
+
RUN chmod +x /usr/local/bin/verify_build.sh /usr/local/bin/run_go_tests.py /usr/local/bin/run_go_linter.py /usr/local/bin/run_go_coverage.sh
|
|
52
52
|
|
|
53
53
|
WORKDIR /workspace
|
|
54
54
|
|
package/README.md
CHANGED
|
@@ -45,8 +45,8 @@ This keeps command handlers focused on choosing a flow and providing parameters
|
|
|
45
45
|
- `docker-compose.yml` — runtime services for Codex and build verification
|
|
46
46
|
- `Dockerfile.codex` — container image for Codex runtime
|
|
47
47
|
- `verify_build.sh` — aggregated verification entrypoint used by `verify-build`
|
|
48
|
-
- `run_go_tests.
|
|
49
|
-
- `run_go_linter.
|
|
48
|
+
- `run_go_tests.py` — isolated Go test verification entrypoint
|
|
49
|
+
- `run_go_linter.py` — isolated Go generate + lint verification entrypoint
|
|
50
50
|
- `run_go_coverage.sh` — isolated Go coverage verification entrypoint
|
|
51
51
|
- `package.json` — npm package metadata and scripts
|
|
52
52
|
- `tsconfig.json` — TypeScript configuration
|
|
@@ -212,8 +212,8 @@ Main services:
|
|
|
212
212
|
- `codex` — interactive Codex container
|
|
213
213
|
- `codex-exec` — non-interactive `codex exec`
|
|
214
214
|
- `verify-build` — project verification script inside container
|
|
215
|
-
- `run-go-tests` — isolated `run_go_tests.
|
|
216
|
-
- `run-go-linter` — isolated `run_go_linter.
|
|
215
|
+
- `run-go-tests` — isolated `run_go_tests.py` execution inside container
|
|
216
|
+
- `run-go-linter` — isolated `run_go_linter.py` execution inside container
|
|
217
217
|
- `run-go-coverage` — isolated `run_go_coverage.sh` execution inside container
|
|
218
218
|
- `codex-login` — interactive login container
|
|
219
219
|
- `dockerd` — internal Docker daemon for testcontainers/build flows
|
package/dist/artifacts.js
CHANGED
|
@@ -156,6 +156,12 @@ export function reviewFixJsonFile(taskKey, iteration) {
|
|
|
156
156
|
export function reviewFixSelectionJsonFile(taskKey, iteration) {
|
|
157
157
|
return artifactJsonFile("review-fix-selection", taskKey, iteration);
|
|
158
158
|
}
|
|
159
|
+
export function runGoLinterResultJsonFile(taskKey, iteration) {
|
|
160
|
+
return artifactJsonFile("run-go-linter-result", taskKey, iteration);
|
|
161
|
+
}
|
|
162
|
+
export function runGoTestsResultJsonFile(taskKey, iteration) {
|
|
163
|
+
return artifactJsonFile("run-go-tests-result", taskKey, iteration);
|
|
164
|
+
}
|
|
159
165
|
export function requireArtifacts(paths, message) {
|
|
160
166
|
const missing = paths.filter((filePath) => !existsSync(filePath));
|
|
161
167
|
if (missing.length > 0) {
|
package/dist/index.js
CHANGED
|
@@ -414,8 +414,8 @@ function buildBaseConfig(command, options = {}) {
|
|
|
414
414
|
dryRun: options.dryRun ?? false,
|
|
415
415
|
verbose: options.verbose ?? false,
|
|
416
416
|
dockerComposeFile: defaultDockerComposeFile(PACKAGE_ROOT),
|
|
417
|
-
runGoTestsScript: path.join(homeDir, "run_go_tests.
|
|
418
|
-
runGoLinterScript: path.join(homeDir, "run_go_linter.
|
|
417
|
+
runGoTestsScript: path.join(homeDir, "run_go_tests.py"),
|
|
418
|
+
runGoLinterScript: path.join(homeDir, "run_go_linter.py"),
|
|
419
419
|
runGoCoverageScript: path.join(homeDir, "run_go_coverage.sh"),
|
|
420
420
|
};
|
|
421
421
|
}
|
|
@@ -522,8 +522,8 @@ const FLOW_DESCRIPTIONS = {
|
|
|
522
522
|
implement: "Реализует задачу по утверждённым design/plan артефактам и при необходимости запускает post-verify сборки.",
|
|
523
523
|
review: "Запускает Claude-код-ревью текущих изменений, валидирует structured findings, затем готовит ответ на замечания через Codex.",
|
|
524
524
|
"review-fix": "Исправляет замечания после review-reply, обновляет код и прогоняет обязательные проверки после правок.",
|
|
525
|
-
"run-go-tests-loop": "Циклически запускает `./run_go_tests.
|
|
526
|
-
"run-go-linter-loop": "Циклически запускает `./run_go_linter.
|
|
525
|
+
"run-go-tests-loop": "Циклически запускает `./run_go_tests.py` локально, анализирует последнюю ошибку и правит код до успешного прохождения или исчерпания попыток.",
|
|
526
|
+
"run-go-linter-loop": "Циклически запускает `./run_go_linter.py` локально, исправляет проблемы линтера или генерации и повторяет попытки до успеха.",
|
|
527
527
|
};
|
|
528
528
|
function flowDescription(id) {
|
|
529
529
|
return FLOW_DESCRIPTIONS[id] ?? "Описание для этого flow пока не задано.";
|
|
@@ -1128,11 +1128,11 @@ function buildConfigFromArgs(args) {
|
|
|
1128
1128
|
}
|
|
1129
1129
|
async function runInteractive(jiraRef, forceRefresh = false, scopeName) {
|
|
1130
1130
|
let currentScope = jiraRef?.trim() ? resolveTaskScope(jiraRef, scopeName) : resolveProjectScope(scopeName);
|
|
1131
|
-
const currentIssueKey = currentScope.scopeKey;
|
|
1132
1131
|
const gitBranchName = detectGitBranchName();
|
|
1133
1132
|
let exiting = false;
|
|
1134
1133
|
const ui = new InteractiveUi({
|
|
1135
|
-
|
|
1134
|
+
scopeKey: currentScope.scopeKey,
|
|
1135
|
+
jiraIssueKey: currentScope.scopeType === "task" ? currentScope.jiraIssueKey : null,
|
|
1136
1136
|
summaryText: "",
|
|
1137
1137
|
cwd: process.cwd(),
|
|
1138
1138
|
gitBranchName,
|
|
@@ -1186,7 +1186,7 @@ async function runInteractive(jiraRef, forceRefresh = false, scopeName) {
|
|
|
1186
1186
|
});
|
|
1187
1187
|
const nextScope = await resolveScopeForCommand(baseConfig, (form) => ui.requestUserInput(form));
|
|
1188
1188
|
currentScope = nextScope;
|
|
1189
|
-
ui.
|
|
1189
|
+
ui.setScope(currentScope.scopeKey, currentScope.scopeType === "task" ? currentScope.jiraIssueKey : null);
|
|
1190
1190
|
if (currentScope.scopeType === "task" && (previousScopeType !== "task" || previousScopeKey !== currentScope.scopeKey)) {
|
|
1191
1191
|
syncInteractiveTaskSummary(ui, currentScope, forceRefresh);
|
|
1192
1192
|
}
|
package/dist/interactive-ui.js
CHANGED
|
@@ -4,6 +4,8 @@ import { renderMarkdownToTerminal } from "./markdown.js";
|
|
|
4
4
|
import { setOutputAdapter, stripAnsi } from "./tui.js";
|
|
5
5
|
import { TaskRunnerError } from "./errors.js";
|
|
6
6
|
import { buildInitialUserInputValues, validateUserInputValues, } from "./user-input.js";
|
|
7
|
+
const CONFIRM_MIN_WIDTH = 44;
|
|
8
|
+
const CONFIRM_MIN_HEIGHT = 8;
|
|
7
9
|
export class InteractiveUi {
|
|
8
10
|
options;
|
|
9
11
|
screen;
|
|
@@ -39,7 +41,8 @@ export class InteractiveUi {
|
|
|
39
41
|
failedFlowId = null;
|
|
40
42
|
activeFormSession = null;
|
|
41
43
|
confirmSession = null;
|
|
42
|
-
|
|
44
|
+
scopeKey;
|
|
45
|
+
jiraIssueKey;
|
|
43
46
|
summaryVisible;
|
|
44
47
|
constructor(options) {
|
|
45
48
|
this.options = options;
|
|
@@ -48,12 +51,13 @@ export class InteractiveUi {
|
|
|
48
51
|
}
|
|
49
52
|
this.flowMap = new Map(options.flows.map((flow) => [flow.id, flow]));
|
|
50
53
|
this.selectedFlowId = options.flows[0]?.id ?? "auto";
|
|
51
|
-
this.
|
|
54
|
+
this.scopeKey = options.scopeKey;
|
|
55
|
+
this.jiraIssueKey = options.jiraIssueKey ?? null;
|
|
52
56
|
this.summaryVisible = options.summaryText.trim().length > 0;
|
|
53
57
|
this.screen = blessed.screen({
|
|
54
58
|
smartCSR: true,
|
|
55
59
|
fullUnicode: true,
|
|
56
|
-
title: `AgentWeaver ${this.
|
|
60
|
+
title: `AgentWeaver ${this.scopeKey}`,
|
|
57
61
|
dockBorders: true,
|
|
58
62
|
autoPadding: false,
|
|
59
63
|
});
|
|
@@ -584,7 +588,8 @@ export class InteractiveUi {
|
|
|
584
588
|
this.header.setContent([
|
|
585
589
|
"{bold}AgentWeaver{/bold}",
|
|
586
590
|
divider,
|
|
587
|
-
`{bold}
|
|
591
|
+
`{bold}Scope{/bold} {green-fg}${this.scopeKey}{/green-fg}`,
|
|
592
|
+
this.jiraIssueKey ? `${divider}{bold}Jira{/bold} {yellow-fg}${this.jiraIssueKey}{/yellow-fg}` : "",
|
|
588
593
|
divider,
|
|
589
594
|
`{bold}Flow{/bold} ${flowLabel}`,
|
|
590
595
|
divider,
|
|
@@ -1180,7 +1185,17 @@ export class InteractiveUi {
|
|
|
1180
1185
|
lines.push("", session.details.trim());
|
|
1181
1186
|
}
|
|
1182
1187
|
lines.push("", actionLabels, "", "Left/Right or Tab: choose Enter: confirm Esc: cancel");
|
|
1183
|
-
|
|
1188
|
+
const content = lines.join("\n");
|
|
1189
|
+
const contentLines = content.split("\n");
|
|
1190
|
+
const lineCount = contentLines.length;
|
|
1191
|
+
const maxLineLength = contentLines.reduce((max, line) => Math.max(max, stripAnsi(line).length), 0);
|
|
1192
|
+
const screenWidth = Math.max(Number(this.screen.width ?? 0), CONFIRM_MIN_WIDTH);
|
|
1193
|
+
const screenHeight = Math.max(Number(this.screen.height ?? 0), CONFIRM_MIN_HEIGHT);
|
|
1194
|
+
const desiredWidth = Math.max(CONFIRM_MIN_WIDTH, maxLineLength + 6);
|
|
1195
|
+
const desiredHeight = Math.max(CONFIRM_MIN_HEIGHT, lineCount + 4);
|
|
1196
|
+
this.confirm.width = Math.min(desiredWidth, Math.max(CONFIRM_MIN_WIDTH, screenWidth - 4));
|
|
1197
|
+
this.confirm.height = Math.min(desiredHeight, Math.max(CONFIRM_MIN_HEIGHT, screenHeight - 2));
|
|
1198
|
+
this.confirm.setContent(content);
|
|
1184
1199
|
this.confirm.show();
|
|
1185
1200
|
this.confirm.setFront();
|
|
1186
1201
|
this.confirm.focus();
|
|
@@ -1298,9 +1313,10 @@ export class InteractiveUi {
|
|
|
1298
1313
|
}
|
|
1299
1314
|
this.requestRender();
|
|
1300
1315
|
}
|
|
1301
|
-
|
|
1302
|
-
this.
|
|
1303
|
-
this.
|
|
1316
|
+
setScope(scopeKey, jiraIssueKey) {
|
|
1317
|
+
this.scopeKey = scopeKey;
|
|
1318
|
+
this.jiraIssueKey = jiraIssueKey ?? null;
|
|
1319
|
+
this.screen.title = `AgentWeaver ${scopeKey}`;
|
|
1304
1320
|
this.updateHeader();
|
|
1305
1321
|
this.requestRender();
|
|
1306
1322
|
}
|
|
@@ -14,10 +14,31 @@
|
|
|
14
14
|
{ "ref": "params.runGoLinterScript" }
|
|
15
15
|
]
|
|
16
16
|
},
|
|
17
|
+
"outputFile": {
|
|
18
|
+
"artifact": {
|
|
19
|
+
"kind": "run-go-linter-result-json-file",
|
|
20
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
21
|
+
"iteration": { "const": 1 }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
17
24
|
"labelText": {
|
|
18
|
-
"const": "Running run_go_linter.
|
|
25
|
+
"const": "Running run_go_linter.py locally (attempt 1)"
|
|
19
26
|
}
|
|
20
27
|
},
|
|
28
|
+
"expect": [
|
|
29
|
+
{
|
|
30
|
+
"kind": "require-file",
|
|
31
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
32
|
+
"path": {
|
|
33
|
+
"artifact": {
|
|
34
|
+
"kind": "run-go-linter-result-json-file",
|
|
35
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
36
|
+
"iteration": { "const": 1 }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"message": "run-go-linter-loop did not produce the structured linter result artifact."
|
|
40
|
+
}
|
|
41
|
+
],
|
|
21
42
|
"stopFlowIf": {
|
|
22
43
|
"equals": [
|
|
23
44
|
{ "ref": "steps.run_go_linter_try_1.run_go_linter.outputs.parsed.ok" },
|
|
@@ -36,14 +57,31 @@
|
|
|
36
57
|
"node": "codex-local-prompt",
|
|
37
58
|
"prompt": {
|
|
38
59
|
"templateRef": "run-go-linter-loop-fix",
|
|
60
|
+
"vars": {
|
|
61
|
+
"linter_result_json_file": {
|
|
62
|
+
"artifact": {
|
|
63
|
+
"kind": "run-go-linter-result-json-file",
|
|
64
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
65
|
+
"iteration": { "const": 1 }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
39
69
|
"extraPrompt": {
|
|
40
70
|
"appendPrompt": {
|
|
41
71
|
"base": { "ref": "params.extraPrompt" },
|
|
42
72
|
"suffix": {
|
|
43
|
-
"template": "Последний результат run_go_linter.
|
|
73
|
+
"template": "Последний результат run_go_linter.py сохранён в {result_file}. exitCode={exit_code}, summary={summary}.\nПолный raw-вывод последнего запуска:\n{raw_output}\nИсправь только то, что мешает успешному прохождению проверки.",
|
|
44
74
|
"vars": {
|
|
75
|
+
"result_file": {
|
|
76
|
+
"artifact": {
|
|
77
|
+
"kind": "run-go-linter-result-json-file",
|
|
78
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
79
|
+
"iteration": { "const": 1 }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
45
82
|
"exit_code": { "ref": "steps.run_go_linter_try_1.run_go_linter.outputs.parsed.exitCode" },
|
|
46
|
-
"summary": { "ref": "steps.run_go_linter_try_1.run_go_linter.outputs.parsed.summary" }
|
|
83
|
+
"summary": { "ref": "steps.run_go_linter_try_1.run_go_linter.outputs.parsed.summary" },
|
|
84
|
+
"raw_output": { "ref": "steps.run_go_linter_try_1.run_go_linter.outputs.parsed.details.raw" }
|
|
47
85
|
}
|
|
48
86
|
}
|
|
49
87
|
}
|
|
@@ -84,10 +122,31 @@
|
|
|
84
122
|
{ "ref": "params.runGoLinterScript" }
|
|
85
123
|
]
|
|
86
124
|
},
|
|
125
|
+
"outputFile": {
|
|
126
|
+
"artifact": {
|
|
127
|
+
"kind": "run-go-linter-result-json-file",
|
|
128
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
129
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
130
|
+
}
|
|
131
|
+
},
|
|
87
132
|
"labelText": {
|
|
88
|
-
"template": "Running run_go_linter.
|
|
133
|
+
"template": "Running run_go_linter.py locally (attempt ${attempt})"
|
|
89
134
|
}
|
|
90
135
|
},
|
|
136
|
+
"expect": [
|
|
137
|
+
{
|
|
138
|
+
"kind": "require-file",
|
|
139
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
140
|
+
"path": {
|
|
141
|
+
"artifact": {
|
|
142
|
+
"kind": "run-go-linter-result-json-file",
|
|
143
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
144
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"message": "run-go-linter-loop did not produce the structured linter result artifact."
|
|
148
|
+
}
|
|
149
|
+
],
|
|
91
150
|
"stopFlowIf": {
|
|
92
151
|
"equals": [
|
|
93
152
|
{ "ref": "steps.run_go_linter_try_${attempt}.run_go_linter.outputs.parsed.ok" },
|
|
@@ -106,14 +165,31 @@
|
|
|
106
165
|
"node": "codex-local-prompt",
|
|
107
166
|
"prompt": {
|
|
108
167
|
"templateRef": "run-go-linter-loop-fix",
|
|
168
|
+
"vars": {
|
|
169
|
+
"linter_result_json_file": {
|
|
170
|
+
"artifact": {
|
|
171
|
+
"kind": "run-go-linter-result-json-file",
|
|
172
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
173
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
109
177
|
"extraPrompt": {
|
|
110
178
|
"appendPrompt": {
|
|
111
179
|
"base": { "ref": "params.extraPrompt" },
|
|
112
180
|
"suffix": {
|
|
113
|
-
"template": "Последний результат run_go_linter.
|
|
181
|
+
"template": "Последний результат run_go_linter.py сохранён в {result_file}. exitCode={exit_code}, summary={summary}.\nПолный raw-вывод последнего запуска:\n{raw_output}\nИсправь только то, что мешает успешному прохождению проверки.",
|
|
114
182
|
"vars": {
|
|
183
|
+
"result_file": {
|
|
184
|
+
"artifact": {
|
|
185
|
+
"kind": "run-go-linter-result-json-file",
|
|
186
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
187
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
188
|
+
}
|
|
189
|
+
},
|
|
115
190
|
"exit_code": { "ref": "steps.run_go_linter_try_${attempt}.run_go_linter.outputs.parsed.exitCode" },
|
|
116
|
-
"summary": { "ref": "steps.run_go_linter_try_${attempt}.run_go_linter.outputs.parsed.summary" }
|
|
191
|
+
"summary": { "ref": "steps.run_go_linter_try_${attempt}.run_go_linter.outputs.parsed.summary" },
|
|
192
|
+
"raw_output": { "ref": "steps.run_go_linter_try_${attempt}.run_go_linter.outputs.parsed.details.raw" }
|
|
117
193
|
}
|
|
118
194
|
}
|
|
119
195
|
}
|
|
@@ -145,7 +221,7 @@
|
|
|
145
221
|
"kind": "step-output",
|
|
146
222
|
"value": { "ref": "steps.run_go_linter_try_5.run_go_linter.outputs.parsed.ok" },
|
|
147
223
|
"equals": { "const": true },
|
|
148
|
-
"message": "run-go-linter-loop exhausted all attempts without a successful run_go_linter.
|
|
224
|
+
"message": "run-go-linter-loop exhausted all attempts without a successful run_go_linter.py execution."
|
|
149
225
|
}
|
|
150
226
|
]
|
|
151
227
|
}
|
|
@@ -14,10 +14,31 @@
|
|
|
14
14
|
{ "ref": "params.runGoTestsScript" }
|
|
15
15
|
]
|
|
16
16
|
},
|
|
17
|
+
"outputFile": {
|
|
18
|
+
"artifact": {
|
|
19
|
+
"kind": "run-go-tests-result-json-file",
|
|
20
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
21
|
+
"iteration": { "const": 1 }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
17
24
|
"labelText": {
|
|
18
|
-
"const": "Running run_go_tests.
|
|
25
|
+
"const": "Running run_go_tests.py locally (attempt 1)"
|
|
19
26
|
}
|
|
20
27
|
},
|
|
28
|
+
"expect": [
|
|
29
|
+
{
|
|
30
|
+
"kind": "require-file",
|
|
31
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
32
|
+
"path": {
|
|
33
|
+
"artifact": {
|
|
34
|
+
"kind": "run-go-tests-result-json-file",
|
|
35
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
36
|
+
"iteration": { "const": 1 }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"message": "run-go-tests-loop did not produce the structured tests result artifact."
|
|
40
|
+
}
|
|
41
|
+
],
|
|
21
42
|
"stopFlowIf": {
|
|
22
43
|
"equals": [
|
|
23
44
|
{ "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.ok" },
|
|
@@ -36,14 +57,31 @@
|
|
|
36
57
|
"node": "codex-local-prompt",
|
|
37
58
|
"prompt": {
|
|
38
59
|
"templateRef": "run-go-tests-loop-fix",
|
|
60
|
+
"vars": {
|
|
61
|
+
"tests_result_json_file": {
|
|
62
|
+
"artifact": {
|
|
63
|
+
"kind": "run-go-tests-result-json-file",
|
|
64
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
65
|
+
"iteration": { "const": 1 }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
39
69
|
"extraPrompt": {
|
|
40
70
|
"appendPrompt": {
|
|
41
71
|
"base": { "ref": "params.extraPrompt" },
|
|
42
72
|
"suffix": {
|
|
43
|
-
"template": "Последний результат run_go_tests.
|
|
73
|
+
"template": "Последний результат run_go_tests.py сохранён в {result_file}. exitCode={exit_code}, summary={summary}.\nПолный raw-вывод последнего запуска:\n{raw_output}\nИсправь только то, что мешает успешному прохождению проверки.",
|
|
44
74
|
"vars": {
|
|
75
|
+
"result_file": {
|
|
76
|
+
"artifact": {
|
|
77
|
+
"kind": "run-go-tests-result-json-file",
|
|
78
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
79
|
+
"iteration": { "const": 1 }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
45
82
|
"exit_code": { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.exitCode" },
|
|
46
|
-
"summary": { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.summary" }
|
|
83
|
+
"summary": { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.summary" },
|
|
84
|
+
"raw_output": { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.details.raw" }
|
|
47
85
|
}
|
|
48
86
|
}
|
|
49
87
|
}
|
|
@@ -84,10 +122,31 @@
|
|
|
84
122
|
{ "ref": "params.runGoTestsScript" }
|
|
85
123
|
]
|
|
86
124
|
},
|
|
125
|
+
"outputFile": {
|
|
126
|
+
"artifact": {
|
|
127
|
+
"kind": "run-go-tests-result-json-file",
|
|
128
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
129
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
130
|
+
}
|
|
131
|
+
},
|
|
87
132
|
"labelText": {
|
|
88
|
-
"template": "Running run_go_tests.
|
|
133
|
+
"template": "Running run_go_tests.py locally (attempt ${attempt})"
|
|
89
134
|
}
|
|
90
135
|
},
|
|
136
|
+
"expect": [
|
|
137
|
+
{
|
|
138
|
+
"kind": "require-file",
|
|
139
|
+
"when": { "not": { "ref": "context.dryRun" } },
|
|
140
|
+
"path": {
|
|
141
|
+
"artifact": {
|
|
142
|
+
"kind": "run-go-tests-result-json-file",
|
|
143
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
144
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"message": "run-go-tests-loop did not produce the structured tests result artifact."
|
|
148
|
+
}
|
|
149
|
+
],
|
|
91
150
|
"stopFlowIf": {
|
|
92
151
|
"equals": [
|
|
93
152
|
{ "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.ok" },
|
|
@@ -106,14 +165,31 @@
|
|
|
106
165
|
"node": "codex-local-prompt",
|
|
107
166
|
"prompt": {
|
|
108
167
|
"templateRef": "run-go-tests-loop-fix",
|
|
168
|
+
"vars": {
|
|
169
|
+
"tests_result_json_file": {
|
|
170
|
+
"artifact": {
|
|
171
|
+
"kind": "run-go-tests-result-json-file",
|
|
172
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
173
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
109
177
|
"extraPrompt": {
|
|
110
178
|
"appendPrompt": {
|
|
111
179
|
"base": { "ref": "params.extraPrompt" },
|
|
112
180
|
"suffix": {
|
|
113
|
-
"template": "Последний результат run_go_tests.
|
|
181
|
+
"template": "Последний результат run_go_tests.py сохранён в {result_file}. exitCode={exit_code}, summary={summary}.\nПолный raw-вывод последнего запуска:\n{raw_output}\nИсправь только то, что мешает успешному прохождению проверки.",
|
|
114
182
|
"vars": {
|
|
183
|
+
"result_file": {
|
|
184
|
+
"artifact": {
|
|
185
|
+
"kind": "run-go-tests-result-json-file",
|
|
186
|
+
"taskKey": { "ref": "params.taskKey" },
|
|
187
|
+
"iteration": { "ref": "repeat.attempt" }
|
|
188
|
+
}
|
|
189
|
+
},
|
|
115
190
|
"exit_code": { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.exitCode" },
|
|
116
|
-
"summary": { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.summary" }
|
|
191
|
+
"summary": { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.summary" },
|
|
192
|
+
"raw_output": { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.details.raw" }
|
|
117
193
|
}
|
|
118
194
|
}
|
|
119
195
|
}
|
|
@@ -145,7 +221,7 @@
|
|
|
145
221
|
"kind": "step-output",
|
|
146
222
|
"value": { "ref": "steps.run_go_tests_try_5.run_go_tests.outputs.parsed.ok" },
|
|
147
223
|
"equals": { "const": true },
|
|
148
|
-
"message": "run-go-tests-loop exhausted all attempts without a successful run_go_tests.
|
|
224
|
+
"message": "run-go-tests-loop exhausted all attempts without a successful run_go_tests.py execution."
|
|
149
225
|
}
|
|
150
226
|
]
|
|
151
227
|
}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"id": "run_codex_task_describe",
|
|
35
35
|
"node": "codex-local-prompt",
|
|
36
36
|
"prompt": {
|
|
37
|
-
"
|
|
37
|
+
"templateRef": "task-describe",
|
|
38
38
|
"vars": {
|
|
39
39
|
"jira_task_file": {
|
|
40
40
|
"artifact": {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { TaskRunnerError } from "../../errors.js";
|
|
2
4
|
import { printInfo } from "../../tui.js";
|
|
3
5
|
function parseStructuredResult(output, commandLabel) {
|
|
@@ -59,22 +61,62 @@ function parseStructuredResult(output, commandLabel) {
|
|
|
59
61
|
}
|
|
60
62
|
throw new TaskRunnerError(`Structured result is missing or invalid in output of '${commandLabel}'.`);
|
|
61
63
|
}
|
|
64
|
+
function fallbackStructuredResult(output, commandLabel, exitCode) {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
kind: "check",
|
|
68
|
+
stage: commandLabel,
|
|
69
|
+
exitCode,
|
|
70
|
+
summary: `${commandLabel} failed`,
|
|
71
|
+
command: commandLabel,
|
|
72
|
+
details: output.trim().length > 0 ? { raw: output } : {},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function persistStructuredResult(filePath, parsed) {
|
|
76
|
+
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
77
|
+
writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
|
|
78
|
+
}
|
|
62
79
|
export const localScriptCheckNode = {
|
|
63
80
|
kind: "local-script-check",
|
|
64
81
|
version: 1,
|
|
65
82
|
async run(context, params) {
|
|
66
83
|
printInfo(params.labelText);
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
const commandLabel = params.argv.join(" ");
|
|
85
|
+
let output = "";
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
output = await context.runtime.runCommand(params.argv, {
|
|
89
|
+
dryRun: context.dryRun,
|
|
90
|
+
verbose: context.verbose,
|
|
91
|
+
label: commandLabel,
|
|
92
|
+
printFailureOutput: true,
|
|
93
|
+
env: { ...context.env },
|
|
94
|
+
});
|
|
95
|
+
parsed = parseStructuredResult(output, commandLabel);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
output = String(error.output ?? "");
|
|
99
|
+
const exitCode = Number(error.returnCode ?? 1);
|
|
100
|
+
try {
|
|
101
|
+
parsed = parseStructuredResult(output, commandLabel);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
parsed = fallbackStructuredResult(output, commandLabel, exitCode);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (typeof parsed.details.raw !== "string") {
|
|
108
|
+
parsed.details = {
|
|
109
|
+
...parsed.details,
|
|
110
|
+
raw: output,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (params.outputFile) {
|
|
114
|
+
persistStructuredResult(params.outputFile, parsed);
|
|
115
|
+
}
|
|
74
116
|
return {
|
|
75
117
|
value: {
|
|
76
118
|
output,
|
|
77
|
-
parsed
|
|
119
|
+
parsed,
|
|
78
120
|
},
|
|
79
121
|
};
|
|
80
122
|
},
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { BUG_ANALYZE_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE, REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE, REVIEW_REPLY_PROMPT_TEMPLATE, REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE, REVIEW_SUMMARY_PROMPT_TEMPLATE, RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE, RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE, TASK_SUMMARY_PROMPT_TEMPLATE, } from "../prompts.js";
|
|
1
|
+
import { BUG_ANALYZE_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, JIRA_DESCRIPTION_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE, REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE, REVIEW_REPLY_PROMPT_TEMPLATE, REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE, REVIEW_SUMMARY_PROMPT_TEMPLATE, RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE, RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE, TASK_SUMMARY_PROMPT_TEMPLATE, } from "../prompts.js";
|
|
2
2
|
const promptTemplates = {
|
|
3
3
|
"bug-analyze": BUG_ANALYZE_PROMPT_TEMPLATE,
|
|
4
4
|
"bug-fix": BUG_FIX_PROMPT_TEMPLATE,
|
|
5
5
|
implement: IMPLEMENT_PROMPT_TEMPLATE,
|
|
6
|
+
"task-describe": JIRA_DESCRIPTION_PROMPT_TEMPLATE,
|
|
6
7
|
"mr-description": MR_DESCRIPTION_PROMPT_TEMPLATE,
|
|
7
8
|
plan: PLAN_PROMPT_TEMPLATE,
|
|
8
9
|
review: REVIEW_PROMPT_TEMPLATE,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { artifactFile, bugAnalyzeArtifacts, bugAnalyzeFile, bugAnalyzeJsonFile, bugFixDesignFile, bugFixDesignJsonFile, bugFixPlanFile, bugFixPlanJsonFile, designFile, designJsonFile, gitlabReviewFile, gitlabReviewInputJsonFile, gitlabReviewJsonFile, jiraDescriptionFile, jiraDescriptionJsonFile, jiraTaskFile, mrDescriptionFile, mrDescriptionJsonFile, planArtifacts, planFile, planJsonFile, qaFile, qaJsonFile, readyToMergeFile, reviewFile, reviewFixFile, reviewFixJsonFile, reviewJsonFile, reviewReplyFile, reviewReplyJsonFile, taskSummaryFile, taskSummaryJsonFile, } from "../artifacts.js";
|
|
2
|
+
import { artifactFile, bugAnalyzeArtifacts, bugAnalyzeFile, bugAnalyzeJsonFile, bugFixDesignFile, bugFixDesignJsonFile, bugFixPlanFile, bugFixPlanJsonFile, designFile, designJsonFile, gitlabReviewFile, gitlabReviewInputJsonFile, gitlabReviewJsonFile, jiraDescriptionFile, jiraDescriptionJsonFile, jiraTaskFile, mrDescriptionFile, mrDescriptionJsonFile, planArtifacts, planFile, planJsonFile, qaFile, qaJsonFile, readyToMergeFile, reviewFile, reviewFixFile, reviewFixJsonFile, reviewJsonFile, reviewReplyFile, reviewReplyJsonFile, runGoLinterResultJsonFile, runGoTestsResultJsonFile, taskSummaryFile, taskSummaryJsonFile, } from "../artifacts.js";
|
|
3
3
|
import { TaskRunnerError } from "../errors.js";
|
|
4
4
|
import { formatTemplate } from "../prompts.js";
|
|
5
5
|
function readStepRef(segments, context, originalPath) {
|
|
@@ -144,6 +144,16 @@ function resolveArtifact(spec, context) {
|
|
|
144
144
|
throw new TaskRunnerError("review-reply-json-file requires iteration");
|
|
145
145
|
}
|
|
146
146
|
return reviewReplyJsonFile(taskKey, iteration);
|
|
147
|
+
case "run-go-linter-result-json-file":
|
|
148
|
+
if (iteration === undefined) {
|
|
149
|
+
throw new TaskRunnerError("run-go-linter-result-json-file requires iteration");
|
|
150
|
+
}
|
|
151
|
+
return runGoLinterResultJsonFile(taskKey, iteration);
|
|
152
|
+
case "run-go-tests-result-json-file":
|
|
153
|
+
if (iteration === undefined) {
|
|
154
|
+
throw new TaskRunnerError("run-go-tests-result-json-file requires iteration");
|
|
155
|
+
}
|
|
156
|
+
return runGoTestsResultJsonFile(taskKey, iteration);
|
|
147
157
|
case "review-reply-summary-file":
|
|
148
158
|
if (iteration === undefined) {
|
|
149
159
|
throw new TaskRunnerError("review-reply-summary-file requires iteration");
|
package/dist/prompts.js
CHANGED
|
@@ -65,8 +65,13 @@ export const REVIEW_FIX_PROMPT_TEMPLATE = "Используй только ст
|
|
|
65
65
|
export const TASK_SUMMARY_PROMPT_TEMPLATE = "Посмотри в {jira_task_file}. " +
|
|
66
66
|
"Сделай краткое резюме задачи, на 1-2 абзаца. " +
|
|
67
67
|
"Сначала запиши source-of-truth JSON в {task_summary_json_file} в виде объекта { summary: string }, затем markdown-версию в {task_summary_file}.";
|
|
68
|
-
export const
|
|
69
|
-
|
|
68
|
+
export const JIRA_DESCRIPTION_PROMPT_TEMPLATE = "Посмотри задачу в {jira_task_file}. " +
|
|
69
|
+
"Проанализируй код и оформи краткое описание для Jira, упомяни ключевые точки, модели данных, сервисы, REST-методы. " +
|
|
70
|
+
"Сначала запиши source-of-truth JSON в {jira_description_json_file} в виде объекта { summary: string }, затем markdown-версию в {jira_description_file}.";
|
|
71
|
+
export const RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE = "Используй структурированный результат последнего запуска run_go_tests.py из {tests_result_json_file} как source of truth. " +
|
|
72
|
+
"Проанализируй последнюю ошибку проверки, исправь код и подготовь изменения так, чтобы следующий прогон run_go_tests.py прошёл успешно.";
|
|
73
|
+
export const RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE = "Используй структурированный результат последнего запуска run_go_linter.py из {linter_result_json_file} как source of truth. " +
|
|
74
|
+
"Проанализируй последнюю ошибку линтера или генерации, исправь код и подготовь изменения так, чтобы следующий прогон run_go_linter.py прошёл успешно.";
|
|
70
75
|
export const AUTO_REVIEW_FIX_EXTRA_PROMPT = "Исправлять только блокеры, критикалы и важные";
|
|
71
76
|
export function formatTemplate(template, values) {
|
|
72
77
|
let result = template;
|