fraim-framework 2.0.43 → 2.0.45
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/bin/fraim.js +1 -1
- package/dist/registry/ai-manager-rules/design-phases/design-completeness-review.md +73 -0
- package/dist/registry/ai-manager-rules/design-phases/design-design.md +145 -0
- package/dist/registry/ai-manager-rules/design-phases/design.md +108 -0
- package/dist/registry/ai-manager-rules/design-phases/finalize.md +60 -0
- package/dist/registry/ai-manager-rules/design-phases/validate.md +125 -0
- package/dist/registry/ai-manager-rules/implement-phases/code.md +323 -0
- package/dist/registry/ai-manager-rules/implement-phases/completeness-review.md +94 -0
- package/dist/registry/ai-manager-rules/implement-phases/finalize.md +177 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-code.md +286 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-completeness-review.md +120 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-regression.md +173 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-repro.md +104 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-scoping.md +100 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-smoke.md +230 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-spike.md +121 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-validate.md +371 -0
- package/dist/registry/ai-manager-rules/implement-phases/quality-review.md +304 -0
- package/dist/registry/ai-manager-rules/implement-phases/regression.md +159 -0
- package/dist/registry/ai-manager-rules/implement-phases/repro.md +101 -0
- package/dist/registry/ai-manager-rules/implement-phases/scoping.md +93 -0
- package/dist/registry/ai-manager-rules/implement-phases/smoke.md +225 -0
- package/dist/registry/ai-manager-rules/implement-phases/spike.md +118 -0
- package/dist/registry/ai-manager-rules/implement-phases/validate.md +347 -0
- package/dist/registry/ai-manager-rules/shared-phases/finalize.md +169 -0
- package/dist/registry/ai-manager-rules/shared-phases/submit-pr.md +202 -0
- package/dist/registry/ai-manager-rules/shared-phases/wait-for-pr-review.md +170 -0
- package/dist/registry/ai-manager-rules/spec-phases/finalize.md +60 -0
- package/dist/registry/ai-manager-rules/spec-phases/spec-completeness-review.md +66 -0
- package/dist/registry/ai-manager-rules/spec-phases/spec-spec.md +139 -0
- package/dist/registry/ai-manager-rules/spec-phases/spec.md +102 -0
- package/dist/registry/ai-manager-rules/spec-phases/validate.md +118 -0
- package/dist/src/ai-manager/ai-manager.js +380 -119
- package/dist/src/ai-manager/evidence-validator.js +309 -0
- package/dist/src/ai-manager/phase-flow.js +244 -0
- package/dist/src/ai-manager/types.js +5 -0
- package/dist/src/fraim-mcp-server.js +45 -153
- package/dist/src/static-website-middleware.js +75 -0
- package/dist/tests/test-ai-coach-edge-cases.js +415 -0
- package/dist/tests/test-ai-coach-mcp-integration.js +432 -0
- package/dist/tests/test-ai-coach-performance.js +328 -0
- package/dist/tests/test-ai-coach-phase-content.js +264 -0
- package/dist/tests/test-ai-coach-workflows.js +487 -0
- package/dist/tests/test-ai-manager-phase-protocol.js +147 -0
- package/dist/tests/test-ai-manager.js +60 -71
- package/dist/tests/test-evidence-validation.js +221 -0
- package/dist/tests/test-mcp-lifecycle-methods.js +18 -23
- package/dist/tests/test-pr-review-integration.js +1 -0
- package/dist/tests/test-pr-review-workflow.js +299 -0
- package/dist/website/.nojekyll +0 -0
- package/dist/website/404.html +101 -0
- package/dist/website/CNAME +1 -0
- package/dist/website/README.md +22 -0
- package/dist/website/demo.html +604 -0
- package/dist/website/images/.gitkeep +1 -0
- package/dist/website/images/fraim-logo.png +0 -0
- package/dist/website/index.html +290 -0
- package/dist/website/pricing.html +414 -0
- package/dist/website/script.js +55 -0
- package/dist/website/styles.css +2647 -0
- package/package.json +2 -1
- package/registry/agent-guardrails.md +1 -1
- package/registry/stubs/workflows/brainstorming/blue-sky-brainstorming.md +11 -0
- package/registry/stubs/workflows/brainstorming/codebase-brainstorming.md +11 -0
- package/registry/stubs/workflows/compliance/detect-compliance-requirements.md +11 -0
- package/registry/stubs/workflows/compliance/generate-audit-evidence.md +11 -0
- package/registry/stubs/workflows/learning/synthesize-learnings.md +11 -0
- package/registry/stubs/workflows/legal/nda.md +11 -0
- package/registry/stubs/workflows/legal/patent-filing.md +11 -0
- package/registry/stubs/workflows/legal/trademark-filing.md +11 -0
- package/registry/stubs/workflows/marketing/domain-registration.md +11 -0
- package/registry/stubs/workflows/product-building/design.md +1 -1
- package/registry/stubs/workflows/product-building/implement.md +1 -2
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Evidence Validator - Validates agent claims with concrete evidence
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EvidenceValidator = void 0;
|
|
7
|
+
class EvidenceValidator {
|
|
8
|
+
/**
|
|
9
|
+
* Validate test evidence
|
|
10
|
+
*/
|
|
11
|
+
validateTestEvidence(evidence) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
const warnings = [];
|
|
14
|
+
let score = 0;
|
|
15
|
+
// Check if test output is provided
|
|
16
|
+
if (!evidence.testOutput) {
|
|
17
|
+
issues.push("❌ CRITICAL: No test output provided. Cannot verify test claims.");
|
|
18
|
+
return { isValid: false, issues, warnings, score: 0 };
|
|
19
|
+
}
|
|
20
|
+
// Parse test output for validation
|
|
21
|
+
const testOutput = evidence.testOutput.toLowerCase();
|
|
22
|
+
// Check for 100% pass rate
|
|
23
|
+
if (this.hasFailingTests(testOutput)) {
|
|
24
|
+
issues.push("❌ CRITICAL: Test output shows failing tests. Cannot proceed with failing tests.");
|
|
25
|
+
score = 0;
|
|
26
|
+
}
|
|
27
|
+
else if (this.hasPassingTests(testOutput)) {
|
|
28
|
+
score += 40; // Base score for passing tests
|
|
29
|
+
// Check for comprehensive test coverage
|
|
30
|
+
if (this.hasComprehensiveTestCoverage(testOutput)) {
|
|
31
|
+
score += 20;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
warnings.push("⚠️ WARNING: Test coverage appears limited. Consider adding more test scenarios.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
issues.push("❌ CRITICAL: Cannot determine test results from provided output. Please provide complete test output.");
|
|
39
|
+
score = 0;
|
|
40
|
+
}
|
|
41
|
+
// Check for test count (should have meaningful number of tests)
|
|
42
|
+
const testCount = this.extractTestCount(testOutput);
|
|
43
|
+
if (testCount === 0) {
|
|
44
|
+
issues.push("❌ CRITICAL: No tests detected in output. Must have tests to validate functionality.");
|
|
45
|
+
score = 0;
|
|
46
|
+
}
|
|
47
|
+
else if (testCount < 3) {
|
|
48
|
+
warnings.push(`⚠️ WARNING: Only ${testCount} tests detected. Consider adding more comprehensive tests.`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
score += 10; // Bonus for having multiple tests
|
|
52
|
+
}
|
|
53
|
+
// Check for timeout or hanging tests
|
|
54
|
+
if (this.hasTimeoutIssues(testOutput)) {
|
|
55
|
+
issues.push("❌ CRITICAL: Test output shows timeouts or hanging tests. Must resolve before proceeding.");
|
|
56
|
+
score = Math.max(0, score - 30);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
isValid: issues.length === 0,
|
|
60
|
+
issues,
|
|
61
|
+
warnings,
|
|
62
|
+
score: Math.min(100, score)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validate manual validation evidence
|
|
67
|
+
*/
|
|
68
|
+
validateManualEvidence(evidence) {
|
|
69
|
+
const issues = [];
|
|
70
|
+
const warnings = [];
|
|
71
|
+
let score = 0;
|
|
72
|
+
// Check for manual validation steps
|
|
73
|
+
if (!evidence.manualValidationSteps || evidence.manualValidationSteps.length === 0) {
|
|
74
|
+
issues.push("❌ CRITICAL: No manual validation steps provided. Manual testing is mandatory.");
|
|
75
|
+
return { isValid: false, issues, warnings, score: 0 };
|
|
76
|
+
}
|
|
77
|
+
// Check for screenshots (for UI changes)
|
|
78
|
+
if (!evidence.screenshots || evidence.screenshots.length === 0) {
|
|
79
|
+
warnings.push("⚠️ WARNING: No screenshots provided. For UI changes, screenshots are required evidence.");
|
|
80
|
+
score += 20; // Partial credit
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
score += 40; // Good evidence
|
|
84
|
+
// Check screenshot quality
|
|
85
|
+
if (this.hasQualityScreenshots(evidence.screenshots)) {
|
|
86
|
+
score += 20;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Check for API responses (for API changes)
|
|
90
|
+
if (evidence.apiResponses && evidence.apiResponses.length > 0) {
|
|
91
|
+
score += 20; // Bonus for API testing
|
|
92
|
+
if (this.hasComprehensiveApiTesting(evidence.apiResponses)) {
|
|
93
|
+
score += 10;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Validate manual validation steps quality
|
|
97
|
+
const stepsQuality = this.assessManualValidationQuality(evidence.manualValidationSteps);
|
|
98
|
+
if (stepsQuality.score < 50) {
|
|
99
|
+
issues.push("❌ CRITICAL: Manual validation steps are insufficient. Must provide detailed step-by-step validation.");
|
|
100
|
+
score = 0;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
score += stepsQuality.score * 0.2; // Up to 20 points
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
isValid: issues.length === 0,
|
|
107
|
+
issues,
|
|
108
|
+
warnings,
|
|
109
|
+
score: Math.min(100, score)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Validate reflection analysis
|
|
114
|
+
*/
|
|
115
|
+
validateReflectionEvidence(evidence) {
|
|
116
|
+
const issues = [];
|
|
117
|
+
const warnings = [];
|
|
118
|
+
let score = 0;
|
|
119
|
+
if (!evidence.reflectionAnalysis) {
|
|
120
|
+
issues.push("❌ CRITICAL: No reflection analysis provided. Mandatory pre-completion reflection is required.");
|
|
121
|
+
return { isValid: false, issues, warnings, score: 0 };
|
|
122
|
+
}
|
|
123
|
+
const reflection = evidence.reflectionAnalysis.toLowerCase();
|
|
124
|
+
// Check for all 4 phases
|
|
125
|
+
const phases = ['phase 1', 'phase 2', 'phase 3', 'phase 4'];
|
|
126
|
+
const missingPhases = phases.filter(phase => !reflection.includes(phase));
|
|
127
|
+
if (missingPhases.length > 0) {
|
|
128
|
+
issues.push(`❌ CRITICAL: Missing reflection phases: ${missingPhases.join(', ')}. All 4 phases are mandatory.`);
|
|
129
|
+
score = 0;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
score += 40; // Base score for having all phases
|
|
133
|
+
}
|
|
134
|
+
// Check for specific reflection elements
|
|
135
|
+
const requiredElements = [
|
|
136
|
+
'evidence',
|
|
137
|
+
'manual testing',
|
|
138
|
+
'ship to customers',
|
|
139
|
+
'bet money',
|
|
140
|
+
'reproducible'
|
|
141
|
+
];
|
|
142
|
+
const missingElements = requiredElements.filter(element => !reflection.includes(element));
|
|
143
|
+
if (missingElements.length > 0) {
|
|
144
|
+
warnings.push(`⚠️ WARNING: Reflection may be incomplete. Consider addressing: ${missingElements.join(', ')}`);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
score += 30; // Bonus for comprehensive reflection
|
|
148
|
+
}
|
|
149
|
+
// Check for honesty indicators
|
|
150
|
+
if (this.hasHonestyIndicators(reflection)) {
|
|
151
|
+
score += 20;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
warnings.push("⚠️ WARNING: Reflection may lack sufficient self-assessment depth.");
|
|
155
|
+
}
|
|
156
|
+
// Check for any "NO" answers in critical questions
|
|
157
|
+
if (this.hasCriticalNoAnswers(reflection)) {
|
|
158
|
+
issues.push("❌ CRITICAL: Reflection contains 'NO' answers to critical questions. Must address issues before proceeding.");
|
|
159
|
+
score = 0;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
isValid: issues.length === 0,
|
|
163
|
+
issues,
|
|
164
|
+
warnings,
|
|
165
|
+
score: Math.min(100, score)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Comprehensive evidence validation
|
|
170
|
+
*/
|
|
171
|
+
validateAllEvidence(evidence) {
|
|
172
|
+
const testValidation = this.validateTestEvidence(evidence);
|
|
173
|
+
const manualValidation = this.validateManualEvidence(evidence);
|
|
174
|
+
const reflectionValidation = this.validateReflectionEvidence(evidence);
|
|
175
|
+
const allIssues = [
|
|
176
|
+
...testValidation.issues,
|
|
177
|
+
...manualValidation.issues,
|
|
178
|
+
...reflectionValidation.issues
|
|
179
|
+
];
|
|
180
|
+
const allWarnings = [
|
|
181
|
+
...testValidation.warnings,
|
|
182
|
+
...manualValidation.warnings,
|
|
183
|
+
...reflectionValidation.warnings
|
|
184
|
+
];
|
|
185
|
+
// Calculate weighted score
|
|
186
|
+
const weightedScore = (testValidation.score * 0.4 + // 40% weight on tests
|
|
187
|
+
manualValidation.score * 0.4 + // 40% weight on manual validation
|
|
188
|
+
reflectionValidation.score * 0.2 // 20% weight on reflection
|
|
189
|
+
);
|
|
190
|
+
return {
|
|
191
|
+
isValid: allIssues.length === 0 && weightedScore >= 70, // Minimum 70% score required
|
|
192
|
+
issues: allIssues,
|
|
193
|
+
warnings: allWarnings,
|
|
194
|
+
score: Math.round(weightedScore)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// Helper methods for parsing evidence
|
|
198
|
+
hasFailingTests(testOutput) {
|
|
199
|
+
const failureIndicators = [
|
|
200
|
+
'failed',
|
|
201
|
+
'error',
|
|
202
|
+
'failing',
|
|
203
|
+
'fail 1',
|
|
204
|
+
'fail 2',
|
|
205
|
+
'timeout',
|
|
206
|
+
'assertion error',
|
|
207
|
+
'test failed'
|
|
208
|
+
];
|
|
209
|
+
return failureIndicators.some(indicator => testOutput.includes(indicator));
|
|
210
|
+
}
|
|
211
|
+
hasPassingTests(testOutput) {
|
|
212
|
+
const passIndicators = [
|
|
213
|
+
'pass',
|
|
214
|
+
'passed',
|
|
215
|
+
'success',
|
|
216
|
+
'ok',
|
|
217
|
+
'✓',
|
|
218
|
+
'✔',
|
|
219
|
+
'all tests passed'
|
|
220
|
+
];
|
|
221
|
+
return passIndicators.some(indicator => testOutput.includes(indicator));
|
|
222
|
+
}
|
|
223
|
+
hasComprehensiveTestCoverage(testOutput) {
|
|
224
|
+
const coverageIndicators = [
|
|
225
|
+
'coverage',
|
|
226
|
+
'multiple test',
|
|
227
|
+
'integration',
|
|
228
|
+
'unit test',
|
|
229
|
+
'e2e',
|
|
230
|
+
'smoke test'
|
|
231
|
+
];
|
|
232
|
+
return coverageIndicators.some(indicator => testOutput.includes(indicator));
|
|
233
|
+
}
|
|
234
|
+
extractTestCount(testOutput) {
|
|
235
|
+
// Look for patterns like "5 tests passed", "tests 10", etc.
|
|
236
|
+
const testCountPatterns = [
|
|
237
|
+
/(\d+)\s+tests?\s+passed/i,
|
|
238
|
+
/tests?\s+(\d+)/i,
|
|
239
|
+
/(\d+)\s+passing/i,
|
|
240
|
+
/pass\s+(\d+)/i
|
|
241
|
+
];
|
|
242
|
+
for (const pattern of testCountPatterns) {
|
|
243
|
+
const match = testOutput.match(pattern);
|
|
244
|
+
if (match) {
|
|
245
|
+
return parseInt(match[1], 10);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
hasTimeoutIssues(testOutput) {
|
|
251
|
+
const timeoutIndicators = [
|
|
252
|
+
'timeout',
|
|
253
|
+
'timed out',
|
|
254
|
+
'hanging',
|
|
255
|
+
'stuck',
|
|
256
|
+
'exceeded timeout'
|
|
257
|
+
];
|
|
258
|
+
return timeoutIndicators.some(indicator => testOutput.includes(indicator));
|
|
259
|
+
}
|
|
260
|
+
hasQualityScreenshots(screenshots) {
|
|
261
|
+
// Check if screenshots have descriptive names/content
|
|
262
|
+
return screenshots.some(screenshot => screenshot.length > 20 && // Has some description
|
|
263
|
+
(screenshot.includes('working') || screenshot.includes('success') || screenshot.includes('complete')));
|
|
264
|
+
}
|
|
265
|
+
hasComprehensiveApiTesting(apiResponses) {
|
|
266
|
+
return apiResponses.some(response => response.includes('200') || response.includes('success') || response.includes('json'));
|
|
267
|
+
}
|
|
268
|
+
assessManualValidationQuality(steps) {
|
|
269
|
+
let score = 0;
|
|
270
|
+
const issues = [];
|
|
271
|
+
if (steps.length < 3) {
|
|
272
|
+
issues.push("Insufficient manual validation steps");
|
|
273
|
+
return { score: 20, issues };
|
|
274
|
+
}
|
|
275
|
+
// Check for specific validation elements
|
|
276
|
+
const stepText = steps.join(' ').toLowerCase();
|
|
277
|
+
if (stepText.includes('browser') || stepText.includes('ui'))
|
|
278
|
+
score += 25;
|
|
279
|
+
if (stepText.includes('api') || stepText.includes('curl'))
|
|
280
|
+
score += 25;
|
|
281
|
+
if (stepText.includes('error') || stepText.includes('edge case'))
|
|
282
|
+
score += 25;
|
|
283
|
+
if (stepText.includes('user flow') || stepText.includes('end-to-end'))
|
|
284
|
+
score += 25;
|
|
285
|
+
return { score, issues };
|
|
286
|
+
}
|
|
287
|
+
hasHonestyIndicators(reflection) {
|
|
288
|
+
const honestyIndicators = [
|
|
289
|
+
'honestly',
|
|
290
|
+
'truthfully',
|
|
291
|
+
'actually tested',
|
|
292
|
+
'real validation',
|
|
293
|
+
'concrete evidence'
|
|
294
|
+
];
|
|
295
|
+
return honestyIndicators.some(indicator => reflection.includes(indicator));
|
|
296
|
+
}
|
|
297
|
+
hasCriticalNoAnswers(reflection) {
|
|
298
|
+
// Look for "NO" answers to critical questions
|
|
299
|
+
const criticalNoPatterns = [
|
|
300
|
+
/ship to customers:\s*no/i,
|
|
301
|
+
/bet money:\s*no/i,
|
|
302
|
+
/reproducible:\s*no/i,
|
|
303
|
+
/evidence quality:\s*no/i,
|
|
304
|
+
/honesty check:\s*no/i
|
|
305
|
+
];
|
|
306
|
+
return criticalNoPatterns.some(pattern => pattern.test(reflection));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
exports.EvidenceValidator = EvidenceValidator;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase flow logic for AI Manager workflows
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getNextPhase = getNextPhase;
|
|
7
|
+
exports.isPhaseValidForWorkflow = isPhaseValidForWorkflow;
|
|
8
|
+
exports.getPhaseOnFailure = getPhaseOnFailure;
|
|
9
|
+
exports.getPhasesForWorkflow = getPhasesForWorkflow;
|
|
10
|
+
exports.getNextPhaseForImplement = getNextPhaseForImplement;
|
|
11
|
+
exports.isPhaseValidForIssueType = isPhaseValidForIssueType;
|
|
12
|
+
exports.getPhasesForIssueType = getPhasesForIssueType;
|
|
13
|
+
exports.getPhaseOnImplementFailure = getPhaseOnImplementFailure;
|
|
14
|
+
/**
|
|
15
|
+
* Phase flows for different workflow types
|
|
16
|
+
*/
|
|
17
|
+
const BUG_PHASE_FLOW = [
|
|
18
|
+
'implement-scoping',
|
|
19
|
+
'implement-repro',
|
|
20
|
+
'implement-code',
|
|
21
|
+
'implement-validate',
|
|
22
|
+
'implement-regression',
|
|
23
|
+
'implement-completeness-review',
|
|
24
|
+
'submit-pr',
|
|
25
|
+
'wait-for-pr-review',
|
|
26
|
+
];
|
|
27
|
+
const FEATURE_PHASE_FLOW = [
|
|
28
|
+
'implement-scoping',
|
|
29
|
+
'implement-spike',
|
|
30
|
+
'implement-code',
|
|
31
|
+
'implement-validate',
|
|
32
|
+
'implement-smoke',
|
|
33
|
+
'implement-regression',
|
|
34
|
+
'implement-completeness-review',
|
|
35
|
+
'submit-pr',
|
|
36
|
+
'wait-for-pr-review',
|
|
37
|
+
];
|
|
38
|
+
const SPEC_PHASE_FLOW = [
|
|
39
|
+
'spec-spec',
|
|
40
|
+
'spec-completeness-review',
|
|
41
|
+
'submit-pr',
|
|
42
|
+
'wait-for-pr-review',
|
|
43
|
+
];
|
|
44
|
+
const DESIGN_PHASE_FLOW = [
|
|
45
|
+
'design-design',
|
|
46
|
+
'design-completeness-review',
|
|
47
|
+
'submit-pr',
|
|
48
|
+
'wait-for-pr-review',
|
|
49
|
+
];
|
|
50
|
+
const TEST_PHASE_FLOW = [
|
|
51
|
+
'test-test',
|
|
52
|
+
'test-validate',
|
|
53
|
+
'submit-pr',
|
|
54
|
+
'wait-for-pr-review',
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Get the next phase in the workflow
|
|
58
|
+
* @param currentPhase - Current phase
|
|
59
|
+
* @param workflowType - Type of workflow
|
|
60
|
+
* @param issueType - Type of issue (only used for implement workflow)
|
|
61
|
+
* @returns Next phase or null if at end of workflow
|
|
62
|
+
*/
|
|
63
|
+
function getNextPhase(currentPhase, workflowType, issueType) {
|
|
64
|
+
let flow;
|
|
65
|
+
if (workflowType === 'implement') {
|
|
66
|
+
if (!issueType) {
|
|
67
|
+
throw new Error('Issue type is required for implement workflow');
|
|
68
|
+
}
|
|
69
|
+
flow = issueType === 'bug' ? BUG_PHASE_FLOW : FEATURE_PHASE_FLOW;
|
|
70
|
+
}
|
|
71
|
+
else if (workflowType === 'spec') {
|
|
72
|
+
flow = SPEC_PHASE_FLOW;
|
|
73
|
+
}
|
|
74
|
+
else if (workflowType === 'design') {
|
|
75
|
+
flow = DESIGN_PHASE_FLOW;
|
|
76
|
+
}
|
|
77
|
+
else if (workflowType === 'test') {
|
|
78
|
+
flow = TEST_PHASE_FLOW;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw new Error(`Unknown workflow type: ${workflowType}`);
|
|
82
|
+
}
|
|
83
|
+
const currentIndex = flow.indexOf(currentPhase);
|
|
84
|
+
if (currentIndex === -1) {
|
|
85
|
+
throw new Error(`Invalid phase "${currentPhase}" for workflow type "${workflowType}"`);
|
|
86
|
+
}
|
|
87
|
+
if (currentIndex >= flow.length - 1) {
|
|
88
|
+
return null; // At end of workflow
|
|
89
|
+
}
|
|
90
|
+
return flow[currentIndex + 1];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if a phase is valid for the given workflow type
|
|
94
|
+
* @param phase - Phase to check
|
|
95
|
+
* @param workflowType - Type of workflow
|
|
96
|
+
* @param issueType - Type of issue (only used for implement workflow)
|
|
97
|
+
* @returns True if phase is valid for workflow type
|
|
98
|
+
*/
|
|
99
|
+
function isPhaseValidForWorkflow(phase, workflowType, issueType) {
|
|
100
|
+
let flow;
|
|
101
|
+
if (workflowType === 'implement') {
|
|
102
|
+
if (!issueType)
|
|
103
|
+
return false;
|
|
104
|
+
flow = issueType === 'bug' ? BUG_PHASE_FLOW : FEATURE_PHASE_FLOW;
|
|
105
|
+
}
|
|
106
|
+
else if (workflowType === 'spec') {
|
|
107
|
+
flow = SPEC_PHASE_FLOW;
|
|
108
|
+
}
|
|
109
|
+
else if (workflowType === 'design') {
|
|
110
|
+
flow = DESIGN_PHASE_FLOW;
|
|
111
|
+
}
|
|
112
|
+
else if (workflowType === 'test') {
|
|
113
|
+
flow = TEST_PHASE_FLOW;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return flow.includes(phase);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get the phase to return to when a phase fails
|
|
122
|
+
* @param failedPhase - The phase that failed
|
|
123
|
+
* @param workflowType - Type of workflow
|
|
124
|
+
* @param issueType - Type of issue (only used for implement workflow)
|
|
125
|
+
* @returns Phase to return to
|
|
126
|
+
*/
|
|
127
|
+
function getPhaseOnFailure(failedPhase, workflowType, issueType) {
|
|
128
|
+
if (workflowType === 'implement') {
|
|
129
|
+
// Implement workflow failure handling
|
|
130
|
+
switch (failedPhase) {
|
|
131
|
+
case 'implement-scoping':
|
|
132
|
+
return 'implement-scoping'; // Start over at scoping
|
|
133
|
+
case 'implement-repro':
|
|
134
|
+
return 'implement-scoping'; // Go back to understand the issue better
|
|
135
|
+
case 'implement-spike':
|
|
136
|
+
return 'implement-scoping'; // Go back to understand requirements better
|
|
137
|
+
case 'implement-code':
|
|
138
|
+
return 'implement-scoping'; // Go back to re-understand requirements
|
|
139
|
+
case 'implement-validate':
|
|
140
|
+
return 'implement-code'; // Implementation doesn't work, fix the code
|
|
141
|
+
case 'implement-smoke':
|
|
142
|
+
return 'implement-code'; // Broke existing functionality, fix the implementation
|
|
143
|
+
case 'implement-regression':
|
|
144
|
+
return 'implement-code'; // Test issues likely indicate implementation problems
|
|
145
|
+
case 'implement-completeness-review':
|
|
146
|
+
return 'implement-validate'; // Missing validation, go back to validate properly
|
|
147
|
+
case 'submit-pr':
|
|
148
|
+
return 'implement-completeness-review'; // PR submission issues, review completeness
|
|
149
|
+
case 'wait-for-pr-review':
|
|
150
|
+
// This phase determines where to go based on PR comment analysis
|
|
151
|
+
// Will be handled by the PR comment analysis logic
|
|
152
|
+
return 'implement-code'; // Default fallback for PR feedback
|
|
153
|
+
default:
|
|
154
|
+
return 'implement-code'; // Default fallback
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (workflowType === 'spec') {
|
|
158
|
+
// Spec workflow failure handling
|
|
159
|
+
switch (failedPhase) {
|
|
160
|
+
case 'spec-spec':
|
|
161
|
+
return 'spec-spec'; // Start over at spec
|
|
162
|
+
case 'spec-completeness-review':
|
|
163
|
+
return 'spec-spec'; // Go back to improve spec
|
|
164
|
+
case 'submit-pr':
|
|
165
|
+
return 'spec-completeness-review';
|
|
166
|
+
case 'wait-for-pr-review':
|
|
167
|
+
return 'spec-spec'; // PR feedback usually means spec changes needed
|
|
168
|
+
default:
|
|
169
|
+
return 'spec-spec';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (workflowType === 'design') {
|
|
173
|
+
// Design workflow failure handling
|
|
174
|
+
switch (failedPhase) {
|
|
175
|
+
case 'design-design':
|
|
176
|
+
return 'design-design'; // Start over at design
|
|
177
|
+
case 'design-completeness-review':
|
|
178
|
+
return 'design-design'; // Go back to improve design
|
|
179
|
+
case 'submit-pr':
|
|
180
|
+
return 'design-completeness-review';
|
|
181
|
+
case 'wait-for-pr-review':
|
|
182
|
+
return 'design-design'; // PR feedback usually means design changes needed
|
|
183
|
+
default:
|
|
184
|
+
return 'design-design';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else if (workflowType === 'test') {
|
|
188
|
+
// Test workflow failure handling
|
|
189
|
+
switch (failedPhase) {
|
|
190
|
+
case 'test-test':
|
|
191
|
+
return 'test-test'; // Start over at test
|
|
192
|
+
case 'test-validate':
|
|
193
|
+
return 'test-test'; // Go back to fix tests
|
|
194
|
+
case 'submit-pr':
|
|
195
|
+
return 'test-validate';
|
|
196
|
+
case 'wait-for-pr-review':
|
|
197
|
+
return 'test-test'; // PR feedback usually means test changes needed
|
|
198
|
+
default:
|
|
199
|
+
return 'test-test';
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Unknown workflow, return first phase of implement as fallback
|
|
203
|
+
return 'implement-scoping';
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get all phases for a workflow type
|
|
207
|
+
* @param workflowType - Type of workflow
|
|
208
|
+
* @param issueType - Type of issue (only used for implement workflow)
|
|
209
|
+
* @returns Array of phases
|
|
210
|
+
*/
|
|
211
|
+
function getPhasesForWorkflow(workflowType, issueType) {
|
|
212
|
+
if (workflowType === 'implement') {
|
|
213
|
+
if (!issueType) {
|
|
214
|
+
throw new Error('Issue type is required for implement workflow');
|
|
215
|
+
}
|
|
216
|
+
return issueType === 'bug' ? [...BUG_PHASE_FLOW] : [...FEATURE_PHASE_FLOW];
|
|
217
|
+
}
|
|
218
|
+
else if (workflowType === 'spec') {
|
|
219
|
+
return [...SPEC_PHASE_FLOW];
|
|
220
|
+
}
|
|
221
|
+
else if (workflowType === 'design') {
|
|
222
|
+
return [...DESIGN_PHASE_FLOW];
|
|
223
|
+
}
|
|
224
|
+
else if (workflowType === 'test') {
|
|
225
|
+
return [...TEST_PHASE_FLOW];
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
throw new Error(`Unknown workflow type: ${workflowType}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Legacy functions for backward compatibility
|
|
232
|
+
function getNextPhaseForImplement(currentPhase, issueType) {
|
|
233
|
+
return getNextPhase(currentPhase, 'implement', issueType);
|
|
234
|
+
}
|
|
235
|
+
function isPhaseValidForIssueType(phase, issueType) {
|
|
236
|
+
return isPhaseValidForWorkflow(phase, 'implement', issueType);
|
|
237
|
+
}
|
|
238
|
+
function getPhasesForIssueType(issueType) {
|
|
239
|
+
return getPhasesForWorkflow('implement', issueType);
|
|
240
|
+
}
|
|
241
|
+
// Legacy function for backward compatibility
|
|
242
|
+
function getPhaseOnImplementFailure(failedPhase, issueType) {
|
|
243
|
+
return getPhaseOnFailure(failedPhase, 'implement', issueType);
|
|
244
|
+
}
|