agentweaver 0.1.10 → 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 +218 -224
- package/dist/artifacts.js +100 -55
- 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 +469 -514
- package/dist/interactive-ui.js +144 -43
- package/dist/jira.js +52 -5
- package/dist/pipeline/auto-flow.js +6 -6
- package/dist/pipeline/context.js +1 -0
- package/dist/pipeline/flow-catalog.js +34 -4
- 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-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/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/opencode/auto-opencode.json +0 -1365
- package/dist/pipeline/flow-specs/opencode/bugz/bug-analyze-opencode.json +0 -382
- package/dist/pipeline/flow-specs/opencode/bugz/bug-fix-opencode.json +0 -56
- package/dist/pipeline/flow-specs/opencode/gitlab/gitlab-diff-review-opencode.json +0 -308
- package/dist/pipeline/flow-specs/opencode/gitlab/gitlab-review-opencode.json +0 -437
- package/dist/pipeline/flow-specs/opencode/gitlab/mr-description-opencode.json +0 -117
- package/dist/pipeline/flow-specs/opencode/go/run-go-linter-loop-opencode.json +0 -321
- package/dist/pipeline/flow-specs/opencode/go/run-go-tests-loop-opencode.json +0 -321
- package/dist/pipeline/flow-specs/opencode/implement-opencode.json +0 -64
- package/dist/pipeline/flow-specs/opencode/plan-opencode.json +0 -603
- package/dist/pipeline/flow-specs/opencode/review/review-fix-opencode.json +0 -209
- package/dist/pipeline/flow-specs/opencode/review/review-opencode.json +0 -452
- package/dist/pipeline/flow-specs/opencode/task-describe-opencode.json +0 -148
- package/dist/pipeline/flow-specs/review-project.json +0 -243
- package/dist/pipeline/flow-specs/review.json +0 -312
- 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
package/dist/prompts.js
CHANGED
|
@@ -1,113 +1,107 @@
|
|
|
1
|
-
|
|
2
|
-
export const
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"
|
|
82
|
-
export const
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
"
|
|
89
|
-
|
|
90
|
-
export const
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"Сначала запиши source-of-truth JSON в {jira_description_json_file} в виде объекта { summary: string }, затем markdown-версию в {jira_description_file}.";
|
|
106
|
-
export const RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE = "Используй структурированный результат последнего запуска run_go_tests.py из {tests_result_json_file} как source of truth. " +
|
|
107
|
-
"Проанализируй последнюю ошибку проверки, исправь код и подготовь изменения так, чтобы следующий прогон run_go_tests.py прошёл успешно.";
|
|
108
|
-
export const RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE = "Используй структурированный результат последнего запуска run_go_linter.py из {linter_result_json_file} как source of truth. " +
|
|
109
|
-
"Проанализируй последнюю ошибку линтера или генерации, исправь код и подготовь изменения так, чтобы следующий прогон run_go_linter.py прошёл успешно.";
|
|
110
|
-
export const AUTO_REVIEW_FIX_EXTRA_PROMPT = "Исправлять только блокеры, критикалы и важные";
|
|
1
|
+
import { renderStructuredArtifactSchema, } from "./structured-artifact-schema-registry.js";
|
|
2
|
+
export const BASE_PROMPT_HEADER = "Primary task:";
|
|
3
|
+
export const EXTRA_PROMPT_HEADER = "Additional instructions:";
|
|
4
|
+
export const STRUCTURED_JSON_LANGUAGE_INSTRUCTION = "All structured JSON artifacts are machine-readable and must use English for all generated semantic string values. " +
|
|
5
|
+
"If a JSON artifact needs to preserve verbatim user-provided or external source text, keep that quoted source text unchanged, but write all generated summaries, titles, descriptions, decisions, and explanations in English. ";
|
|
6
|
+
function strictSchemaInstruction(outputFileVar, schemaId) {
|
|
7
|
+
return (`The artifact format for ${outputFileVar} must fully conform to schema ${schemaId} from the registry. ` +
|
|
8
|
+
"Do not skip required fields, do not rename fields, do not change types, do not replace arrays with objects or strings, and do not leave required strings empty. " +
|
|
9
|
+
"The final JSON must pass validation against this schema without manual corrections. " +
|
|
10
|
+
STRUCTURED_JSON_LANGUAGE_INSTRUCTION +
|
|
11
|
+
`Canonical schema:\n${renderStructuredArtifactSchema(schemaId)}\n`);
|
|
12
|
+
}
|
|
13
|
+
export const PLAN_PROMPT_TEMPLATE = "Review and analyze the task in {jira_task_file}. " +
|
|
14
|
+
"Be sure to analyze additional materials from Jira attachments manifest {jira_attachments_manifest_file} and text context {jira_attachments_context_file}; if an attachment contains more detailed requirements, constraints, file lists, migration strategy, or invariants, treat the attachment as source of truth for planning alongside the Jira issue. " +
|
|
15
|
+
"First create structured JSON artifacts - they are the source of truth for subsequent flows. " +
|
|
16
|
+
"Create human-readable markdown files as detailed derivative representations of these JSON artifacts for the user, not as brief summaries. " +
|
|
17
|
+
"Markdown should not influence JSON structure: first determine the correct JSON types, then build markdown as a derivative representation. " +
|
|
18
|
+
"Do not collapse specifics from the task and attachments: preserve explicit files, methods, APIs, invariants, migration steps, DB constraints, business rules, and acceptance criteria. " +
|
|
19
|
+
"Develop a system design for the solution and write JSON to {design_json_file}, then markdown to {design_file}. " +
|
|
20
|
+
strictSchemaInstruction("{design_json_file}", "implementation-design/v1") +
|
|
21
|
+
"Develop a detailed implementation plan and write JSON to {plan_json_file}, then markdown to {plan_file}. " +
|
|
22
|
+
strictSchemaInstruction("{plan_json_file}", "implementation-plan/v1") +
|
|
23
|
+
"Develop a QA test plan and write JSON to {qa_json_file}, then markdown to {qa_file}. " +
|
|
24
|
+
strictSchemaInstruction("{qa_json_file}", "qa-plan/v1") +
|
|
25
|
+
"Format markdown for design and plan comprehensively, with separate sections for Summary, Current State, Target State, Affected Code, Decisions, Migration/DB Changes, Risks, Implementation Steps, Tests, Rollout. " +
|
|
26
|
+
"JSON files must be valid and contain only JSON without markdown wrapping. ";
|
|
27
|
+
export const PLAN_QUESTIONS_PROMPT_TEMPLATE = "Review and analyze the task in {jira_task_file}. " +
|
|
28
|
+
"Be sure to analyze additional materials from Jira attachments manifest {jira_attachments_manifest_file} and text context {jira_attachments_context_file}; if an attachment contains more detailed requirements, constraints, file lists, migration strategy, or invariants, treat the attachment as source of truth for planning alongside the Jira issue. " +
|
|
29
|
+
"Before final planning, determine if any clarifications are needed from the user. " +
|
|
30
|
+
strictSchemaInstruction("{planning_questions_json_file}", "planning-questions/v1") +
|
|
31
|
+
"Ask only questions without which the design/plan could be incorrect or too speculative. " +
|
|
32
|
+
"Do not ask obvious, decorative, or duplicate questions. " +
|
|
33
|
+
"Usually 1-5 questions are sufficient. " +
|
|
34
|
+
"The JSON file must be valid and contain only JSON without markdown wrapping. ";
|
|
35
|
+
export const BUG_ANALYZE_PROMPT_TEMPLATE = "Review and analyze the bug in {jira_task_file}. " +
|
|
36
|
+
"First create structured JSON artifacts - they are the source of truth for subsequent flows. " +
|
|
37
|
+
"Create human-readable markdown files as brief derivative representations of these JSON artifacts for the user. " +
|
|
38
|
+
"Write structured bug analysis to {bug_analyze_json_file}, then a brief markdown version to {bug_analyze_file}. " +
|
|
39
|
+
"Write structured fix design to {bug_fix_design_json_file}, then a brief markdown version to {bug_fix_design_file}. " +
|
|
40
|
+
"Write structured implementation plan to {bug_fix_plan_json_file}, then a brief markdown version to {bug_fix_plan_file}. " +
|
|
41
|
+
"JSON files must be valid and contain only JSON without markdown wrapping. " +
|
|
42
|
+
strictSchemaInstruction("{bug_analyze_json_file}", "bug-analysis/v1") +
|
|
43
|
+
strictSchemaInstruction("{bug_fix_design_json_file}", "bug-fix-design/v1") +
|
|
44
|
+
strictSchemaInstruction("{bug_fix_plan_json_file}", "bug-fix-plan/v1");
|
|
45
|
+
export const BUG_FIX_PROMPT_TEMPLATE = "Use only structured artifacts as source of truth. " +
|
|
46
|
+
"Analyze the bug from {bug_analyze_json_file}. " +
|
|
47
|
+
"Use the fix design from {bug_fix_design_json_file}. " +
|
|
48
|
+
"Use the implementation plan from {bug_fix_plan_json_file}. " +
|
|
49
|
+
"Markdown artifacts are intended only for human reading and should not define the implementation. " +
|
|
50
|
+
"After that, proceed to implement the fix in code. ";
|
|
51
|
+
export const MR_DESCRIPTION_PROMPT_TEMPLATE = "Review the task in {jira_task_file} and the current changes in the repository. " +
|
|
52
|
+
"Prepare a very brief intent description for the merge request without implementation details, file lists, or technical details. " +
|
|
53
|
+
`First write the source-of-truth JSON to {mr_description_json_file}. ${strictSchemaInstruction("{mr_description_json_file}", "mr-description/v1")}Then write the derivative markdown version to {mr_description_file}. `;
|
|
54
|
+
export const IMPLEMENT_PROMPT_TEMPLATE = "Use only structured artifacts as source of truth. " +
|
|
55
|
+
"Analyze the system design {design_json_file}, implementation plan {plan_json_file}, and proceed with implementation according to the plan. " +
|
|
56
|
+
"Markdown artifacts are intended only for human reading and should not define the implementation. ";
|
|
57
|
+
export const REVIEW_PROMPT_TEMPLATE = "Conduct a code review of the current changes. " +
|
|
58
|
+
"Use only structured artifacts as source of truth: the task in {jira_task_file}, design in {design_json_file}, and plan in {plan_json_file}. " +
|
|
59
|
+
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
60
|
+
"Then write the derivative markdown version to {review_file}. " +
|
|
61
|
+
"If ready_to_merge=true and there are no blockers preventing merge - create the ready-to-merge.md file.";
|
|
62
|
+
export const REVIEW_PROJECT_PROMPT_TEMPLATE = "Conduct a code review of current changes in the project without Jira context. " +
|
|
63
|
+
"Evaluate the quality of changes based on current code, tests, regression risks, and overall engineering quality. " +
|
|
64
|
+
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
65
|
+
"Then write the derivative markdown version to {review_file}. " +
|
|
66
|
+
"If ready_to_merge=true and there are no blockers, create the {ready_to_merge_file} file.";
|
|
67
|
+
export const GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE = "Conduct a code review of the GitLab merge request diff. " +
|
|
68
|
+
"Use the structured diff artifact {gitlab_diff_json_file} as source of truth, and markdown {gitlab_diff_file} only as a convenient human-readable representation. " +
|
|
69
|
+
"Evaluate only the changes from the diff: correctness, regression risks, missing tests, dangerous edge cases, contract violations, and maintainability. " +
|
|
70
|
+
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
71
|
+
"Then write the derivative markdown version to {review_file}. " +
|
|
72
|
+
"If ready_to_merge=true and there are no blockers, create the {ready_to_merge_file} file.";
|
|
73
|
+
export const REVIEW_SUMMARY_PROMPT_TEMPLATE = "Look at {review_file}. " +
|
|
74
|
+
"Create a brief list of comments without details, 3-7 items. " +
|
|
75
|
+
"Write the result to {review_summary_file}.";
|
|
76
|
+
export const REVIEW_FIX_PROMPT_TEMPLATE = "Use only structured artifacts as source of truth. " +
|
|
77
|
+
"Analyze the findings in {review_json_file}. " +
|
|
78
|
+
"Fix what is contained in the additional instructions, and if there are none - fix all items. " +
|
|
79
|
+
"After completion, be sure to run the linter outside the sandbox, all tests, generate make swagger. " +
|
|
80
|
+
"Fix any linter and test errors if they occur. " +
|
|
81
|
+
`Upon completion, first write the structured report to {review_fix_json_file}. ${strictSchemaInstruction("{review_fix_json_file}", "review-fix-report/v1")}Then write the derivative markdown version to {review_fix_file}.`;
|
|
82
|
+
export const TASK_SUMMARY_PROMPT_TEMPLATE = "Look at {jira_task_file}. " +
|
|
83
|
+
"Create a brief summary of the task, 1-2 paragraphs. " +
|
|
84
|
+
`First write the source-of-truth JSON to {task_summary_json_file}. ${strictSchemaInstruction("{task_summary_json_file}", "task-summary/v1")}Then write the markdown version to {task_summary_file}.`;
|
|
85
|
+
export const JIRA_DESCRIPTION_PROMPT_TEMPLATE = "Look at the task in {jira_task_file}. " +
|
|
86
|
+
"Formulate a typical Jira task description in simple product language, without overloading with technical details. " +
|
|
87
|
+
"Description structure: Problem, Context, What needs to be done, Acceptance criteria. " +
|
|
88
|
+
"Write only what helps understand the essence of the task and expected result; technical details, internal service names, data models, file names, REST methods, and implementation steps should only be mentioned if without them the task's meaning is lost. " +
|
|
89
|
+
`First write the source-of-truth JSON to {jira_description_json_file}. ${strictSchemaInstruction("{jira_description_json_file}", "jira-description/v1")}Then write the markdown version to {jira_description_file}.`;
|
|
90
|
+
export const RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE = "Use the structured result of the last run of run_go_tests.py from {tests_result_json_file} as source of truth. " +
|
|
91
|
+
"Analyze the last test error, fix the code, and prepare changes so that the next run of run_go_tests.py succeeds.";
|
|
92
|
+
export const RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE = "Use the structured result of the last run of run_go_linter.py from {linter_result_json_file} as source of truth. " +
|
|
93
|
+
"Analyze the last linter or generation error, fix the code, and prepare changes so that the next run of run_go_linter.py succeeds.";
|
|
94
|
+
export const COMMIT_MESSAGE_PROMPT_TEMPLATE = "Generate a commit message for the current changes. " +
|
|
95
|
+
"Task context (Jira): {jira_task_file}. " +
|
|
96
|
+
"Current changes (git diff): {git_diff_file}. " +
|
|
97
|
+
"List of changed files: {git_status_json_file}. " +
|
|
98
|
+
"Rules: " +
|
|
99
|
+
"1) Subject line ≤72 characters. " +
|
|
100
|
+
"2) Format: {taskKey}: {taskDescription} (e.g., DEMO-1234: Add user authentication). " +
|
|
101
|
+
"3) Include task key from Jira task. " +
|
|
102
|
+
"4) Commit message language: English. " +
|
|
103
|
+
"5) Write JSON to {commit_message_json_file}: {\"subject\": \"...\"}.";
|
|
104
|
+
export const AUTO_REVIEW_FIX_EXTRA_PROMPT = "Fix only blockers, criticals, and important issues";
|
|
111
105
|
export function formatTemplate(template, values) {
|
|
112
106
|
let result = template;
|
|
113
107
|
for (const [key, value] of Object.entries(values)) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { accessSync, constants } from "node:fs";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import path from "node:path";
|
|
4
3
|
import { TaskRunnerError } from "../errors.js";
|
|
5
4
|
function splitArgs(input) {
|
|
6
5
|
const result = [];
|
|
@@ -100,40 +99,3 @@ export function resolveCmd(commandName, envVarName) {
|
|
|
100
99
|
}
|
|
101
100
|
throw new TaskRunnerError(`Missing required command: ${commandName}`);
|
|
102
101
|
}
|
|
103
|
-
export function requireDockerCompose() {
|
|
104
|
-
if (!commandExists("docker")) {
|
|
105
|
-
throw new TaskRunnerError("Missing required command: docker");
|
|
106
|
-
}
|
|
107
|
-
const result = spawnSync("docker", ["compose", "version"], { stdio: "ignore" });
|
|
108
|
-
if (result.status !== 0) {
|
|
109
|
-
throw new TaskRunnerError("Missing required docker compose plugin");
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
export function resolveDockerComposeCmd() {
|
|
113
|
-
const configured = process.env.DOCKER_COMPOSE_BIN?.trim() ?? "";
|
|
114
|
-
if (configured) {
|
|
115
|
-
const parts = splitArgs(configured);
|
|
116
|
-
if (parts.length === 0) {
|
|
117
|
-
throw new TaskRunnerError("DOCKER_COMPOSE_BIN is set but empty.");
|
|
118
|
-
}
|
|
119
|
-
const executable = parts[0] ?? "";
|
|
120
|
-
try {
|
|
121
|
-
if (path.isAbsolute(executable)) {
|
|
122
|
-
accessSync(executable, constants.X_OK);
|
|
123
|
-
return parts;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
throw new TaskRunnerError(`Configured docker compose command is not executable: ${configured}`);
|
|
128
|
-
}
|
|
129
|
-
if (commandExists(executable)) {
|
|
130
|
-
return parts;
|
|
131
|
-
}
|
|
132
|
-
throw new TaskRunnerError(`Configured docker compose command is not executable: ${configured}`);
|
|
133
|
-
}
|
|
134
|
-
if (commandExists("docker-compose")) {
|
|
135
|
-
return ["docker-compose"];
|
|
136
|
-
}
|
|
137
|
-
requireDockerCompose();
|
|
138
|
-
return ["docker", "compose"];
|
|
139
|
-
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
function parseEnvFile(envFilePath, protectedKeys) {
|
|
5
|
+
if (!existsSync(envFilePath)) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const lines = readFileSync(envFilePath, "utf8").split(/\r?\n/);
|
|
9
|
+
for (const rawLine of lines) {
|
|
10
|
+
let line = rawLine.trim();
|
|
11
|
+
if (!line || line.startsWith("#")) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (line.startsWith("export ")) {
|
|
15
|
+
line = line.slice(7).trim();
|
|
16
|
+
}
|
|
17
|
+
const separatorIndex = line.indexOf("=");
|
|
18
|
+
if (separatorIndex < 0) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
22
|
+
if (!key || protectedKeys.has(key)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
let value = line.slice(separatorIndex + 1).trim();
|
|
26
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
27
|
+
value = value.slice(1, -1);
|
|
28
|
+
}
|
|
29
|
+
process.env[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function globalConfigDir() {
|
|
33
|
+
return path.join(os.homedir(), ".agentweaver");
|
|
34
|
+
}
|
|
35
|
+
function ensureGlobalConfigDir() {
|
|
36
|
+
mkdirSync(globalConfigDir(), { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
export function loadTieredEnv(projectDir) {
|
|
39
|
+
ensureGlobalConfigDir();
|
|
40
|
+
const shellEnvKeys = new Set(Object.keys(process.env));
|
|
41
|
+
parseEnvFile(path.join(globalConfigDir(), ".env"), shellEnvKeys);
|
|
42
|
+
parseEnvFile(path.join(projectDir, ".agentweaver", ".env"), shellEnvKeys);
|
|
43
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { TaskRunnerError } from "./errors.js";
|
|
5
|
+
export const STRUCTURED_ARTIFACT_SCHEMA_IDS = [
|
|
6
|
+
"bug-analysis/v1",
|
|
7
|
+
"bug-fix-design/v1",
|
|
8
|
+
"bug-fix-plan/v1",
|
|
9
|
+
"gitlab-mr-diff/v1",
|
|
10
|
+
"gitlab-review/v1",
|
|
11
|
+
"implementation-design/v1",
|
|
12
|
+
"implementation-plan/v1",
|
|
13
|
+
"jira-description/v1",
|
|
14
|
+
"mr-description/v1",
|
|
15
|
+
"planning-questions/v1",
|
|
16
|
+
"qa-plan/v1",
|
|
17
|
+
"review-findings/v1",
|
|
18
|
+
"review-fix-report/v1",
|
|
19
|
+
"task-summary/v1",
|
|
20
|
+
"user-input/v1",
|
|
21
|
+
];
|
|
22
|
+
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
export const SCHEMA_REGISTRY_PATH = path.join(MODULE_DIR, "structured-artifact-schemas.json");
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
export function loadStructuredArtifactSchemaRegistry() {
|
|
28
|
+
if (!existsSync(SCHEMA_REGISTRY_PATH)) {
|
|
29
|
+
throw new TaskRunnerError(`Structured artifact schema registry not found: ${SCHEMA_REGISTRY_PATH}`);
|
|
30
|
+
}
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = JSON.parse(readFileSync(SCHEMA_REGISTRY_PATH, "utf8"));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new TaskRunnerError(`Failed to parse structured artifact schema registry: ${error.message}`);
|
|
37
|
+
}
|
|
38
|
+
if (!isRecord(parsed)) {
|
|
39
|
+
throw new TaskRunnerError(`Structured artifact schema registry ${SCHEMA_REGISTRY_PATH} must be a JSON object.`);
|
|
40
|
+
}
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
const schemaRegistry = loadStructuredArtifactSchemaRegistry();
|
|
44
|
+
export function getStructuredArtifactSchema(schemaId) {
|
|
45
|
+
const schema = schemaRegistry[schemaId];
|
|
46
|
+
if (!schema) {
|
|
47
|
+
throw new TaskRunnerError(`Structured artifact schema is not registered: ${schemaId}`);
|
|
48
|
+
}
|
|
49
|
+
return schema;
|
|
50
|
+
}
|
|
51
|
+
export function renderStructuredArtifactSchema(schemaId) {
|
|
52
|
+
return JSON.stringify(getStructuredArtifactSchema(schemaId), null, 2);
|
|
53
|
+
}
|
|
@@ -521,26 +521,6 @@
|
|
|
521
521
|
},
|
|
522
522
|
"required": ["summary", "completed_actions", "validation_steps"]
|
|
523
523
|
},
|
|
524
|
-
"review-reply/v1": {
|
|
525
|
-
"type": "object",
|
|
526
|
-
"properties": {
|
|
527
|
-
"summary": { "type": "string", "nonEmpty": true },
|
|
528
|
-
"responses": {
|
|
529
|
-
"type": "array",
|
|
530
|
-
"items": {
|
|
531
|
-
"type": "object",
|
|
532
|
-
"properties": {
|
|
533
|
-
"finding_title": { "type": "string", "nonEmpty": true },
|
|
534
|
-
"disposition": { "type": "string", "nonEmpty": true },
|
|
535
|
-
"action": { "type": "string", "nonEmpty": true }
|
|
536
|
-
},
|
|
537
|
-
"required": ["finding_title", "disposition", "action"]
|
|
538
|
-
}
|
|
539
|
-
},
|
|
540
|
-
"ready_to_merge": { "type": "boolean" }
|
|
541
|
-
},
|
|
542
|
-
"required": ["summary", "responses", "ready_to_merge"]
|
|
543
|
-
},
|
|
544
524
|
"task-summary/v1": {
|
|
545
525
|
"type": "object",
|
|
546
526
|
"properties": {
|
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
2
|
import { TaskRunnerError } from "./errors.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"bug-fix-design/v1",
|
|
8
|
-
"bug-fix-plan/v1",
|
|
9
|
-
"gitlab-mr-diff/v1",
|
|
10
|
-
"gitlab-review/v1",
|
|
11
|
-
"implementation-design/v1",
|
|
12
|
-
"implementation-plan/v1",
|
|
13
|
-
"jira-description/v1",
|
|
14
|
-
"mr-description/v1",
|
|
15
|
-
"planning-questions/v1",
|
|
16
|
-
"qa-plan/v1",
|
|
17
|
-
"review-findings/v1",
|
|
18
|
-
"review-fix-report/v1",
|
|
19
|
-
"review-reply/v1",
|
|
20
|
-
"task-summary/v1",
|
|
21
|
-
"user-input/v1",
|
|
22
|
-
];
|
|
23
|
-
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
24
|
-
const SCHEMA_REGISTRY_PATH = path.join(MODULE_DIR, "structured-artifact-schemas.json");
|
|
3
|
+
import { STRUCTURED_ARTIFACT_SCHEMA_IDS, getStructuredArtifactSchema, } from "./structured-artifact-schema-registry.js";
|
|
4
|
+
export { STRUCTURED_ARTIFACT_SCHEMA_IDS };
|
|
25
5
|
function isRecord(value) {
|
|
26
6
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27
7
|
}
|
|
@@ -99,23 +79,6 @@ function validateNode(value, schema, currentPath) {
|
|
|
99
79
|
}
|
|
100
80
|
}
|
|
101
81
|
}
|
|
102
|
-
function loadSchemaRegistry() {
|
|
103
|
-
if (!existsSync(SCHEMA_REGISTRY_PATH)) {
|
|
104
|
-
throw new TaskRunnerError(`Structured artifact schema registry not found: ${SCHEMA_REGISTRY_PATH}`);
|
|
105
|
-
}
|
|
106
|
-
let parsed;
|
|
107
|
-
try {
|
|
108
|
-
parsed = JSON.parse(readFileSync(SCHEMA_REGISTRY_PATH, "utf8"));
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
throw new TaskRunnerError(`Failed to parse structured artifact schema registry: ${error.message}`);
|
|
112
|
-
}
|
|
113
|
-
if (!isRecord(parsed)) {
|
|
114
|
-
throw new TaskRunnerError(`Structured artifact schema registry ${SCHEMA_REGISTRY_PATH} must be a JSON object.`);
|
|
115
|
-
}
|
|
116
|
-
return parsed;
|
|
117
|
-
}
|
|
118
|
-
const schemas = loadSchemaRegistry();
|
|
119
82
|
export function validateStructuredArtifact(path, schemaId) {
|
|
120
83
|
if (!existsSync(path)) {
|
|
121
84
|
throw new TaskRunnerError(`Structured artifact file not found: ${path}`);
|
|
@@ -127,10 +90,7 @@ export function validateStructuredArtifact(path, schemaId) {
|
|
|
127
90
|
catch (error) {
|
|
128
91
|
throw new TaskRunnerError(`Structured artifact ${path} is not valid JSON: ${error.message}`);
|
|
129
92
|
}
|
|
130
|
-
const schema =
|
|
131
|
-
if (!schema) {
|
|
132
|
-
throw new TaskRunnerError(`Structured artifact schema is not registered: ${schemaId}`);
|
|
133
|
-
}
|
|
93
|
+
const schema = getStructuredArtifactSchema(schemaId);
|
|
134
94
|
const issues = validateNode(parsed, schema, path);
|
|
135
95
|
if (issues.length > 0) {
|
|
136
96
|
throw new TaskRunnerError(`Structured artifact ${path} failed schema ${schemaId} validation:\n${issues.join("\n")}`);
|
package/dist/user-input.js
CHANGED
|
@@ -71,6 +71,16 @@ export function validateUserInputValues(form, values) {
|
|
|
71
71
|
throw new TaskRunnerError("Select at least one finding or enable 'apply all'.");
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
if (form.formId === "task-describe-source-input") {
|
|
75
|
+
const jiraRef = typeof values.jira_ref === "string" ? normalizeText(values.jira_ref) : "";
|
|
76
|
+
const taskDescription = typeof values.task_description === "string" ? normalizeText(values.task_description) : "";
|
|
77
|
+
if (!jiraRef && !taskDescription) {
|
|
78
|
+
throw new TaskRunnerError("Provide either Jira URL/key or a short task description.");
|
|
79
|
+
}
|
|
80
|
+
if (jiraRef && taskDescription) {
|
|
81
|
+
throw new TaskRunnerError("Provide either Jira URL/key or a short task description, not both.");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
74
84
|
}
|
|
75
85
|
function parseBoolean(value) {
|
|
76
86
|
const normalized = normalizeText(value).toLowerCase();
|
|
@@ -120,8 +130,26 @@ export async function requestUserInputInTerminal(form) {
|
|
|
120
130
|
}
|
|
121
131
|
if (field.type === "text") {
|
|
122
132
|
const current = String(values[field.id] ?? "");
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
if (field.multiline) {
|
|
134
|
+
process.stdout.write(`${field.label}${current ? " (leave empty to keep current value)" : ""}:\n`);
|
|
135
|
+
if (field.help?.trim()) {
|
|
136
|
+
process.stdout.write(`${field.help.trim()}\n`);
|
|
137
|
+
}
|
|
138
|
+
process.stdout.write("Finish input with an empty line.\n");
|
|
139
|
+
const lines = [];
|
|
140
|
+
while (true) {
|
|
141
|
+
const line = await rl.question(lines.length === 0 ? "> " : "... ");
|
|
142
|
+
if (!line.trim()) {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
lines.push(line);
|
|
146
|
+
}
|
|
147
|
+
values[field.id] = lines.length > 0 ? lines.join("\n") : current;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const answer = await rl.question(`${field.label}${current ? ` (${current})` : ""}: `);
|
|
151
|
+
values[field.id] = answer.trim() ? answer : current;
|
|
152
|
+
}
|
|
125
153
|
continue;
|
|
126
154
|
}
|
|
127
155
|
const options = field.options.map((option, index) => `${index + 1}. ${option.label}`).join("\n");
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentweaver",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "CLI orchestrator for Jira/Codex
|
|
3
|
+
"version": "0.1.11",
|
|
4
|
+
"description": "CLI orchestrator for Jira/Codex engineering workflows",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
7
7
|
"cli",
|
|
8
8
|
"jira",
|
|
9
9
|
"codex",
|
|
10
|
-
"claude",
|
|
11
10
|
"tui",
|
|
12
11
|
"developer-tools"
|
|
13
12
|
],
|
|
@@ -29,9 +28,6 @@
|
|
|
29
28
|
"files": [
|
|
30
29
|
"dist",
|
|
31
30
|
"README.md",
|
|
32
|
-
"docker-compose.yml",
|
|
33
|
-
"Dockerfile.codex",
|
|
34
|
-
"verify_build.sh",
|
|
35
31
|
"run_go_tests.py",
|
|
36
32
|
"run_go_linter.py",
|
|
37
33
|
"run_go_coverage.sh"
|