wogiflow 2.4.2 → 2.4.4
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/.claude/commands/wogi-start.md +124 -0
- package/.claude/docs/claude-code-compatibility.md +51 -0
- package/.claude/docs/explore-agents.md +11 -0
- package/.claude/settings.json +12 -1
- package/.workflow/models/registry.json +1 -1
- package/bin/flow +11 -1
- package/lib/workspace-contracts.js +599 -0
- package/lib/workspace-intelligence.js +600 -0
- package/lib/workspace-messages.js +441 -0
- package/lib/workspace-routing.js +485 -0
- package/lib/workspace-sync.js +339 -0
- package/lib/workspace.js +1073 -0
- package/package.json +4 -4
- package/scripts/MEMORY-ARCHITECTURE.md +1 -1
- package/scripts/base-workflow-step.js +136 -0
- package/scripts/flow-adaptive-learning.js +8 -9
- package/scripts/flow-aggregate.js +11 -6
- package/scripts/flow-api-index.js +4 -6
- package/scripts/flow-assumption-detector.js +0 -2
- package/scripts/flow-audit.js +15 -2
- package/scripts/flow-auto-context.js +8 -12
- package/scripts/flow-auto-learn.js +49 -49
- package/scripts/flow-background.js +5 -6
- package/scripts/flow-bridge-state.js +8 -10
- package/scripts/flow-bulk-loop.js +1 -3
- package/scripts/flow-bulk-orchestrator.js +1 -3
- package/scripts/flow-cascade-completion.js +0 -2
- package/scripts/flow-cascade.js +4 -4
- package/scripts/flow-checkpoint.js +10 -13
- package/scripts/flow-code-intelligence.js +10 -12
- package/scripts/flow-community-sync.js +4 -4
- package/scripts/flow-community.js +12 -20
- package/scripts/flow-config-defaults.js +28 -2
- package/scripts/flow-config-interactive.js +9 -5
- package/scripts/flow-config-loader.js +49 -92
- package/scripts/flow-config-substitution.js +0 -2
- package/scripts/flow-context-estimator.js +4 -4
- package/scripts/flow-context-init.js +10 -12
- package/scripts/flow-context-manager.js +0 -2
- package/scripts/flow-context-scoring.js +2 -2
- package/scripts/flow-contract-scan.js +6 -9
- package/scripts/flow-correct.js +29 -27
- package/scripts/flow-correction-detector.js +5 -1
- package/scripts/flow-damage-control.js +47 -54
- package/scripts/flow-decisions-merge.js +4 -14
- package/scripts/flow-diff.js +5 -8
- package/scripts/flow-done-gates.js +786 -0
- package/scripts/flow-done-report.js +123 -0
- package/scripts/flow-done.js +71 -717
- package/scripts/flow-entropy-monitor.js +1 -3
- package/scripts/flow-eval-calibration.js +257 -0
- package/scripts/flow-eval-judge.js +10 -1
- package/scripts/flow-eval.js +14 -5
- package/scripts/flow-extraction-review.js +1 -0
- package/scripts/flow-failure-categories.js +0 -2
- package/scripts/flow-figma-confirm.js +5 -9
- package/scripts/flow-figma-generate.js +8 -10
- package/scripts/flow-figma-index.js +8 -10
- package/scripts/flow-figma-match.js +3 -5
- package/scripts/flow-figma-mcp-server.js +2 -4
- package/scripts/flow-figma-orchestrator.js +2 -3
- package/scripts/flow-figma-registry.js +2 -3
- package/scripts/flow-framework-resolver.js +0 -2
- package/scripts/flow-function-index.js +4 -6
- package/scripts/flow-gate-confidence.js +2 -2
- package/scripts/flow-gitignore.js +0 -2
- package/scripts/flow-guided-edit.js +5 -6
- package/scripts/flow-health.js +5 -6
- package/scripts/flow-hook-errors.js +6 -0
- package/scripts/flow-hook-status.js +263 -0
- package/scripts/flow-hooks.js +17 -29
- package/scripts/flow-http-client.js +9 -8
- package/scripts/flow-hybrid-interactive.js +7 -12
- package/scripts/flow-hybrid-test.js +12 -13
- package/scripts/flow-instruction-richness.js +1 -1
- package/scripts/flow-io.js +21 -4
- package/scripts/flow-knowledge-router.js +9 -3
- package/scripts/flow-learning-orchestrator.js +318 -13
- package/scripts/flow-links.js +5 -7
- package/scripts/flow-long-input-association.js +275 -0
- package/scripts/flow-long-input-chunking.js +1 -0
- package/scripts/flow-long-input-cli.js +0 -2
- package/scripts/flow-long-input-complexity.js +0 -2
- package/scripts/flow-long-input-constants.js +0 -2
- package/scripts/flow-long-input-contradictions.js +351 -0
- package/scripts/flow-long-input-detection.js +0 -2
- package/scripts/flow-long-input-passes.js +885 -0
- package/scripts/flow-long-input-stories.js +1 -1
- package/scripts/flow-long-input-voice.js +0 -2
- package/scripts/flow-long-input.js +425 -3005
- package/scripts/flow-loop-retry-learning.js +2 -3
- package/scripts/flow-lsp.js +3 -3
- package/scripts/flow-mcp-docs.js +3 -4
- package/scripts/flow-memory-db.js +6 -8
- package/scripts/flow-memory-sync.js +18 -11
- package/scripts/flow-metrics.js +1 -2
- package/scripts/flow-model-adapter.js +2 -3
- package/scripts/flow-model-config.js +72 -104
- package/scripts/flow-model-router.js +2 -2
- package/scripts/flow-model-types.js +0 -2
- package/scripts/flow-multi-approach.js +5 -6
- package/scripts/flow-orchestrate-context.js +3 -7
- package/scripts/flow-orchestrate-rollback.js +3 -8
- package/scripts/flow-orchestrate-state.js +8 -14
- package/scripts/flow-orchestrate-templates.js +2 -6
- package/scripts/flow-orchestrate-validator.js +5 -9
- package/scripts/flow-orchestrate.js +126 -103
- package/scripts/flow-output.js +0 -2
- package/scripts/flow-parallel.js +1 -1
- package/scripts/flow-paths.js +23 -2
- package/scripts/flow-pattern-enforcer.js +30 -28
- package/scripts/flow-pattern-extractor.js +3 -4
- package/scripts/flow-pending.js +0 -2
- package/scripts/flow-permissions.js +2 -3
- package/scripts/flow-plugin-registry.js +10 -12
- package/scripts/flow-prd-manager.js +1 -1
- package/scripts/flow-progress.js +7 -9
- package/scripts/flow-prompt-composer.js +3 -3
- package/scripts/flow-prompt-template.js +2 -2
- package/scripts/flow-providers.js +7 -4
- package/scripts/flow-registry-manager.js +7 -12
- package/scripts/flow-regression.js +9 -11
- package/scripts/flow-roadmap.js +2 -2
- package/scripts/flow-run-trace.js +16 -15
- package/scripts/flow-safety.js +2 -5
- package/scripts/flow-scanner-base.js +5 -7
- package/scripts/flow-scenario-engine.js +1 -5
- package/scripts/flow-security.js +29 -0
- package/scripts/flow-session-end.js +32 -41
- package/scripts/flow-session-learning.js +53 -49
- package/scripts/flow-setup-hooks.js +2 -3
- package/scripts/flow-skill-create.js +7 -12
- package/scripts/flow-skill-generator.js +12 -16
- package/scripts/flow-skill-learn.js +17 -8
- package/scripts/flow-skill-matcher.js +1 -2
- package/scripts/flow-spec-generator.js +2 -4
- package/scripts/flow-stack-wizard.js +5 -7
- package/scripts/flow-standards-learner.js +35 -16
- package/scripts/flow-start.js +2 -0
- package/scripts/flow-stats-collector.js +2 -2
- package/scripts/flow-status.js +10 -10
- package/scripts/flow-statusline-setup.js +2 -2
- package/scripts/flow-step-changelog.js +2 -3
- package/scripts/flow-step-comments.js +66 -81
- package/scripts/flow-step-complexity.js +50 -70
- package/scripts/flow-step-coverage.js +3 -5
- package/scripts/flow-step-knowledge.js +2 -3
- package/scripts/flow-step-pr-tests.js +64 -74
- package/scripts/flow-step-regression.js +3 -5
- package/scripts/flow-step-review.js +86 -103
- package/scripts/flow-step-security.js +111 -121
- package/scripts/flow-step-silent-failures.js +56 -83
- package/scripts/flow-step-simplifier.js +52 -70
- package/scripts/flow-story.js +4 -7
- package/scripts/flow-strict-adherence.js +3 -4
- package/scripts/flow-task-checkpoint.js +36 -5
- package/scripts/flow-task-enforcer.js +2 -24
- package/scripts/flow-tech-debt.js +1 -1
- package/scripts/flow-template-extractor.js +1 -0
- package/scripts/flow-templates.js +11 -13
- package/scripts/flow-test-api.js +9 -13
- package/scripts/flow-test-discovery.js +1 -1
- package/scripts/flow-test-generate.js +5 -9
- package/scripts/flow-test-integrity.js +3 -7
- package/scripts/flow-test-ui.js +5 -9
- package/scripts/flow-testing-deps.js +1 -3
- package/scripts/flow-tiered-learning.js +4 -4
- package/scripts/flow-todowrite-sync.js +1 -1
- package/scripts/flow-tokens.js +0 -2
- package/scripts/flow-verification-profile.js +6 -10
- package/scripts/flow-verify.js +12 -16
- package/scripts/flow-version-check.js +4 -12
- package/scripts/flow-webmcp-generator.js +3 -5
- package/scripts/flow-workflow-steps.js +0 -2
- package/scripts/flow-workflow.js +9 -11
- package/scripts/hooks/adapters/claude-code.js +31 -0
- package/scripts/hooks/core/config-change.js +1 -0
- package/scripts/hooks/core/extension-registry.js +0 -2
- package/scripts/hooks/core/instructions-loaded.js +1 -1
- package/scripts/hooks/core/observation-capture.js +5 -5
- package/scripts/hooks/core/phase-gate.js +5 -0
- package/scripts/hooks/core/post-compact.js +1 -12
- package/scripts/hooks/core/research-gate.js +2 -12
- package/scripts/hooks/core/routing-gate.js +6 -0
- package/scripts/hooks/core/task-completed.js +12 -0
- package/scripts/hooks/core/task-created.js +83 -0
- package/scripts/hooks/core/worktree-lifecycle.js +1 -1
- package/scripts/hooks/entry/claude-code/config-change.js +6 -29
- package/scripts/hooks/entry/claude-code/instructions-loaded.js +5 -30
- package/scripts/hooks/entry/claude-code/post-compact.js +4 -31
- package/scripts/hooks/entry/claude-code/post-tool-use.js +121 -172
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +260 -361
- package/scripts/hooks/entry/claude-code/session-end.js +4 -28
- package/scripts/hooks/entry/claude-code/session-start.js +205 -243
- package/scripts/hooks/entry/claude-code/setup.js +8 -49
- package/scripts/hooks/entry/claude-code/stop.js +40 -72
- package/scripts/hooks/entry/claude-code/task-completed.js +4 -28
- package/scripts/hooks/entry/claude-code/task-created.js +15 -0
- package/scripts/hooks/entry/claude-code/user-prompt-submit.js +113 -195
- package/scripts/hooks/entry/claude-code/worktree-create.js +6 -25
- package/scripts/hooks/entry/claude-code/worktree-remove.js +6 -25
- package/scripts/hooks/entry/shared/hook-runner.js +99 -0
- package/scripts/hooks/entry/shared/read-stdin.js +0 -2
- package/scripts/postinstall.js +2 -0
- package/scripts/registries/api-registry.js +0 -2
- package/scripts/registries/component-registry.js +5 -9
- package/scripts/registries/contract-scanner.js +2 -9
- package/scripts/registries/function-registry.js +0 -2
- package/scripts/registries/schema-registry.js +14 -18
- package/scripts/registries/service-registry.js +23 -27
|
@@ -10,84 +10,73 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('node:fs');
|
|
12
12
|
const path = require('node:path');
|
|
13
|
-
const {
|
|
13
|
+
const { BaseWorkflowStep } = require('./base-workflow-step');
|
|
14
|
+
const { colors, readJson, PATHS } = require('./flow-utils');
|
|
15
|
+
|
|
16
|
+
class PrTestStep extends BaseWorkflowStep {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('prTestAnalyzer', {
|
|
19
|
+
extensions: ['.js', '.ts', '.jsx', '.tsx'],
|
|
20
|
+
excludeTests: true,
|
|
21
|
+
excludeDts: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
// Override filterFiles for PR-test-specific exclusions
|
|
26
|
+
filterFiles(files) {
|
|
27
|
+
return super.filterFiles(files).filter(f =>
|
|
28
|
+
!f.includes('__tests__') && !f.includes('__mocks__')
|
|
29
|
+
);
|
|
30
|
+
}
|
|
16
31
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* @param {object} options.stepConfig - Step configuration
|
|
23
|
-
* @param {string} options.mode - Step mode (block/warn/prompt/auto)
|
|
24
|
-
* @returns {object} - { passed: boolean, message: string, details?: object }
|
|
25
|
-
*/
|
|
26
|
-
async function run(options = {}) {
|
|
27
|
-
const { files = [], stepConfig = {} } = options;
|
|
28
|
-
const checkCoverage = stepConfig.checkCoverage !== false;
|
|
29
|
-
const checkQuality = stepConfig.checkQuality !== false;
|
|
30
|
-
const minCoverageForModified = stepConfig.minCoverageForModified || 70;
|
|
31
|
-
|
|
32
|
-
// Filter to source files (not test files)
|
|
33
|
-
const sourceExtensions = ['.js', '.ts', '.jsx', '.tsx'];
|
|
34
|
-
const sourceFiles = files.filter(f =>
|
|
35
|
-
sourceExtensions.some(ext => f.endsWith(ext)) &&
|
|
36
|
-
!f.includes('.test.') &&
|
|
37
|
-
!f.includes('.spec.') &&
|
|
38
|
-
!f.includes('.d.ts') &&
|
|
39
|
-
!f.includes('__tests__') &&
|
|
40
|
-
!f.includes('__mocks__')
|
|
41
|
-
);
|
|
32
|
+
async execute(sourceFiles, options) {
|
|
33
|
+
const { stepConfig = {} } = options;
|
|
34
|
+
const checkCoverage = stepConfig.checkCoverage !== false;
|
|
35
|
+
const checkQuality = stepConfig.checkQuality !== false;
|
|
36
|
+
const minCoverageForModified = stepConfig.minCoverageForModified || 70;
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
38
|
+
// We need the original unfiltered files for test quality analysis
|
|
39
|
+
const allFiles = options.files ?? sourceFiles;
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Check coverage for modified files
|
|
52
|
-
if (checkCoverage) {
|
|
53
|
-
const coverageIssues = await analyzeCoverage(sourceFiles, minCoverageForModified);
|
|
54
|
-
issues.push(...coverageIssues.issues);
|
|
55
|
-
Object.assign(coverageReport, coverageIssues.report);
|
|
56
|
-
}
|
|
41
|
+
const issues = [];
|
|
42
|
+
const coverageReport = {};
|
|
43
|
+
const qualityReport = {};
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
if (checkCoverage) {
|
|
46
|
+
const coverageIssues = await analyzeCoverage(sourceFiles, minCoverageForModified);
|
|
47
|
+
issues.push(...coverageIssues.issues);
|
|
48
|
+
Object.assign(coverageReport, coverageIssues.report);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (checkQuality) {
|
|
52
|
+
const qualityIssues = await analyzeTestQuality(sourceFiles, allFiles);
|
|
53
|
+
issues.push(...qualityIssues.issues);
|
|
54
|
+
Object.assign(qualityReport, qualityIssues.report);
|
|
55
|
+
}
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
57
|
+
if (issues.length > 0) {
|
|
58
|
+
console.log(colors.yellow + '\n PR Test Analysis Issues:' + colors.reset);
|
|
59
|
+
for (const issue of issues) {
|
|
60
|
+
const icon = issue.severity === 'high' ? '\u{1F534}' : '\u{1F7E1}';
|
|
61
|
+
console.log(` ${icon} ${issue.file}`);
|
|
62
|
+
console.log(` ${issue.type}: ${issue.message}`);
|
|
63
|
+
if (issue.suggestion) {
|
|
64
|
+
console.log(colors.dim + ` \u{2192} ${issue.suggestion}` + colors.reset);
|
|
65
|
+
}
|
|
74
66
|
}
|
|
75
67
|
}
|
|
76
|
-
}
|
|
77
68
|
|
|
78
|
-
|
|
69
|
+
const highSeverity = issues.filter(i => i.severity === 'high');
|
|
79
70
|
|
|
80
|
-
|
|
81
|
-
passed: highSeverity.length === 0,
|
|
82
|
-
message: issues.length === 0
|
|
71
|
+
const message = issues.length === 0
|
|
83
72
|
? `Test analysis passed (${sourceFiles.length} files)`
|
|
84
|
-
: `${issues.length} issue(s) found (${highSeverity.length} high severity)
|
|
85
|
-
details:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
73
|
+
: `${issues.length} issue(s) found (${highSeverity.length} high severity)`;
|
|
74
|
+
const details = { issues, coverage: coverageReport, quality: qualityReport };
|
|
75
|
+
|
|
76
|
+
return highSeverity.length === 0
|
|
77
|
+
? { passed: true, message, details }
|
|
78
|
+
: this.fail(message, details);
|
|
79
|
+
}
|
|
91
80
|
}
|
|
92
81
|
|
|
93
82
|
/**
|
|
@@ -98,7 +87,7 @@ async function analyzeCoverage(sourceFiles, minCoverage) {
|
|
|
98
87
|
const report = { checked: [], missing: [], below: [] };
|
|
99
88
|
|
|
100
89
|
// Check if coverage report exists
|
|
101
|
-
const coveragePath = path.join(
|
|
90
|
+
const coveragePath = path.join(PATHS.root, 'coverage', 'coverage-summary.json');
|
|
102
91
|
let coverageData = null;
|
|
103
92
|
|
|
104
93
|
if (fs.existsSync(coveragePath)) {
|
|
@@ -106,7 +95,7 @@ async function analyzeCoverage(sourceFiles, minCoverage) {
|
|
|
106
95
|
}
|
|
107
96
|
|
|
108
97
|
for (const file of sourceFiles) {
|
|
109
|
-
const filePath = path.join(
|
|
98
|
+
const filePath = path.join(PATHS.root, file);
|
|
110
99
|
if (!fs.existsSync(filePath)) continue;
|
|
111
100
|
|
|
112
101
|
// Find corresponding test file
|
|
@@ -118,7 +107,7 @@ async function analyzeCoverage(sourceFiles, minCoverage) {
|
|
|
118
107
|
];
|
|
119
108
|
|
|
120
109
|
const hasTest = testPatterns.some(pattern => {
|
|
121
|
-
const testPath = path.join(
|
|
110
|
+
const testPath = path.join(PATHS.root, pattern);
|
|
122
111
|
return fs.existsSync(testPath);
|
|
123
112
|
});
|
|
124
113
|
|
|
@@ -144,7 +133,7 @@ async function analyzeCoverage(sourceFiles, minCoverage) {
|
|
|
144
133
|
|
|
145
134
|
// Check coverage if available
|
|
146
135
|
if (coverageData) {
|
|
147
|
-
const absPath = path.resolve(
|
|
136
|
+
const absPath = path.resolve(PATHS.root, file);
|
|
148
137
|
const fileCoverage = coverageData[absPath];
|
|
149
138
|
|
|
150
139
|
if (fileCoverage) {
|
|
@@ -182,7 +171,7 @@ async function analyzeTestQuality(sourceFiles, allFiles) {
|
|
|
182
171
|
);
|
|
183
172
|
|
|
184
173
|
for (const testFile of testFiles) {
|
|
185
|
-
const testPath = path.join(
|
|
174
|
+
const testPath = path.join(PATHS.root, testFile);
|
|
186
175
|
if (!fs.existsSync(testPath)) continue;
|
|
187
176
|
|
|
188
177
|
try {
|
|
@@ -203,7 +192,7 @@ async function analyzeTestQuality(sourceFiles, allFiles) {
|
|
|
203
192
|
|
|
204
193
|
// Also check source files for testability concerns
|
|
205
194
|
for (const sourceFile of sourceFiles) {
|
|
206
|
-
const sourcePath = path.join(
|
|
195
|
+
const sourcePath = path.join(PATHS.root, sourceFile);
|
|
207
196
|
if (!fs.existsSync(sourcePath)) continue;
|
|
208
197
|
|
|
209
198
|
try {
|
|
@@ -357,4 +346,5 @@ function checkTestability(content, fileName) {
|
|
|
357
346
|
return issues;
|
|
358
347
|
}
|
|
359
348
|
|
|
360
|
-
|
|
349
|
+
const step = new PrTestStep();
|
|
350
|
+
module.exports = { run: (opts) => step.run(opts), analyzeCoverage, analyzeTestQuality };
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
const { execSync } = require('node:child_process');
|
|
11
11
|
const path = require('node:path');
|
|
12
|
-
const { getProjectRoot } = require('./flow-utils');
|
|
13
|
-
|
|
14
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
12
|
+
const { getProjectRoot, PATHS } = require('./flow-utils');
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
15
|
* Run regression tests as a workflow step
|
|
@@ -28,9 +26,9 @@ async function run(options = {}) {
|
|
|
28
26
|
|
|
29
27
|
try {
|
|
30
28
|
// Run regression tests
|
|
31
|
-
const regressionScript = path.join(
|
|
29
|
+
const regressionScript = path.join(PATHS.root, 'scripts', 'flow-regression.js');
|
|
32
30
|
const result = execSync(`node "${regressionScript}" --count ${sampleSize} --json`, {
|
|
33
|
-
cwd:
|
|
31
|
+
cwd: PATHS.root,
|
|
34
32
|
encoding: 'utf8',
|
|
35
33
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
36
34
|
});
|
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('node:fs');
|
|
16
16
|
const path = require('node:path');
|
|
17
|
-
const {
|
|
18
|
-
|
|
19
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
17
|
+
const { BaseWorkflowStep } = require('./base-workflow-step');
|
|
18
|
+
const { colors, PATHS } = require('./flow-utils');
|
|
20
19
|
|
|
21
20
|
// High-risk patterns that trigger multi-agent review
|
|
22
21
|
const HIGH_RISK_PATTERNS = [
|
|
@@ -28,120 +27,103 @@ const HIGH_RISK_PATTERNS = [
|
|
|
28
27
|
'database', 'migration', 'schema',
|
|
29
28
|
];
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* @param {string} options.taskType - Type of task (feature/bugfix/refactor)
|
|
39
|
-
* @returns {object} - { passed: boolean, message: string, details?: object[] }
|
|
40
|
-
*/
|
|
41
|
-
async function run(options = {}) {
|
|
42
|
-
const { files = [], stepConfig = {}, taskType } = options;
|
|
43
|
-
const multiAgentThreshold = stepConfig.multiAgentThreshold || 5;
|
|
44
|
-
const confidenceThreshold = stepConfig.confidenceThreshold || 80;
|
|
45
|
-
const highRiskPatterns = stepConfig.highRiskPatterns || HIGH_RISK_PATTERNS;
|
|
46
|
-
|
|
47
|
-
// Filter to reviewable files
|
|
48
|
-
const reviewableExtensions = ['.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs'];
|
|
49
|
-
const reviewableFiles = files.filter(f =>
|
|
50
|
-
reviewableExtensions.some(ext => f.endsWith(ext)) &&
|
|
51
|
-
!f.includes('.test.') &&
|
|
52
|
-
!f.includes('.spec.') &&
|
|
53
|
-
!f.includes('.d.ts')
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
if (reviewableFiles.length === 0) {
|
|
57
|
-
return { passed: true, message: 'No reviewable files modified' };
|
|
30
|
+
class ReviewStep extends BaseWorkflowStep {
|
|
31
|
+
constructor() {
|
|
32
|
+
super('codeReview', {
|
|
33
|
+
extensions: ['.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs'],
|
|
34
|
+
excludeTests: true,
|
|
35
|
+
excludeDts: true,
|
|
36
|
+
});
|
|
58
37
|
}
|
|
59
38
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
async execute(files, options) {
|
|
40
|
+
const { stepConfig = {}, taskType } = options;
|
|
41
|
+
const multiAgentThreshold = stepConfig.multiAgentThreshold || 5;
|
|
42
|
+
const confidenceThreshold = stepConfig.confidenceThreshold || 80;
|
|
43
|
+
const highRiskPatterns = stepConfig.highRiskPatterns || HIGH_RISK_PATTERNS;
|
|
63
44
|
|
|
64
|
-
|
|
65
|
-
|
|
45
|
+
// Determine if high-risk
|
|
46
|
+
const isHighRisk = taskType === 'refactor' ||
|
|
47
|
+
files.some(f => highRiskPatterns.some(p => f.toLowerCase().includes(p)));
|
|
66
48
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log(colors.cyan + ' Running multi-agent code review...' + colors.reset);
|
|
70
|
-
issues = await runMultiAgentReview(reviewableFiles, stepConfig);
|
|
71
|
-
} else {
|
|
72
|
-
console.log(colors.cyan + ' Running simple code review...' + colors.reset);
|
|
73
|
-
issues = await runSimpleReview(reviewableFiles, stepConfig);
|
|
74
|
-
}
|
|
49
|
+
// Choose review mode
|
|
50
|
+
const useMultiAgent = files.length > multiAgentThreshold || isHighRisk;
|
|
75
51
|
|
|
76
|
-
|
|
77
|
-
|
|
52
|
+
let issues;
|
|
53
|
+
if (useMultiAgent) {
|
|
54
|
+
console.log(colors.cyan + ' Running multi-agent code review...' + colors.reset);
|
|
55
|
+
issues = await runMultiAgentReview(files, stepConfig);
|
|
56
|
+
} else {
|
|
57
|
+
console.log(colors.cyan + ' Running simple code review...' + colors.reset);
|
|
58
|
+
issues = await runSimpleReview(files, stepConfig);
|
|
59
|
+
}
|
|
78
60
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
passed: true,
|
|
82
|
-
message: useMultiAgent
|
|
83
|
-
? `Multi-agent review passed (${reviewableFiles.length} files)`
|
|
84
|
-
: `Simple review passed (${reviewableFiles.length} files)`,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
61
|
+
// Filter by confidence threshold
|
|
62
|
+
const reportableIssues = issues.filter(i => i.confidence >= confidenceThreshold);
|
|
87
63
|
|
|
88
|
-
|
|
89
|
-
|
|
64
|
+
if (reportableIssues.length === 0) {
|
|
65
|
+
return this.pass(useMultiAgent
|
|
66
|
+
? `Multi-agent review passed (${files.length} files)`
|
|
67
|
+
: `Simple review passed (${files.length} files)`);
|
|
68
|
+
}
|
|
90
69
|
|
|
91
|
-
|
|
92
|
-
|
|
70
|
+
// Report issues
|
|
71
|
+
console.log(colors.yellow + '\n Code Review Issues:' + colors.reset);
|
|
93
72
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
for (const issue of criticalIssues) {
|
|
97
|
-
printIssue(issue);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
73
|
+
const criticalIssues = reportableIssues.filter(i => i.severity === 'critical');
|
|
74
|
+
const importantIssues = reportableIssues.filter(i => i.severity === 'important');
|
|
100
75
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
76
|
+
if (criticalIssues.length > 0) {
|
|
77
|
+
console.log(colors.red + ' Critical:' + colors.reset);
|
|
78
|
+
for (const issue of criticalIssues) {
|
|
79
|
+
printIssue(issue);
|
|
80
|
+
}
|
|
105
81
|
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Critical issues block, important issues warn
|
|
109
|
-
const hasCritical = criticalIssues.length > 0;
|
|
110
82
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
} catch (err) {
|
|
117
|
-
// Auto-learn not available or failed - continue silently
|
|
83
|
+
if (importantIssues.length > 0) {
|
|
84
|
+
console.log(colors.yellow + ' Important:' + colors.reset);
|
|
85
|
+
for (const issue of importantIssues) {
|
|
86
|
+
printIssue(issue);
|
|
87
|
+
}
|
|
118
88
|
}
|
|
119
89
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
90
|
+
// Auto-capture learnings from issues found
|
|
91
|
+
if (reportableIssues.length > 0) {
|
|
92
|
+
try {
|
|
93
|
+
const { captureFromSessionReview } = require('./flow-auto-learn');
|
|
94
|
+
captureFromSessionReview(reportableIssues);
|
|
95
|
+
} catch (_err) {
|
|
96
|
+
// Auto-learn not available or failed - continue silently
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const { TechDebtManager } = require('./flow-tech-debt');
|
|
101
|
+
const debtManager = new TechDebtManager();
|
|
102
|
+
const { added, updated } = debtManager.addIssues(reportableIssues.map(issue => ({
|
|
103
|
+
file: issue.file,
|
|
104
|
+
line: issue.line,
|
|
105
|
+
category: issue.perspective || 'code',
|
|
106
|
+
severity: issue.severity === 'critical' ? 'critical' : (issue.severity === 'important' ? 'high' : 'medium'),
|
|
107
|
+
description: issue.description,
|
|
108
|
+
fix: issue.fix || ''
|
|
109
|
+
})));
|
|
110
|
+
if (added > 0 || updated > 0) {
|
|
111
|
+
console.log(colors.dim + ` Tech debt: ${added} new, ${updated} updated` + colors.reset);
|
|
112
|
+
}
|
|
113
|
+
} catch (_err) {
|
|
114
|
+
// Tech debt manager not available or failed - continue silently
|
|
134
115
|
}
|
|
135
|
-
} catch (err) {
|
|
136
|
-
// Tech debt manager not available or failed - continue silently
|
|
137
116
|
}
|
|
138
|
-
}
|
|
139
117
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
118
|
+
const hasCritical = criticalIssues.length > 0;
|
|
119
|
+
|
|
120
|
+
return hasCritical
|
|
121
|
+
? this.fail(
|
|
122
|
+
`${reportableIssues.length} issue(s) found (${criticalIssues.length} critical, ${importantIssues.length} important)`,
|
|
123
|
+
reportableIssues
|
|
124
|
+
)
|
|
125
|
+
: this.pass(`${reportableIssues.length} issue(s) found (${criticalIssues.length} critical, ${importantIssues.length} important)`);
|
|
126
|
+
}
|
|
145
127
|
}
|
|
146
128
|
|
|
147
129
|
/**
|
|
@@ -164,7 +146,7 @@ async function runMultiAgentReview(files, config) {
|
|
|
164
146
|
const allIssues = [];
|
|
165
147
|
|
|
166
148
|
for (const file of files) {
|
|
167
|
-
const filePath = path.join(
|
|
149
|
+
const filePath = path.join(PATHS.root, file);
|
|
168
150
|
if (!fs.existsSync(filePath)) continue;
|
|
169
151
|
|
|
170
152
|
try {
|
|
@@ -198,7 +180,7 @@ async function runSimpleReview(files, config) {
|
|
|
198
180
|
const allIssues = [];
|
|
199
181
|
|
|
200
182
|
for (const file of files) {
|
|
201
|
-
const filePath = path.join(
|
|
183
|
+
const filePath = path.join(PATHS.root, file);
|
|
202
184
|
if (!fs.existsSync(filePath)) continue;
|
|
203
185
|
|
|
204
186
|
try {
|
|
@@ -532,4 +514,5 @@ function mergeIssues(issues) {
|
|
|
532
514
|
return merged;
|
|
533
515
|
}
|
|
534
516
|
|
|
535
|
-
|
|
517
|
+
const step = new ReviewStep();
|
|
518
|
+
module.exports = { run: (opts) => step.run(opts), runMultiAgentReview, runSimpleReview };
|