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.
@@ -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. **TEST**: Run tests to ensure everything works
378
- 6. **FIX ISSUES**: Address any lint or test failures
379
- 7. **COMMIT**: Commit your changes with a descriptive message
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. **Testing**:
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. **TEST IMPLEMENTATION**: Run tests to ensure:
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
- 3. **IMPLEMENT CODE**: Write the actual implementation using Edit/Write tools
22
- 4. **TEST**: Run tests to ensure everything works
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. **Testing**:
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 and ensure ALL test cases can pass
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. **Testing & Validation**:
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
- - Test the implemented functionality thoroughly
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,2 @@
1
+ export { writeCodeTests, checkCodeTestingRequirements, type CodeTestingOptions, type CodeTestingResult, } from './analyzer.js';
2
+ export { fetchCodeTestingContext, formatContextForPrompt, type CodeTestingContext, } from './context-fetcher.js';
@@ -0,0 +1,2 @@
1
+ export { writeCodeTests, checkCodeTestingRequirements, } from './analyzer.js';
2
+ export { fetchCodeTestingContext, formatContextForPrompt, } from './context-fetcher.js';
@@ -0,0 +1,3 @@
1
+ import { EdsgerConfig } from '../../types/index.js';
2
+ export declare const createCodeTestingSystemPrompt: (_config: EdsgerConfig) => string;
3
+ export declare const createCodeTestingPromptWithContext: (featureId: string, contextInfo: string) => string;
@@ -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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {