agentweaver 0.1.13 → 0.1.15

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 (51) hide show
  1. package/README.md +24 -19
  2. package/dist/artifacts.js +6 -1
  3. package/dist/doctor/checks/cwd-context.js +4 -3
  4. package/dist/doctor/checks/env-diagnostics.js +168 -71
  5. package/dist/doctor/checks/flow-readiness.js +210 -198
  6. package/dist/doctor/index.js +1 -1
  7. package/dist/doctor/orchestrator.js +18 -7
  8. package/dist/doctor/runner.js +9 -8
  9. package/dist/doctor/types.js +12 -0
  10. package/dist/index.js +119 -55
  11. package/dist/interactive-ui.js +25 -25
  12. package/dist/pipeline/declarative-flows.js +1 -0
  13. package/dist/pipeline/flow-catalog.js +4 -0
  14. package/dist/pipeline/flow-specs/auto-common.json +1 -0
  15. package/dist/pipeline/flow-specs/auto-golang.json +2 -1
  16. package/dist/pipeline/flow-specs/bugz/bug-analyze.json +1 -0
  17. package/dist/pipeline/flow-specs/bugz/bug-fix.json +1 -0
  18. package/dist/pipeline/flow-specs/design-review.json +239 -0
  19. package/dist/pipeline/flow-specs/git-commit.json +1 -0
  20. package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +3 -2
  21. package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +3 -2
  22. package/dist/pipeline/flow-specs/gitlab/mr-description.json +1 -0
  23. package/dist/pipeline/flow-specs/go/run-go-linter-loop.json +3 -2
  24. package/dist/pipeline/flow-specs/go/run-go-tests-loop.json +3 -2
  25. package/dist/pipeline/flow-specs/implement.json +13 -0
  26. package/dist/pipeline/flow-specs/plan-revise.json +261 -0
  27. package/dist/pipeline/flow-specs/plan.json +2 -1
  28. package/dist/pipeline/flow-specs/review/review-fix.json +1 -0
  29. package/dist/pipeline/flow-specs/review/review-loop.json +1 -0
  30. package/dist/pipeline/flow-specs/review/review-project.json +1 -0
  31. package/dist/pipeline/flow-specs/review/review.json +2 -1
  32. package/dist/pipeline/flow-specs/task-describe.json +67 -8
  33. package/dist/pipeline/node-registry.js +8 -0
  34. package/dist/pipeline/nodes/ensure-summary-json-node.js +59 -0
  35. package/dist/pipeline/nodes/git-commit-node.js +1 -1
  36. package/dist/pipeline/nodes/git-status-node.js +1 -1
  37. package/dist/pipeline/nodes/review-findings-form-node.js +8 -8
  38. package/dist/pipeline/nodes/user-input-node.js +2 -2
  39. package/dist/pipeline/prompt-registry.js +3 -1
  40. package/dist/pipeline/spec-types.js +2 -0
  41. package/dist/pipeline/value-resolver.js +11 -1
  42. package/dist/prompts.js +49 -2
  43. package/dist/runtime/design-review-input-contract.js +112 -0
  44. package/dist/runtime/plan-revise-input-contract.js +144 -0
  45. package/dist/runtime/process-runner.js +2 -2
  46. package/dist/runtime/ready-to-merge.js +10 -0
  47. package/dist/scope.js +13 -4
  48. package/dist/structured-artifact-schema-registry.js +1 -0
  49. package/dist/structured-artifact-schemas.json +117 -0
  50. package/dist/structured-artifacts.js +6 -0
  51. package/package.json +3 -2
