agentweaver 0.1.14 → 0.1.16

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.
Files changed (100) hide show
  1. package/README.md +29 -7
  2. package/dist/artifact-manifest.js +219 -0
  3. package/dist/artifacts.js +21 -1
  4. package/dist/doctor/checks/cwd-context.js +4 -3
  5. package/dist/doctor/checks/env-diagnostics.js +193 -71
  6. package/dist/doctor/checks/flow-readiness.js +212 -203
  7. package/dist/doctor/index.js +1 -1
  8. package/dist/doctor/orchestrator.js +18 -7
  9. package/dist/doctor/runner.js +9 -8
  10. package/dist/doctor/types.js +12 -0
  11. package/dist/flow-state.js +75 -15
  12. package/dist/index.js +499 -199
  13. package/dist/interactive/blessed-session.js +361 -0
  14. package/dist/interactive/controller.js +1293 -0
  15. package/dist/interactive/create-interactive-session.js +5 -0
  16. package/dist/interactive/ink/index.js +576 -0
  17. package/dist/interactive/progress.js +245 -0
  18. package/dist/interactive/selectors.js +14 -0
  19. package/dist/interactive/session.js +1 -0
  20. package/dist/interactive/state.js +34 -0
  21. package/dist/interactive/tree.js +155 -0
  22. package/dist/interactive/types.js +1 -0
  23. package/dist/interactive/view-model.js +1 -0
  24. package/dist/interactive-ui.js +159 -194
  25. package/dist/pipeline/context.js +1 -0
  26. package/dist/pipeline/declarative-flow-runner.js +212 -6
  27. package/dist/pipeline/declarative-flows.js +27 -0
  28. package/dist/pipeline/execution-routing-config.js +15 -0
  29. package/dist/pipeline/flow-catalog.js +23 -3
  30. package/dist/pipeline/flow-run-resume.js +29 -0
  31. package/dist/pipeline/flow-specs/auto-common.json +89 -360
  32. package/dist/pipeline/flow-specs/auto-golang.json +58 -363
  33. package/dist/pipeline/flow-specs/auto-simple.json +141 -0
  34. package/dist/pipeline/flow-specs/bugz/bug-analyze.json +2 -0
  35. package/dist/pipeline/flow-specs/bugz/bug-fix.json +1 -0
  36. package/dist/pipeline/flow-specs/design-review/design-review-loop.json +304 -0
  37. package/dist/pipeline/flow-specs/design-review.json +249 -0
  38. package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +11 -0
  39. package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +2 -0
  40. package/dist/pipeline/flow-specs/gitlab/mr-description.json +1 -0
  41. package/dist/pipeline/flow-specs/go/run-go-linter-loop.json +2 -0
  42. package/dist/pipeline/flow-specs/go/run-go-tests-loop.json +2 -0
  43. package/dist/pipeline/flow-specs/implement.json +24 -5
  44. package/dist/pipeline/flow-specs/instant-task.json +177 -0
  45. package/dist/pipeline/flow-specs/normalize-task-source.json +311 -0
  46. package/dist/pipeline/flow-specs/plan-revise.json +267 -0
  47. package/dist/pipeline/flow-specs/plan.json +48 -70
  48. package/dist/pipeline/flow-specs/review/review-fix.json +24 -4
  49. package/dist/pipeline/flow-specs/review/review-loop.json +351 -45
  50. package/dist/pipeline/flow-specs/review/review-project-loop.json +590 -0
  51. package/dist/pipeline/flow-specs/review/review-project.json +12 -0
  52. package/dist/pipeline/flow-specs/review/review.json +37 -31
  53. package/dist/pipeline/flow-specs/task-describe.json +62 -2
  54. package/dist/pipeline/flow-specs/task-source/jira-fetch.json +70 -0
  55. package/dist/pipeline/flow-specs/task-source/manual-input.json +216 -0
  56. package/dist/pipeline/node-registry.js +49 -1
  57. package/dist/pipeline/node-runner.js +3 -2
  58. package/dist/pipeline/nodes/build-review-fix-prompt-node.js +5 -1
  59. package/dist/pipeline/nodes/clear-ready-to-merge-node.js +11 -0
  60. package/dist/pipeline/nodes/commit-message-form-node.js +8 -0
  61. package/dist/pipeline/nodes/design-review-verdict-node.js +36 -0
  62. package/dist/pipeline/nodes/ensure-summary-json-node.js +70 -0
  63. package/dist/pipeline/nodes/fetch-gitlab-diff-node.js +19 -2
  64. package/dist/pipeline/nodes/fetch-gitlab-review-node.js +19 -2
  65. package/dist/pipeline/nodes/flow-run-node.js +226 -7
  66. package/dist/pipeline/nodes/git-commit-form-node.js +8 -0
  67. package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +19 -2
  68. package/dist/pipeline/nodes/jira-fetch-node.js +50 -4
  69. package/dist/pipeline/nodes/llm-prompt-node.js +32 -12
  70. package/dist/pipeline/nodes/planning-bundle-node.js +10 -0
  71. package/dist/pipeline/nodes/review-verdict-node.js +86 -0
  72. package/dist/pipeline/nodes/select-files-form-node.js +8 -0
  73. package/dist/pipeline/nodes/structured-summary-node.js +24 -0
  74. package/dist/pipeline/nodes/user-input-node.js +38 -3
  75. package/dist/pipeline/nodes/write-selection-file-node.js +20 -4
  76. package/dist/pipeline/prompt-registry.js +5 -1
  77. package/dist/pipeline/prompt-runtime.js +4 -1
  78. package/dist/pipeline/review-iteration.js +26 -0
  79. package/dist/pipeline/spec-compiler.js +2 -0
  80. package/dist/pipeline/spec-types.js +5 -0
  81. package/dist/pipeline/spec-validator.js +14 -0
  82. package/dist/pipeline/value-resolver.js +84 -1
  83. package/dist/prompts.js +82 -13
  84. package/dist/review-severity.js +45 -0
  85. package/dist/runtime/artifact-registry.js +402 -0
  86. package/dist/runtime/design-review-input-contract.js +113 -0
  87. package/dist/runtime/env-loader.js +3 -0
  88. package/dist/runtime/execution-routing-store.js +134 -0
  89. package/dist/runtime/execution-routing.js +227 -0
  90. package/dist/runtime/interactive-execution-routing.js +462 -0
  91. package/dist/runtime/plan-revise-input-contract.js +147 -0
  92. package/dist/runtime/planning-bundle.js +123 -0
  93. package/dist/runtime/ready-to-merge.js +31 -0
  94. package/dist/runtime/review-input-contract.js +100 -0
  95. package/dist/scope.js +11 -2
  96. package/dist/structured-artifact-schema-registry.js +10 -0
  97. package/dist/structured-artifact-schemas.json +257 -1
  98. package/dist/structured-artifacts.js +83 -6
  99. package/dist/user-input.js +70 -3
  100. package/package.json +6 -3
