agentweaver 0.1.9 → 0.1.11
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 +226 -200
- package/dist/artifacts.js +101 -56
- package/dist/errors.js +7 -0
- package/dist/executors/{codex-local-executor.js → codex-executor.js} +4 -4
- package/dist/executors/configs/{codex-local-config.js → codex-config.js} +1 -1
- package/dist/executors/configs/jira-fetch-config.js +2 -0
- package/dist/executors/configs/telegram-notifier-config.js +3 -0
- package/dist/executors/fetch-gitlab-diff-executor.js +1 -1
- package/dist/executors/fetch-gitlab-review-executor.js +1 -1
- package/dist/executors/git-commit-executor.js +25 -0
- package/dist/executors/telegram-notifier-executor.js +54 -0
- package/dist/flow-state.js +46 -1
- package/dist/gitlab.js +13 -8
- package/dist/index.js +507 -520
- package/dist/interactive-ui.js +495 -87
- package/dist/jira.js +52 -5
- package/dist/pipeline/auto-flow.js +6 -6
- package/dist/pipeline/context.js +1 -0
- package/dist/pipeline/declarative-flows.js +7 -4
- package/dist/pipeline/flow-catalog.js +60 -23
- package/dist/pipeline/flow-model-settings.js +77 -0
- package/dist/pipeline/flow-specs/auto-common.json +446 -0
- package/dist/pipeline/flow-specs/auto-golang.json +563 -0
- package/dist/pipeline/flow-specs/{bug-analyze.json → bugz/bug-analyze.json} +43 -25
- package/dist/pipeline/flow-specs/{bug-fix.json → bugz/bug-fix.json} +5 -4
- package/dist/pipeline/flow-specs/git-commit.json +196 -0
- package/dist/pipeline/flow-specs/{gitlab-diff-review.json → gitlab/gitlab-diff-review.json} +20 -50
- package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +165 -0
- package/dist/pipeline/flow-specs/{mr-description.json → gitlab/mr-description.json} +17 -10
- package/dist/pipeline/flow-specs/{run-go-linter-loop.json → go/run-go-linter-loop.json} +40 -14
- package/dist/pipeline/flow-specs/{run-go-tests-loop.json → go/run-go-tests-loop.json} +40 -14
- package/dist/pipeline/flow-specs/implement.json +5 -4
- package/dist/pipeline/flow-specs/plan.json +40 -148
- package/dist/pipeline/flow-specs/{review-fix.json → review/review-fix.json} +73 -13
- package/dist/pipeline/flow-specs/review/review-loop.json +280 -0
- package/dist/pipeline/flow-specs/review/review-project.json +87 -0
- package/dist/pipeline/flow-specs/review/review.json +126 -0
- package/dist/pipeline/flow-specs/task-describe.json +191 -11
- package/dist/pipeline/launch-profile-config.js +38 -0
- package/dist/pipeline/node-registry.js +75 -45
- package/dist/pipeline/nodes/build-failure-summary-node.js +16 -29
- package/dist/pipeline/nodes/build-review-fix-prompt-node.js +36 -0
- package/dist/pipeline/nodes/codex-prompt-node.js +41 -0
- package/dist/pipeline/nodes/commit-message-form-node.js +79 -0
- package/dist/pipeline/nodes/git-commit-form-node.js +138 -0
- package/dist/pipeline/nodes/git-commit-node.js +28 -0
- package/dist/pipeline/nodes/git-status-node.js +221 -0
- package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +10 -6
- package/dist/pipeline/nodes/jira-context-node.js +10 -0
- package/dist/pipeline/nodes/llm-prompt-node.js +62 -0
- package/dist/pipeline/nodes/plan-codex-node.js +1 -1
- package/dist/pipeline/nodes/read-file-node.js +11 -0
- package/dist/pipeline/nodes/review-findings-form-node.js +18 -14
- package/dist/pipeline/nodes/select-files-form-node.js +72 -0
- package/dist/pipeline/nodes/telegram-notifier-node.js +28 -0
- package/dist/pipeline/nodes/user-input-node.js +29 -8
- package/dist/pipeline/nodes/write-selection-file-node.js +46 -0
- package/dist/pipeline/prompt-registry.js +2 -4
- package/dist/pipeline/prompt-runtime.js +13 -3
- package/dist/pipeline/registry.js +6 -8
- package/dist/pipeline/spec-compiler.js +5 -0
- package/dist/pipeline/spec-loader.js +18 -7
- package/dist/pipeline/spec-types.js +7 -3
- package/dist/pipeline/spec-validator.js +4 -0
- package/dist/pipeline/types.js +1 -0
- package/dist/pipeline/value-resolver.js +40 -38
- package/dist/prompts.js +104 -110
- package/dist/runtime/agentweaver-home.js +8 -0
- package/dist/runtime/command-resolution.js +0 -38
- package/dist/runtime/env-loader.js +43 -0
- package/dist/runtime/process-runner.js +45 -1
- package/dist/structured-artifact-schema-registry.js +53 -0
- package/dist/structured-artifact-schemas.json +0 -20
- package/dist/structured-artifacts.js +3 -43
- package/dist/user-input.js +30 -2
- package/package.json +2 -6
- package/Dockerfile.codex +0 -56
- package/dist/executors/claude-executor.js +0 -46
- package/dist/executors/codex-docker-executor.js +0 -27
- package/dist/executors/configs/claude-config.js +0 -12
- package/dist/executors/configs/codex-docker-config.js +0 -10
- package/dist/executors/configs/verify-build-config.js +0 -7
- package/dist/executors/verify-build-executor.js +0 -123
- package/dist/pipeline/flow-specs/auto.json +0 -979
- package/dist/pipeline/flow-specs/gitlab-review.json +0 -317
- package/dist/pipeline/flow-specs/plan-opencode.json +0 -603
- package/dist/pipeline/flow-specs/preflight.json +0 -206
- package/dist/pipeline/flow-specs/review-project.json +0 -243
- package/dist/pipeline/flow-specs/review.json +0 -312
- package/dist/pipeline/flow-specs/run-linter-loop.json +0 -155
- package/dist/pipeline/flow-specs/run-tests-loop.json +0 -155
- package/dist/pipeline/flows/preflight-flow.js +0 -19
- package/dist/pipeline/nodes/claude-prompt-node.js +0 -54
- package/dist/pipeline/nodes/codex-docker-prompt-node.js +0 -32
- package/dist/pipeline/nodes/codex-local-prompt-node.js +0 -32
- package/dist/pipeline/nodes/review-claude-node.js +0 -38
- package/dist/pipeline/nodes/review-reply-codex-node.js +0 -40
- package/dist/pipeline/nodes/verify-build-node.js +0 -15
- package/dist/runtime/docker-runtime.js +0 -51
- package/docker-compose.yml +0 -445
- package/verify_build.sh +0 -105
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { TaskRunnerError } from "../../errors.js";
|
|
3
|
+
const SEVERITY_FIX_THRESHOLD = ["blocker", "critical", "major"];
|
|
3
4
|
export const reviewFindingsFormNode = {
|
|
4
5
|
kind: "review-findings-form",
|
|
5
6
|
version: 1,
|
|
6
7
|
async run(_context, params) {
|
|
7
8
|
let parsed;
|
|
8
9
|
try {
|
|
9
|
-
parsed = JSON.parse(readFileSync(params.
|
|
10
|
+
parsed = JSON.parse(readFileSync(params.reviewFindingsJsonFile, "utf8"));
|
|
10
11
|
}
|
|
11
12
|
catch (error) {
|
|
12
|
-
throw new TaskRunnerError(`Failed to read review
|
|
13
|
+
throw new TaskRunnerError(`Failed to read review findings from ${params.reviewFindingsJsonFile}: ${error.message}`);
|
|
13
14
|
}
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const selectableFindings =
|
|
17
|
-
.map((
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const reviewFindings = parsed;
|
|
16
|
+
const findings = Array.isArray(reviewFindings.findings) ? reviewFindings.findings : [];
|
|
17
|
+
const selectableFindings = findings
|
|
18
|
+
.map((finding) => ({
|
|
19
|
+
severity: typeof finding.severity === "string" ? finding.severity.trim().toLowerCase() : "",
|
|
20
|
+
title: typeof finding.title === "string" ? finding.title.trim() : "",
|
|
21
|
+
description: typeof finding.description === "string" ? finding.description.trim() : "",
|
|
22
|
+
disposition: typeof finding.disposition === "string" ? finding.disposition.trim().toLowerCase() : null,
|
|
21
23
|
}))
|
|
22
|
-
.filter((
|
|
24
|
+
.filter((finding) => finding.title.length > 0 &&
|
|
25
|
+
SEVERITY_FIX_THRESHOLD.includes(finding.severity) &&
|
|
26
|
+
finding.disposition !== "resolved");
|
|
23
27
|
const fields = [
|
|
24
28
|
{
|
|
25
29
|
id: "apply_all",
|
|
@@ -35,10 +39,10 @@ export const reviewFindingsFormNode = {
|
|
|
35
39
|
type: "multi-select",
|
|
36
40
|
label: "Какие findings исправить сейчас",
|
|
37
41
|
help: "Space переключает пункт. Если apply_all=false, выберите хотя бы один finding.",
|
|
38
|
-
options: selectableFindings.map((
|
|
39
|
-
value:
|
|
40
|
-
label: `${
|
|
41
|
-
...(
|
|
42
|
+
options: selectableFindings.map((finding) => ({
|
|
43
|
+
value: finding.title,
|
|
44
|
+
label: `${finding.title} | ${finding.severity || "-"}`,
|
|
45
|
+
...(finding.description ? { description: finding.description } : {}),
|
|
42
46
|
})),
|
|
43
47
|
default: [],
|
|
44
48
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { TaskRunnerError } from "../../errors.js";
|
|
4
|
+
import { validateUserInputValues } from "../../user-input.js";
|
|
5
|
+
export const selectFilesFormNode = {
|
|
6
|
+
kind: "select-files-form",
|
|
7
|
+
version: 1,
|
|
8
|
+
async run(context, params) {
|
|
9
|
+
let gitStatusFiles;
|
|
10
|
+
try {
|
|
11
|
+
const statusContent = readFileSync(params.gitStatusJsonFile, "utf8");
|
|
12
|
+
const statusParsed = JSON.parse(statusContent);
|
|
13
|
+
gitStatusFiles = (statusParsed.files ?? []);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
throw new TaskRunnerError(`Failed to read git status from ${params.gitStatusJsonFile}: ${error.message}`);
|
|
17
|
+
}
|
|
18
|
+
const fileOptions = gitStatusFiles.map((file) => ({
|
|
19
|
+
value: file.file,
|
|
20
|
+
label: file.originalFile
|
|
21
|
+
? `${file.xy} ${file.originalFile} -> ${file.file}`
|
|
22
|
+
: `${file.xy} ${file.file}`,
|
|
23
|
+
}));
|
|
24
|
+
const form = {
|
|
25
|
+
formId: params.formId,
|
|
26
|
+
title: params.title,
|
|
27
|
+
...(params.description ? { description: params.description } : {}),
|
|
28
|
+
submitLabel: "Next",
|
|
29
|
+
fields: [
|
|
30
|
+
{
|
|
31
|
+
id: "selected_files",
|
|
32
|
+
type: "multi-select",
|
|
33
|
+
label: "Select files to commit",
|
|
34
|
+
help: "Choose the files you want to include in this commit",
|
|
35
|
+
required: true,
|
|
36
|
+
options: fileOptions,
|
|
37
|
+
default: gitStatusFiles.map((f) => f.file),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
const requester = context.requestUserInput ?? (await import("../../user-input.js")).requestUserInputInTerminal;
|
|
42
|
+
const result = await requester(form);
|
|
43
|
+
const selectedFilesValue = result.values.selected_files;
|
|
44
|
+
if (!Array.isArray(selectedFilesValue) || selectedFilesValue.length === 0) {
|
|
45
|
+
throw new TaskRunnerError("At least one file must be selected for commit.");
|
|
46
|
+
}
|
|
47
|
+
validateUserInputValues(form, result.values);
|
|
48
|
+
const outputDir = path.dirname(params.outputFile);
|
|
49
|
+
mkdirSync(outputDir, { recursive: true });
|
|
50
|
+
const outputContent = {
|
|
51
|
+
form_id: result.formId,
|
|
52
|
+
submitted_at: result.submittedAt,
|
|
53
|
+
values: result.values,
|
|
54
|
+
};
|
|
55
|
+
writeFileSync(params.outputFile, `${JSON.stringify(outputContent, null, 2)}\n`, "utf8");
|
|
56
|
+
return {
|
|
57
|
+
value: {
|
|
58
|
+
formId: result.formId,
|
|
59
|
+
submittedAt: result.submittedAt,
|
|
60
|
+
values: result.values,
|
|
61
|
+
outputFile: params.outputFile,
|
|
62
|
+
},
|
|
63
|
+
outputs: [
|
|
64
|
+
{
|
|
65
|
+
kind: "artifact",
|
|
66
|
+
path: params.outputFile,
|
|
67
|
+
required: true,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { printInfo } from "../../tui.js";
|
|
2
|
+
import { toExecutorContext } from "../types.js";
|
|
3
|
+
export const telegramNotifierNode = {
|
|
4
|
+
kind: "telegram-notify",
|
|
5
|
+
version: 1,
|
|
6
|
+
async run(context, params) {
|
|
7
|
+
const labelText = params.label ?? "Sending Telegram notification";
|
|
8
|
+
printInfo(labelText);
|
|
9
|
+
const chatId = context.env.TELEGRAM_CHAT_ID;
|
|
10
|
+
if (!chatId) {
|
|
11
|
+
printInfo("Telegram notification skipped: chat_id environment variable is not set");
|
|
12
|
+
return { value: { success: false } };
|
|
13
|
+
}
|
|
14
|
+
const executor = context.executors.get("telegram-notifier");
|
|
15
|
+
const input = {
|
|
16
|
+
chatId,
|
|
17
|
+
text: params.message,
|
|
18
|
+
};
|
|
19
|
+
const value = await executor.execute(toExecutorContext(context), input, executor.defaultConfig);
|
|
20
|
+
if (value.success) {
|
|
21
|
+
printInfo(`Telegram notification sent successfully`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
printInfo(`Telegram notification failed`);
|
|
25
|
+
}
|
|
26
|
+
return { value };
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -18,24 +18,45 @@ function buildReviewFixPromptSuffix(params, values) {
|
|
|
18
18
|
throw new TaskRunnerError("Review-fix requires selecting at least one finding or enabling 'apply all'.");
|
|
19
19
|
}
|
|
20
20
|
const selectionSummary = applyAll
|
|
21
|
-
? "
|
|
22
|
-
:
|
|
21
|
+
? "All findings selected."
|
|
22
|
+
: `Selected findings:\n- ${selectedFindings.join("\n- ")}`;
|
|
23
23
|
const promptSuffix = [
|
|
24
|
-
"
|
|
25
|
-
|
|
24
|
+
"Use the user selection below as source of truth for the current review-fix scope.",
|
|
25
|
+
`Selection file: ${params.outputFile}`,
|
|
26
26
|
`apply_all: ${applyAll ? "true" : "false"}`,
|
|
27
|
-
applyAll ? "
|
|
28
|
-
extraNotes ?
|
|
27
|
+
applyAll ? "Fix all findings in the current iteration." : `Fix only selected findings:\n- ${selectedFindings.join("\n- ")}`,
|
|
28
|
+
extraNotes ? `User additional instructions:\n${extraNotes}` : "",
|
|
29
29
|
]
|
|
30
30
|
.filter((item) => item.trim().length > 0)
|
|
31
31
|
.join("\n\n");
|
|
32
|
-
const summaryText = extraNotes ? `${selectionSummary}\n\n
|
|
32
|
+
const summaryText = extraNotes ? `${selectionSummary}\n\nNote:\n${extraNotes}` : selectionSummary;
|
|
33
33
|
return { promptSuffix, summaryText };
|
|
34
34
|
}
|
|
35
|
+
function buildTaskDescribePromptSuffix(params, values) {
|
|
36
|
+
const jiraRef = typeof values.jira_ref === "string" ? values.jira_ref.trim() : "";
|
|
37
|
+
const taskDescription = typeof values.task_description === "string" ? values.task_description.trim() : "";
|
|
38
|
+
if (jiraRef) {
|
|
39
|
+
return {
|
|
40
|
+
promptSuffix: "",
|
|
41
|
+
summaryText: `Источник задачи: Jira\nJira: ${jiraRef}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
promptSuffix: [
|
|
46
|
+
"Use the user task description as source of truth.",
|
|
47
|
+
`User input file: ${params.outputFile}`,
|
|
48
|
+
`Task description:\n${taskDescription}`,
|
|
49
|
+
].join("\n\n"),
|
|
50
|
+
summaryText: `Task source: user-input\n\n${taskDescription}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
35
53
|
function buildPromptSuffix(params, values) {
|
|
36
54
|
if (params.formId === "review-fix-selection") {
|
|
37
55
|
return buildReviewFixPromptSuffix(params, values);
|
|
38
56
|
}
|
|
57
|
+
if (params.formId === "task-describe-source-input") {
|
|
58
|
+
return buildTaskDescribePromptSuffix(params, values);
|
|
59
|
+
}
|
|
39
60
|
if (params.fields.length === 0) {
|
|
40
61
|
return {
|
|
41
62
|
promptSuffix: "",
|
|
@@ -58,7 +79,7 @@ function buildPromptSuffix(params, values) {
|
|
|
58
79
|
});
|
|
59
80
|
const summaryText = lines.join("\n");
|
|
60
81
|
return {
|
|
61
|
-
promptSuffix:
|
|
82
|
+
promptSuffix: `Use user input from file ${params.outputFile}.\n\n${summaryText}`,
|
|
62
83
|
summaryText,
|
|
63
84
|
};
|
|
64
85
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { TaskRunnerError } from "../../errors.js";
|
|
4
|
+
const SEVERITY_AUTO_SELECT = ["blocker", "critical"];
|
|
5
|
+
export const writeSelectionFileNode = {
|
|
6
|
+
kind: "write-selection-file",
|
|
7
|
+
version: 1,
|
|
8
|
+
async run(_context, params) {
|
|
9
|
+
let parsed;
|
|
10
|
+
try {
|
|
11
|
+
parsed = JSON.parse(readFileSync(params.reviewFindingsJsonFile, "utf8"));
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
throw new TaskRunnerError(`Failed to read review findings from ${params.reviewFindingsJsonFile}: ${error.message}`);
|
|
15
|
+
}
|
|
16
|
+
const reviewFindings = parsed;
|
|
17
|
+
const findings = Array.isArray(reviewFindings.findings) ? reviewFindings.findings : [];
|
|
18
|
+
const selectedFindings = findings
|
|
19
|
+
.filter((finding) => {
|
|
20
|
+
const severity = typeof finding.severity === "string" ? finding.severity.trim().toLowerCase() : "";
|
|
21
|
+
const disposition = typeof finding.disposition === "string" ? finding.disposition.trim().toLowerCase() : null;
|
|
22
|
+
return SEVERITY_AUTO_SELECT.includes(severity) && disposition !== "resolved" && disposition != null;
|
|
23
|
+
})
|
|
24
|
+
.map((finding) => finding.title)
|
|
25
|
+
.filter((title) => typeof title === "string" && title.trim().length > 0);
|
|
26
|
+
const applyAll = selectedFindings.length === 0;
|
|
27
|
+
const artifact = {
|
|
28
|
+
form_id: "review-fix-selection",
|
|
29
|
+
submitted_at: new Date().toISOString(),
|
|
30
|
+
values: {
|
|
31
|
+
apply_all: applyAll,
|
|
32
|
+
selected_findings: selectedFindings,
|
|
33
|
+
extra_notes: "",
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
writeFileSync(params.outputFile, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
|
|
37
|
+
return {
|
|
38
|
+
value: {
|
|
39
|
+
outputFile: params.outputFile,
|
|
40
|
+
findingsCount: selectedFindings.length,
|
|
41
|
+
selectedFindings,
|
|
42
|
+
applyAll,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { BUG_ANALYZE_PROMPT_TEMPLATE, GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, JIRA_DESCRIPTION_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_QUESTIONS_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE,
|
|
1
|
+
import { BUG_ANALYZE_PROMPT_TEMPLATE, COMMIT_MESSAGE_PROMPT_TEMPLATE, GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, JIRA_DESCRIPTION_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_QUESTIONS_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_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
|
+
"commit-message": COMMIT_MESSAGE_PROMPT_TEMPLATE,
|
|
5
6
|
"gitlab-diff-review": GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE,
|
|
6
7
|
implement: IMPLEMENT_PROMPT_TEMPLATE,
|
|
7
8
|
"task-describe": JIRA_DESCRIPTION_PROMPT_TEMPLATE,
|
|
@@ -11,9 +12,6 @@ const promptTemplates = {
|
|
|
11
12
|
review: REVIEW_PROMPT_TEMPLATE,
|
|
12
13
|
"review-project": REVIEW_PROJECT_PROMPT_TEMPLATE,
|
|
13
14
|
"review-fix": REVIEW_FIX_PROMPT_TEMPLATE,
|
|
14
|
-
"review-reply": REVIEW_REPLY_PROMPT_TEMPLATE,
|
|
15
|
-
"review-reply-project": REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE,
|
|
16
|
-
"review-reply-summary": REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE,
|
|
17
15
|
"review-summary": REVIEW_SUMMARY_PROMPT_TEMPLATE,
|
|
18
16
|
"run-go-linter-loop-fix": RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE,
|
|
19
17
|
"run-go-tests-loop-fix": RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TaskRunnerError } from "../errors.js";
|
|
2
|
-
import { formatPrompt, formatTemplate } from "../prompts.js";
|
|
2
|
+
import { STRUCTURED_JSON_LANGUAGE_INSTRUCTION, formatPrompt, formatTemplate } from "../prompts.js";
|
|
3
3
|
import { getPromptTemplate } from "./prompt-registry.js";
|
|
4
4
|
import { resolveValue } from "./value-resolver.js";
|
|
5
5
|
export function renderPrompt(binding, context) {
|
|
@@ -11,8 +11,18 @@ export function renderPrompt(binding, context) {
|
|
|
11
11
|
const basePrompt = formatTemplate(baseTemplate, vars);
|
|
12
12
|
const resolvedExtraPrompt = binding.extraPrompt ? resolveValue(binding.extraPrompt, context) : null;
|
|
13
13
|
const extraPrompt = resolvedExtraPrompt === null || resolvedExtraPrompt === undefined ? null : String(resolvedExtraPrompt);
|
|
14
|
+
const mdLang = context.flowParams.mdLang;
|
|
15
|
+
const jsonInstruction = STRUCTURED_JSON_LANGUAGE_INSTRUCTION.trim();
|
|
16
|
+
let langInstruction = null;
|
|
17
|
+
if (mdLang === "en") {
|
|
18
|
+
langInstruction = "Generate all markdown output files in English language.";
|
|
19
|
+
}
|
|
20
|
+
else if (mdLang === "ru" || mdLang === null || mdLang === undefined) {
|
|
21
|
+
langInstruction = "Generate all markdown output files in Russian language.";
|
|
22
|
+
}
|
|
23
|
+
const finalExtraPrompt = [extraPrompt, jsonInstruction, langInstruction].filter(Boolean).join("\n");
|
|
14
24
|
if ((binding.format ?? "task-prompt") === "plain") {
|
|
15
|
-
return basePrompt;
|
|
25
|
+
return finalExtraPrompt ? `${basePrompt}\n\n${finalExtraPrompt}` : basePrompt;
|
|
16
26
|
}
|
|
17
|
-
return formatPrompt(basePrompt,
|
|
27
|
+
return formatPrompt(basePrompt, finalExtraPrompt);
|
|
18
28
|
}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { commandCheckExecutor } from "../executors/command-check-executor.js";
|
|
2
|
-
import {
|
|
3
|
-
import { codexDockerExecutor } from "../executors/codex-docker-executor.js";
|
|
4
|
-
import { codexLocalExecutor } from "../executors/codex-local-executor.js";
|
|
2
|
+
import { codexExecutor } from "../executors/codex-executor.js";
|
|
5
3
|
import { fetchGitLabDiffExecutor } from "../executors/fetch-gitlab-diff-executor.js";
|
|
6
4
|
import { fetchGitLabReviewExecutor } from "../executors/fetch-gitlab-review-executor.js";
|
|
5
|
+
import { gitCommitExecutor } from "../executors/git-commit-executor.js";
|
|
7
6
|
import { jiraFetchExecutor } from "../executors/jira-fetch-executor.js";
|
|
8
7
|
import { opencodeExecutor } from "../executors/opencode-executor.js";
|
|
9
8
|
import { processExecutor } from "../executors/process-executor.js";
|
|
10
|
-
import {
|
|
9
|
+
import { telegramNotifierExecutor } from "../executors/telegram-notifier-executor.js";
|
|
11
10
|
const builtInExecutors = {
|
|
12
11
|
process: processExecutor,
|
|
13
12
|
"command-check": commandCheckExecutor,
|
|
14
13
|
"fetch-gitlab-diff": fetchGitLabDiffExecutor,
|
|
15
14
|
"fetch-gitlab-review": fetchGitLabReviewExecutor,
|
|
15
|
+
"git-commit": gitCommitExecutor,
|
|
16
16
|
"jira-fetch": jiraFetchExecutor,
|
|
17
|
-
|
|
18
|
-
"codex-docker": codexDockerExecutor,
|
|
17
|
+
codex: codexExecutor,
|
|
19
18
|
opencode: opencodeExecutor,
|
|
20
|
-
|
|
21
|
-
"verify-build": verifyBuildExecutor,
|
|
19
|
+
"telegram-notifier": telegramNotifierExecutor,
|
|
22
20
|
};
|
|
23
21
|
export function createExecutorRegistry() {
|
|
24
22
|
return {
|
|
@@ -54,6 +54,11 @@ function interpolateValueSpec(value, repeatVars) {
|
|
|
54
54
|
},
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
+
if ("add" in value) {
|
|
58
|
+
return {
|
|
59
|
+
add: value.add.map((candidate) => interpolateValueSpec(candidate, repeatVars)),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
57
62
|
if ("concat" in value) {
|
|
58
63
|
return {
|
|
59
64
|
concat: value.concat.map((candidate) => interpolateValueSpec(candidate, repeatVars)),
|
|
@@ -22,20 +22,31 @@ export function listBuiltInFlowSpecFiles() {
|
|
|
22
22
|
if (!existsSync(BUILT_IN_FLOW_SPECS_DIR)) {
|
|
23
23
|
return [];
|
|
24
24
|
}
|
|
25
|
-
return
|
|
26
|
-
.
|
|
27
|
-
.map((entry) => entry.name)
|
|
25
|
+
return collectJsonFilesRecursively(BUILT_IN_FLOW_SPECS_DIR)
|
|
26
|
+
.map((filePath) => path.relative(BUILT_IN_FLOW_SPECS_DIR, filePath))
|
|
28
27
|
.sort((left, right) => left.localeCompare(right));
|
|
29
28
|
}
|
|
29
|
+
function collectJsonFilesRecursively(directory) {
|
|
30
|
+
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
31
|
+
const files = [];
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const entryPath = path.join(directory, entry.name);
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
files.push(...collectJsonFilesRecursively(entryPath));
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
39
|
+
files.push(entryPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return files;
|
|
43
|
+
}
|
|
30
44
|
export function listProjectFlowSpecFiles(cwd) {
|
|
31
45
|
const directory = projectFlowSpecsDir(cwd);
|
|
32
46
|
if (!existsSync(directory)) {
|
|
33
47
|
return [];
|
|
34
48
|
}
|
|
35
|
-
return
|
|
36
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
|
|
37
|
-
.map((entry) => path.join(directory, entry.name))
|
|
38
|
-
.sort((left, right) => left.localeCompare(right));
|
|
49
|
+
return collectJsonFilesRecursively(directory);
|
|
39
50
|
}
|
|
40
51
|
export function loadFlowSpecSync(source) {
|
|
41
52
|
return parseFlowSpec(source.source === "built-in" ? resolveBuiltInFlowSpecPath(source.fileName) : source.filePath);
|
|
@@ -31,13 +31,17 @@ export const ARTIFACT_REF_KINDS = [
|
|
|
31
31
|
"review-json-file",
|
|
32
32
|
"review-fix-file",
|
|
33
33
|
"review-fix-json-file",
|
|
34
|
-
"review-reply-file",
|
|
35
|
-
"review-reply-json-file",
|
|
36
34
|
"run-go-linter-result-json-file",
|
|
37
35
|
"run-go-tests-result-json-file",
|
|
38
|
-
"review-reply-summary-file",
|
|
39
36
|
"review-summary-file",
|
|
40
37
|
"task-summary-file",
|
|
41
38
|
"task-summary-json-file",
|
|
39
|
+
"task-describe-input-json-file",
|
|
40
|
+
"git-status-json-file",
|
|
41
|
+
"git-diff-file",
|
|
42
|
+
"git-commit-message-json-file",
|
|
43
|
+
"git-commit-input-json-file",
|
|
44
|
+
"select-files-output-json-file",
|
|
45
|
+
"commit-message-output-json-file",
|
|
42
46
|
];
|
|
43
47
|
export const ARTIFACT_LIST_REF_KINDS = ["bug-analyze-artifacts", "plan-artifacts"];
|
|
@@ -51,6 +51,10 @@ function validateValueSpec(value, path) {
|
|
|
51
51
|
validateValueSpec(value.appendPrompt.suffix, `${path}.appendPrompt.suffix`);
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
+
if ("add" in value) {
|
|
55
|
+
value.add.forEach((candidate, index) => validateValueSpec(candidate, `${path}.add[${index}]`));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
54
58
|
if ("concat" in value) {
|
|
55
59
|
value.concat.forEach((candidate, index) => validateValueSpec(candidate, `${path}.concat[${index}]`));
|
|
56
60
|
return;
|
package/dist/pipeline/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { artifactFile, bugAnalyzeArtifacts, bugAnalyzeFile, bugAnalyzeJsonFile, bugFixDesignFile, bugFixDesignJsonFile, bugFixPlanFile, bugFixPlanJsonFile, designFile, designJsonFile, gitlabDiffFile, gitlabDiffJsonFile, gitlabDiffReviewInputJsonFile, gitlabReviewFile, gitlabReviewInputJsonFile, gitlabReviewJsonFile, jiraAttachmentsContextFile, jiraAttachmentsManifestFile, jiraDescriptionFile, jiraDescriptionJsonFile, jiraTaskFile, mrDescriptionFile, mrDescriptionJsonFile, planningAnswersJsonFile, planningQuestionsJsonFile, planArtifacts, planFile, planJsonFile, qaFile, qaJsonFile, readyToMergeFile, reviewFile, reviewFixFile, reviewFixJsonFile, reviewJsonFile,
|
|
2
|
+
import { artifactFile, bugAnalyzeArtifacts, bugAnalyzeFile, bugAnalyzeJsonFile, bugFixDesignFile, bugFixDesignJsonFile, bugFixPlanFile, bugFixPlanJsonFile, designFile, designJsonFile, gitlabDiffFile, gitlabDiffJsonFile, gitlabDiffReviewInputJsonFile, gitlabReviewFile, gitlabReviewInputJsonFile, gitlabReviewJsonFile, jiraAttachmentsContextFile, jiraAttachmentsManifestFile, jiraDescriptionFile, jiraDescriptionJsonFile, jiraTaskFile, mrDescriptionFile, mrDescriptionJsonFile, planningAnswersJsonFile, planningQuestionsJsonFile, planArtifacts, planFile, planJsonFile, qaFile, qaJsonFile, readyToMergeFile, reviewFile, reviewFixFile, reviewFixJsonFile, reviewJsonFile, runGoLinterResultJsonFile, runGoTestsResultJsonFile, taskSummaryFile, taskDescribeInputJsonFile, taskSummaryJsonFile, gitStatusJsonFile, gitCommitMessageJsonFile, gitCommitInputJsonFile, selectFilesOutputJsonFile, commitMessageOutputJsonFile, gitDiffFile as gitDiffFileHelper, } from "../artifacts.js";
|
|
3
3
|
import { TaskRunnerError } from "../errors.js";
|
|
4
4
|
import { formatTemplate } from "../prompts.js";
|
|
5
5
|
function readStepRef(segments, context, originalPath) {
|
|
@@ -73,59 +73,59 @@ function resolveArtifact(spec, context) {
|
|
|
73
73
|
const iteration = spec.iteration === undefined ? undefined : Number(resolveValue(spec.iteration, context));
|
|
74
74
|
switch (spec.kind) {
|
|
75
75
|
case "bug-analyze-file":
|
|
76
|
-
return bugAnalyzeFile(taskKey);
|
|
76
|
+
return bugAnalyzeFile(taskKey, iteration);
|
|
77
77
|
case "bug-analyze-json-file":
|
|
78
|
-
return bugAnalyzeJsonFile(taskKey);
|
|
78
|
+
return bugAnalyzeJsonFile(taskKey, iteration);
|
|
79
79
|
case "bug-fix-design-file":
|
|
80
|
-
return bugFixDesignFile(taskKey);
|
|
80
|
+
return bugFixDesignFile(taskKey, iteration);
|
|
81
81
|
case "bug-fix-design-json-file":
|
|
82
|
-
return bugFixDesignJsonFile(taskKey);
|
|
82
|
+
return bugFixDesignJsonFile(taskKey, iteration);
|
|
83
83
|
case "bug-fix-plan-file":
|
|
84
|
-
return bugFixPlanFile(taskKey);
|
|
84
|
+
return bugFixPlanFile(taskKey, iteration);
|
|
85
85
|
case "bug-fix-plan-json-file":
|
|
86
|
-
return bugFixPlanJsonFile(taskKey);
|
|
86
|
+
return bugFixPlanJsonFile(taskKey, iteration);
|
|
87
87
|
case "design-file":
|
|
88
|
-
return designFile(taskKey);
|
|
88
|
+
return designFile(taskKey, iteration);
|
|
89
89
|
case "design-json-file":
|
|
90
|
-
return designJsonFile(taskKey);
|
|
90
|
+
return designJsonFile(taskKey, iteration);
|
|
91
91
|
case "gitlab-diff-file":
|
|
92
|
-
return gitlabDiffFile(taskKey);
|
|
92
|
+
return gitlabDiffFile(taskKey, iteration);
|
|
93
93
|
case "gitlab-diff-json-file":
|
|
94
|
-
return gitlabDiffJsonFile(taskKey);
|
|
94
|
+
return gitlabDiffJsonFile(taskKey, iteration);
|
|
95
95
|
case "gitlab-diff-review-input-json-file":
|
|
96
96
|
return gitlabDiffReviewInputJsonFile(taskKey);
|
|
97
97
|
case "gitlab-review-file":
|
|
98
|
-
return gitlabReviewFile(taskKey);
|
|
98
|
+
return gitlabReviewFile(taskKey, iteration);
|
|
99
99
|
case "gitlab-review-input-json-file":
|
|
100
100
|
return gitlabReviewInputJsonFile(taskKey);
|
|
101
101
|
case "gitlab-review-json-file":
|
|
102
|
-
return gitlabReviewJsonFile(taskKey);
|
|
102
|
+
return gitlabReviewJsonFile(taskKey, iteration);
|
|
103
103
|
case "jira-attachments-context-file":
|
|
104
104
|
return jiraAttachmentsContextFile(taskKey);
|
|
105
105
|
case "jira-attachments-manifest-file":
|
|
106
106
|
return jiraAttachmentsManifestFile(taskKey);
|
|
107
107
|
case "jira-description-file":
|
|
108
|
-
return jiraDescriptionFile(taskKey);
|
|
108
|
+
return jiraDescriptionFile(taskKey, iteration);
|
|
109
109
|
case "jira-description-json-file":
|
|
110
|
-
return jiraDescriptionJsonFile(taskKey);
|
|
110
|
+
return jiraDescriptionJsonFile(taskKey, iteration);
|
|
111
111
|
case "jira-task-file":
|
|
112
112
|
return jiraTaskFile(taskKey);
|
|
113
113
|
case "mr-description-file":
|
|
114
|
-
return mrDescriptionFile(taskKey);
|
|
114
|
+
return mrDescriptionFile(taskKey, iteration);
|
|
115
115
|
case "mr-description-json-file":
|
|
116
|
-
return mrDescriptionJsonFile(taskKey);
|
|
116
|
+
return mrDescriptionJsonFile(taskKey, iteration);
|
|
117
117
|
case "planning-answers-json-file":
|
|
118
118
|
return planningAnswersJsonFile(taskKey);
|
|
119
119
|
case "planning-questions-json-file":
|
|
120
120
|
return planningQuestionsJsonFile(taskKey);
|
|
121
121
|
case "plan-file":
|
|
122
|
-
return planFile(taskKey);
|
|
122
|
+
return planFile(taskKey, iteration);
|
|
123
123
|
case "plan-json-file":
|
|
124
|
-
return planJsonFile(taskKey);
|
|
124
|
+
return planJsonFile(taskKey, iteration);
|
|
125
125
|
case "qa-file":
|
|
126
|
-
return qaFile(taskKey);
|
|
126
|
+
return qaFile(taskKey, iteration);
|
|
127
127
|
case "qa-json-file":
|
|
128
|
-
return qaJsonFile(taskKey);
|
|
128
|
+
return qaJsonFile(taskKey, iteration);
|
|
129
129
|
case "ready-to-merge-file":
|
|
130
130
|
return readyToMergeFile(taskKey);
|
|
131
131
|
case "review-file":
|
|
@@ -148,16 +148,6 @@ function resolveArtifact(spec, context) {
|
|
|
148
148
|
throw new TaskRunnerError("review-fix-json-file requires iteration");
|
|
149
149
|
}
|
|
150
150
|
return reviewFixJsonFile(taskKey, iteration);
|
|
151
|
-
case "review-reply-file":
|
|
152
|
-
if (iteration === undefined) {
|
|
153
|
-
throw new TaskRunnerError("review-reply-file requires iteration");
|
|
154
|
-
}
|
|
155
|
-
return reviewReplyFile(taskKey, iteration);
|
|
156
|
-
case "review-reply-json-file":
|
|
157
|
-
if (iteration === undefined) {
|
|
158
|
-
throw new TaskRunnerError("review-reply-json-file requires iteration");
|
|
159
|
-
}
|
|
160
|
-
return reviewReplyJsonFile(taskKey, iteration);
|
|
161
151
|
case "run-go-linter-result-json-file":
|
|
162
152
|
if (iteration === undefined) {
|
|
163
153
|
throw new TaskRunnerError("run-go-linter-result-json-file requires iteration");
|
|
@@ -168,20 +158,29 @@ function resolveArtifact(spec, context) {
|
|
|
168
158
|
throw new TaskRunnerError("run-go-tests-result-json-file requires iteration");
|
|
169
159
|
}
|
|
170
160
|
return runGoTestsResultJsonFile(taskKey, iteration);
|
|
171
|
-
case "review-reply-summary-file":
|
|
172
|
-
if (iteration === undefined) {
|
|
173
|
-
throw new TaskRunnerError("review-reply-summary-file requires iteration");
|
|
174
|
-
}
|
|
175
|
-
return artifactFile("review-reply-summary", taskKey, iteration);
|
|
176
161
|
case "review-summary-file":
|
|
177
162
|
if (iteration === undefined) {
|
|
178
163
|
throw new TaskRunnerError("review-summary-file requires iteration");
|
|
179
164
|
}
|
|
180
165
|
return artifactFile("review-summary", taskKey, iteration);
|
|
181
166
|
case "task-summary-file":
|
|
182
|
-
return taskSummaryFile(taskKey);
|
|
167
|
+
return taskSummaryFile(taskKey, iteration);
|
|
183
168
|
case "task-summary-json-file":
|
|
184
|
-
return taskSummaryJsonFile(taskKey);
|
|
169
|
+
return taskSummaryJsonFile(taskKey, iteration);
|
|
170
|
+
case "task-describe-input-json-file":
|
|
171
|
+
return taskDescribeInputJsonFile(taskKey);
|
|
172
|
+
case "git-status-json-file":
|
|
173
|
+
return gitStatusJsonFile(taskKey);
|
|
174
|
+
case "git-diff-file":
|
|
175
|
+
return gitDiffFileHelper(taskKey);
|
|
176
|
+
case "git-commit-message-json-file":
|
|
177
|
+
return gitCommitMessageJsonFile(taskKey);
|
|
178
|
+
case "git-commit-input-json-file":
|
|
179
|
+
return gitCommitInputJsonFile(taskKey);
|
|
180
|
+
case "select-files-output-json-file":
|
|
181
|
+
return selectFilesOutputJsonFile(taskKey);
|
|
182
|
+
case "commit-message-output-json-file":
|
|
183
|
+
return commitMessageOutputJsonFile(taskKey);
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
186
|
function resolveArtifactList(spec, context) {
|
|
@@ -223,6 +222,9 @@ export function resolveValue(value, context) {
|
|
|
223
222
|
}
|
|
224
223
|
return `${baseText}\n${suffixText}`;
|
|
225
224
|
}
|
|
225
|
+
if ("add" in value) {
|
|
226
|
+
return value.add.reduce((sum, candidate) => sum + Number(resolveValue(candidate, context)), 0);
|
|
227
|
+
}
|
|
226
228
|
if ("concat" in value) {
|
|
227
229
|
return value.concat
|
|
228
230
|
.map((candidate) => resolveValue(candidate, context))
|