@@ -0,0 +1,144 @@
1
+ import { existsSync } from "node:fs";
2
+ import { designFile, designJsonFile, designReviewFile, designReviewJsonFile, jiraAttachmentsContextFile, jiraAttachmentsManifestFile, jiraTaskFile, latestArtifactIteration, planFile, planJsonFile, planningAnswersJsonFile, qaFile, qaJsonFile, requireArtifacts, } from "../artifacts.js";
3
+ import { TaskRunnerError } from "../errors.js";
4
+ import { validateStructuredArtifacts } from "../structured-artifacts.js";
5
+ const OPTIONAL_INPUT_NOT_PROVIDED = "not provided";
6
+ function resolveLatestDesignReviewIteration(taskKey) {
7
+ const latestMd = latestArtifactIteration(taskKey, "design-review", "md");
8
+ const latestJson = latestArtifactIteration(taskKey, "design-review", "json");
9
+ const maxIteration = Math.max(latestMd ?? 0, latestJson ?? 0);
10
+ if (maxIteration === 0) {
11
+ throw new TaskRunnerError("Plan-revise requires at least one completed design-review iteration, but no design-review artifacts were found.");
12
+ }
13
+ for (let iteration = maxIteration; iteration >= 1; iteration -= 1) {
14
+ const mdPath = designReviewFile(taskKey, iteration);
15
+ const jsonPath = designReviewJsonFile(taskKey, iteration);
16
+ if (existsSync(mdPath) && existsSync(jsonPath)) {
17
+ return iteration;
18
+ }
19
+ }
20
+ const fallbackMd = designReviewFile(taskKey, maxIteration);
21
+ const fallbackJson = designReviewJsonFile(taskKey, maxIteration);
22
+ requireArtifacts([fallbackMd, fallbackJson], "Plan-revise requires design-review markdown and JSON artifacts from the latest completed design-review run.");
23
+ throw new TaskRunnerError("Unreachable plan-revise design-review artifact resolution state.");
24
+ }
25
+ function resolveLatestCompletedPlanningIteration(taskKey) {
26
+ const latestDesignMd = latestArtifactIteration(taskKey, "design", "md") ?? 0;
27
+ const latestDesignJson = latestArtifactIteration(taskKey, "design", "json") ?? 0;
28
+ const latestPlanMd = latestArtifactIteration(taskKey, "plan", "md") ?? 0;
29
+ const latestPlanJson = latestArtifactIteration(taskKey, "plan", "json") ?? 0;
30
+ const maxIteration = Math.max(latestDesignMd, latestDesignJson, latestPlanMd, latestPlanJson);
31
+ for (let iteration = maxIteration; iteration >= 1; iteration -= 1) {
32
+ const paths = [
33
+ designFile(taskKey, iteration),
34
+ designJsonFile(taskKey, iteration),
35
+ planFile(taskKey, iteration),
36
+ planJsonFile(taskKey, iteration),
37
+ ];
38
+ if (paths.every((candidate) => existsSync(candidate))) {
39
+ return iteration;
40
+ }
41
+ }
42
+ const fallbackIteration = maxIteration || 1;
43
+ const fallbackPaths = [
44
+ designFile(taskKey, fallbackIteration),
45
+ designJsonFile(taskKey, fallbackIteration),
46
+ planFile(taskKey, fallbackIteration),
47
+ planJsonFile(taskKey, fallbackIteration),
48
+ ];
49
+ requireArtifacts(fallbackPaths, "Plan-revise requires design and plan markdown/JSON artifacts from the latest completed planning run.");
50
+ throw new TaskRunnerError("Unreachable plan-revise planning artifact resolution state.");
51
+ }
52
+ function resolveOptionalPromptFile(filePath) {
53
+ if (!existsSync(filePath)) {
54
+ return {
55
+ present: false,
56
+ path: null,
57
+ promptValue: OPTIONAL_INPUT_NOT_PROVIDED,
58
+ };
59
+ }
60
+ return {
61
+ present: true,
62
+ path: filePath,
63
+ promptValue: filePath,
64
+ };
65
+ }
66
+ function resolveOptionalQaPair(taskKey, iteration) {
67
+ const markdownPath = qaFile(taskKey, iteration);
68
+ const jsonPath = qaJsonFile(taskKey, iteration);
69
+ const markdownExists = existsSync(markdownPath);
70
+ const jsonExists = existsSync(jsonPath);
71
+ if (!markdownExists && !jsonExists) {
72
+ return {
73
+ hasQaArtifacts: false,
74
+ qaFilePath: null,
75
+ qaJsonFilePath: null,
76
+ qaFile: OPTIONAL_INPUT_NOT_PROVIDED,
77
+ qaJsonFile: OPTIONAL_INPUT_NOT_PROVIDED,
78
+ };
79
+ }
80
+ if (!markdownExists || !jsonExists) {
81
+ requireArtifacts([markdownPath, jsonPath], "Plan-revise accepts QA artifacts only as a complete markdown/JSON pair for the source planning iteration.");
82
+ }
83
+ validateStructuredArtifacts([{ path: jsonPath, schemaId: "qa-plan/v1" }], "Plan-revise QA structured artifact is invalid.");
84
+ return {
85
+ hasQaArtifacts: true,
86
+ qaFilePath: markdownPath,
87
+ qaJsonFilePath: jsonPath,
88
+ qaFile: markdownPath,
89
+ qaJsonFile: jsonPath,
90
+ };
91
+ }
92
+ export function resolvePlanReviseInputContract(taskKey) {
93
+ const reviewIteration = resolveLatestDesignReviewIteration(taskKey);
94
+ const reviewMd = designReviewFile(taskKey, reviewIteration);
95
+ const reviewJson = designReviewJsonFile(taskKey, reviewIteration);
96
+ requireArtifacts([reviewMd, reviewJson], "Plan-revise requires design-review markdown and JSON artifacts.");
97
+ validateStructuredArtifacts([{ path: reviewJson, schemaId: "design-review/v1" }], "Plan-revise design-review structured artifact is invalid.");
98
+ const sourcePlanningIteration = resolveLatestCompletedPlanningIteration(taskKey);
99
+ const srcDesignMd = designFile(taskKey, sourcePlanningIteration);
100
+ const srcDesignJson = designJsonFile(taskKey, sourcePlanningIteration);
101
+ const srcPlanMd = planFile(taskKey, sourcePlanningIteration);
102
+ const srcPlanJson = planJsonFile(taskKey, sourcePlanningIteration);
103
+ requireArtifacts([srcDesignMd, srcDesignJson, srcPlanMd, srcPlanJson], "Plan-revise requires design and plan markdown/JSON artifacts from the source planning iteration.");
104
+ validateStructuredArtifacts([
105
+ { path: srcDesignJson, schemaId: "implementation-design/v1" },
106
+ { path: srcPlanJson, schemaId: "implementation-plan/v1" },
107
+ ], "Plan-revise source planning structured artifacts are invalid.");
108
+ const outputIteration = sourcePlanningIteration + 1;
109
+ const qaArtifacts = resolveOptionalQaPair(taskKey, sourcePlanningIteration);
110
+ const jiraTask = resolveOptionalPromptFile(jiraTaskFile(taskKey));
111
+ const jiraAttachmentsManifest = resolveOptionalPromptFile(jiraAttachmentsManifestFile(taskKey));
112
+ const jiraAttachmentsContext = resolveOptionalPromptFile(jiraAttachmentsContextFile(taskKey));
113
+ const planningAnswers = resolveOptionalPromptFile(planningAnswersJsonFile(taskKey));
114
+ return {
115
+ reviewIteration,
116
+ reviewFile: reviewMd,
117
+ reviewJsonFile: reviewJson,
118
+ sourcePlanningIteration,
119
+ outputIteration,
120
+ designFile: srcDesignMd,
121
+ designJsonFile: srcDesignJson,
122
+ planFile: srcPlanMd,
123
+ planJsonFile: srcPlanJson,
124
+ ...qaArtifacts,
125
+ revisedDesignFile: designFile(taskKey, outputIteration),
126
+ revisedDesignJsonFile: designJsonFile(taskKey, outputIteration),
127
+ revisedPlanFile: planFile(taskKey, outputIteration),
128
+ revisedPlanJsonFile: planJsonFile(taskKey, outputIteration),
129
+ revisedQaFile: qaFile(taskKey, outputIteration),
130
+ revisedQaJsonFile: qaJsonFile(taskKey, outputIteration),
131
+ hasJiraTaskFile: jiraTask.present,
132
+ jiraTaskFilePath: jiraTask.path,
133
+ jiraTaskFile: jiraTask.promptValue,
134
+ hasJiraAttachmentsManifestFile: jiraAttachmentsManifest.present,
135
+ jiraAttachmentsManifestFilePath: jiraAttachmentsManifest.path,
136
+ jiraAttachmentsManifestFile: jiraAttachmentsManifest.promptValue,
137
+ hasJiraAttachmentsContextFile: jiraAttachmentsContext.present,
138
+ jiraAttachmentsContextFilePath: jiraAttachmentsContext.path,
139
+ jiraAttachmentsContextFile: jiraAttachmentsContext.promptValue,
140
+ hasPlanningAnswersJsonFile: planningAnswers.present,
141
+ planningAnswersJsonFilePath: planningAnswers.path,
142
+ planningAnswersJsonFile: planningAnswers.promptValue,
143
+ };
144
+ }
@@ -112,7 +112,7 @@ export async function runCommand(argv, options = {}) {
112
112
  }
