edsger 0.2.0 → 0.2.2
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/api/features/feature-utils.d.ts +13 -0
- package/dist/api/features/feature-utils.js +46 -0
- package/dist/api/features/get-feature.d.ts +5 -0
- package/dist/api/features/get-feature.js +19 -0
- package/dist/api/features/index.d.ts +7 -0
- package/dist/api/features/index.js +9 -0
- package/dist/api/features/status-updater.d.ts +27 -0
- package/dist/api/features/status-updater.js +64 -0
- package/dist/api/features/test-cases.d.ts +21 -0
- package/dist/api/features/test-cases.js +63 -0
- package/dist/api/features/update-feature.d.ts +13 -0
- package/dist/api/features/update-feature.js +31 -0
- package/dist/api/features/user-stories.d.ts +21 -0
- package/dist/api/features/user-stories.js +63 -0
- package/dist/api/features.d.ts +100 -0
- package/dist/api/features.js +219 -0
- package/dist/api/mcp-client.d.ts +18 -0
- package/dist/api/mcp-client.js +58 -0
- package/dist/api/products.d.ts +10 -0
- package/dist/api/products.js +22 -0
- package/dist/api/test-reports.d.ts +9 -0
- package/dist/api/test-reports.js +25 -0
- package/dist/cli/commands/code-implementation-command.d.ts +2 -0
- package/dist/cli/commands/code-implementation-command.js +36 -0
- package/dist/cli/commands/code-review-command.d.ts +2 -0
- package/dist/cli/commands/code-review-command.js +39 -0
- package/dist/cli/commands/feature-analysis-command.d.ts +2 -0
- package/dist/cli/commands/feature-analysis-command.js +36 -0
- package/dist/cli/commands/functional-testing-command.d.ts +2 -0
- package/dist/cli/commands/functional-testing-command.js +36 -0
- package/dist/cli/commands/technical-design-command.d.ts +2 -0
- package/dist/cli/commands/technical-design-command.js +36 -0
- package/dist/cli/commands/workflow-command.d.ts +2 -0
- package/dist/cli/commands/workflow-command.js +34 -0
- package/dist/cli/formatters/code-implementation-formatter.d.ts +9 -0
- package/dist/cli/formatters/code-implementation-formatter.js +27 -0
- package/dist/cli/formatters/feature-analysis-formatter.d.ts +2 -0
- package/dist/cli/formatters/feature-analysis-formatter.js +27 -0
- package/dist/cli/formatters/functional-testing-formatter.d.ts +15 -0
- package/dist/cli/formatters/functional-testing-formatter.js +37 -0
- package/dist/cli/formatters/technical-design-formatter.d.ts +7 -0
- package/dist/cli/formatters/technical-design-formatter.js +30 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/utils/validation.d.ts +25 -0
- package/dist/cli/utils/validation.js +58 -0
- package/dist/cli/utils/workflow-utils.d.ts +21 -0
- package/dist/cli/utils/workflow-utils.js +47 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +11 -466
- package/dist/config.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/{bug-fixing → phases/bug-fixing}/analyzer.d.ts +1 -1
- package/dist/{bug-fixing → phases/bug-fixing}/analyzer.js +1 -1
- package/dist/{bug-fixing → phases/bug-fixing}/context-fetcher.d.ts +4 -22
- package/dist/{bug-fixing → phases/bug-fixing}/context-fetcher.js +14 -58
- package/dist/{bug-fixing → phases/bug-fixing}/mcp-server.js +1 -30
- package/dist/phases/code-implementation/analyzer.d.ts +33 -0
- package/dist/{code-implementation → phases/code-implementation}/analyzer.js +174 -15
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/{code-implementation → phases/code-implementation}/mcp-server.js +1 -30
- package/dist/{code-review → phases/code-review}/reviewer.d.ts +1 -1
- package/dist/{feature-analysis → phases/feature-analysis}/analyzer.d.ts +3 -2
- package/dist/{feature-analysis → phases/feature-analysis}/analyzer.js +29 -127
- package/dist/phases/feature-analysis/context-fetcher.d.ts +18 -0
- package/dist/phases/feature-analysis/context-fetcher.js +86 -0
- package/dist/{feature-analysis → phases/feature-analysis}/http-fallback.js +1 -1
- package/dist/{feature-analysis → phases/feature-analysis}/mcp-server.js +1 -24
- package/dist/{functional-testing → phases/functional-testing}/analyzer.d.ts +17 -2
- package/dist/{functional-testing → phases/functional-testing}/analyzer.js +225 -31
- package/dist/phases/functional-testing/context-fetcher.d.ts +16 -0
- package/dist/phases/functional-testing/context-fetcher.js +81 -0
- package/dist/{functional-testing → phases/functional-testing}/http-fallback.js +1 -1
- package/dist/{functional-testing → phases/functional-testing}/index.d.ts +1 -1
- package/dist/{functional-testing → phases/functional-testing}/index.js +1 -1
- package/dist/{functional-testing → phases/functional-testing}/mcp-server.js +1 -30
- package/dist/{functional-testing → phases/functional-testing}/test-report-creator.d.ts +26 -0
- package/dist/{functional-testing → phases/functional-testing}/test-report-creator.js +87 -5
- package/dist/phases/functional-testing/test-retry-handler.d.ts +16 -0
- package/dist/phases/functional-testing/test-retry-handler.js +75 -0
- package/dist/{pull-request → phases/pull-request}/creator.js +47 -6
- package/dist/phases/pull-request/handler.d.ts +16 -0
- package/dist/phases/pull-request/handler.js +60 -0
- package/dist/{technical-design → phases/technical-design}/analyzer.d.ts +7 -2
- package/dist/phases/technical-design/analyzer.js +418 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/{technical-design → phases/technical-design}/http-fallback.js +1 -1
- package/dist/{technical-design → phases/technical-design}/mcp-server.js +1 -30
- package/dist/prompts/bug-fixing.d.ts +2 -0
- package/dist/prompts/bug-fixing.js +63 -0
- package/dist/prompts/code-implementation.d.ts +3 -0
- package/dist/prompts/code-implementation.js +132 -0
- package/dist/prompts/feature-analysis.d.ts +3 -0
- package/dist/prompts/feature-analysis.js +149 -0
- package/dist/prompts/formatters.d.ts +29 -0
- package/dist/prompts/formatters.js +139 -0
- package/dist/prompts/functional-testing.d.ts +3 -0
- package/dist/prompts/functional-testing.js +126 -0
- package/dist/prompts/index.d.ts +6 -0
- package/dist/prompts/index.js +7 -0
- package/dist/prompts/technical-design.d.ts +3 -0
- package/dist/prompts/technical-design.js +130 -0
- package/dist/services/checklist.d.ts +99 -0
- package/dist/services/checklist.js +337 -0
- package/dist/types/features.d.ts +29 -0
- package/dist/types/features.js +1 -0
- package/dist/types/index.d.ts +112 -0
- package/dist/types/index.js +1 -0
- package/dist/types/pipeline.d.ts +25 -0
- package/dist/types/pipeline.js +4 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/pipeline-logger.d.ts +8 -0
- package/dist/utils/pipeline-logger.js +35 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +34 -0
- package/dist/workflow-runner/config/stage-configs.d.ts +5 -0
- package/dist/workflow-runner/config/stage-configs.js +34 -0
- package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
- package/dist/workflow-runner/core/feature-filter.js +46 -0
- package/dist/workflow-runner/core/feature-filter.test.d.ts +4 -0
- package/dist/workflow-runner/core/feature-filter.test.js +127 -0
- package/dist/workflow-runner/core/index.d.ts +8 -0
- package/dist/workflow-runner/core/index.js +12 -0
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
- package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
- package/dist/workflow-runner/core/state-manager.d.ts +24 -0
- package/dist/workflow-runner/core/state-manager.js +42 -0
- package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
- package/dist/workflow-runner/core/workflow-logger.js +65 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/phase-executor.js +183 -0
- package/dist/workflow-runner/executors/stage-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/stage-executor.js +49 -0
- package/dist/workflow-runner/feature-service.d.ts +17 -0
- package/dist/workflow-runner/feature-service.js +60 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +113 -0
- package/dist/workflow-runner/index.d.ts +0 -1
- package/dist/workflow-runner/index.js +0 -1
- package/dist/workflow-runner/pipeline-runner.d.ts +9 -19
- package/dist/workflow-runner/pipeline-runner.js +247 -256
- package/dist/workflow-runner/pipeline.d.ts +18 -0
- package/dist/workflow-runner/pipeline.js +197 -0
- package/dist/workflow-runner/processor.d.ts +40 -0
- package/dist/workflow-runner/processor.js +191 -0
- package/dist/workflow-runner/types.d.ts +48 -0
- package/dist/workflow-runner/types.js +4 -0
- package/dist/workflow-runner/workflow-processor.d.ts +6 -23
- package/dist/workflow-runner/workflow-processor.js +38 -100
- package/package.json +2 -2
- package/dist/code-implementation/analyzer.d.ts +0 -19
- package/dist/code-implementation/context-fetcher.d.ts +0 -38
- package/dist/code-implementation/context-fetcher.js +0 -147
- package/dist/feature-analysis/context-fetcher.d.ts +0 -54
- package/dist/feature-analysis/context-fetcher.js +0 -193
- package/dist/functional-testing/context-fetcher.d.ts +0 -47
- package/dist/functional-testing/context-fetcher.js +0 -192
- package/dist/technical-design/analyzer.js +0 -338
- package/dist/technical-design/context-fetcher.d.ts +0 -42
- package/dist/technical-design/context-fetcher.js +0 -170
- /package/dist/{bug-fixing → phases/bug-fixing}/index.d.ts +0 -0
- /package/dist/{bug-fixing → phases/bug-fixing}/index.js +0 -0
- /package/dist/{bug-fixing → phases/bug-fixing}/mcp-server.d.ts +0 -0
- /package/dist/{code-implementation → phases/code-implementation}/mcp-server.d.ts +0 -0
- /package/dist/{code-review → phases/code-review}/reviewer.js +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/http-fallback.d.ts +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/index.d.ts +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/index.js +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/mcp-server.d.ts +0 -0
- /package/dist/{functional-testing → phases/functional-testing}/http-fallback.d.ts +0 -0
- /package/dist/{functional-testing → phases/functional-testing}/mcp-server.d.ts +0 -0
- /package/dist/{pull-request → phases/pull-request}/creator.d.ts +0 -0
- /package/dist/{technical-design → phases/technical-design}/http-fallback.d.ts +0 -0
- /package/dist/{technical-design → phases/technical-design}/mcp-server.d.ts +0 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
2
|
+
import { logInfo, logError } from '../../utils/logger.js';
|
|
3
|
+
import { saveTechnicalDesignViaHttp } from './http-fallback.js';
|
|
4
|
+
import { fetchTechnicalDesignContext, } from './context-fetcher.js';
|
|
5
|
+
import { updateTechnicalDesign } from '../../api/features/index.js';
|
|
6
|
+
import { formatTechnicalDesignContext } from '../../prompts/formatters.js';
|
|
7
|
+
import { createTechnicalDesignSystemPrompt, createTechnicalDesignPromptWithContext, } from '../../prompts/technical-design.js';
|
|
8
|
+
import { formatChecklistsForContext, } from '../../services/checklist.js';
|
|
9
|
+
function userMessage(content) {
|
|
10
|
+
return {
|
|
11
|
+
type: 'user',
|
|
12
|
+
message: { role: 'user', content: content },
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async function* prompt(analysisPrompt) {
|
|
16
|
+
yield userMessage(analysisPrompt);
|
|
17
|
+
await new Promise((res) => setTimeout(res, 10000));
|
|
18
|
+
}
|
|
19
|
+
export const generateTechnicalDesign = async (options, config, checklistContext) => {
|
|
20
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
21
|
+
if (verbose) {
|
|
22
|
+
logInfo(`Starting technical design generation for feature ID: ${featureId}`);
|
|
23
|
+
logInfo(`Using MCP server: ${mcpServerUrl}`);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
// Fetch all required context information via MCP endpoints
|
|
27
|
+
if (verbose) {
|
|
28
|
+
logInfo('Fetching technical design context via MCP endpoints...');
|
|
29
|
+
}
|
|
30
|
+
const context = await fetchTechnicalDesignContext(mcpServerUrl, mcpToken, featureId, verbose);
|
|
31
|
+
const systemPrompt = createTechnicalDesignSystemPrompt(config, mcpServerUrl, mcpToken, featureId);
|
|
32
|
+
const contextInfo = formatTechnicalDesignContext(context);
|
|
33
|
+
// Add checklist context to the design prompt
|
|
34
|
+
let finalContextInfo = contextInfo;
|
|
35
|
+
if (checklistContext && checklistContext.checklists.length > 0) {
|
|
36
|
+
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
37
|
+
finalContextInfo = contextInfo + '\n\n' + checklistInfo;
|
|
38
|
+
if (verbose) {
|
|
39
|
+
logInfo(`Added ${checklistContext.checklists.length} checklists to design context`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const designPrompt = createTechnicalDesignPromptWithContext(featureId, finalContextInfo);
|
|
43
|
+
let lastAssistantResponse = '';
|
|
44
|
+
let structuredDesignResult = null;
|
|
45
|
+
if (verbose) {
|
|
46
|
+
logInfo('Starting Claude Code query with pre-fetched information...');
|
|
47
|
+
}
|
|
48
|
+
// Use Claude Code SDK without MCP servers - all info is pre-fetched
|
|
49
|
+
for await (const message of query({
|
|
50
|
+
prompt: prompt(designPrompt),
|
|
51
|
+
options: {
|
|
52
|
+
appendSystemPrompt: systemPrompt,
|
|
53
|
+
model: config.claude.model || 'sonnet',
|
|
54
|
+
maxTurns: 1000,
|
|
55
|
+
permissionMode: 'bypassPermissions',
|
|
56
|
+
},
|
|
57
|
+
})) {
|
|
58
|
+
if (verbose) {
|
|
59
|
+
logInfo(`Received message type: ${message.type}`);
|
|
60
|
+
}
|
|
61
|
+
// Stream the technical design generation process
|
|
62
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
63
|
+
for (const content of message.message.content) {
|
|
64
|
+
if (content.type === 'text') {
|
|
65
|
+
lastAssistantResponse += content.text + '\n';
|
|
66
|
+
if (verbose) {
|
|
67
|
+
console.log(`\n🤖 ${content.text}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (content.type === 'tool_use') {
|
|
71
|
+
if (verbose) {
|
|
72
|
+
console.log(`\n🔧 ${content.name}: ${content.input.description || 'Running...'}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (message.type === 'result') {
|
|
78
|
+
if (message.subtype === 'success') {
|
|
79
|
+
logInfo('\n🎨 Technical design generation completed, parsing results...');
|
|
80
|
+
try {
|
|
81
|
+
// Try to extract JSON from markdown code block or parse directly
|
|
82
|
+
const responseText = message.result || lastAssistantResponse;
|
|
83
|
+
let jsonResult = null;
|
|
84
|
+
// DEBUG: Log response text details
|
|
85
|
+
console.log('=== DEBUG: Response Text Analysis ===');
|
|
86
|
+
console.log('message.result exists:', !!message.result);
|
|
87
|
+
console.log('lastAssistantResponse exists:', !!lastAssistantResponse);
|
|
88
|
+
console.log('responseText length:', responseText.length);
|
|
89
|
+
console.log('responseText first 200 chars:', JSON.stringify(responseText.substring(0, 200)));
|
|
90
|
+
console.log('responseText last 200 chars:', JSON.stringify(responseText.substring(responseText.length - 200)));
|
|
91
|
+
console.log('Contains ```json:', responseText.includes('```json'));
|
|
92
|
+
console.log('Contains technical_design_result:', responseText.includes('"technical_design_result"'));
|
|
93
|
+
// First try to extract JSON from markdown code block
|
|
94
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
95
|
+
console.log('=== DEBUG: Markdown Block Match ===');
|
|
96
|
+
console.log('jsonBlockMatch found:', !!jsonBlockMatch);
|
|
97
|
+
if (jsonBlockMatch) {
|
|
98
|
+
console.log('Matched JSON length:', jsonBlockMatch[1].length);
|
|
99
|
+
console.log('Matched JSON first 100 chars:', JSON.stringify(jsonBlockMatch[1].substring(0, 100)));
|
|
100
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log('=== DEBUG: JSON Object Search ===');
|
|
104
|
+
// Try to find JSON object containing "technical_design_result"
|
|
105
|
+
const lines = responseText.split('\n');
|
|
106
|
+
let jsonStartIndex = -1;
|
|
107
|
+
console.log('Total lines:', lines.length);
|
|
108
|
+
console.log('Lines preview:', lines
|
|
109
|
+
.slice(0, 10)
|
|
110
|
+
.map((line, i) => `${i}: ${JSON.stringify(line.substring(0, 50))}`));
|
|
111
|
+
// Find the line that contains the start of a JSON object with "technical_design_result"
|
|
112
|
+
for (let i = 0; i < lines.length; i++) {
|
|
113
|
+
const line = lines[i].trim();
|
|
114
|
+
if (line.startsWith('{') &&
|
|
115
|
+
responseText.includes('"technical_design_result"')) {
|
|
116
|
+
console.log(`Found { at line ${i}: ${JSON.stringify(line)}`);
|
|
117
|
+
const fromThisLine = lines.slice(i).join('\n');
|
|
118
|
+
if (fromThisLine.includes('"technical_design_result"')) {
|
|
119
|
+
jsonStartIndex = responseText.indexOf(lines[i]);
|
|
120
|
+
console.log(`JSON start found at line ${i}, responseText index: ${jsonStartIndex}`);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (jsonStartIndex !== -1) {
|
|
126
|
+
// Find the complete JSON object starting from this position
|
|
127
|
+
let braceCount = 0;
|
|
128
|
+
let endIndex = jsonStartIndex;
|
|
129
|
+
let inString = false;
|
|
130
|
+
let escapeNext = false;
|
|
131
|
+
for (let i = jsonStartIndex; i < responseText.length; i++) {
|
|
132
|
+
const char = responseText[i];
|
|
133
|
+
if (escapeNext) {
|
|
134
|
+
escapeNext = false;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (char === '\\' && inString) {
|
|
138
|
+
escapeNext = true;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (char === '"') {
|
|
142
|
+
inString = !inString;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (!inString) {
|
|
146
|
+
if (char === '{') {
|
|
147
|
+
braceCount++;
|
|
148
|
+
}
|
|
149
|
+
else if (char === '}') {
|
|
150
|
+
braceCount--;
|
|
151
|
+
if (braceCount === 0) {
|
|
152
|
+
endIndex = i;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const jsonStr = responseText.substring(jsonStartIndex, endIndex + 1);
|
|
159
|
+
console.log('=== DEBUG: JSON Extraction ===');
|
|
160
|
+
console.log('JSON start index:', jsonStartIndex);
|
|
161
|
+
console.log('JSON end index:', endIndex);
|
|
162
|
+
console.log('Extracted JSON length:', jsonStr.length);
|
|
163
|
+
console.log('Extracted JSON first 100 chars:', JSON.stringify(jsonStr.substring(0, 100)));
|
|
164
|
+
console.log('Extracted JSON last 100 chars:', JSON.stringify(jsonStr.substring(jsonStr.length - 100)));
|
|
165
|
+
try {
|
|
166
|
+
jsonResult = JSON.parse(jsonStr);
|
|
167
|
+
console.log('JSON parsing succeeded!');
|
|
168
|
+
}
|
|
169
|
+
catch (parseError) {
|
|
170
|
+
console.log('Failed to parse extracted JSON:', parseError);
|
|
171
|
+
console.log('Extracted JSON string:', jsonStr.substring(0, 200) + '...');
|
|
172
|
+
console.log('=== DEBUG: Fallback to full response ===');
|
|
173
|
+
console.log('Attempting to parse entire responseText as JSON');
|
|
174
|
+
// Try to parse the entire response as JSON as fallback
|
|
175
|
+
jsonResult = JSON.parse(responseText);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
console.log('=== DEBUG: No JSON start found ===');
|
|
180
|
+
console.log('Falling back to parse entire responseText as JSON');
|
|
181
|
+
// Try to parse the entire response as JSON
|
|
182
|
+
jsonResult = JSON.parse(responseText);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
console.log('=== DEBUG: Final Result Processing ===');
|
|
186
|
+
console.log('jsonResult exists:', !!jsonResult);
|
|
187
|
+
console.log('jsonResult has technical_design_result:', !!(jsonResult && jsonResult.technical_design_result));
|
|
188
|
+
if (jsonResult && jsonResult.technical_design_result) {
|
|
189
|
+
console.log('checklist_item_results in parsed JSON:', !!jsonResult.technical_design_result.checklist_item_results);
|
|
190
|
+
if (jsonResult.technical_design_result.checklist_item_results) {
|
|
191
|
+
console.log('checklist_item_results length:', jsonResult.technical_design_result.checklist_item_results
|
|
192
|
+
.length);
|
|
193
|
+
}
|
|
194
|
+
structuredDesignResult = jsonResult.technical_design_result;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
throw new Error('Invalid JSON structure');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
logError(`Failed to parse structured design result: ${error}`);
|
|
202
|
+
// Extract technical design from response if JSON parsing fails
|
|
203
|
+
const extractedDesign = extractTechnicalDesignFromResponse(message.result || lastAssistantResponse);
|
|
204
|
+
structuredDesignResult = {
|
|
205
|
+
status: extractedDesign ? 'success' : 'error',
|
|
206
|
+
technical_design: extractedDesign,
|
|
207
|
+
summary: extractedDesign
|
|
208
|
+
? 'Technical design generated successfully'
|
|
209
|
+
: 'Failed to generate technical design',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
logError(`\n⚠️ Technical design generation incomplete: ${message.subtype}`);
|
|
215
|
+
if (message.subtype === 'error_max_turns') {
|
|
216
|
+
logError('💡 Try increasing timeout or reducing complexity');
|
|
217
|
+
}
|
|
218
|
+
// Try to parse results from the last assistant response
|
|
219
|
+
if (lastAssistantResponse) {
|
|
220
|
+
try {
|
|
221
|
+
const responseText = lastAssistantResponse;
|
|
222
|
+
let jsonResult = null;
|
|
223
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
224
|
+
if (jsonBlockMatch) {
|
|
225
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
226
|
+
if (jsonResult && jsonResult.technical_design_result) {
|
|
227
|
+
structuredDesignResult = jsonResult.technical_design_result;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Try to find JSON object containing "technical_design_result"
|
|
232
|
+
const lines = responseText.split('\n');
|
|
233
|
+
let jsonStartIndex = -1;
|
|
234
|
+
// Find the line that contains the start of a JSON object with "technical_design_result"
|
|
235
|
+
for (let i = 0; i < lines.length; i++) {
|
|
236
|
+
const line = lines[i].trim();
|
|
237
|
+
if (line.startsWith('{') &&
|
|
238
|
+
responseText.includes('"technical_design_result"')) {
|
|
239
|
+
const fromThisLine = lines.slice(i).join('\n');
|
|
240
|
+
if (fromThisLine.includes('"technical_design_result"')) {
|
|
241
|
+
jsonStartIndex = responseText.indexOf(lines[i]);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (jsonStartIndex !== -1) {
|
|
247
|
+
// Find the complete JSON object starting from this position
|
|
248
|
+
let braceCount = 0;
|
|
249
|
+
let endIndex = jsonStartIndex;
|
|
250
|
+
let inString = false;
|
|
251
|
+
let escapeNext = false;
|
|
252
|
+
for (let i = jsonStartIndex; i < responseText.length; i++) {
|
|
253
|
+
const char = responseText[i];
|
|
254
|
+
if (escapeNext) {
|
|
255
|
+
escapeNext = false;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (char === '\\' && inString) {
|
|
259
|
+
escapeNext = true;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (char === '"') {
|
|
263
|
+
inString = !inString;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (!inString) {
|
|
267
|
+
if (char === '{') {
|
|
268
|
+
braceCount++;
|
|
269
|
+
}
|
|
270
|
+
else if (char === '}') {
|
|
271
|
+
braceCount--;
|
|
272
|
+
if (braceCount === 0) {
|
|
273
|
+
endIndex = i;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const jsonStr = responseText.substring(jsonStartIndex, endIndex + 1);
|
|
280
|
+
try {
|
|
281
|
+
jsonResult = JSON.parse(jsonStr);
|
|
282
|
+
if (jsonResult && jsonResult.technical_design_result) {
|
|
283
|
+
structuredDesignResult =
|
|
284
|
+
jsonResult.technical_design_result;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch (parseError) {
|
|
288
|
+
logError(`Failed to parse extracted JSON: ${parseError}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (!structuredDesignResult) {
|
|
292
|
+
const extractedDesign = extractTechnicalDesignFromResponse(lastAssistantResponse);
|
|
293
|
+
if (extractedDesign) {
|
|
294
|
+
structuredDesignResult = {
|
|
295
|
+
status: 'success',
|
|
296
|
+
technical_design: extractedDesign,
|
|
297
|
+
summary: 'Technical design generated successfully',
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
logError(`Failed to parse assistant response: ${error}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Save the technical design if we have it
|
|
311
|
+
if (structuredDesignResult?.technical_design) {
|
|
312
|
+
if (verbose) {
|
|
313
|
+
logInfo('Saving technical design...');
|
|
314
|
+
}
|
|
315
|
+
const designSaved = await updateTechnicalDesign(mcpServerUrl, mcpToken, featureId, structuredDesignResult.technical_design, verbose);
|
|
316
|
+
// Try HTTP fallback if direct update failed
|
|
317
|
+
if (!designSaved) {
|
|
318
|
+
if (verbose) {
|
|
319
|
+
logInfo('Direct update failed, trying HTTP fallback...');
|
|
320
|
+
}
|
|
321
|
+
const fallbackSaved = await saveTechnicalDesignViaHttp({
|
|
322
|
+
mcpServerUrl,
|
|
323
|
+
mcpToken,
|
|
324
|
+
featureId,
|
|
325
|
+
technicalDesign: structuredDesignResult.technical_design,
|
|
326
|
+
verbose,
|
|
327
|
+
});
|
|
328
|
+
if (!fallbackSaved && verbose) {
|
|
329
|
+
logError('⚠️ Both direct update and HTTP fallback failed');
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
featureId,
|
|
333
|
+
technicalDesign: structuredDesignResult.technical_design,
|
|
334
|
+
status: fallbackSaved ? 'success' : 'error',
|
|
335
|
+
summary: fallbackSaved
|
|
336
|
+
? 'Technical design generated and saved via HTTP fallback'
|
|
337
|
+
: 'Technical design generated but failed to save',
|
|
338
|
+
savedViaHttp: fallbackSaved,
|
|
339
|
+
data: {
|
|
340
|
+
checklist_item_results: structuredDesignResult.checklist_item_results || [],
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
featureId,
|
|
346
|
+
technicalDesign: structuredDesignResult.technical_design,
|
|
347
|
+
status: 'success',
|
|
348
|
+
summary: 'Technical design generated and saved successfully',
|
|
349
|
+
data: {
|
|
350
|
+
checklist_item_results: structuredDesignResult.checklist_item_results || [],
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
featureId,
|
|
356
|
+
technicalDesign: null,
|
|
357
|
+
status: 'error',
|
|
358
|
+
summary: 'No technical design was generated',
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
logError(`Technical design generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
363
|
+
return {
|
|
364
|
+
featureId,
|
|
365
|
+
technicalDesign: null,
|
|
366
|
+
status: 'error',
|
|
367
|
+
summary: `Generation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
const extractTechnicalDesignFromResponse = (response) => {
|
|
372
|
+
// Try to extract technical design content from the response
|
|
373
|
+
// Look for markdown sections that contain technical design
|
|
374
|
+
const lines = response.split('\n');
|
|
375
|
+
let inTechnicalDesign = false;
|
|
376
|
+
const technicalDesignLines = [];
|
|
377
|
+
for (let i = 0; i < lines.length; i++) {
|
|
378
|
+
const line = lines[i].toLowerCase();
|
|
379
|
+
// Look for technical design section headers
|
|
380
|
+
if (line.includes('technical design') ||
|
|
381
|
+
line.includes('architecture') ||
|
|
382
|
+
line.includes('# design') ||
|
|
383
|
+
line.includes('## technical')) {
|
|
384
|
+
inTechnicalDesign = true;
|
|
385
|
+
technicalDesignLines.push(lines[i]);
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
if (inTechnicalDesign) {
|
|
389
|
+
// Continue until we hit another major section or JSON
|
|
390
|
+
if (line.startsWith('{') && line.includes('"technical_design_result"')) {
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
technicalDesignLines.push(lines[i]);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (technicalDesignLines.length > 0) {
|
|
397
|
+
return technicalDesignLines.join('\n').trim();
|
|
398
|
+
}
|
|
399
|
+
// Ultimate fallback: return the whole response if it seems to contain design content
|
|
400
|
+
if (response.length > 100 &&
|
|
401
|
+
(response.toLowerCase().includes('architecture') ||
|
|
402
|
+
response.toLowerCase().includes('component') ||
|
|
403
|
+
response.toLowerCase().includes('database'))) {
|
|
404
|
+
return response.trim();
|
|
405
|
+
}
|
|
406
|
+
return null;
|
|
407
|
+
};
|
|
408
|
+
export const checkTechnicalDesignRequirements = async () => {
|
|
409
|
+
try {
|
|
410
|
+
// Check if Claude Code SDK is available
|
|
411
|
+
const claudeCode = await import('@anthropic-ai/claude-code');
|
|
412
|
+
return claudeCode && typeof claudeCode.query === 'function';
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
console.log('Technical design requirements check failed:', error instanceof Error ? error.message : error);
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FeatureInfo, UserStory, TestCase } from '../../types/features.js';
|
|
2
|
+
import { type ProductInfo } from '../../api/products.js';
|
|
3
|
+
export interface TechnicalDesignContext {
|
|
4
|
+
feature: FeatureInfo;
|
|
5
|
+
product: ProductInfo;
|
|
6
|
+
user_stories: UserStory[];
|
|
7
|
+
test_cases: TestCase[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Fetch all technical design context information via MCP endpoints
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchTechnicalDesignContext(mcpServerUrl: string, mcpToken: string, featureId: string, verbose?: boolean): Promise<TechnicalDesignContext>;
|
|
@@ -0,0 +1,39 @@
|
|
|
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 technical design context information via MCP endpoints
|
|
6
|
+
*/
|
|
7
|
+
export async function fetchTechnicalDesignContext(mcpServerUrl, mcpToken, featureId, verbose) {
|
|
8
|
+
try {
|
|
9
|
+
if (verbose) {
|
|
10
|
+
logInfo(`Fetching complete technical design 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(`✅ Technical design 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} (${test_cases.filter((tc) => tc.is_critical).length} critical)`);
|
|
25
|
+
logInfo(` Existing Technical Design: ${feature.technical_design ? 'Yes' : 'No'}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
feature,
|
|
29
|
+
product,
|
|
30
|
+
user_stories,
|
|
31
|
+
test_cases,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
36
|
+
logError(`Failed to fetch technical design context: ${errorMessage}`);
|
|
37
|
+
throw new Error(`Context fetch failed: ${errorMessage}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,35 +1,6 @@
|
|
|
1
1
|
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-code';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
async function callMcpEndpoint(mcpServerUrl, mcpToken, method, params) {
|
|
5
|
-
try {
|
|
6
|
-
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
7
|
-
method: 'POST',
|
|
8
|
-
headers: {
|
|
9
|
-
'Content-Type': 'application/json',
|
|
10
|
-
Authorization: `Bearer ${mcpToken}`,
|
|
11
|
-
},
|
|
12
|
-
body: JSON.stringify({
|
|
13
|
-
jsonrpc: '2.0',
|
|
14
|
-
method,
|
|
15
|
-
params,
|
|
16
|
-
id: Math.random().toString(36).substring(7),
|
|
17
|
-
}),
|
|
18
|
-
});
|
|
19
|
-
if (!response.ok) {
|
|
20
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
21
|
-
}
|
|
22
|
-
const data = await response.json();
|
|
23
|
-
if (data.error) {
|
|
24
|
-
throw new Error(data.error.message || 'MCP call failed');
|
|
25
|
-
}
|
|
26
|
-
return data.result;
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.error(`MCP call failed for ${method}:`, error instanceof Error ? error.message : String(error));
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
3
|
+
import { callMcpEndpoint } from '../../api/mcp-client.js';
|
|
33
4
|
// Create an SDK MCP server with custom tools for technical design generation
|
|
34
5
|
export const createTechnicalDesignMcpServer = (mcpServerUrl, mcpToken) => {
|
|
35
6
|
return createSdkMcpServer({
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const createBugFixingSystemPrompt = (_config) => {
|
|
2
|
+
return `You are an expert software engineer specializing in fixing bugs and test failures. Your goal is to analyze test failures and fix the underlying issues in the code.
|
|
3
|
+
|
|
4
|
+
**Your Role**: Fix bugs and test failures while maintaining existing functionality and code quality.
|
|
5
|
+
|
|
6
|
+
**Available Tools**:
|
|
7
|
+
- Bash: Run commands, tests, and git operations
|
|
8
|
+
- Glob: Find files and understand project structure
|
|
9
|
+
- Read: Examine existing code and files
|
|
10
|
+
- Edit: Modify existing files to fix issues
|
|
11
|
+
- Write: Create new files if absolutely necessary
|
|
12
|
+
- TodoWrite: Track bug fixing tasks (use proactively)
|
|
13
|
+
|
|
14
|
+
**Bug Fixing Process**:
|
|
15
|
+
1. **Git Pull Rebase**: Ensure main branch is up to date: git pull origin main --rebase
|
|
16
|
+
2. **Analyze Failures**: Study test error messages and stack traces to identify root causes
|
|
17
|
+
3. **Examine Code**: Read the relevant code files to understand current implementation
|
|
18
|
+
4. **Fix Issues**: Make minimal, targeted changes to resolve the failures
|
|
19
|
+
5. **Test Fixes**: Run tests to verify fixes work and don't break other functionality
|
|
20
|
+
6. **Validate**: Ensure all critical test cases pass
|
|
21
|
+
|
|
22
|
+
**Important Guidelines**:
|
|
23
|
+
- All feature context, user stories, test cases, and test reports are provided in the prompt
|
|
24
|
+
- Focus ONLY on fixing the reported test failures
|
|
25
|
+
- Do not refactor or optimize unrelated code
|
|
26
|
+
- Preserve existing functionality and patterns
|
|
27
|
+
- Make minimal necessary changes
|
|
28
|
+
- Test your fixes thoroughly
|
|
29
|
+
|
|
30
|
+
**CRITICAL - Result Format**:
|
|
31
|
+
You MUST end your response with a JSON object containing the bug fix results in this EXACT format:
|
|
32
|
+
|
|
33
|
+
\`\`\`json
|
|
34
|
+
{
|
|
35
|
+
"fix_result": {
|
|
36
|
+
"feature_id": "FEATURE_ID_PLACEHOLDER",
|
|
37
|
+
"attempt_number": 1,
|
|
38
|
+
"summary": "Brief description of what was fixed",
|
|
39
|
+
"files_modified": ["file1.ts", "file2.tsx"],
|
|
40
|
+
"tests_passed": true,
|
|
41
|
+
"fixes_applied": [
|
|
42
|
+
{
|
|
43
|
+
"issue": "Description of the issue",
|
|
44
|
+
"fix": "Description of how it was fixed",
|
|
45
|
+
"file": "path/to/file.ts"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"remaining_issues": ["Any issues that could not be resolved"],
|
|
49
|
+
"recommendations": "Additional recommendations for the development team"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
\`\`\`
|
|
53
|
+
|
|
54
|
+
**Quality Guidelines**:
|
|
55
|
+
- Focus on minimal, surgical fixes that address specific test failures
|
|
56
|
+
- Preserve existing code patterns and architecture
|
|
57
|
+
- Ensure backward compatibility
|
|
58
|
+
- Add appropriate error handling where missing
|
|
59
|
+
- Update documentation if interfaces change
|
|
60
|
+
- Test thoroughly before considering issues resolved
|
|
61
|
+
|
|
62
|
+
Focus on systematic debugging and targeted fixes based on the provided test failure information.`;
|
|
63
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../types/index.js';
|
|
2
|
+
export declare const createCodeImplementationSystemPrompt: (_config: EdsgerConfig, baseBranch: string) => string;
|
|
3
|
+
export declare const createCodeImplementationPromptWithContext: (featureId: string, contextInfo: string, baseBranch: string) => string;
|