edsger 0.5.3 → 0.5.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/dist/phases/code-implementation/analyzer.js +6 -17
- package/dist/phases/code-implementation/prompts.js +9 -17
- package/dist/phases/code-testing/analyzer.d.ts +22 -0
- package/dist/phases/code-testing/analyzer.js +224 -0
- package/dist/phases/code-testing/context-fetcher.d.ts +16 -0
- package/dist/phases/code-testing/context-fetcher.js +81 -0
- package/dist/phases/code-testing/index.d.ts +2 -0
- package/dist/phases/code-testing/index.js +2 -0
- package/dist/phases/code-testing/prompts.d.ts +3 -0
- package/dist/phases/code-testing/prompts.js +144 -0
- package/dist/workflow-runner/config/phase-configs.js +7 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +2 -2
- package/dist/workflow-runner/executors/phase-executor.js +2 -2
- package/dist/workflow-runner/pipeline-runner.js +11 -2
- package/package.json +1 -1
|
@@ -374,10 +374,9 @@ CRITICAL: Checklists are not optional suggestions - they are mandatory quality g
|
|
|
374
374
|
2. **CREATE BRANCH**: Create a new feature branch from ${baseBranch}
|
|
375
375
|
3. **ANALYZE CODEBASE**: Use Glob and Read to understand the existing code structure
|
|
376
376
|
4. **IMPLEMENT CODE**: Write the actual implementation using Edit/Write tools
|
|
377
|
-
5. **
|
|
378
|
-
6. **
|
|
379
|
-
7. **COMMIT**:
|
|
380
|
-
8. **HANDLE PRE-COMMIT**: This project has strict pre-commit hooks - handle them properly:
|
|
377
|
+
5. **FIX ISSUES**: Address any lint or build failures
|
|
378
|
+
6. **COMMIT**: Commit your changes with a descriptive message
|
|
379
|
+
7. **HANDLE PRE-COMMIT**: This project has strict pre-commit hooks - handle them properly:
|
|
381
380
|
- If lint-staged fails: Fix formatting and linting issues, then retry commit
|
|
382
381
|
- If AI code review fails: Either fix code quality issues or use SKIP_REVIEW=1
|
|
383
382
|
- If other issues persist: Only use --no-verify as last resort after confirming code quality
|
|
@@ -395,12 +394,7 @@ CRITICAL: Checklists are not optional suggestions - they are mandatory quality g
|
|
|
395
394
|
- Add appropriate error handling and validation
|
|
396
395
|
- Write clean, maintainable code with proper comments where necessary
|
|
397
396
|
|
|
398
|
-
3. **
|
|
399
|
-
- Run existing tests to ensure nothing breaks
|
|
400
|
-
- Add new tests if implementing new functionality
|
|
401
|
-
- Ensure all tests pass before committing
|
|
402
|
-
|
|
403
|
-
4. **Pre-commit Handling**:
|
|
397
|
+
3. **Pre-commit Handling**:
|
|
404
398
|
- This project has strict pre-commit hooks including lint-staged, linting, and AI code review
|
|
405
399
|
- When pre-commit hooks fail, READ the error messages carefully
|
|
406
400
|
- Fix ALL issues reported (lint errors, type errors, formatting, code quality)
|
|
@@ -528,12 +522,7 @@ Follow this systematic approach:
|
|
|
528
522
|
- Following existing code patterns and conventions
|
|
529
523
|
- Adding proper error handling and validation
|
|
530
524
|
|
|
531
|
-
4. **
|
|
532
|
-
- All existing tests still pass
|
|
533
|
-
- New functionality works correctly
|
|
534
|
-
- Critical test cases are satisfied
|
|
535
|
-
|
|
536
|
-
5. **COMMIT CHANGES**: Commit your work with a descriptive message
|
|
525
|
+
4. **COMMIT CHANGES**: Commit your work with a descriptive message
|
|
537
526
|
- This project has strict pre-commit hooks (lint-staged, linting, AI code review)
|
|
538
527
|
- If hooks fail, try these approaches in order:
|
|
539
528
|
1. Fix the reported issues (preferred)
|
|
@@ -542,10 +531,10 @@ Follow this systematic approach:
|
|
|
542
531
|
|
|
543
532
|
## Important Notes
|
|
544
533
|
- Focus on implementing ALL user stories completely
|
|
545
|
-
- Use the test cases to validate your implementation
|
|
546
534
|
- Follow the technical design if provided, or create your own approach
|
|
547
535
|
- Maintain existing code quality and patterns
|
|
548
536
|
- Never skip pre-commit checks - always fix the issues
|
|
537
|
+
- Focus on implementation only - automated tests will be written in a separate phase
|
|
549
538
|
|
|
550
539
|
${checklistInstructions}
|
|
551
540
|
|
|
@@ -18,9 +18,8 @@ export const createCodeImplementationSystemPrompt = (_config, baseBranch) => {
|
|
|
18
18
|
- git pull origin ${baseBranch} --rebase
|
|
19
19
|
2. **CREATE BRANCH**: Create a new feature branch from ${baseBranch}
|
|
20
20
|
3. **ANALYZE CODEBASE**: Use Glob and Read to understand the existing code structure
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
5. **FIX ISSUES**: Address any lint or test failures
|
|
21
|
+
4. **IMPLEMENT CODE**: Write the actual implementation using Edit/Write tools
|
|
22
|
+
5. **FIX ISSUES**: Address any lint or build failures
|
|
24
23
|
6. **COMMIT**: Commit your changes with a descriptive message
|
|
25
24
|
7. **HANDLE PRE-COMMIT**: This project has strict pre-commit hooks - handle them properly:
|
|
26
25
|
- If lint-staged fails: Fix formatting and linting issues, then retry commit
|
|
@@ -40,18 +39,13 @@ export const createCodeImplementationSystemPrompt = (_config, baseBranch) => {
|
|
|
40
39
|
- Add appropriate error handling and validation
|
|
41
40
|
- Write clean, maintainable code with proper comments where necessary
|
|
42
41
|
|
|
43
|
-
3. **
|
|
44
|
-
- Run relevant tests during development to catch issues early
|
|
45
|
-
- Ensure all existing tests continue to pass
|
|
46
|
-
- Add new tests if creating new functionality
|
|
47
|
-
- Fix any broken tests as part of the implementation
|
|
48
|
-
|
|
49
|
-
4. **Implementation Standards**:
|
|
42
|
+
3. **Implementation Standards**:
|
|
50
43
|
- All feature information, user stories, test cases, and technical design are provided in the prompt
|
|
51
44
|
- Follow the technical design specifications closely
|
|
52
|
-
- Implement ALL user stories
|
|
45
|
+
- Implement ALL user stories completely
|
|
53
46
|
- Create production-ready, maintainable code
|
|
54
47
|
- Handle edge cases and error scenarios appropriately
|
|
48
|
+
- Focus on implementation only - tests will be written in a separate phase
|
|
55
49
|
|
|
56
50
|
**CRITICAL - Result Format**:
|
|
57
51
|
You MUST end your response with a JSON object containing the implementation results in this EXACT format:
|
|
@@ -78,8 +72,8 @@ You MUST end your response with a JSON object containing the implementation resu
|
|
|
78
72
|
- Proper error handling and validation
|
|
79
73
|
- Clean, maintainable, and well-documented code
|
|
80
74
|
- All user stories fully implemented
|
|
81
|
-
- All test cases should be able to pass
|
|
82
75
|
- Proper git hygiene with clear commit messages
|
|
76
|
+
- Focus on implementation - automated tests will be written in a separate phase
|
|
83
77
|
|
|
84
78
|
Focus on systematic implementation based on the provided specifications and requirements.`;
|
|
85
79
|
};
|
|
@@ -104,15 +98,12 @@ Follow this systematic approach:
|
|
|
104
98
|
3. **Implementation**:
|
|
105
99
|
- Follow the technical design specifications provided above
|
|
106
100
|
- Implement ALL user stories listed above
|
|
107
|
-
- Ensure ALL test cases can pass when implemented
|
|
108
101
|
- Create new files and modify existing files as needed
|
|
109
102
|
- Follow existing code patterns and conventions
|
|
110
103
|
|
|
111
|
-
4. **
|
|
112
|
-
- Run tests during development to catch issues early
|
|
113
|
-
- Ensure all existing tests continue to pass
|
|
104
|
+
4. **Validation**:
|
|
114
105
|
- Fix any lint or formatting issues
|
|
115
|
-
-
|
|
106
|
+
- Ensure the code builds successfully
|
|
116
107
|
|
|
117
108
|
5. **Commit Changes**:
|
|
118
109
|
- Stage all changes: git add .
|
|
@@ -127,6 +118,7 @@ Follow this systematic approach:
|
|
|
127
118
|
- Use proper TypeScript types and interfaces
|
|
128
119
|
- Add appropriate validation and error handling
|
|
129
120
|
- Follow the existing code patterns in the repository
|
|
121
|
+
- Focus on implementation only - automated tests will be written in a separate phase
|
|
130
122
|
|
|
131
123
|
Begin implementation based on the technical design and requirements provided above.`;
|
|
132
124
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
export interface CodeTestingOptions {
|
|
3
|
+
featureId: string;
|
|
4
|
+
mcpServerUrl: string;
|
|
5
|
+
mcpToken: string;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface CodeTestingResult {
|
|
9
|
+
featureId: string;
|
|
10
|
+
branchName: string;
|
|
11
|
+
testSummary: string | null;
|
|
12
|
+
status: 'success' | 'error';
|
|
13
|
+
message: string;
|
|
14
|
+
testFilesCreated?: string[];
|
|
15
|
+
testFilesModified?: string[];
|
|
16
|
+
commitHash?: string;
|
|
17
|
+
totalTestsWritten?: number;
|
|
18
|
+
testsPassing?: boolean;
|
|
19
|
+
testCoverage?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const writeCodeTests: (options: CodeTestingOptions, config: EdsgerConfig) => Promise<CodeTestingResult>;
|
|
22
|
+
export declare const checkCodeTestingRequirements: () => Promise<boolean>;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
2
|
+
import { logInfo, logError } from '../../utils/logger.js';
|
|
3
|
+
import { fetchCodeTestingContext, formatContextForPrompt, } from './context-fetcher.js';
|
|
4
|
+
import { createCodeTestingSystemPrompt, createCodeTestingPromptWithContext, } from './prompts.js';
|
|
5
|
+
function userMessage(content) {
|
|
6
|
+
return {
|
|
7
|
+
type: 'user',
|
|
8
|
+
message: { role: 'user', content: content },
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
async function* prompt(testingPrompt) {
|
|
12
|
+
yield userMessage(testingPrompt);
|
|
13
|
+
await new Promise((res) => setTimeout(res, 10000));
|
|
14
|
+
}
|
|
15
|
+
export const writeCodeTests = async (options, config) => {
|
|
16
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
17
|
+
if (verbose) {
|
|
18
|
+
logInfo(`Starting code testing phase for feature ID: ${featureId}`);
|
|
19
|
+
logInfo(`Using MCP server: ${mcpServerUrl}`);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
// Fetch all required context information via MCP endpoints
|
|
23
|
+
if (verbose) {
|
|
24
|
+
logInfo('Fetching code testing context via MCP endpoints...');
|
|
25
|
+
}
|
|
26
|
+
const context = await fetchCodeTestingContext(mcpServerUrl, mcpToken, featureId, verbose);
|
|
27
|
+
const systemPrompt = createCodeTestingSystemPrompt(config);
|
|
28
|
+
const testingPrompt = createCodeTestingPromptWithContext(featureId, formatContextForPrompt(context));
|
|
29
|
+
const branchName = `dev/${featureId}`;
|
|
30
|
+
if (verbose) {
|
|
31
|
+
logInfo('Starting Claude Code query for code testing...');
|
|
32
|
+
}
|
|
33
|
+
let lastAssistantResponse = '';
|
|
34
|
+
// Execute testing query
|
|
35
|
+
for await (const message of query({
|
|
36
|
+
prompt: prompt(testingPrompt),
|
|
37
|
+
options: {
|
|
38
|
+
appendSystemPrompt: systemPrompt,
|
|
39
|
+
model: config.claude.model || 'sonnet',
|
|
40
|
+
maxTurns: 3000,
|
|
41
|
+
permissionMode: 'bypassPermissions',
|
|
42
|
+
},
|
|
43
|
+
})) {
|
|
44
|
+
if (verbose) {
|
|
45
|
+
logInfo(`Received message type: ${message.type}`);
|
|
46
|
+
}
|
|
47
|
+
// Stream the testing process
|
|
48
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
49
|
+
for (const content of message.message.content) {
|
|
50
|
+
if (content.type === 'text') {
|
|
51
|
+
lastAssistantResponse += content.text + '\n';
|
|
52
|
+
if (verbose) {
|
|
53
|
+
console.log(`\n🤖 ${content.text}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (content.type === 'tool_use') {
|
|
57
|
+
if (verbose) {
|
|
58
|
+
console.log(`\n🔧 ${content.name}: ${content.input.description || 'Running...'}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (message.type === 'result') {
|
|
64
|
+
if (message.subtype === 'success') {
|
|
65
|
+
logInfo('\n✅ Code testing completed, parsing results...');
|
|
66
|
+
try {
|
|
67
|
+
const responseText = message.result || lastAssistantResponse;
|
|
68
|
+
let jsonResult = null;
|
|
69
|
+
// Try to extract JSON from markdown code block
|
|
70
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
71
|
+
if (jsonBlockMatch) {
|
|
72
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
jsonResult = JSON.parse(responseText);
|
|
76
|
+
}
|
|
77
|
+
if (jsonResult && jsonResult.code_test_result) {
|
|
78
|
+
const result = jsonResult.code_test_result;
|
|
79
|
+
return {
|
|
80
|
+
featureId,
|
|
81
|
+
branchName: result.branch_name || branchName,
|
|
82
|
+
testSummary: result.summary || 'Tests written successfully',
|
|
83
|
+
status: 'success',
|
|
84
|
+
message: result.summary || 'Code tests written successfully',
|
|
85
|
+
testFilesCreated: result.test_files_created || [],
|
|
86
|
+
testFilesModified: result.test_files_modified || [],
|
|
87
|
+
commitHash: result.commit_hash || '',
|
|
88
|
+
totalTestsWritten: result.total_tests_written || 0,
|
|
89
|
+
testsPassing: result.tests_passing || false,
|
|
90
|
+
testCoverage: result.test_coverage || '',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
throw new Error('Invalid JSON structure');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
logError(`Failed to parse structured test result: ${error}`);
|
|
99
|
+
// Fallback parsing
|
|
100
|
+
const parsedResult = parseTestingResponse(message.result || lastAssistantResponse, featureId);
|
|
101
|
+
return {
|
|
102
|
+
featureId,
|
|
103
|
+
branchName: parsedResult.branchName,
|
|
104
|
+
testSummary: parsedResult.summary || 'Tests written',
|
|
105
|
+
status: 'success',
|
|
106
|
+
message: parsedResult.summary || 'Code tests written successfully',
|
|
107
|
+
testFilesCreated: parsedResult.testFilesCreated,
|
|
108
|
+
testFilesModified: parsedResult.testFilesModified,
|
|
109
|
+
commitHash: parsedResult.commitHash,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
logError(`\n⚠️ Code testing incomplete: ${message.subtype}`);
|
|
115
|
+
if (message.subtype === 'error_max_turns') {
|
|
116
|
+
logError('💡 Try breaking down the testing into smaller tasks');
|
|
117
|
+
}
|
|
118
|
+
// Try to parse results from the last assistant response
|
|
119
|
+
if (lastAssistantResponse) {
|
|
120
|
+
try {
|
|
121
|
+
const responseText = lastAssistantResponse;
|
|
122
|
+
let jsonResult = null;
|
|
123
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
124
|
+
if (jsonBlockMatch) {
|
|
125
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
126
|
+
if (jsonResult && jsonResult.code_test_result) {
|
|
127
|
+
const result = jsonResult.code_test_result;
|
|
128
|
+
return {
|
|
129
|
+
featureId,
|
|
130
|
+
branchName: result.branch_name || branchName,
|
|
131
|
+
testSummary: result.summary || 'Tests partially written',
|
|
132
|
+
status: 'error',
|
|
133
|
+
message: result.summary || 'Code testing incomplete',
|
|
134
|
+
testFilesCreated: result.test_files_created || [],
|
|
135
|
+
testFilesModified: result.test_files_modified || [],
|
|
136
|
+
commitHash: result.commit_hash || '',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
logError(`Failed to parse assistant response: ${error}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// If we get here, no valid result was found
|
|
149
|
+
logError('⚠️ Code testing completed but no structured result found');
|
|
150
|
+
return {
|
|
151
|
+
featureId,
|
|
152
|
+
branchName,
|
|
153
|
+
testSummary: null,
|
|
154
|
+
status: 'error',
|
|
155
|
+
message: 'Code testing completed but could not extract results',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
logError(`Code testing failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
160
|
+
return {
|
|
161
|
+
featureId,
|
|
162
|
+
branchName: `dev/${featureId}`,
|
|
163
|
+
testSummary: null,
|
|
164
|
+
status: 'error',
|
|
165
|
+
message: `Testing failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const parseTestingResponse = (response, featureId) => {
|
|
170
|
+
console.log('Parsing code testing response...');
|
|
171
|
+
try {
|
|
172
|
+
// Try to find JSON in the response
|
|
173
|
+
const jsonMatch = response.match(/```json\s*([\s\S]*?)\s*```/) ||
|
|
174
|
+
response.match(/\{[\s\S]*"code_test_result"[\s\S]*\}/);
|
|
175
|
+
if (jsonMatch) {
|
|
176
|
+
const jsonStr = jsonMatch[1] || jsonMatch[0];
|
|
177
|
+
const parsed = JSON.parse(jsonStr);
|
|
178
|
+
if (parsed.code_test_result) {
|
|
179
|
+
const result = parsed.code_test_result;
|
|
180
|
+
return {
|
|
181
|
+
branchName: result.branch_name || `dev/${featureId}`,
|
|
182
|
+
testFilesCreated: result.test_files_created || [],
|
|
183
|
+
testFilesModified: result.test_files_modified || [],
|
|
184
|
+
commitHash: result.commit_hash || '',
|
|
185
|
+
summary: result.summary || '',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Fallback: try to extract information from the text
|
|
190
|
+
const branchMatch = response.match(/branch[:\s]+(\S+)/i);
|
|
191
|
+
const filesMatch = response.match(/files?[:\s]+([^\n]+)/i);
|
|
192
|
+
const commitMatch = response.match(/commit[:\s]+([a-f0-9]{7,})/i);
|
|
193
|
+
return {
|
|
194
|
+
branchName: branchMatch?.[1] || `dev/${featureId}`,
|
|
195
|
+
testFilesCreated: filesMatch
|
|
196
|
+
? filesMatch[1].split(/[,\s]+/).filter((f) => f)
|
|
197
|
+
: [],
|
|
198
|
+
testFilesModified: [],
|
|
199
|
+
commitHash: commitMatch?.[1] || '',
|
|
200
|
+
summary: 'Code tests written',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.log('Response parsing failed:', error);
|
|
205
|
+
return {
|
|
206
|
+
branchName: `dev/${featureId}`,
|
|
207
|
+
testFilesCreated: [],
|
|
208
|
+
testFilesModified: [],
|
|
209
|
+
commitHash: '',
|
|
210
|
+
summary: 'Code tests written',
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
export const checkCodeTestingRequirements = async () => {
|
|
215
|
+
try {
|
|
216
|
+
// Check if Claude Code SDK is available
|
|
217
|
+
const claudeCode = await import('@anthropic-ai/claude-code');
|
|
218
|
+
return claudeCode && typeof claudeCode.query === 'function';
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
console.log('Code testing requirements check failed:', error instanceof Error ? error.message : error);
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FeatureInfo, UserStory, TestCase } from '../../types/features.js';
|
|
2
|
+
import { type ProductInfo } from '../../api/products.js';
|
|
3
|
+
export interface CodeTestingContext {
|
|
4
|
+
feature: FeatureInfo;
|
|
5
|
+
product: ProductInfo;
|
|
6
|
+
user_stories: UserStory[];
|
|
7
|
+
test_cases: TestCase[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Fetch all code testing context information via MCP endpoints
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchCodeTestingContext(mcpServerUrl: string, mcpToken: string, featureId: string, verbose?: boolean): Promise<CodeTestingContext>;
|
|
13
|
+
/**
|
|
14
|
+
* Format the context into a readable string for Claude Code
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatContextForPrompt(context: CodeTestingContext): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { logInfo, logError } from '../../utils/logger.js';
|
|
2
|
+
import { getFeature, getUserStories, getTestCases, } from '../../api/features/index.js';
|
|
3
|
+
import { getProduct } from '../../api/products.js';
|
|
4
|
+
/**
|
|
5
|
+
* Fetch all code testing context information via MCP endpoints
|
|
6
|
+
*/
|
|
7
|
+
export async function fetchCodeTestingContext(mcpServerUrl, mcpToken, featureId, verbose) {
|
|
8
|
+
try {
|
|
9
|
+
if (verbose) {
|
|
10
|
+
logInfo(`Fetching complete code testing context for feature: ${featureId}`);
|
|
11
|
+
}
|
|
12
|
+
// Fetch all required data in parallel for better performance
|
|
13
|
+
const [feature, user_stories, test_cases] = await Promise.all([
|
|
14
|
+
getFeature(mcpServerUrl, mcpToken, featureId, verbose),
|
|
15
|
+
getUserStories(mcpServerUrl, mcpToken, featureId, verbose),
|
|
16
|
+
getTestCases(mcpServerUrl, mcpToken, featureId, verbose),
|
|
17
|
+
]);
|
|
18
|
+
const product = await getProduct(mcpServerUrl, mcpToken, feature.product_id, verbose);
|
|
19
|
+
if (verbose) {
|
|
20
|
+
logInfo(`✅ Code testing context fetched successfully:`);
|
|
21
|
+
logInfo(` Feature: ${feature.name}`);
|
|
22
|
+
logInfo(` Product: ${product.name}`);
|
|
23
|
+
logInfo(` User Stories: ${user_stories.length}`);
|
|
24
|
+
logInfo(` Test Cases: ${test_cases.length}`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
feature,
|
|
28
|
+
product,
|
|
29
|
+
user_stories,
|
|
30
|
+
test_cases,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
35
|
+
logError(`Failed to fetch code testing context: ${errorMessage}`);
|
|
36
|
+
throw new Error(`Context fetch failed: ${errorMessage}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Format the context into a readable string for Claude Code
|
|
41
|
+
*/
|
|
42
|
+
export function formatContextForPrompt(context) {
|
|
43
|
+
const formatUserStories = (stories) => {
|
|
44
|
+
if (stories.length === 0)
|
|
45
|
+
return 'No user stories defined.';
|
|
46
|
+
return stories
|
|
47
|
+
.map((story, index) => `${index + 1}. **${story.title}** (Status: ${story.status})
|
|
48
|
+
${story.description}`)
|
|
49
|
+
.join('\n\n');
|
|
50
|
+
};
|
|
51
|
+
const formatTestCases = (cases) => {
|
|
52
|
+
if (cases.length === 0)
|
|
53
|
+
return 'No test cases defined.';
|
|
54
|
+
return cases
|
|
55
|
+
.map((testCase, index) => `${index + 1}. **${testCase.name}** ${testCase.is_critical ? '[CRITICAL]' : '[OPTIONAL]'}
|
|
56
|
+
${testCase.description}`)
|
|
57
|
+
.join('\n\n');
|
|
58
|
+
};
|
|
59
|
+
return `# Code Testing Context
|
|
60
|
+
|
|
61
|
+
## Feature Information
|
|
62
|
+
- **ID**: ${context.feature.id}
|
|
63
|
+
- **Name**: ${context.feature.name}
|
|
64
|
+
- **Description**: ${context.feature.description || 'No description provided'}
|
|
65
|
+
- **Current Status**: ${context.feature.status}
|
|
66
|
+
|
|
67
|
+
## Product Information
|
|
68
|
+
- **Product**: ${context.product.name}
|
|
69
|
+
- **Product ID**: ${context.product.id}
|
|
70
|
+
- **Description**: ${context.product.description || 'No product description'}
|
|
71
|
+
|
|
72
|
+
## User Stories (${context.user_stories.length})
|
|
73
|
+
${formatUserStories(context.user_stories)}
|
|
74
|
+
|
|
75
|
+
## Test Cases (${context.test_cases.length})
|
|
76
|
+
${formatTestCases(context.test_cases)}
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
**Testing Instructions**: The feature has been implemented. Write comprehensive automated tests (unit tests, integration tests, etc.) for all implemented functionality based on the user stories and test cases provided above.`;
|
|
81
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export const createCodeTestingSystemPrompt = (_config) => {
|
|
2
|
+
return `You are an expert test engineer specializing in writing comprehensive automated tests. Your task is to write tests for the implemented code based on feature specifications.
|
|
3
|
+
|
|
4
|
+
**Your Role**: Write comprehensive automated tests (unit tests, integration tests, etc.) for the implemented feature based on requirements, user stories, and technical design.
|
|
5
|
+
|
|
6
|
+
**Available Tools**:
|
|
7
|
+
- Bash: Git operations, running tests, and commands
|
|
8
|
+
- Glob: Find files and understand project structure
|
|
9
|
+
- Read: Examine existing code and tests
|
|
10
|
+
- Edit: Modify existing test files
|
|
11
|
+
- Write: Create new test files
|
|
12
|
+
- TodoWrite: Track testing tasks (use proactively)
|
|
13
|
+
|
|
14
|
+
**CRITICAL WORKFLOW - YOU MUST FOLLOW THESE STEPS IN ORDER**:
|
|
15
|
+
|
|
16
|
+
1. **GIT CHECKOUT**: Checkout the feature branch that contains the implementation
|
|
17
|
+
2. **ANALYZE CODE**: Use Glob and Read to understand:
|
|
18
|
+
- The implemented code structure
|
|
19
|
+
- Existing test patterns and frameworks
|
|
20
|
+
- Test utilities and helpers available
|
|
21
|
+
- What needs to be tested
|
|
22
|
+
3. **WRITE TESTS**: Create comprehensive automated tests:
|
|
23
|
+
- Unit tests for individual functions and methods
|
|
24
|
+
- Integration tests for component interactions
|
|
25
|
+
- Test edge cases and error conditions
|
|
26
|
+
- Test data validation and transformations
|
|
27
|
+
- Follow existing test patterns
|
|
28
|
+
4. **RUN TESTS**: Execute tests to ensure they work correctly
|
|
29
|
+
5. **FIX ISSUES**: Address any failing tests or issues
|
|
30
|
+
6. **COMMIT**: Commit your test files with a descriptive message
|
|
31
|
+
|
|
32
|
+
**Important Rules**:
|
|
33
|
+
1. **Git Workflow**:
|
|
34
|
+
- Checkout the feature branch (dev/<feature-id>)
|
|
35
|
+
- Work on the same branch as the implementation
|
|
36
|
+
- Use descriptive commit messages for test changes
|
|
37
|
+
|
|
38
|
+
2. **Testing Standards**:
|
|
39
|
+
- Write clear, focused tests
|
|
40
|
+
- Follow existing test patterns and conventions
|
|
41
|
+
- Use appropriate test frameworks (Jest, Vitest, etc.)
|
|
42
|
+
- Write descriptive test names that explain what is being tested
|
|
43
|
+
- Use proper arrange-act-assert patterns
|
|
44
|
+
- Mock external dependencies appropriately
|
|
45
|
+
- Write both unit tests and integration tests as needed
|
|
46
|
+
|
|
47
|
+
3. **Test Coverage**:
|
|
48
|
+
- Test all critical functionality
|
|
49
|
+
- Include positive and negative test cases
|
|
50
|
+
- Test edge cases and boundary conditions
|
|
51
|
+
- Test error handling and validation
|
|
52
|
+
- Aim for high code coverage of critical paths
|
|
53
|
+
- Test component interactions and integrations
|
|
54
|
+
|
|
55
|
+
4. **Code Quality**:
|
|
56
|
+
- Follow project testing conventions
|
|
57
|
+
- Write maintainable, readable tests
|
|
58
|
+
- Avoid test duplication
|
|
59
|
+
- Keep tests focused and isolated
|
|
60
|
+
- Ensure tests are deterministic and reliable
|
|
61
|
+
|
|
62
|
+
**CRITICAL - Result Format**:
|
|
63
|
+
You MUST end your response with a JSON object containing the test results in this EXACT format:
|
|
64
|
+
|
|
65
|
+
\`\`\`json
|
|
66
|
+
{
|
|
67
|
+
"code_test_result": {
|
|
68
|
+
"feature_id": "FEATURE_ID_PLACEHOLDER",
|
|
69
|
+
"branch_name": "dev/feature-name",
|
|
70
|
+
"commit_hash": "abc123def456",
|
|
71
|
+
"summary": "Brief description of tests written",
|
|
72
|
+
"test_files_created": ["test-file1.test.ts", "test-file2.test.tsx"],
|
|
73
|
+
"test_files_modified": ["existing-test1.test.ts"],
|
|
74
|
+
"total_tests_written": 25,
|
|
75
|
+
"tests_passing": true,
|
|
76
|
+
"test_coverage": "Description of what functionality is covered by tests",
|
|
77
|
+
"status": "success",
|
|
78
|
+
"notes": "Any important notes about the tests"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
**Quality Expectations**:
|
|
84
|
+
- Comprehensive test coverage of implemented functionality
|
|
85
|
+
- Clear, maintainable test code
|
|
86
|
+
- All tests passing
|
|
87
|
+
- Proper use of test frameworks and utilities
|
|
88
|
+
- Good documentation of test scenarios
|
|
89
|
+
- Mix of unit and integration tests as appropriate
|
|
90
|
+
|
|
91
|
+
Focus on writing high-quality automated tests that verify the implementation works correctly.`;
|
|
92
|
+
};
|
|
93
|
+
export const createCodeTestingPromptWithContext = (featureId, contextInfo) => {
|
|
94
|
+
return `Write comprehensive automated tests for feature ID: ${featureId}
|
|
95
|
+
|
|
96
|
+
${contextInfo}
|
|
97
|
+
|
|
98
|
+
## Testing Instructions
|
|
99
|
+
|
|
100
|
+
Follow this systematic approach:
|
|
101
|
+
|
|
102
|
+
1. **Git Setup**:
|
|
103
|
+
- Checkout the feature branch: git checkout dev/${featureId}
|
|
104
|
+
- Ensure you're on the correct branch with the implementation
|
|
105
|
+
|
|
106
|
+
2. **Code Analysis**:
|
|
107
|
+
- Use Glob to find the implemented files
|
|
108
|
+
- Use Read to understand the code that needs testing
|
|
109
|
+
- Identify all functions, methods, and components to test
|
|
110
|
+
- Review existing test patterns in the codebase
|
|
111
|
+
|
|
112
|
+
3. **Write Automated Tests**:
|
|
113
|
+
- Create test files following project conventions
|
|
114
|
+
- Write unit tests for individual functions and methods
|
|
115
|
+
- Write integration tests for component interactions
|
|
116
|
+
- Include tests for:
|
|
117
|
+
- Happy path scenarios
|
|
118
|
+
- Edge cases and boundary conditions
|
|
119
|
+
- Error handling and validation
|
|
120
|
+
- Data transformations
|
|
121
|
+
- Component interactions
|
|
122
|
+
- Use appropriate mocking for dependencies
|
|
123
|
+
- Follow existing test patterns and conventions
|
|
124
|
+
|
|
125
|
+
4. **Run and Verify Tests**:
|
|
126
|
+
- Run the test suite to verify all tests pass
|
|
127
|
+
- Fix any failing tests
|
|
128
|
+
- Ensure good test coverage
|
|
129
|
+
|
|
130
|
+
5. **Commit Tests**:
|
|
131
|
+
- Stage test files: git add .
|
|
132
|
+
- Commit with descriptive message: git commit -m "test: add automated tests for [feature]"
|
|
133
|
+
|
|
134
|
+
## Important Testing Notes:
|
|
135
|
+
- Write both unit tests and integration tests as appropriate
|
|
136
|
+
- Test behavior, not implementation details
|
|
137
|
+
- Write clear, descriptive test names
|
|
138
|
+
- Keep tests isolated and independent
|
|
139
|
+
- Use proper test utilities and helpers
|
|
140
|
+
- Follow the existing test patterns in the repository
|
|
141
|
+
- Ensure all tests are deterministic and reliable
|
|
142
|
+
|
|
143
|
+
Begin by checking out the feature branch and analyzing the implemented code.`;
|
|
144
|
+
};
|
|
@@ -5,6 +5,7 @@ import { analyzeFeatureWithMCP, checkFeatureAnalysisRequirements, } from '../../
|
|
|
5
5
|
import { generateTechnicalDesign, checkTechnicalDesignRequirements, } from '../../phases/technical-design/analyzer.js';
|
|
6
6
|
import { implementFeatureCode, checkCodeImplementationRequirements, } from '../../phases/code-implementation/analyzer.js';
|
|
7
7
|
import { runFunctionalTesting, checkFunctionalTestingRequirements, } from '../../phases/functional-testing/analyzer.js';
|
|
8
|
+
import { writeCodeTests, checkCodeTestingRequirements, } from '../../phases/code-testing/analyzer.js';
|
|
8
9
|
import { refineCodeFromPRFeedback, checkCodeRefineRequirements, } from '../../phases/code-refine/analyzer.js';
|
|
9
10
|
import { verifyAndResolveComments, checkCodeRefineVerificationRequirements, } from '../../phases/code-refine-verification/verifier.js';
|
|
10
11
|
import { reviewPullRequest, checkCodeReviewRequirements, } from '../../phases/code-review/analyzer.js';
|
|
@@ -92,6 +93,12 @@ export const phaseConfigs = [
|
|
|
92
93
|
execute: runFunctionalTesting,
|
|
93
94
|
requirementsError: 'Functional testing requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
94
95
|
},
|
|
96
|
+
{
|
|
97
|
+
name: 'code-testing',
|
|
98
|
+
checkRequirements: checkCodeTestingRequirements,
|
|
99
|
+
execute: writeCodeTests,
|
|
100
|
+
requirementsError: 'Code testing requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
101
|
+
},
|
|
95
102
|
{
|
|
96
103
|
name: 'code-refine',
|
|
97
104
|
checkRequirements: checkCodeRefineRequirements,
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
import { EdsgerConfig } from '../../types/index.js';
|
|
5
5
|
import { PipelinePhaseOptions, PipelineResult, PhaseConfig } from '../../types/pipeline.js';
|
|
6
6
|
export declare const createPhaseRunner: (phaseConfig: PhaseConfig) => (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
7
|
-
declare const runFeatureAnalysisPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefinePhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefineVerificationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeReviewPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
8
|
-
export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
|
|
7
|
+
declare const runFeatureAnalysisPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefinePhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefineVerificationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeReviewPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
8
|
+
export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
|
|
@@ -243,6 +243,6 @@ export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
|
243
243
|
}
|
|
244
244
|
};
|
|
245
245
|
// Create phase runners using the configuration
|
|
246
|
-
const [runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase,] = phaseConfigs.map(createPhaseRunner);
|
|
246
|
+
const [runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase,] = phaseConfigs.map(createPhaseRunner);
|
|
247
247
|
// Export individual phase runners for granular control
|
|
248
|
-
export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
|
|
248
|
+
export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Uses functional programming principles
|
|
7
7
|
*/
|
|
8
8
|
import { updateFeatureStatusForPhase } from '../api/features/index.js';
|
|
9
|
-
import { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeReviewPhase, } from './executors/phase-executor.js';
|
|
9
|
+
import { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeReviewPhase, } from './executors/phase-executor.js';
|
|
10
10
|
import { logPipelineStart, logPhaseResult, logPipelineComplete, shouldContinuePipeline, } from '../utils/pipeline-logger.js';
|
|
11
11
|
import { handleTestFailuresWithRetry } from '../phases/functional-testing/test-retry-handler.js';
|
|
12
12
|
import { handleCodeRefineWithRetry } from '../phases/code-refine/retry-handler.js';
|
|
@@ -362,7 +362,7 @@ const runFromCodeReview = async (options, config) => {
|
|
|
362
362
|
};
|
|
363
363
|
/**
|
|
364
364
|
* Continue with code review and refine after PR creation
|
|
365
|
-
* This is the post-PR workflow: code-review → code-refine → code-refine-verification
|
|
365
|
+
* This is the post-PR workflow: code-review → code-refine → code-refine-verification → code-testing
|
|
366
366
|
*/
|
|
367
367
|
const continueWithCodeReviewAndRefine = async (options, config, results, verbose) => {
|
|
368
368
|
if (verbose) {
|
|
@@ -381,4 +381,13 @@ const continueWithCodeReviewAndRefine = async (options, config, results, verbose
|
|
|
381
381
|
results,
|
|
382
382
|
verbose,
|
|
383
383
|
});
|
|
384
|
+
if (!shouldContinuePipeline(results)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
// 3. Code Testing - write automated tests for the implemented code
|
|
388
|
+
if (verbose) {
|
|
389
|
+
console.log('\n📝 Starting code testing phase...');
|
|
390
|
+
}
|
|
391
|
+
const testingResult = await runCodeTestingPhase(options, config);
|
|
392
|
+
results.push(logPhaseResult(testingResult, verbose));
|
|
384
393
|
};
|