agentweaver 0.1.15 → 0.1.17
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 +76 -19
- package/dist/artifact-manifest.js +219 -0
- package/dist/artifacts.js +88 -3
- package/dist/doctor/checks/env-diagnostics.js +25 -0
- package/dist/doctor/checks/executors.js +2 -2
- package/dist/doctor/checks/flow-readiness.js +15 -18
- package/dist/flow-state.js +212 -15
- package/dist/index.js +539 -209
- package/dist/interactive/blessed-session.js +361 -0
- package/dist/interactive/controller.js +1326 -0
- package/dist/interactive/create-interactive-session.js +5 -0
- package/dist/interactive/ink/index.js +597 -0
- package/dist/interactive/progress.js +245 -0
- package/dist/interactive/selectors.js +14 -0
- package/dist/interactive/session.js +1 -0
- package/dist/interactive/state.js +34 -0
- package/dist/interactive/tree.js +155 -0
- package/dist/interactive/types.js +1 -0
- package/dist/interactive/view-model.js +1 -0
- package/dist/interactive-ui.js +159 -194
- package/dist/pipeline/auto-flow.js +9 -6
- package/dist/pipeline/context.js +7 -5
- package/dist/pipeline/declarative-flow-runner.js +212 -6
- package/dist/pipeline/declarative-flows.js +63 -17
- package/dist/pipeline/execution-routing-config.js +15 -0
- package/dist/pipeline/flow-catalog.js +50 -12
- package/dist/pipeline/flow-run-resume.js +29 -0
- package/dist/pipeline/flow-specs/auto-common.json +90 -360
- package/dist/pipeline/flow-specs/auto-golang.json +81 -360
- package/dist/pipeline/flow-specs/auto-simple.json +141 -0
- package/dist/pipeline/flow-specs/bugz/bug-analyze.json +2 -0
- package/dist/pipeline/flow-specs/bugz/bug-fix.json +1 -0
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +316 -0
- package/dist/pipeline/flow-specs/design-review.json +10 -0
- package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +11 -0
- package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +2 -0
- package/dist/pipeline/flow-specs/gitlab/mr-description.json +1 -0
- package/dist/pipeline/flow-specs/go/run-go-linter-loop.json +2 -0
- package/dist/pipeline/flow-specs/go/run-go-tests-loop.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +13 -6
- package/dist/pipeline/flow-specs/instant-task.json +177 -0
- package/dist/pipeline/flow-specs/normalize-task-source.json +311 -0
- package/dist/pipeline/flow-specs/plan-revise.json +7 -1
- package/dist/pipeline/flow-specs/plan.json +51 -71
- package/dist/pipeline/flow-specs/review/review-fix.json +24 -4
- package/dist/pipeline/flow-specs/review/review-loop.json +351 -45
- package/dist/pipeline/flow-specs/review/review-project-loop.json +590 -0
- package/dist/pipeline/flow-specs/review/review-project.json +12 -0
- package/dist/pipeline/flow-specs/review/review.json +37 -31
- package/dist/pipeline/flow-specs/task-describe.json +2 -0
- package/dist/pipeline/flow-specs/task-source/jira-fetch.json +70 -0
- package/dist/pipeline/flow-specs/task-source/manual-input.json +216 -0
- package/dist/pipeline/launch-profile-config.js +30 -18
- package/dist/pipeline/node-contract.js +1 -0
- package/dist/pipeline/node-registry.js +115 -6
- package/dist/pipeline/node-runner.js +3 -2
- package/dist/pipeline/nodes/build-review-fix-prompt-node.js +5 -1
- package/dist/pipeline/nodes/clear-ready-to-merge-node.js +11 -0
- package/dist/pipeline/nodes/commit-message-form-node.js +8 -0
- package/dist/pipeline/nodes/design-review-verdict-node.js +36 -0
- package/dist/pipeline/nodes/ensure-summary-json-node.js +13 -2
- package/dist/pipeline/nodes/fetch-gitlab-diff-node.js +19 -2
- package/dist/pipeline/nodes/fetch-gitlab-review-node.js +19 -2
- package/dist/pipeline/nodes/flow-run-node.js +242 -8
- package/dist/pipeline/nodes/git-commit-form-node.js +8 -0
- package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +19 -2
- package/dist/pipeline/nodes/jira-fetch-node.js +50 -4
- package/dist/pipeline/nodes/llm-prompt-node.js +38 -36
- package/dist/pipeline/nodes/planning-bundle-node.js +10 -0
- package/dist/pipeline/nodes/review-verdict-node.js +86 -0
- package/dist/pipeline/nodes/select-files-form-node.js +8 -0
- package/dist/pipeline/nodes/structured-summary-node.js +24 -0
- package/dist/pipeline/nodes/user-input-node.js +38 -3
- package/dist/pipeline/nodes/write-selection-file-node.js +20 -4
- package/dist/pipeline/plugin-loader.js +389 -0
- package/dist/pipeline/plugin-types.js +1 -0
- package/dist/pipeline/prompt-registry.js +3 -1
- package/dist/pipeline/prompt-runtime.js +4 -1
- package/dist/pipeline/registry.js +71 -4
- package/dist/pipeline/review-iteration.js +26 -0
- package/dist/pipeline/spec-compiler.js +3 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +3 -0
- package/dist/pipeline/spec-validator.js +20 -0
- package/dist/pipeline/value-resolver.js +76 -2
- package/dist/plugin-sdk.js +1 -0
- package/dist/prompts.js +36 -14
- package/dist/review-severity.js +45 -0
- package/dist/runtime/artifact-registry.js +405 -0
- package/dist/runtime/design-review-input-contract.js +17 -16
- package/dist/runtime/env-loader.js +3 -0
- package/dist/runtime/execution-routing-store.js +134 -0
- package/dist/runtime/execution-routing.js +233 -0
- package/dist/runtime/interactive-execution-routing.js +471 -0
- package/dist/runtime/plan-revise-input-contract.js +35 -32
- package/dist/runtime/planning-bundle.js +123 -0
- package/dist/runtime/ready-to-merge.js +22 -1
- package/dist/runtime/review-input-contract.js +100 -0
- package/dist/structured-artifact-schema-registry.js +9 -0
- package/dist/structured-artifact-schemas.json +140 -1
- package/dist/structured-artifacts.js +77 -6
- package/dist/user-input.js +70 -3
- package/docs/example/.flows/examples/claude-example.json +50 -0
- package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/examples/.flows/claude-example.json +50 -0
- package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/plugin-sdk.md +731 -0
- package/package.json +11 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { TaskRunnerError } from "../errors.js";
|
|
2
2
|
import { STRUCTURED_ARTIFACT_SCHEMA_IDS } from "../structured-artifacts.js";
|
|
3
3
|
import { isPromptTemplateRef } from "./prompt-registry.js";
|
|
4
|
+
import { EXECUTION_ROUTING_GROUPS } from "./execution-routing-config.js";
|
|
4
5
|
import { ARTIFACT_LIST_REF_KINDS as artifactListRefKinds, ARTIFACT_REF_KINDS as artifactRefKinds, } from "./spec-types.js";
|
|
5
6
|
function isArtifactRefKind(value) {
|
|
6
7
|
return artifactRefKinds.includes(value);
|
|
@@ -18,6 +19,9 @@ function validateArtifactRefSpec(spec, path) {
|
|
|
18
19
|
function validateArtifactListRefSpec(spec, path) {
|
|
19
20
|
assert(isArtifactListRefKind(spec.kind), `Unknown artifact list kind '${spec.kind}' at ${path}.kind`);
|
|
20
21
|
validateValueSpec(spec.taskKey, `${path}.taskKey`);
|
|
22
|
+
if (spec.iteration) {
|
|
23
|
+
validateValueSpec(spec.iteration, `${path}.iteration`);
|
|
24
|
+
}
|
|
21
25
|
}
|
|
22
26
|
function assert(condition, message) {
|
|
23
27
|
if (!condition) {
|
|
@@ -102,6 +106,10 @@ function validateStep(step, nodeRegistry, executorRegistry, path, options) {
|
|
|
102
106
|
assert(executorRegistry.has(executorId), `Unknown executor '${executorId}' required by node '${step.node}' at ${path}.node`);
|
|
103
107
|
}
|
|
104
108
|
validateCondition(step.when, `${path}.when`);
|
|
109
|
+
if (step.routingGroup) {
|
|
110
|
+
assert(step.node === "llm-prompt", `routingGroup is only supported for llm-prompt steps at ${path}.routingGroup`);
|
|
111
|
+
assert(EXECUTION_ROUTING_GROUPS.includes(step.routingGroup), `Unknown routingGroup '${step.routingGroup}' at ${path}.routingGroup`);
|
|
112
|
+
}
|
|
105
113
|
if (step.prompt) {
|
|
106
114
|
assert(nodeMeta.prompt !== "forbidden", `Node '${step.node}' does not accept prompt binding at ${path}.prompt`);
|
|
107
115
|
assert(Boolean(step.prompt.templateRef || step.prompt.inlineTemplate), `Prompt binding at ${path}.prompt must define templateRef or inlineTemplate`);
|
|
@@ -110,6 +118,9 @@ function validateStep(step, nodeRegistry, executorRegistry, path, options) {
|
|
|
110
118
|
for (const requiredParam of nodeMeta.requiredParams ?? []) {
|
|
111
119
|
assert(step.params?.[requiredParam] !== undefined, `Node '${step.node}' requires param '${requiredParam}' at ${path}.params.${requiredParam}`);
|
|
112
120
|
}
|
|
121
|
+
if (step.node === "llm-prompt") {
|
|
122
|
+
assert(step.routingGroup !== undefined || step.params?.executor !== undefined, `Node 'llm-prompt' requires routingGroup or param 'executor' at ${path}`);
|
|
123
|
+
}
|
|
113
124
|
if (step.prompt?.templateRef) {
|
|
114
125
|
assert(isPromptTemplateRef(step.prompt.templateRef), `Unknown prompt template '${step.prompt.templateRef}' at ${path}.prompt.templateRef`);
|
|
115
126
|
}
|
|
@@ -147,6 +158,9 @@ function validateStep(step, nodeRegistry, executorRegistry, path, options) {
|
|
|
147
158
|
if (step.stopFlowIf) {
|
|
148
159
|
validateCondition(step.stopFlowIf, `${path}.stopFlowIf`);
|
|
149
160
|
}
|
|
161
|
+
if (step.stopFlowOutcome) {
|
|
162
|
+
assert(step.stopFlowOutcome === "success" || step.stopFlowOutcome === "stopped", `Unsupported stopFlowOutcome '${step.stopFlowOutcome}' at ${path}.stopFlowOutcome`);
|
|
163
|
+
}
|
|
150
164
|
if (step.after) {
|
|
151
165
|
step.after.forEach((action, index) => validateAfterAction(action, `${path}.after[${index}]`));
|
|
152
166
|
}
|
|
@@ -230,6 +244,9 @@ function validateExpandedValueSpec(value, phases, currentPhaseIndex, currentStep
|
|
|
230
244
|
}
|
|
231
245
|
if ("artifactList" in value) {
|
|
232
246
|
validateExpandedValueSpec(value.artifactList.taskKey, phases, currentPhaseIndex, currentStepIndex, `${path}.artifactList.taskKey`, allowCurrentStepRef);
|
|
247
|
+
if (value.artifactList.iteration) {
|
|
248
|
+
validateExpandedValueSpec(value.artifactList.iteration, phases, currentPhaseIndex, currentStepIndex, `${path}.artifactList.iteration`, allowCurrentStepRef);
|
|
249
|
+
}
|
|
233
250
|
return;
|
|
234
251
|
}
|
|
235
252
|
if ("template" in value) {
|
|
@@ -281,6 +298,9 @@ function validateExpandedCondition(condition, phases, currentPhaseIndex, current
|
|
|
281
298
|
}
|
|
282
299
|
}
|
|
283
300
|
export function validateFlowSpec(spec, nodeRegistry, executorRegistry, options = {}) {
|
|
301
|
+
if (spec.catalogVisibility !== undefined) {
|
|
302
|
+
assert(spec.catalogVisibility === "visible" || spec.catalogVisibility === "hidden", `Unsupported catalogVisibility '${spec.catalogVisibility}' at flow.catalogVisibility`);
|
|
303
|
+
}
|
|
284
304
|
assert(spec.kind.trim().length > 0, "Flow spec kind must be non-empty");
|
|
285
305
|
assert(Number.isInteger(spec.version) && spec.version > 0, "Flow spec version must be a positive integer");
|
|
286
306
|
spec.phases.forEach((item, index) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { artifactFile, bugAnalyzeArtifacts, bugAnalyzeFile, bugAnalyzeJsonFile, bugFixDesignFile, bugFixDesignJsonFile, bugFixPlanFile, bugFixPlanJsonFile, designFile, designJsonFile, designReviewFile, designReviewJsonFile, gitlabDiffFile, gitlabDiffJsonFile, gitlabDiffReviewInputJsonFile, gitlabReviewFile, gitlabReviewInputJsonFile, gitlabReviewJsonFile, jiraAttachmentsContextFile, jiraAttachmentsManifestFile, jiraDescriptionFile, jiraDescriptionJsonFile, jiraTaskFile, mrDescriptionFile, mrDescriptionJsonFile, planningAnswersJsonFile, planningQuestionsJsonFile, planArtifacts, planFile, planJsonFile, qaFile, qaJsonFile, readyToMergeFile, reviewAssessmentFile, reviewAssessmentJsonFile, reviewFile, reviewFixFile, reviewFixJsonFile, reviewJsonFile, runGoLinterResultJsonFile, runGoTestsResultJsonFile, taskSummaryFile, taskDescribeInputJsonFile, taskSummaryJsonFile, gitStatusJsonFile, gitCommitMessageJsonFile, gitCommitInputJsonFile, selectFilesOutputJsonFile, commitMessageOutputJsonFile, gitDiffFile as gitDiffFileHelper, } from "../artifacts.js";
|
|
2
|
+
import { artifactFile, bugAnalyzeArtifacts, bugAnalyzeFile, bugAnalyzeJsonFile, bugFixDesignFile, bugFixDesignJsonFile, bugFixPlanFile, bugFixPlanJsonFile, designFile, designJsonFile, designReviewFile, designReviewJsonFile, gitlabDiffFile, gitlabDiffJsonFile, gitlabDiffReviewInputJsonFile, gitlabReviewFile, gitlabReviewInputJsonFile, gitlabReviewJsonFile, jiraAttachmentsContextFile, jiraAttachmentsManifestFile, jiraDescriptionFile, jiraDescriptionJsonFile, instantTaskInputJsonFile, jiraTaskFile, mrDescriptionFile, mrDescriptionJsonFile, planningAnswersJsonFile, planningQuestionsJsonFile, planArtifacts, planFile, planJsonFile, qaFile, qaJsonFile, readyToMergeFile, reviewAssessmentFile, reviewAssessmentJsonFile, reviewFile, reviewFixFile, reviewFixJsonFile, reviewJsonFile, runGoLinterResultJsonFile, runGoTestsResultJsonFile, taskSummaryFile, taskDescribeInputJsonFile, taskSummaryJsonFile, taskContextFile, taskContextJsonFile, 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) {
|
|
@@ -120,6 +120,8 @@ function resolveArtifact(spec, context) {
|
|
|
120
120
|
return jiraDescriptionJsonFile(taskKey, iteration);
|
|
121
121
|
case "jira-task-file":
|
|
122
122
|
return jiraTaskFile(taskKey);
|
|
123
|
+
case "instant-task-input-json-file":
|
|
124
|
+
return instantTaskInputJsonFile(taskKey);
|
|
123
125
|
case "mr-description-file":
|
|
124
126
|
return mrDescriptionFile(taskKey, iteration);
|
|
125
127
|
case "mr-description-json-file":
|
|
@@ -183,6 +185,10 @@ function resolveArtifact(spec, context) {
|
|
|
183
185
|
throw new TaskRunnerError("review-summary-file requires iteration");
|
|
184
186
|
}
|
|
185
187
|
return artifactFile("review-summary", taskKey, iteration);
|
|
188
|
+
case "task-context-file":
|
|
189
|
+
return taskContextFile(taskKey, iteration);
|
|
190
|
+
case "task-context-json-file":
|
|
191
|
+
return taskContextJsonFile(taskKey, iteration);
|
|
186
192
|
case "task-summary-file":
|
|
187
193
|
return taskSummaryFile(taskKey, iteration);
|
|
188
194
|
case "task-summary-json-file":
|
|
@@ -205,11 +211,12 @@ function resolveArtifact(spec, context) {
|
|
|
205
211
|
}
|
|
206
212
|
function resolveArtifactList(spec, context) {
|
|
207
213
|
const taskKey = String(resolveValue(spec.taskKey, context));
|
|
214
|
+
const iteration = spec.iteration === undefined ? undefined : Number(resolveValue(spec.iteration, context));
|
|
208
215
|
switch (spec.kind) {
|
|
209
216
|
case "bug-analyze-artifacts":
|
|
210
217
|
return bugAnalyzeArtifacts(taskKey);
|
|
211
218
|
case "plan-artifacts":
|
|
212
|
-
return planArtifacts(taskKey);
|
|
219
|
+
return planArtifacts(taskKey, iteration);
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
222
|
export function resolveValue(value, context) {
|
|
@@ -263,6 +270,73 @@ export function resolveParams(params, context) {
|
|
|
263
270
|
}
|
|
264
271
|
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, resolveValue(value, context)]));
|
|
265
272
|
}
|
|
273
|
+
export const ARTIFACT_LINEAGE_REF_PATHS_PARAM = "__artifactLineageRefPaths";
|
|
274
|
+
function collectAnnotatedRefArtifactPathCandidates(refPath, context) {
|
|
275
|
+
const annotatedRefPaths = context.flowParams[ARTIFACT_LINEAGE_REF_PATHS_PARAM];
|
|
276
|
+
if (!annotatedRefPaths || typeof annotatedRefPaths !== "object" || Array.isArray(annotatedRefPaths)) {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
const candidate = annotatedRefPaths[refPath];
|
|
280
|
+
const paths = typeof candidate === "string" ? [candidate] : Array.isArray(candidate) ? candidate : [];
|
|
281
|
+
return paths.filter((value) => typeof value === "string" && existsSync(value));
|
|
282
|
+
}
|
|
283
|
+
export function collectResolvedArtifactPathCandidates(value, context) {
|
|
284
|
+
const candidates = new Set();
|
|
285
|
+
const addCandidate = (candidatePath) => {
|
|
286
|
+
if (existsSync(candidatePath)) {
|
|
287
|
+
candidates.add(candidatePath);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const visit = (current) => {
|
|
291
|
+
if (!current || "const" in current) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if ("ref" in current) {
|
|
295
|
+
collectAnnotatedRefArtifactPathCandidates(current.ref, context).forEach((candidatePath) => addCandidate(candidatePath));
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if ("artifact" in current) {
|
|
299
|
+
addCandidate(resolveArtifact(current.artifact, context));
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if ("artifactList" in current) {
|
|
303
|
+
resolveArtifactList(current.artifactList, context).forEach((candidatePath) => addCandidate(candidatePath));
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if ("template" in current) {
|
|
307
|
+
Object.values(current.vars ?? {}).forEach((candidate) => visit(candidate));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if ("appendPrompt" in current) {
|
|
311
|
+
visit(current.appendPrompt.base);
|
|
312
|
+
visit(current.appendPrompt.suffix);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if ("add" in current) {
|
|
316
|
+
current.add.forEach((candidate) => visit(candidate));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if ("concat" in current) {
|
|
320
|
+
current.concat.forEach((candidate) => visit(candidate));
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if ("list" in current) {
|
|
324
|
+
current.list.forEach((candidate) => visit(candidate));
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
visit(value);
|
|
328
|
+
return Array.from(candidates).sort();
|
|
329
|
+
}
|
|
330
|
+
export function collectResolvedPromptArtifactPathCandidates(binding, context) {
|
|
331
|
+
const candidates = new Set();
|
|
332
|
+
for (const value of Object.values(binding?.vars ?? {})) {
|
|
333
|
+
collectResolvedArtifactPathCandidates(value, context).forEach((candidate) => candidates.add(candidate));
|
|
334
|
+
}
|
|
335
|
+
if (binding?.extraPrompt) {
|
|
336
|
+
collectResolvedArtifactPathCandidates(binding.extraPrompt, context).forEach((candidate) => candidates.add(candidate));
|
|
337
|
+
}
|
|
338
|
+
return Array.from(candidates).sort();
|
|
339
|
+
}
|
|
266
340
|
function truthy(value) {
|
|
267
341
|
return Boolean(value);
|
|
268
342
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AGENTWEAVER_PLUGIN_SDK_VERSION } from "./pipeline/plugin-types.js";
|
package/dist/prompts.js
CHANGED
|
@@ -10,12 +10,12 @@ function strictSchemaInstruction(outputFileVar, schemaId) {
|
|
|
10
10
|
STRUCTURED_JSON_LANGUAGE_INSTRUCTION +
|
|
11
11
|
`Canonical schema:\n${renderStructuredArtifactSchema(schemaId)}\n`);
|
|
12
12
|
}
|
|
13
|
-
export const PLAN_PROMPT_TEMPLATE = "Review and analyze the task in {
|
|
14
|
-
"
|
|
13
|
+
export const PLAN_PROMPT_TEMPLATE = "Review and analyze the normalized task context in {task_context_json_file}. " +
|
|
14
|
+
"Use planning answers from {planning_answers_json_file} when they exist and treat them as structured user clarifications. " +
|
|
15
15
|
"First create structured JSON artifacts - they are the source of truth for subsequent flows. " +
|
|
16
16
|
"Create human-readable markdown files as detailed derivative representations of these JSON artifacts for the user, not as brief summaries. " +
|
|
17
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
|
|
18
|
+
"Do not collapse specifics from the task context: preserve explicit files, methods, APIs, invariants, migration steps, DB constraints, business rules, acceptance criteria, and constraints. " +
|
|
19
19
|
"Develop a system design for the solution and write JSON to {design_json_file}, then markdown to {design_file}. " +
|
|
20
20
|
strictSchemaInstruction("{design_json_file}", "implementation-design/v1") +
|
|
21
21
|
"Develop a detailed implementation plan and write JSON to {plan_json_file}, then markdown to {plan_file}. " +
|
|
@@ -24,14 +24,31 @@ export const PLAN_PROMPT_TEMPLATE = "Review and analyze the task in {jira_task_f
|
|
|
24
24
|
strictSchemaInstruction("{qa_json_file}", "qa-plan/v1") +
|
|
25
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
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 {
|
|
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. " +
|
|
27
|
+
export const PLAN_QUESTIONS_PROMPT_TEMPLATE = "Review and analyze the normalized task context in {task_context_json_file}. " +
|
|
29
28
|
"Before final planning, determine if any clarifications are needed from the user. " +
|
|
30
29
|
strictSchemaInstruction("{planning_questions_json_file}", "planning-questions/v1") +
|
|
31
30
|
"Ask only questions without which the design/plan could be incorrect or too speculative. " +
|
|
32
31
|
"Do not ask obvious, decorative, or duplicate questions. " +
|
|
33
32
|
"Usually 1-5 questions are sufficient. " +
|
|
34
33
|
"The JSON file must be valid and contain only JSON without markdown wrapping. ";
|
|
34
|
+
export const TASK_CONTEXT_FROM_JIRA_PROMPT_TEMPLATE = "Normalize the Jira task context into a connector-agnostic task context. " +
|
|
35
|
+
"Use Jira issue JSON {jira_task_file} as the primary source of truth. " +
|
|
36
|
+
"Also analyze Jira attachments manifest {jira_attachments_manifest_file} and attachments text context {jira_attachments_context_file}; if attachments contain more specific requirements, constraints, file lists, migration strategy, or invariants, preserve them in the normalized result. " +
|
|
37
|
+
"Write the source-of-truth JSON to {task_context_json_file}. " +
|
|
38
|
+
strictSchemaInstruction("{task_context_json_file}", "task-context/v1") +
|
|
39
|
+
"Set source_type to 'jira'. " +
|
|
40
|
+
"Write the derivative markdown version to {task_context_file}. " +
|
|
41
|
+
"Do not invent metadata that is not supported by Jira content or attachments. " +
|
|
42
|
+
"Keep JSON semantic fields in English. JSON files must contain only JSON without markdown wrapping.";
|
|
43
|
+
export const TASK_CONTEXT_FROM_MANUAL_PROMPT_TEMPLATE = "Normalize the manual task input into a connector-agnostic task context. " +
|
|
44
|
+
"Use the structured user input in {task_input_file}. " +
|
|
45
|
+
"Use values.task_description as the primary source of truth and values.additional_instructions as additional context when present. " +
|
|
46
|
+
"Do not reshape the input into Jira-like fields or invent Jira metadata. " +
|
|
47
|
+
"Write the source-of-truth JSON to {task_context_json_file}. " +
|
|
48
|
+
strictSchemaInstruction("{task_context_json_file}", "task-context/v1") +
|
|
49
|
+
"Set source_type to 'manual'. " +
|
|
50
|
+
"Write the derivative markdown version to {task_context_file}. " +
|
|
51
|
+
"Keep JSON semantic fields in English. JSON files must contain only JSON without markdown wrapping.";
|
|
35
52
|
export const BUG_ANALYZE_PROMPT_TEMPLATE = "Review and analyze the bug in {jira_task_file}. " +
|
|
36
53
|
"First create structured JSON artifacts - they are the source of truth for subsequent flows. " +
|
|
37
54
|
"Create human-readable markdown files as brief derivative representations of these JSON artifacts for the user. " +
|
|
@@ -58,15 +75,19 @@ export const IMPLEMENT_PROMPT_TEMPLATE = "Use only structured artifacts as sourc
|
|
|
58
75
|
"If some QA scenarios cannot be automated in the current change, still implement the code so those scenarios are satisfied and keep them explicit in your reasoning while editing. " +
|
|
59
76
|
"Markdown artifacts such as {design_file}, {plan_file}, and {qa_file} are intended only for human reading and should not define the implementation. ";
|
|
60
77
|
export const REVIEW_PROMPT_TEMPLATE = "Conduct a code review of the current changes. " +
|
|
61
|
-
"Use only structured artifacts as source of truth
|
|
78
|
+
"Use only structured artifacts as source of truth. " +
|
|
79
|
+
"Required planning inputs: design markdown {design_file}, design JSON {design_json_file}, plan markdown {plan_file}, and plan JSON {plan_json_file}. " +
|
|
80
|
+
"Optional task context is provided through these variables and may contain the literal value 'not provided' when absent: normalized task context JSON {task_context_json_file}, Jira task JSON {jira_task_file}, instant-task input JSON {task_input_json_file}. " +
|
|
81
|
+
"When an optional variable is 'not provided', treat that source as unavailable and do not invent details from it. " +
|
|
82
|
+
"Evaluate the current code against the available task context and the structured planning artifacts. " +
|
|
83
|
+
"Use exactly one severity per finding from this list: blocker, critical, high, medium, low, info. " +
|
|
62
84
|
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
63
|
-
"Then write the derivative markdown version to {review_file}. "
|
|
64
|
-
"If ready_to_merge=true and there are no blockers preventing merge - create the ready-to-merge.md file.";
|
|
85
|
+
"Then write the derivative markdown version to {review_file}. ";
|
|
65
86
|
export const DESIGN_REVIEW_PROMPT_TEMPLATE = "Conduct a structured planning critique as a specification critic, not as an implementer. " +
|
|
66
87
|
"Use structured JSON artifacts as the source of truth for semantics. " +
|
|
67
88
|
"Required planning inputs: design markdown {design_file}, design JSON {design_json_file}, implementation plan markdown {plan_file}, implementation plan JSON {plan_json_file}. " +
|
|
68
89
|
"Review the markdown files as derivative human-readable renderings of the same planning run, but do not let markdown override the structured JSON. " +
|
|
69
|
-
"Optional supplemental context is provided through these variables and may contain the literal value 'not provided' when absent: QA markdown {qa_file}, QA JSON {qa_json_file}, Jira task JSON {jira_task_file}, Jira attachments manifest {jira_attachments_manifest_file}, Jira attachments context {jira_attachments_context_file}, planning answers JSON {planning_answers_json_file}. " +
|
|
90
|
+
"Optional supplemental context is provided through these variables and may contain the literal value 'not provided' when absent: normalized task context JSON {task_context_json_file}, QA markdown {qa_file}, QA JSON {qa_json_file}, Jira task JSON {jira_task_file}, Jira attachments manifest {jira_attachments_manifest_file}, Jira attachments context {jira_attachments_context_file}, planning answers JSON {planning_answers_json_file}, instant-task input JSON {task_input_json_file}. " +
|
|
70
91
|
"When an optional variable is 'not provided', treat that source as unavailable and do not invent details from it. " +
|
|
71
92
|
"Evaluate completeness, consistency, implementation readiness, risk coverage, QA coverage, and scope discipline across the available planning artifacts and optional context. " +
|
|
72
93
|
"Identify blocking findings, major non-blocking findings, warnings, missing information, consistency check results, QA coverage gaps, and concise recommended actions. " +
|
|
@@ -80,19 +101,20 @@ export const DESIGN_REVIEW_PROMPT_TEMPLATE = "Conduct a structured planning crit
|
|
|
80
101
|
"Do not create ready-to-merge.md when status is needs_revision.";
|
|
81
102
|
export const REVIEW_PROJECT_PROMPT_TEMPLATE = "Conduct a code review of current changes in the project without Jira context. " +
|
|
82
103
|
"Evaluate the quality of changes based on current code, tests, regression risks, and overall engineering quality. " +
|
|
104
|
+
"Use exactly one severity per finding from this list: blocker, critical, high, medium, low, info. " +
|
|
83
105
|
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
84
|
-
"Then write the derivative markdown version to {review_file}. "
|
|
85
|
-
"If ready_to_merge=true and there are no blockers, create the {ready_to_merge_file} file.";
|
|
106
|
+
"Then write the derivative markdown version to {review_file}. ";
|
|
86
107
|
export const GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE = "Conduct a code review of the GitLab merge request diff. " +
|
|
87
108
|
"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. " +
|
|
88
109
|
"Evaluate only the changes from the diff: correctness, regression risks, missing tests, dangerous edge cases, contract violations, and maintainability. " +
|
|
110
|
+
"Use exactly one severity per finding from this list: blocker, critical, high, medium, low, info. " +
|
|
89
111
|
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
90
|
-
"Then write the derivative markdown version to {review_file}. "
|
|
91
|
-
"If ready_to_merge=true and there are no blockers, create the {ready_to_merge_file} file.";
|
|
112
|
+
"Then write the derivative markdown version to {review_file}. ";
|
|
92
113
|
export const GITLAB_REVIEW_PROMPT_TEMPLATE = "Validate GitLab merge request review comments. " +
|
|
93
114
|
"Use the structured GitLab review artifact {gitlab_review_json_file} as source of truth, and markdown {gitlab_review_file} only as a convenient human-readable representation. " +
|
|
94
115
|
"Determine which comments are valid actionable findings that should be addressed in the current code. " +
|
|
95
116
|
"Ignore comments that are obsolete, already resolved, duplicates, purely conversational, or not actionable. " +
|
|
117
|
+
"Use exactly one severity per finding from this list: blocker, critical, high, medium, low, info. " +
|
|
96
118
|
"Normalize the remaining actionable findings into the review findings schema with accurate severities, concise titles, and concrete descriptions. " +
|
|
97
119
|
"For each remaining finding, assess whether the complaint is fair in the current code and propose a concrete fix. " +
|
|
98
120
|
`First write the structured result to {review_json_file}. ${strictSchemaInstruction("{review_json_file}", "review-findings/v1")}` +
|
|
@@ -144,7 +166,7 @@ export const PLAN_REVISE_PROMPT_TEMPLATE = "Revise the planning artifacts based
|
|
|
144
166
|
"Required source planning inputs: design JSON {design_json_file}, design markdown {design_file}, plan JSON {plan_json_file}, plan markdown {plan_file}. " +
|
|
145
167
|
"Optional source QA inputs (may be 'not provided'): QA JSON {qa_json_file}, QA markdown {qa_file}. " +
|
|
146
168
|
"When QA inputs are 'not provided', synthesize a new QA plan from the revised design and plan. " +
|
|
147
|
-
"Optional supplemental context (may be 'not provided'): Jira task JSON {jira_task_file}, Jira attachments manifest {jira_attachments_manifest_file}, Jira attachments context {jira_attachments_context_file}, planning answers JSON {planning_answers_json_file}. " +
|
|
169
|
+
"Optional supplemental context (may be 'not provided'): normalized task context JSON {task_context_json_file}, Jira task JSON {jira_task_file}, Jira attachments manifest {jira_attachments_manifest_file}, Jira attachments context {jira_attachments_context_file}, planning answers JSON {planning_answers_json_file}, instant-task input JSON {task_input_json_file}. " +
|
|
148
170
|
"When an optional variable is 'not provided', treat that source as unavailable and do not invent details from it. " +
|
|
149
171
|
"For every blocking finding and major finding in the verdict, address it directly in the revised artifacts. " +
|
|
150
172
|
"Preserve all content from the original artifacts that is not directly addressed by findings in the verdict — do not drop details, sections, or decisions that remain valid. " +
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { TaskRunnerError } from "./errors.js";
|
|
2
|
+
export const REVIEW_SEVERITIES = ["blocker", "critical", "high", "medium", "low", "info"];
|
|
3
|
+
export const AGENTWEAVER_REVIEW_BLOCKING_SEVERITIES_ENV = "AGENTWEAVER_REVIEW_BLOCKING_SEVERITIES";
|
|
4
|
+
export const DEFAULT_REVIEW_BLOCKING_SEVERITIES = ["blocker", "critical", "high"];
|
|
5
|
+
const REVIEW_SEVERITY_SET = new Set(REVIEW_SEVERITIES);
|
|
6
|
+
export function normalizeReviewSeverity(value) {
|
|
7
|
+
if (typeof value !== "string") {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const normalized = value.trim().toLowerCase();
|
|
11
|
+
return REVIEW_SEVERITY_SET.has(normalized) ? normalized : null;
|
|
12
|
+
}
|
|
13
|
+
export function normalizeReviewSeverityList(values) {
|
|
14
|
+
const result = [];
|
|
15
|
+
for (const value of values) {
|
|
16
|
+
const normalized = normalizeReviewSeverity(value);
|
|
17
|
+
if (!normalized || result.includes(normalized)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
result.push(normalized);
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
export function resolveBlockingReviewSeverities(values) {
|
|
25
|
+
const normalized = Array.isArray(values) ? normalizeReviewSeverityList(values) : [];
|
|
26
|
+
return normalized.length > 0 ? normalized : [...DEFAULT_REVIEW_BLOCKING_SEVERITIES];
|
|
27
|
+
}
|
|
28
|
+
export function parseReviewSeverityCsv(raw) {
|
|
29
|
+
const values = raw
|
|
30
|
+
.split(",")
|
|
31
|
+
.map((item) => item.trim())
|
|
32
|
+
.filter((item) => item.length > 0);
|
|
33
|
+
const normalized = normalizeReviewSeverityList(values);
|
|
34
|
+
if (values.length === 0 || normalized.length !== values.length) {
|
|
35
|
+
throw new TaskRunnerError(`Invalid review severity list '${raw}'. Allowed values: ${REVIEW_SEVERITIES.join(", ")}.`);
|
|
36
|
+
}
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
export function resolveReviewBlockingSeveritiesFromEnv(env = process.env) {
|
|
40
|
+
const raw = env[AGENTWEAVER_REVIEW_BLOCKING_SEVERITIES_ENV]?.trim();
|
|
41
|
+
if (!raw) {
|
|
42
|
+
return [...DEFAULT_REVIEW_BLOCKING_SEVERITIES];
|
|
43
|
+
}
|
|
44
|
+
return parseReviewSeverityCsv(raw);
|
|
45
|
+
}
|