edsger 0.2.3 → 0.2.5
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/README.md +17 -0
- package/dist/api/features/batch-operations.d.ts +16 -0
- package/dist/api/features/batch-operations.js +100 -0
- package/dist/api/features/index.d.ts +1 -0
- package/dist/api/features/index.js +1 -0
- package/dist/api/features/test-cases.d.ts +8 -0
- package/dist/api/features/test-cases.js +45 -0
- package/dist/api/features/user-stories.d.ts +8 -0
- package/dist/api/features/user-stories.js +45 -0
- package/dist/cli/commands/refactor-command.d.ts +2 -0
- package/dist/cli/commands/refactor-command.js +123 -0
- package/dist/cli/formatters/formatter-utils.d.ts +23 -0
- package/dist/cli/formatters/formatter-utils.js +67 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/utils/command-handler.d.ts +23 -0
- package/dist/cli/utils/command-handler.js +39 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +4 -99
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +2 -0
- package/dist/phases/code-implementation/analyzer.js +304 -175
- package/dist/phases/code-implementation-verification/index.d.ts +1 -0
- package/dist/phases/code-implementation-verification/index.js +1 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +62 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +450 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +1 -0
- package/dist/phases/feature-analysis/analyzer.js +132 -219
- package/dist/phases/feature-analysis-verification/index.d.ts +1 -0
- package/dist/phases/feature-analysis-verification/index.js +1 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/pull-request/creator.js +2 -1
- package/dist/phases/technical-design/analyzer-helpers.d.ts +37 -0
- package/dist/phases/technical-design/analyzer-helpers.js +144 -0
- package/dist/phases/technical-design/analyzer.d.ts +3 -0
- package/dist/phases/technical-design/analyzer.js +282 -318
- package/dist/phases/technical-design-verification/index.d.ts +1 -0
- package/dist/phases/technical-design-verification/index.js +1 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +36 -0
- package/dist/phases/technical-design-verification/verifier.js +147 -0
- package/dist/prompts/checklist-verification.d.ts +11 -0
- package/dist/prompts/checklist-verification.js +153 -0
- package/dist/prompts/code-implementation-improvement.d.ts +5 -0
- package/dist/prompts/code-implementation-improvement.js +108 -0
- package/dist/prompts/code-implementation-verification.d.ts +3 -0
- package/dist/prompts/code-implementation-verification.js +176 -0
- package/dist/prompts/feature-analysis-improvement.d.ts +8 -0
- package/dist/prompts/feature-analysis-improvement.js +109 -0
- package/dist/prompts/feature-analysis.js +1 -1
- package/dist/prompts/technical-design-improvement.d.ts +5 -0
- package/dist/prompts/technical-design-improvement.js +93 -0
- package/dist/prompts/technical-design-verification.d.ts +11 -0
- package/dist/prompts/technical-design-verification.js +134 -0
- package/dist/prompts/technical-design.js +1 -1
- package/dist/services/audit-logs.d.ts +60 -0
- package/dist/services/audit-logs.js +115 -0
- package/dist/services/checklist.d.ts +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/workflow-runner/executors/phase-executor.js +56 -12
- package/package.json +1 -1
- package/dist/api/features.d.ts +0 -100
- package/dist/api/features.js +0 -219
- package/dist/logger.d.ts +0 -19
- package/dist/logger.js +0 -52
- package/dist/types.d.ts +0 -99
- package/dist/types.js +0 -1
- package/dist/utils/image-processor.d.ts +0 -5
- package/dist/utils/image-processor.js +0 -55
- package/dist/workflow-runner/config/stage-configs.d.ts +0 -5
- package/dist/workflow-runner/config/stage-configs.js +0 -34
- package/dist/workflow-runner/core/feature-filter.test.d.ts +0 -4
- package/dist/workflow-runner/core/feature-filter.test.js +0 -127
- package/dist/workflow-runner/executors/stage-executor.d.ts +0 -8
- package/dist/workflow-runner/executors/stage-executor.js +0 -49
- package/dist/workflow-runner/feature-fetcher.d.ts +0 -41
- package/dist/workflow-runner/feature-fetcher.js +0 -121
- package/dist/workflow-runner/feature-service.d.ts +0 -17
- package/dist/workflow-runner/feature-service.js +0 -60
- package/dist/workflow-runner/pipeline.d.ts +0 -18
- package/dist/workflow-runner/pipeline.js +0 -197
- package/dist/workflow-runner/processor.d.ts +0 -40
- package/dist/workflow-runner/processor.js +0 -191
- package/dist/workflow-runner/status-updater.d.ts +0 -27
- package/dist/workflow-runner/status-updater.js +0 -80
- package/dist/workflow-runner/types.d.ts +0 -48
- package/dist/workflow-runner/types.js +0 -4
|
@@ -2,6 +2,8 @@ import { query } from '@anthropic-ai/claude-code';
|
|
|
2
2
|
import { logInfo, logError } from '../../utils/logger.js';
|
|
3
3
|
import { formatChecklistsForContext, } from '../../services/checklist.js';
|
|
4
4
|
import { fetchCodeImplementationContext, formatContextForPrompt, } from './context-fetcher.js';
|
|
5
|
+
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
6
|
+
import { performVerificationCycle, buildImplementationResult, buildVerificationFailureResult, buildNoResultsError, } from './analyzer-helpers.js';
|
|
5
7
|
function userMessage(content) {
|
|
6
8
|
return {
|
|
7
9
|
type: 'user',
|
|
@@ -26,204 +28,284 @@ export const implementFeatureCode = async (options, config, checklistContext) =>
|
|
|
26
28
|
}
|
|
27
29
|
const context = await fetchCodeImplementationContext(mcpServerUrl, mcpToken, featureId, verbose);
|
|
28
30
|
const systemPrompt = createSystemPrompt(config, baseBranch, mcpServerUrl, mcpToken, featureId);
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
+
const initialImplementationPrompt = createImplementationPromptWithContext(featureId, context, baseBranch, checklistContext, verbose);
|
|
32
|
+
const maxIterations = options.maxVerificationIterations || 10;
|
|
33
|
+
let currentIteration = 0;
|
|
34
|
+
let currentPrompt = initialImplementationPrompt;
|
|
31
35
|
let structuredImplementationResult = null;
|
|
36
|
+
let verificationResult = null;
|
|
37
|
+
const branchName = `dev/${featureId}`;
|
|
32
38
|
if (verbose) {
|
|
33
39
|
logInfo('Starting Claude Code query with pre-fetched information...');
|
|
34
40
|
}
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const totalItems = checklistContext.checklists.reduce((sum, checklist) => sum + (checklist.items?.length || 0), 0);
|
|
41
|
-
console.log('Total checklist items:', totalItems);
|
|
42
|
-
}
|
|
43
|
-
console.log('Implementation prompt includes checklist:', implementationPrompt.includes('checklist'));
|
|
44
|
-
console.log('System prompt includes checklist:', systemPrompt.includes('checklist'));
|
|
45
|
-
// Use Claude Code SDK without MCP servers - all info is pre-fetched
|
|
46
|
-
for await (const message of query({
|
|
47
|
-
prompt: prompt(implementationPrompt),
|
|
48
|
-
options: {
|
|
49
|
-
appendSystemPrompt: systemPrompt,
|
|
50
|
-
model: config.claude.model || 'sonnet',
|
|
51
|
-
maxTurns: 3000,
|
|
52
|
-
permissionMode: 'bypassPermissions',
|
|
53
|
-
},
|
|
54
|
-
})) {
|
|
55
|
-
if (verbose) {
|
|
56
|
-
logInfo(`Received message type: ${message.type}`);
|
|
41
|
+
// Iterative improvement loop: implement → verify → improve → re-implement
|
|
42
|
+
while (currentIteration < maxIterations) {
|
|
43
|
+
currentIteration++;
|
|
44
|
+
if (verbose && currentIteration > 1) {
|
|
45
|
+
logInfo(`\n🔄 Iteration ${currentIteration}/${maxIterations}: Improving implementation based on code review feedback...`);
|
|
57
46
|
}
|
|
58
|
-
//
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
47
|
+
// Log iteration start (for iterations after the first)
|
|
48
|
+
if (currentIteration > 1) {
|
|
49
|
+
await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
|
|
50
|
+
featureId,
|
|
51
|
+
eventType: 'phase_started',
|
|
52
|
+
phase: 'code_implementation',
|
|
53
|
+
result: 'info',
|
|
54
|
+
metadata: {
|
|
55
|
+
iteration: currentIteration,
|
|
56
|
+
max_iterations: maxIterations,
|
|
57
|
+
re_implementation: true,
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
},
|
|
60
|
+
}, verbose);
|
|
73
61
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
console.log('Matched JSON first 100 chars:', JSON.stringify(jsonBlockMatch[1].substring(0, 100)));
|
|
107
|
-
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
console.log('=== DEBUG: Trying direct JSON parse ===');
|
|
111
|
-
// Try to parse the entire response as JSON
|
|
112
|
-
jsonResult = JSON.parse(responseText);
|
|
113
|
-
}
|
|
114
|
-
console.log('=== DEBUG: Final Result Processing ===');
|
|
115
|
-
console.log('jsonResult exists:', !!jsonResult);
|
|
116
|
-
console.log('jsonResult has implementation_result:', !!(jsonResult && jsonResult.implementation_result));
|
|
117
|
-
if (jsonResult && jsonResult.implementation_result) {
|
|
118
|
-
const implResult = jsonResult.implementation_result;
|
|
119
|
-
console.log('=== DEBUG: Implementation Result Structure ===');
|
|
120
|
-
console.log('Keys in implementation_result:', Object.keys(implResult));
|
|
121
|
-
console.log('Has checklist_item_results field:', 'checklist_item_results' in implResult);
|
|
122
|
-
console.log('checklist_item_results value type:', typeof implResult.checklist_item_results);
|
|
123
|
-
console.log('checklist_item_results is array:', Array.isArray(implResult.checklist_item_results));
|
|
124
|
-
if (implResult.checklist_item_results) {
|
|
125
|
-
console.log('checklist_item_results length:', implResult.checklist_item_results.length);
|
|
126
|
-
if (implResult.checklist_item_results.length > 0) {
|
|
127
|
-
console.log('First checklist item keys:', Object.keys(implResult.checklist_item_results[0]));
|
|
128
|
-
console.log('First checklist item sample:', JSON.stringify(implResult.checklist_item_results[0], null, 2));
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
console.log('checklist_item_results is null/undefined/empty');
|
|
62
|
+
let lastAssistantResponse = '';
|
|
63
|
+
let newImplementationResult = null;
|
|
64
|
+
// DEBUG: Log checklist context before query
|
|
65
|
+
console.log('=== DEBUG: Checklist Context Before Claude Query ===');
|
|
66
|
+
console.log('Has checklistContext:', !!checklistContext);
|
|
67
|
+
if (checklistContext) {
|
|
68
|
+
console.log('Number of checklists:', checklistContext.checklists.length);
|
|
69
|
+
const totalItems = checklistContext.checklists.reduce((sum, checklist) => sum + (checklist.items?.length || 0), 0);
|
|
70
|
+
console.log('Total checklist items:', totalItems);
|
|
71
|
+
}
|
|
72
|
+
console.log('Implementation prompt includes checklist:', currentPrompt.includes('checklist'));
|
|
73
|
+
console.log('System prompt includes checklist:', systemPrompt.includes('checklist'));
|
|
74
|
+
// Execute implementation query
|
|
75
|
+
for await (const message of query({
|
|
76
|
+
prompt: prompt(currentPrompt),
|
|
77
|
+
options: {
|
|
78
|
+
appendSystemPrompt: systemPrompt,
|
|
79
|
+
model: config.claude.model || 'sonnet',
|
|
80
|
+
maxTurns: 3000,
|
|
81
|
+
permissionMode: 'bypassPermissions',
|
|
82
|
+
},
|
|
83
|
+
})) {
|
|
84
|
+
if (verbose) {
|
|
85
|
+
logInfo(`Received message type: ${message.type}`);
|
|
86
|
+
}
|
|
87
|
+
// Stream the implementation process
|
|
88
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
89
|
+
for (const content of message.message.content) {
|
|
90
|
+
if (content.type === 'text') {
|
|
91
|
+
lastAssistantResponse += content.text + '\n';
|
|
92
|
+
if (verbose) {
|
|
93
|
+
console.log(`\n🤖 ${content.text}`);
|
|
133
94
|
}
|
|
134
|
-
structuredImplementationResult = jsonResult.implementation_result;
|
|
135
|
-
console.log('Successfully extracted implementation_result');
|
|
136
95
|
}
|
|
137
|
-
else {
|
|
138
|
-
|
|
139
|
-
|
|
96
|
+
else if (content.type === 'tool_use') {
|
|
97
|
+
if (verbose) {
|
|
98
|
+
console.log(`\n🔧 ${content.name}: ${content.input.description || 'Running...'}`);
|
|
99
|
+
}
|
|
140
100
|
}
|
|
141
101
|
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
console.log('=== DEBUG: JSON Parsing Failed ===');
|
|
144
|
-
console.log('Error type:', error instanceof SyntaxError
|
|
145
|
-
? 'SyntaxError'
|
|
146
|
-
: error instanceof Error
|
|
147
|
-
? error.constructor.name
|
|
148
|
-
: 'Unknown');
|
|
149
|
-
console.log('Error message:', error instanceof Error ? error.message : String(error));
|
|
150
|
-
logError(`Failed to parse structured implementation result: ${error}`);
|
|
151
|
-
console.log('=== DEBUG: Using Fallback Parsing ===');
|
|
152
|
-
// Fallback parsing
|
|
153
|
-
const parsedResult = parseImplementationResponse(message.result || lastAssistantResponse, featureId);
|
|
154
|
-
console.log('Fallback parsed result:', {
|
|
155
|
-
branchName: parsedResult.branchName,
|
|
156
|
-
filesModifiedCount: parsedResult.filesModified?.length || 0,
|
|
157
|
-
hasSummary: !!parsedResult.summary,
|
|
158
|
-
commitHash: parsedResult.commitHash,
|
|
159
|
-
});
|
|
160
|
-
structuredImplementationResult = {
|
|
161
|
-
branch_name: parsedResult.branchName,
|
|
162
|
-
files_modified: parsedResult.filesModified,
|
|
163
|
-
commit_hash: parsedResult.commitHash,
|
|
164
|
-
summary: parsedResult.summary || 'Implementation completed',
|
|
165
|
-
tests_passed: true,
|
|
166
|
-
pre_commit_passed: true,
|
|
167
|
-
checklist_item_results: parsedResult.checklist_item_results || [],
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
102
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
logError('💡 Try breaking down the feature into smaller tasks');
|
|
175
|
-
}
|
|
176
|
-
// Try to parse results from the last assistant response
|
|
177
|
-
if (lastAssistantResponse) {
|
|
178
|
-
console.log('=== DEBUG: Fallback for incomplete result ===');
|
|
179
|
-
console.log('message.subtype:', message.subtype);
|
|
103
|
+
if (message.type === 'result') {
|
|
104
|
+
if (message.subtype === 'success') {
|
|
105
|
+
logInfo('\n💻 Code implementation completed, parsing results...');
|
|
180
106
|
try {
|
|
181
|
-
|
|
107
|
+
// Try to extract JSON from markdown code block or parse directly
|
|
108
|
+
const responseText = message.result || lastAssistantResponse;
|
|
182
109
|
let jsonResult = null;
|
|
183
|
-
|
|
184
|
-
console.log('
|
|
110
|
+
// DEBUG: Log response text details and checklist content
|
|
111
|
+
console.log('=== DEBUG: Code Implementation Response Analysis ===');
|
|
112
|
+
console.log('message.result exists:', !!message.result);
|
|
113
|
+
console.log('lastAssistantResponse exists:', !!lastAssistantResponse);
|
|
114
|
+
console.log('responseText length:', responseText.length);
|
|
115
|
+
console.log('responseText first 200 chars:', JSON.stringify(responseText.substring(0, 200)));
|
|
116
|
+
console.log('responseText last 200 chars:', JSON.stringify(responseText.substring(responseText.length - 200)));
|
|
117
|
+
console.log('Contains ```json:', responseText.includes('```json'));
|
|
118
|
+
console.log('Contains implementation_result:', responseText.includes('"implementation_result"'));
|
|
119
|
+
console.log('=== DEBUG: Checklist Content in Response ===');
|
|
120
|
+
console.log('Contains "checklist":', responseText.toLowerCase().includes('checklist'));
|
|
121
|
+
console.log('Contains "checklist_item_results":', responseText.includes('checklist_item_results'));
|
|
122
|
+
console.log('Contains checklist_item_id:', responseText.includes('checklist_item_id'));
|
|
123
|
+
console.log('Contains is_passed:', responseText.includes('is_passed'));
|
|
124
|
+
// Count checklist-related occurrences
|
|
125
|
+
const checklistMatches = responseText.match(/checklist/gi) || [];
|
|
126
|
+
const checklistItemMatches = responseText.match(/checklist_item/gi) || [];
|
|
127
|
+
console.log('Total "checklist" mentions:', checklistMatches.length);
|
|
128
|
+
console.log('Total "checklist_item" mentions:', checklistItemMatches.length);
|
|
129
|
+
// First try to extract JSON from markdown code block
|
|
185
130
|
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
186
|
-
console.log('
|
|
131
|
+
console.log('=== DEBUG: Markdown Block Match ===');
|
|
132
|
+
console.log('jsonBlockMatch found:', !!jsonBlockMatch);
|
|
187
133
|
if (jsonBlockMatch) {
|
|
134
|
+
console.log('Matched JSON length:', jsonBlockMatch[1].length);
|
|
135
|
+
console.log('Matched JSON first 100 chars:', JSON.stringify(jsonBlockMatch[1].substring(0, 100)));
|
|
188
136
|
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log('=== DEBUG: Trying direct JSON parse ===');
|
|
140
|
+
// Try to parse the entire response as JSON
|
|
141
|
+
jsonResult = JSON.parse(responseText);
|
|
142
|
+
}
|
|
143
|
+
console.log('=== DEBUG: Final Result Processing ===');
|
|
144
|
+
console.log('jsonResult exists:', !!jsonResult);
|
|
145
|
+
console.log('jsonResult has implementation_result:', !!(jsonResult && jsonResult.implementation_result));
|
|
146
|
+
if (jsonResult && jsonResult.implementation_result) {
|
|
147
|
+
const implResult = jsonResult.implementation_result;
|
|
148
|
+
console.log('=== DEBUG: Implementation Result Structure ===');
|
|
149
|
+
console.log('Keys in implementation_result:', Object.keys(implResult));
|
|
150
|
+
console.log('Has checklist_item_results field:', 'checklist_item_results' in implResult);
|
|
151
|
+
console.log('checklist_item_results value type:', typeof implResult.checklist_item_results);
|
|
152
|
+
console.log('checklist_item_results is array:', Array.isArray(implResult.checklist_item_results));
|
|
153
|
+
if (implResult.checklist_item_results) {
|
|
154
|
+
console.log('checklist_item_results length:', implResult.checklist_item_results.length);
|
|
155
|
+
if (implResult.checklist_item_results.length > 0) {
|
|
156
|
+
console.log('First checklist item keys:', Object.keys(implResult.checklist_item_results[0]));
|
|
157
|
+
console.log('First checklist item sample:', JSON.stringify(implResult.checklist_item_results[0], null, 2));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
console.log('checklist_item_results is null/undefined/empty');
|
|
192
162
|
}
|
|
163
|
+
newImplementationResult = jsonResult.implementation_result;
|
|
164
|
+
console.log('Successfully extracted implementation_result');
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.log('ERROR: Invalid JSON structure - missing implementation_result');
|
|
168
|
+
throw new Error('Invalid JSON structure');
|
|
193
169
|
}
|
|
194
170
|
}
|
|
195
171
|
catch (error) {
|
|
196
|
-
|
|
172
|
+
console.log('=== DEBUG: JSON Parsing Failed ===');
|
|
173
|
+
console.log('Error type:', error instanceof SyntaxError
|
|
174
|
+
? 'SyntaxError'
|
|
175
|
+
: error instanceof Error
|
|
176
|
+
? error.constructor.name
|
|
177
|
+
: 'Unknown');
|
|
178
|
+
console.log('Error message:', error instanceof Error ? error.message : String(error));
|
|
179
|
+
logError(`Failed to parse structured implementation result: ${error}`);
|
|
180
|
+
console.log('=== DEBUG: Using Fallback Parsing ===');
|
|
181
|
+
// Fallback parsing
|
|
182
|
+
const parsedResult = parseImplementationResponse(message.result || lastAssistantResponse, featureId);
|
|
183
|
+
console.log('Fallback parsed result:', {
|
|
184
|
+
branchName: parsedResult.branchName,
|
|
185
|
+
filesModifiedCount: parsedResult.filesModified?.length || 0,
|
|
186
|
+
hasSummary: !!parsedResult.summary,
|
|
187
|
+
commitHash: parsedResult.commitHash,
|
|
188
|
+
});
|
|
189
|
+
newImplementationResult = {
|
|
190
|
+
branch_name: parsedResult.branchName,
|
|
191
|
+
files_modified: parsedResult.filesModified,
|
|
192
|
+
commit_hash: parsedResult.commitHash,
|
|
193
|
+
summary: parsedResult.summary || 'Implementation completed',
|
|
194
|
+
tests_passed: true,
|
|
195
|
+
pre_commit_passed: true,
|
|
196
|
+
checklist_item_results: parsedResult.checklist_item_results || [],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
logError(`\n⚠️ Code implementation incomplete: ${message.subtype}`);
|
|
202
|
+
if (message.subtype === 'error_max_turns') {
|
|
203
|
+
logError('💡 Try breaking down the feature into smaller tasks');
|
|
204
|
+
}
|
|
205
|
+
// Try to parse results from the last assistant response
|
|
206
|
+
if (lastAssistantResponse) {
|
|
207
|
+
console.log('=== DEBUG: Fallback for incomplete result ===');
|
|
208
|
+
console.log('message.subtype:', message.subtype);
|
|
209
|
+
try {
|
|
210
|
+
const responseText = lastAssistantResponse;
|
|
211
|
+
let jsonResult = null;
|
|
212
|
+
console.log('lastAssistantResponse length:', responseText.length);
|
|
213
|
+
console.log('lastAssistantResponse first 200 chars:', JSON.stringify(responseText.substring(0, 200)));
|
|
214
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
215
|
+
console.log('jsonBlockMatch in fallback found:', !!jsonBlockMatch);
|
|
216
|
+
if (jsonBlockMatch) {
|
|
217
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
218
|
+
if (jsonResult && jsonResult.implementation_result) {
|
|
219
|
+
newImplementationResult = jsonResult.implementation_result;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
logError(`Failed to parse assistant response: ${error}`);
|
|
225
|
+
}
|
|
197
226
|
}
|
|
198
227
|
}
|
|
199
228
|
}
|
|
200
229
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
230
|
+
// Check if implementation produced results
|
|
231
|
+
if (!newImplementationResult) {
|
|
232
|
+
if (verbose) {
|
|
233
|
+
logError('⚠️ Implementation failed in this iteration');
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
// Update with new implementation result
|
|
238
|
+
structuredImplementationResult = newImplementationResult;
|
|
239
|
+
// Log implementation completion for this iteration
|
|
240
|
+
await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
|
|
205
241
|
featureId,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
242
|
+
eventType: 'phase_completed',
|
|
243
|
+
phase: 'code_implementation',
|
|
244
|
+
result: 'success',
|
|
245
|
+
metadata: {
|
|
246
|
+
iteration: currentIteration,
|
|
247
|
+
max_iterations: maxIterations,
|
|
248
|
+
implementation_step: 'completed',
|
|
249
|
+
branch_name: structuredImplementationResult.branch_name,
|
|
250
|
+
files_modified: structuredImplementationResult.files_modified || [],
|
|
251
|
+
commit_hash: structuredImplementationResult.commit_hash || '',
|
|
252
|
+
timestamp: new Date().toISOString(),
|
|
215
253
|
},
|
|
216
|
-
};
|
|
254
|
+
}, verbose);
|
|
255
|
+
// Push code to remote after commit
|
|
256
|
+
if (verbose) {
|
|
257
|
+
logInfo(`📤 Pushing code to remote repository...`);
|
|
258
|
+
}
|
|
259
|
+
const pushResult = await pushToRemote(structuredImplementationResult.branch_name || branchName, verbose);
|
|
260
|
+
if (!pushResult.success && verbose) {
|
|
261
|
+
logError(`⚠️ Failed to push to remote: ${pushResult.error}`);
|
|
262
|
+
logInfo(' Code is committed locally and will be reviewed. Manual push may be needed.');
|
|
263
|
+
}
|
|
264
|
+
else if (verbose) {
|
|
265
|
+
logInfo('✅ Code pushed to remote successfully');
|
|
266
|
+
}
|
|
267
|
+
// Perform verification cycle
|
|
268
|
+
const verificationCycle = await performVerificationCycle(structuredImplementationResult.branch_name || branchName, baseBranch, checklistContext || null, featureId, context.feature.name, context.feature.description, config, currentIteration, maxIterations, mcpServerUrl, mcpToken, verbose);
|
|
269
|
+
verificationResult = verificationCycle.verificationResult;
|
|
270
|
+
// If verification passed, exit
|
|
271
|
+
if (verificationCycle.passed) {
|
|
272
|
+
if (verbose) {
|
|
273
|
+
logInfo('✅ Verification passed! Code implementation complete.');
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
// Verification failed
|
|
278
|
+
if (currentIteration < maxIterations && verificationCycle.nextPrompt) {
|
|
279
|
+
// We have more iterations - retry with improvement prompt
|
|
280
|
+
if (verbose) {
|
|
281
|
+
logInfo(`🔄 Will improve implementation in next iteration (${maxIterations - currentIteration} attempts remaining)`);
|
|
282
|
+
}
|
|
283
|
+
currentPrompt = verificationCycle.nextPrompt;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
// Max iterations reached or no next prompt - exit loop
|
|
287
|
+
if (verbose) {
|
|
288
|
+
logInfo('⚠️ Max iterations reached. Last implementation committed.');
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
217
292
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
293
|
+
// Handle results
|
|
294
|
+
if (!structuredImplementationResult) {
|
|
295
|
+
return buildNoResultsError(featureId, branchName);
|
|
296
|
+
}
|
|
297
|
+
const { branch_name, files_modified, commit_hash, summary, checklist_results, checklist_item_results, } = structuredImplementationResult;
|
|
298
|
+
// Check if verification failed after all iterations
|
|
299
|
+
if (verificationResult &&
|
|
300
|
+
verificationResult.rejected_count > 0 &&
|
|
301
|
+
checklistContext &&
|
|
302
|
+
checklistContext.checklists.length > 0) {
|
|
303
|
+
logError(`❌ Final result: Code verification FAILED after ${currentIteration} iterations`);
|
|
304
|
+
logError(` Code committed for manual review`);
|
|
305
|
+
return buildVerificationFailureResult(featureId, branch_name || branchName, summary || 'Implementation completed with verification failures', files_modified || [], commit_hash || '', verificationResult, currentIteration);
|
|
226
306
|
}
|
|
307
|
+
// Return success result
|
|
308
|
+
return buildImplementationResult(featureId, branch_name || branchName, summary || 'Implementation completed successfully', files_modified || [], commit_hash || '', currentIteration, checklist_results, checklist_item_results);
|
|
227
309
|
}
|
|
228
310
|
catch (error) {
|
|
229
311
|
logError(`Code implementation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -273,11 +355,11 @@ CRITICAL: Checklists are not optional suggestions - they are mandatory quality g
|
|
|
273
355
|
- git pull origin ${baseBranch} --rebase
|
|
274
356
|
2. **CREATE BRANCH**: Create a new feature branch from ${baseBranch}
|
|
275
357
|
3. **ANALYZE CODEBASE**: Use Glob and Read to understand the existing code structure
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
358
|
+
4. **IMPLEMENT CODE**: Write the actual implementation using Edit/Write tools
|
|
359
|
+
5. **TEST**: Run tests to ensure everything works
|
|
360
|
+
6. **FIX ISSUES**: Address any lint or test failures
|
|
361
|
+
7. **COMMIT**: Commit your changes with a descriptive message
|
|
362
|
+
8. **HANDLE PRE-COMMIT**: This project has strict pre-commit hooks - handle them properly:
|
|
281
363
|
- If lint-staged fails: Fix formatting and linting issues, then retry commit
|
|
282
364
|
- If AI code review fails: Either fix code quality issues or use SKIP_REVIEW=1
|
|
283
365
|
- If other issues persist: Only use --no-verify as last resort after confirming code quality
|
|
@@ -490,6 +572,53 @@ const parseImplementationResponse = (response, featureId) => {
|
|
|
490
572
|
};
|
|
491
573
|
}
|
|
492
574
|
};
|
|
575
|
+
/**
|
|
576
|
+
* Push branch to remote repository
|
|
577
|
+
*/
|
|
578
|
+
async function pushToRemote(branchName, verbose) {
|
|
579
|
+
try {
|
|
580
|
+
// Import exec from child_process
|
|
581
|
+
const { execSync } = await import('child_process');
|
|
582
|
+
if (verbose) {
|
|
583
|
+
logInfo(`Pushing branch ${branchName} to remote...`);
|
|
584
|
+
}
|
|
585
|
+
// Try to push with -u flag (sets upstream if not already set)
|
|
586
|
+
try {
|
|
587
|
+
execSync(`git push -u origin ${branchName}`, {
|
|
588
|
+
encoding: 'utf-8',
|
|
589
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
590
|
+
});
|
|
591
|
+
return { success: true };
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
// If push fails, it might be because branch already has upstream
|
|
595
|
+
// Try without -u flag
|
|
596
|
+
try {
|
|
597
|
+
execSync(`git push origin ${branchName}`, {
|
|
598
|
+
encoding: 'utf-8',
|
|
599
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
600
|
+
});
|
|
601
|
+
return { success: true };
|
|
602
|
+
}
|
|
603
|
+
catch (retryError) {
|
|
604
|
+
const errorMessage = retryError instanceof Error
|
|
605
|
+
? retryError.message
|
|
606
|
+
: String(retryError);
|
|
607
|
+
return {
|
|
608
|
+
success: false,
|
|
609
|
+
error: errorMessage,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
616
|
+
return {
|
|
617
|
+
success: false,
|
|
618
|
+
error: errorMessage,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
493
622
|
export const checkCodeImplementationRequirements = async () => {
|
|
494
623
|
try {
|
|
495
624
|
// Check if Claude Code SDK is available
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { verifyCodeImplementationCompliance, type ChecklistItemVerificationResult, type ChecklistVerificationResult, type VerifyCodeImplementationOptions, } from './verifier.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { verifyCodeImplementationCompliance, } from './verifier.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
export interface ChecklistItemVerificationResult {
|
|
3
|
+
checklist_item_id: string;
|
|
4
|
+
is_satisfied: boolean;
|
|
5
|
+
verification_status: 'confirmed' | 'rejected' | 'uncertain';
|
|
6
|
+
verification_reason: string;
|
|
7
|
+
concerns?: string[];
|
|
8
|
+
improvement_suggestions?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface ChecklistVerificationResult {
|
|
11
|
+
overall_status: 'passed' | 'failed' | 'partial';
|
|
12
|
+
summary: string;
|
|
13
|
+
confirmed_count: number;
|
|
14
|
+
rejected_count: number;
|
|
15
|
+
uncertain_count: number;
|
|
16
|
+
item_verifications: ChecklistItemVerificationResult[];
|
|
17
|
+
overall_suggestions?: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface VerifyCodeImplementationOptions {
|
|
20
|
+
featureId: string;
|
|
21
|
+
branchName: string;
|
|
22
|
+
baseBranch: string;
|
|
23
|
+
featureName: string;
|
|
24
|
+
featureDescription?: string;
|
|
25
|
+
checklistContext: string;
|
|
26
|
+
verbose?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Verify code implementation against checklist requirements by reviewing git diff
|
|
30
|
+
*/
|
|
31
|
+
export declare function verifyCodeImplementationCompliance(options: VerifyCodeImplementationOptions, config: EdsgerConfig): Promise<ChecklistVerificationResult>;
|