113
113
  });
114
114
  if (outputAdapter.renderAuxiliaryOutput !== false) {
115
- printFramedBlock("Запуск", formatLaunchDetails(statusLabel), "cyan");
115
+ printFramedBlock("Launch", formatLaunchDetails(statusLabel), "cyan");
116
116
  }
117
117
  try {
118
118
  const exitCode = await new Promise((resolve, reject) => {
@@ -134,7 +134,7 @@ export async function runCommand(argv, options = {}) {
134
134
  });
135
135
  });
136
136
  if (outputAdapter.renderAuxiliaryOutput !== false) {
137
- printInfo(`Закончили работу: ${statusLabel} (${formatDuration(Date.now() - startedAt)})`);
137
+ printInfo(`Finished: ${statusLabel} (${formatDuration(Date.now() - startedAt)})`);
138
138
  }
139
139
  if (signal?.aborted) {
140
140
  throw Object.assign(new FlowInterruptedError(), {
@@ -0,0 +1,10 @@
1
+ import { existsSync, rmSync } from "node:fs";
2
+ import { readyToMergeFile } from "../artifacts.js";
3
+ export function clearReadyToMergeFile(taskKey) {
4
+ const filePath = readyToMergeFile(taskKey);
5
+ if (!existsSync(filePath)) {
6
+ return false;
7
+ }
8
+ rmSync(filePath);
9
+ return true;
10
+ }
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",
@@ -104,14 +113,14 @@ export function buildJiraTaskInputForm() {
104
113
  return {
105
114
  formId: "jira-task-input",
106
115
  title: "Jira Task",
107
- description: "Укажи Jira issue key или browse URL для task-driven flow.",
116
+ description: "Provide a Jira issue key or browse URL for a task-driven flow.",
108
117
  submitLabel: "Continue",
109
118
  fields: [
110
119
  {
111
120
  id: "jira_ref",
112
121
  type: "text",
113
122
  label: "Jira issue key or browse URL",
114
- help: "Например: DEMO-3288 или https://jira.example.ru/browse/DEMO-3288",
123
+ help: "Example: DEMO-3288 or https://jira.example.com/browse/DEMO-3288",
115
124
  required: true,
116
125
  },
117
126
  ],
@@ -6,6 +6,7 @@ export const STRUCTURED_ARTIFACT_SCHEMA_IDS = [
6
6
  "bug-analysis/v1",
7
7
  "bug-fix-design/v1",
8
8
  "bug-fix-plan/v1",
9
+ "design-review/v1",
9
10
  "gitlab-mr-diff/v1",
10
11
  "gitlab-review/v1",
11
12
  "implementation-design/v1",
@@ -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": {
@@ -11,6 +11,9 @@ function schemaLabel(node) {
11
11
  }
12
12
  switch (node.type) {
13
13
  case "string":
14
+ if (node.enum && node.enum.length > 0) {
15
+ return `one of: ${node.enum.join(", ")}`;
16
+ }
14
17
  return node.nonEmpty ? "a non-empty string" : "a string";
15
18
  case "boolean":
16
19
  return "a boolean";
@@ -43,6 +46,9 @@ function validateNode(value, schema, currentPath) {
43
46
  if (typeof value !== "string" || (schema.nonEmpty && value.trim().length === 0)) {
44
47
  return [`${currentPath} must be ${schemaLabel(schema)}`];
45
48
  }
49
+ if (schema.enum && !schema.enum.includes(value)) {
50
+ return [`${currentPath} must be ${schemaLabel(schema)}`];
51
+ }
46
52
  return [];
47
53
  case "boolean":
48
54
  return typeof value === "boolean" ? [] : [`${currentPath} must be a boolean`];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentweaver",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "CLI orchestrator for Jira/Codex engineering workflows",
5
5
  "keywords": [
6
6
  "agent",
@@ -18,7 +18,7 @@
18
18
  "type": "git",
19
19
  "url": "git+https://github.com/seko99/AgentWeaver.git"
20
20
  },
21
- "license": "UNLICENSED",
21
+ "license": "MIT",
22
22
  "type": "module",
23
23
  "main": "dist/index.js",
24
24
  "exports": "./dist/index.js",
@@ -28,6 +28,7 @@
28
28
  "files": [
29
29
  "dist",
30
30
  "README.md",
31
+ "LICENSE",
31
32
  "run_go_tests.py",
32
33
  "run_go_linter.py",
33
34
  "run_go_coverage.sh"