@@ -0,0 +1,123 @@
1
+ import { existsSync } from "node:fs";
2
+ import { designFile, designJsonFile, latestArtifactIteration, planFile, planJsonFile, qaFile, qaJsonFile, } from "../artifacts.js";
3
+ import { TaskRunnerError } from "../errors.js";
4
+ import { validateStructuredArtifacts } from "../structured-artifacts.js";
5
+ function planningPrefixes(options) {
6
+ return options.requireQa ? ["design", "plan", "qa"] : ["design", "plan"];
7
+ }
8
+ function maxPlanningIteration(taskKey, options) {
9
+ let maxIteration = null;
10
+ for (const prefix of planningPrefixes(options)) {
11
+ for (const extension of ["md", "json"]) {
12
+ const iteration = latestArtifactIteration(taskKey, prefix, extension);
13
+ if (iteration === null) {
14
+ continue;
15
+ }
16
+ maxIteration = maxIteration === null ? iteration : Math.max(maxIteration, iteration);
17
+ }
18
+ }
19
+ return maxIteration;
20
+ }
21
+ export function planningBundlePaths(taskKey, iteration) {
22
+ return {
23
+ designFile: designFile(taskKey, iteration),
24
+ designJsonFile: designJsonFile(taskKey, iteration),
25
+ planFile: planFile(taskKey, iteration),
26
+ planJsonFile: planJsonFile(taskKey, iteration),
27
+ qaFile: qaFile(taskKey, iteration),
28
+ qaJsonFile: qaJsonFile(taskKey, iteration),
29
+ };
30
+ }
31
+ function requiredPlanningPaths(bundle, options) {
32
+ const required = [
33
+ bundle.designFile,
34
+ bundle.designJsonFile,
35
+ bundle.planFile,
36
+ bundle.planJsonFile,
37
+ ];
38
+ if (options.requireQa) {
39
+ required.push(bundle.qaFile, bundle.qaJsonFile);
40
+ }
41
+ return required;
42
+ }
43
+ export function findLatestCompletedPlanningIteration(taskKey, options) {
44
+ const latestKnownIteration = maxPlanningIteration(taskKey, options);
45
+ if (latestKnownIteration === null) {
46
+ return null;
47
+ }
48
+ for (let iteration = latestKnownIteration; iteration >= 1; iteration -= 1) {
49
+ const bundle = planningBundlePaths(taskKey, iteration);
50
+ const requiredPaths = requiredPlanningPaths(bundle, options);
51
+ if (requiredPaths.every((candidate) => existsSync(candidate))) {
52
+ return iteration;
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+ export function resolveLatestCompletedPlanningIteration(taskKey, options) {
58
+ const resolvedIteration = findLatestCompletedPlanningIteration(taskKey, options);
59
+ if (resolvedIteration !== null) {
60
+ return resolvedIteration;
61
+ }
62
+ const fallbackIteration = maxPlanningIteration(taskKey, options) ?? 1;
63
+ const fallbackBundle = planningBundlePaths(taskKey, fallbackIteration);
64
+ const requiredPaths = requiredPlanningPaths(fallbackBundle, options);
65
+ const missing = requiredPaths.filter((candidate) => !existsSync(candidate));
66
+ throw new TaskRunnerError(`${options.missingMessage}\nMissing files: ${missing.join(", ")}`);
67
+ }
68
+ export function inspectLatestPlanningBundle(taskKey) {
69
+ const latestKnownIteration = maxPlanningIteration(taskKey, { requireQa: true });
70
+ if (latestKnownIteration === null) {
71
+ return {
72
+ status: "missing",
73
+ planningIteration: null,
74
+ missingFiles: [],
75
+ bundle: null,
76
+ errorMessage: "Implement mode requires planning artifacts from the planning phase, but none were found.",
77
+ };
78
+ }
79
+ const bundle = planningBundlePaths(taskKey, latestKnownIteration);
80
+ const missingFiles = requiredPlanningPaths(bundle, { requireQa: true }).filter((candidate) => !existsSync(candidate));
81
+ if (missingFiles.length > 0) {
82
+ return {
83
+ status: "incomplete",
84
+ planningIteration: latestKnownIteration,
85
+ missingFiles,
86
+ bundle,
87
+ errorMessage: `Implement mode requires a complete planning bundle for iteration ${latestKnownIteration}.` +
88
+ `\nMissing files: ${missingFiles.join(", ")}`,
89
+ };
90
+ }
91
+ try {
92
+ validateStructuredArtifacts([
93
+ { path: bundle.designJsonFile, schemaId: "implementation-design/v1" },
94
+ { path: bundle.planJsonFile, schemaId: "implementation-plan/v1" },
95
+ { path: bundle.qaJsonFile, schemaId: "qa-plan/v1" },
96
+ ], `Implement mode requires a valid structured planning bundle for iteration ${latestKnownIteration}.`);
97
+ }
98
+ catch (error) {
99
+ return {
100
+ status: "invalid",
101
+ planningIteration: latestKnownIteration,
102
+ missingFiles: [],
103
+ bundle,
104
+ errorMessage: error.message,
105
+ };
106
+ }
107
+ return {
108
+ status: "valid",
109
+ planningIteration: latestKnownIteration,
110
+ missingFiles: [],
111
+ bundle,
112
+ };
113
+ }
114
+ export function resolveLatestPlanningBundle(taskKey) {
115
+ const inspection = inspectLatestPlanningBundle(taskKey);
116
+ if (inspection.status !== "valid") {
117
+ throw new TaskRunnerError(inspection.errorMessage);
118
+ }
119
+ return {
120
+ planningIteration: inspection.planningIteration,
121
+ ...inspection.bundle,
122
+ };
123
+ }
@@ -0,0 +1,31 @@
1
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { readyToMergeFile } from "../artifacts.js";
4
+ export function clearReadyToMergeFile(taskKey) {
5
+ const filePath = readyToMergeFile(taskKey);
6
+ if (!existsSync(filePath)) {
7
+ return false;
8
+ }
9
+ rmSync(filePath);
10
+ return true;
11
+ }
12
+ export function writeReadyToMergeFile(taskKey, options = {}) {
13
+ const filePath = readyToMergeFile(taskKey);
14
+ mkdirSync(path.dirname(filePath), { recursive: true });
15
+ const summary = options.summary?.trim();
16
+ const lines = options.mdLang === "ru"
17
+ ? [
18
+ "# Готово к слиянию",
19
+ "",
20
+ "Блокирующих замечаний не найдено по текущему порогу severity.",
21
+ ...(summary ? ["", "## Summary", "", summary] : []),
22
+ ]
23
+ : [
24
+ "# Ready to Merge",
25
+ "",
26
+ "No blocking findings were detected at the configured severity threshold.",
27
+ ...(summary ? ["", "## Summary", "", summary] : []),
28
+ ];
29
+ writeFileSync(filePath, `${lines.join("\n")}\n`, "utf8");
30
+ return filePath;
31
+ }
@@ -0,0 +1,100 @@
1
+ import { existsSync } from "node:fs";
2
+ import { designFile, designJsonFile, instantTaskInputJsonFile, jiraTaskFile, latestArtifactIteration, planFile, planJsonFile, requireArtifacts, taskContextJsonFile, } from "../artifacts.js";
3
+ import { TaskRunnerError } from "../errors.js";
4
+ import { validateStructuredArtifacts } from "../structured-artifacts.js";
5
+ import { resolveLatestCompletedPlanningIteration } from "./planning-bundle.js";
6
+ const OPTIONAL_INPUT_NOT_PROVIDED = "not provided";
7
+ function resolveOptionalPromptFile(filePath) {
8
+ if (!existsSync(filePath)) {
9
+ return {
10
+ present: false,
11
+ path: null,
12
+ promptValue: OPTIONAL_INPUT_NOT_PROVIDED,
13
+ };
14
+ }
15
+ return {
16
+ present: true,
17
+ path: filePath,
18
+ promptValue: filePath,
19
+ };
20
+ }
21
+ function resolveOptionalValidatedStructuredFile(filePath, schemaId, message) {
22
+ const resolved = resolveOptionalPromptFile(filePath);
23
+ if (!resolved.present) {
24
+ return resolved;
25
+ }
26
+ validateStructuredArtifacts([{ path: filePath, schemaId }], message);
27
+ return resolved;
28
+ }
29
+ export function inspectReviewInputContract(taskKey) {
30
+ let planningIteration;
31
+ try {
32
+ planningIteration = resolveLatestCompletedPlanningIteration(taskKey, {
33
+ requireQa: false,
34
+ missingMessage: "Structured review requires design and plan markdown/JSON artifacts from the latest completed planning run.",
35
+ });
36
+ }
37
+ catch (error) {
38
+ if (error instanceof TaskRunnerError) {
39
+ return { status: "missing-planning" };
40
+ }
41
+ throw error;
42
+ }
43
+ const contract = {
44
+ planningIteration,
45
+ designFile: designFile(taskKey, planningIteration),
46
+ designJsonFile: designJsonFile(taskKey, planningIteration),
47
+ planFile: planFile(taskKey, planningIteration),
48
+ planJsonFile: planJsonFile(taskKey, planningIteration),
49
+ hasTaskContextJsonFile: false,
50
+ taskContextJsonFilePath: null,
51
+ taskContextJsonFile: OPTIONAL_INPUT_NOT_PROVIDED,
52
+ hasJiraTaskFile: false,
53
+ jiraTaskFilePath: null,
54
+ jiraTaskFile: OPTIONAL_INPUT_NOT_PROVIDED,
55
+ hasTaskInputJsonFile: false,
56
+ taskInputJsonFilePath: null,
57
+ taskInputJsonFile: OPTIONAL_INPUT_NOT_PROVIDED,
58
+ };
59
+ requireArtifacts([contract.designFile, contract.designJsonFile, contract.planFile, contract.planJsonFile], "Structured review requires design and plan markdown/JSON artifacts from the latest completed planning run.");
60
+ validateStructuredArtifacts([
61
+ { path: contract.designJsonFile, schemaId: "implementation-design/v1" },
62
+ { path: contract.planJsonFile, schemaId: "implementation-plan/v1" },
63
+ ], "Structured review requires valid design and plan structured artifacts.");
64
+ const taskContextIteration = latestArtifactIteration(taskKey, "task-context", "json");
65
+ const taskContext = taskContextIteration === null
66
+ ? { present: false, path: null, promptValue: OPTIONAL_INPUT_NOT_PROVIDED }
67
+ : resolveOptionalValidatedStructuredFile(taskContextJsonFile(taskKey, taskContextIteration), "task-context/v1", "Structured review task-context structured artifact is invalid.");
68
+ const jiraTask = resolveOptionalPromptFile(jiraTaskFile(taskKey));
69
+ const taskInput = resolveOptionalValidatedStructuredFile(instantTaskInputJsonFile(taskKey), "user-input/v1", "Structured review instant-task input structured artifact is invalid.");
70
+ if (!taskContext.present && !jiraTask.present && !taskInput.present) {
71
+ return {
72
+ status: "missing-task-context",
73
+ planningIteration,
74
+ };
75
+ }
76
+ contract.hasTaskContextJsonFile = taskContext.present;
77
+ contract.taskContextJsonFilePath = taskContext.path;
78
+ contract.taskContextJsonFile = taskContext.promptValue;
79
+ contract.hasJiraTaskFile = jiraTask.present;
80
+ contract.jiraTaskFilePath = jiraTask.path;
81
+ contract.jiraTaskFile = jiraTask.promptValue;
82
+ contract.hasTaskInputJsonFile = taskInput.present;
83
+ contract.taskInputJsonFilePath = taskInput.path;
84
+ contract.taskInputJsonFile = taskInput.promptValue;
85
+ return {
86
+ status: "ready",
87
+ contract,
88
+ };
89
+ }
90
+ export function resolveReviewInputContract(taskKey) {
91
+ const inspection = inspectReviewInputContract(taskKey);
92
+ if (inspection.status === "ready") {
93
+ return inspection.contract;
94
+ }
95
+ if (inspection.status === "missing-planning") {
96
+ throw new TaskRunnerError("Structured review requires design and plan markdown/JSON artifacts from the latest completed planning run.");
97
+ }
98
+ throw new TaskRunnerError(`Structured review requires a normalized task-context artifact, or legacy Jira/instant-task context, in scope '${taskKey}'.`);
99
+ }
100
+ export { OPTIONAL_INPUT_NOT_PROVIDED };
package/dist/scope.js CHANGED
@@ -43,7 +43,7 @@ export function detectGitBranchName() {
43
43
  export function detectProjectRoot() {
44
44
  return gitOutput(["rev-parse", "--show-toplevel"]) ?? process.cwd();
45
45
  }
46
- export function buildProjectScopeKey(explicitScope) {
46
+ export function buildProjectScopeKey(explicitScope, jiraIssueKey) {
47
47
  const projectRoot = detectProjectRoot();
48
48
  const worktreeHash = shortHash(projectRoot);
49
49
  if (explicitScope?.trim()) {
@@ -54,6 +54,14 @@ export function buildProjectScopeKey(explicitScope) {
54
54
  projectRoot,
55
55
  };
56
56
  }
57
+ if (jiraIssueKey?.trim()) {
58
+ return {
59
+ scopeKey: `${sanitizeScopeName(jiraIssueKey)}@${worktreeHash}`,
60
+ gitBranchName: detectGitBranchName(),
61
+ worktreeHash,
62
+ projectRoot,
63
+ };
64
+ }
57
65
  const branchName = detectGitBranchName();
58
66
  const branchSlug = sanitizeScopeName(branchName ?? "detached-head");
59
67
  return {
@@ -72,7 +80,8 @@ export function parseJiraContext(jiraRef) {
72
80
  };
73
81
  }
74
82
  export function resolveProjectScope(explicitScope, jiraRef) {
75
- const { scopeKey, gitBranchName, worktreeHash, projectRoot } = buildProjectScopeKey(explicitScope);
83
+ const jiraIssueKey = jiraRef?.trim() ? extractIssueKey(jiraRef) : undefined;
84
+ const { scopeKey, gitBranchName, worktreeHash, projectRoot } = buildProjectScopeKey(explicitScope, jiraIssueKey);
76
85
  ensureScopeWorkspaceDir(scopeKey);
77
86
  const baseScope = {
78
87
  scopeType: "project",
@@ -3,9 +3,11 @@ import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { TaskRunnerError } from "./errors.js";
5
5
  export const STRUCTURED_ARTIFACT_SCHEMA_IDS = [
6
+ "artifact-manifest/v1",
6
7
  "bug-analysis/v1",
7
8
  "bug-fix-design/v1",
8
9
  "bug-fix-plan/v1",
10
+ "design-review/v1",
9
11
  "gitlab-mr-diff/v1",
10
12
  "gitlab-review/v1",
11
13
  "implementation-design/v1",
@@ -17,9 +19,17 @@ export const STRUCTURED_ARTIFACT_SCHEMA_IDS = [
17
19
  "review-assessment/v1",
18
20
  "review-findings/v1",
19
21
  "review-fix-report/v1",
22
+ "task-context/v1",
20
23
  "task-summary/v1",
21
24
  "user-input/v1",
22
25
  ];
26
+ export const ARTIFACT_PAYLOAD_SCHEMA_IDS = [
27
+ ...STRUCTURED_ARTIFACT_SCHEMA_IDS,
28
+ "helper-json/v1",
29
+ "markdown/v1",
30
+ "opaque-file/v1",
31
+ "plain-text/v1",
32
+ ];
23
33
  const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
24
34
  export const SCHEMA_REGISTRY_PATH = path.join(MODULE_DIR, "structured-artifact-schemas.json");
25
35
  function isRecord(value) {
@@ -485,6 +485,123 @@
485
485
  },
486
486
  "required": ["summary", "test_scenarios", "non_functional_checks"]
487
487
  },
488
+ "design-review/v1": {
489
+ "type": "object",
490
+ "properties": {
491
+ "summary": { "type": "string", "nonEmpty": true },
492
+ "status": {
493
+ "type": "string",
494
+ "enum": ["approved", "approved_with_warnings", "needs_revision"]
495
+ },
496
+ "blocking_findings": {
497
+ "type": "array",
498
+ "items": {
499
+ "type": "object",
500
+ "properties": {
501
+ "title": { "type": "string", "nonEmpty": true },
502
+ "description": { "type": "string", "nonEmpty": true },
503
+ "affected_artifacts": {
504
+ "type": "array",
505
+ "items": { "type": "string", "nonEmpty": true },
506
+ "minItems": 1
507
+ }
508
+ },
509
+ "required": ["title", "description", "affected_artifacts"]
510
+ }
511
+ },
512
+ "major_findings": {
513
+ "type": "array",
514
+ "items": {
515
+ "type": "object",
516
+ "properties": {
517
+ "title": { "type": "string", "nonEmpty": true },
518
+ "description": { "type": "string", "nonEmpty": true },
519
+ "affected_artifacts": {
520
+ "type": "array",
521
+ "items": { "type": "string", "nonEmpty": true },
522
+ "minItems": 1
523
+ }
524
+ },
525
+ "required": ["title", "description", "affected_artifacts"]
526
+ }
527
+ },
528
+ "warnings": {
529
+ "type": "array",
530
+ "items": {
531
+ "type": "object",
532
+ "properties": {
533
+ "title": { "type": "string", "nonEmpty": true },
534
+ "description": { "type": "string", "nonEmpty": true },
535
+ "affected_artifacts": {
536
+ "type": "array",
537
+ "items": { "type": "string", "nonEmpty": true },
538
+ "minItems": 1
539
+ }
540
+ },
541
+ "required": ["title", "description", "affected_artifacts"]
542
+ }
543
+ },
544
+ "missing_information": {
545
+ "type": "array",
546
+ "items": {
547
+ "type": "object",
548
+ "properties": {
549
+ "title": { "type": "string", "nonEmpty": true },
550
+ "description": { "type": "string", "nonEmpty": true },
551
+ "affected_artifacts": {
552
+ "type": "array",
553
+ "items": { "type": "string", "nonEmpty": true },
554
+ "minItems": 1
555
+ }
556
+ },
557
+ "required": ["title", "description", "affected_artifacts"]
558
+ }
559
+ },
560
+ "consistency_checks": {
561
+ "type": "array",
562
+ "items": {
563
+ "type": "object",
564
+ "properties": {
565
+ "name": { "type": "string", "nonEmpty": true },
566
+ "status": { "type": "string", "nonEmpty": true },
567
+ "details": { "type": "string", "nonEmpty": true }
568
+ },
569
+ "required": ["name", "status", "details"]
570
+ }
571
+ },
572
+ "qa_coverage_gaps": {
573
+ "type": "array",
574
+ "items": {
575
+ "type": "object",
576
+ "properties": {
577
+ "title": { "type": "string", "nonEmpty": true },
578
+ "description": { "type": "string", "nonEmpty": true },
579
+ "affected_artifacts": {
580
+ "type": "array",
581
+ "items": { "type": "string", "nonEmpty": true },
582
+ "minItems": 1
583
+ }
584
+ },
585
+ "required": ["title", "description", "affected_artifacts"]
586
+ }
587
+ },
588
+ "recommended_actions": {
589
+ "type": "array",
590
+ "items": { "type": "string", "nonEmpty": true }
591
+ }
592
+ },
593
+ "required": [
594
+ "summary",
595
+ "status",
596
+ "blocking_findings",
597
+ "major_findings",
598
+ "warnings",
599
+ "missing_information",
600
+ "consistency_checks",
601
+ "qa_coverage_gaps",
602
+ "recommended_actions"
603
+ ]
604
+ },
488
605
  "review-findings/v1": {
489
606
  "type": "object",
490
607
  "properties": {
@@ -495,7 +612,7 @@
495
612
  "items": {
496
613
  "type": "object",
497
614
  "properties": {
498
- "severity": { "type": "string", "nonEmpty": true },
615
+ "severity": { "type": "string", "enum": ["blocker", "critical", "high", "medium", "low", "info"] },
499
616
  "title": { "type": "string", "nonEmpty": true },
500
617
  "description": { "type": "string", "nonEmpty": true }
501
618
  },
@@ -543,6 +660,145 @@
543
660
  },
544
661
  "required": ["summary", "completed_actions", "validation_steps"]
545
662
  },
663
+ "helper-json/v1": {
664
+ "type": "json"
665
+ },
666
+ "markdown/v1": {
667
+ "type": "string",
668
+ "nonEmpty": true
669
+ },
670
+ "opaque-file/v1": {
671
+ "type": "bytes"
672
+ },
673
+ "plain-text/v1": {
674
+ "type": "string",
675
+ "nonEmpty": true
676
+ },
677
+ "artifact-manifest/v1": {
678
+ "type": "object",
679
+ "properties": {
680
+ "artifact_id": { "type": "string", "nonEmpty": true },
681
+ "logical_key": { "type": "string", "nonEmpty": true, "pattern": "^[a-z0-9][a-z0-9._/-]*$" },
682
+ "scope": { "type": "string", "nonEmpty": true },
683
+ "run_id": { "type": "string", "nonEmpty": true },
684
+ "flow_id": { "type": "string", "nonEmpty": true },
685
+ "phase_id": { "type": "string", "nonEmpty": true },
686
+ "step_id": { "type": "string", "nonEmpty": true },
687
+ "kind": { "type": "string", "enum": ["artifact", "file"] },
688
+ "version": { "type": "number" },
689
+ "payload_family": { "type": "string", "enum": ["structured-json", "markdown", "plain-text", "helper-json", "opaque-file"] },
690
+ "schema_id": { "type": "string", "nonEmpty": true },
691
+ "schema_version": { "type": "number" },
692
+ "created_at": { "type": "string", "nonEmpty": true },
693
+ "producer": {
694
+ "type": "object",
695
+ "properties": {
696
+ "node": { "type": "string", "nonEmpty": true },
697
+ "executor": { "type": "string", "nonEmpty": true },
698
+ "model": { "type": "string", "nonEmpty": true },
699
+ "summary": { "type": "string", "nonEmpty": true }
700
+ },
701
+ "required": ["node"]
702
+ },
703
+ "inputs": {
704
+ "type": "array",
705
+ "items": {
706
+ "type": "object",
707
+ "properties": {
708
+ "source": { "type": "string", "enum": ["manifest", "external-path"] },
709
+ "path": { "type": "string", "nonEmpty": true },
710
+ "artifact_id": { "type": "string", "nonEmpty": true },
711
+ "logical_key": { "type": "string", "nonEmpty": true, "pattern": "^[a-z0-9][a-z0-9._/-]*$" },
712
+ "schema_id": { "type": "string", "nonEmpty": true },
713
+ "schema_version": { "type": "number" }
714
+ },
715
+ "required": ["source", "path"]
716
+ }
717
+ },
718
+ "content_hash": { "type": "string", "nonEmpty": true, "pattern": "^sha256:[a-f0-9]{64}$" },
719
+ "status": { "type": "string", "enum": ["ready", "superseded", "stale"] },
720
+ "payload_path": { "type": "string", "nonEmpty": true },
721
+ "manifest_path": { "type": "string", "nonEmpty": true },
722
+ "publication_key": { "type": "string", "nonEmpty": true },
723
+ "supersedes": { "type": "string", "nonEmpty": true },
724
+ "status_reason": { "type": "string", "nonEmpty": true },
725
+ "diagnostics": {
726
+ "type": "array",
727
+ "items": {
728
+ "type": "object",
729
+ "properties": {
730
+ "code": { "type": "string", "nonEmpty": true },
731
+ "severity": { "type": "string", "enum": ["info", "warning", "error"] },
732
+ "message": { "type": "string", "nonEmpty": true }
733
+ },
734
+ "required": ["code", "severity", "message"]
735
+ }
736
+ }
737
+ },
738
+ "required": [
739
+ "artifact_id",
740
+ "logical_key",
741
+ "scope",
742
+ "run_id",
743
+ "flow_id",
744
+ "phase_id",
745
+ "step_id",
746
+ "kind",
747
+ "version",
748
+ "payload_family",
749
+ "schema_id",
750
+ "schema_version",
751
+ "created_at",
752
+ "producer",
753
+ "inputs",
754
+ "content_hash",
755
+ "status",
756
+ "payload_path",
757
+ "manifest_path",
758
+ "publication_key"
759
+ ]
760
+ },
761
+ "task-context/v1": {
762
+ "type": "object",
763
+ "properties": {
764
+ "source_type": {
765
+ "type": "string",
766
+ "nonEmpty": true,
767
+ "enum": ["jira", "manual"]
768
+ },
769
+ "title": { "type": "string", "nonEmpty": true },
770
+ "summary": { "type": "string", "nonEmpty": true },
771
+ "problem": { "type": "string", "nonEmpty": true },
772
+ "goal": { "type": "string", "nonEmpty": true },
773
+ "acceptance_criteria": {
774
+ "type": "array",
775
+ "items": { "type": "string", "nonEmpty": true }
776
+ },
777
+ "constraints": {
778
+ "type": "array",
779
+ "items": { "type": "string", "nonEmpty": true }
780
+ },
781
+ "references": {
782
+ "type": "array",
783
+ "items": { "type": "string", "nonEmpty": true }
784
+ },
785
+ "notes": {
786
+ "type": "array",
787
+ "items": { "type": "string", "nonEmpty": true }
788
+ }
789
+ },
790
+ "required": [
791
+ "source_type",
792
+ "title",
793
+ "summary",
794
+ "problem",
795
+ "goal",
796
+ "acceptance_criteria",
797
+ "constraints",
798
+ "references",
799
+ "notes"
800
+ ]
801
+ },
546
802
  "task-summary/v1": {
547
803
  "type": "object",
548
804
  "properties": {