edsger 0.41.2 → 0.42.0
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/.claude/settings.local.json +3 -23
- package/dist/commands/pr-resolve/index.d.ts +1 -0
- package/dist/commands/pr-resolve/index.js +1 -0
- package/dist/commands/workflow/executors/phase-executor.js +1 -3
- package/dist/commands/workflow/phase-orchestrator.js +1 -3
- package/dist/index.js +3 -2
- package/dist/phases/app-store-generation/index.js +1 -3
- package/dist/phases/branch-planning/index.js +1 -3
- package/dist/phases/bug-fixing/analyzer.js +1 -3
- package/dist/phases/code-implementation/index.js +1 -3
- package/dist/phases/code-refine/index.js +1 -3
- package/dist/phases/code-review/index.js +1 -3
- package/dist/phases/code-testing/analyzer.js +1 -3
- package/dist/phases/feature-analysis/index.js +1 -3
- package/dist/phases/functional-testing/analyzer.js +1 -3
- package/dist/phases/growth-analysis/index.js +1 -3
- package/dist/phases/pr-execution/index.js +59 -1
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.js +157 -0
- package/dist/phases/pr-resolve/__tests__/types.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/types.test.js +43 -0
- package/dist/phases/pr-resolve/checklist-learner.d.ts +28 -0
- package/dist/phases/pr-resolve/checklist-learner.js +128 -0
- package/dist/phases/pr-resolve/index.d.ts +4 -0
- package/dist/phases/pr-resolve/index.js +23 -5
- package/dist/phases/pr-resolve/prompts.js +2 -1
- package/dist/phases/pr-resolve/types.d.ts +18 -0
- package/dist/phases/pr-resolve/types.js +14 -0
- package/dist/phases/pr-resolve/workspace.d.ts +1 -1
- package/dist/phases/pr-resolve/workspace.js +1 -1
- package/dist/phases/pr-review/__tests__/review-comments.test.js +4 -2
- package/dist/phases/pr-review/index.js +1 -3
- package/dist/phases/pr-shared/agent-utils.js +0 -1
- package/dist/phases/pr-shared/context.d.ts +1 -1
- package/dist/phases/pr-splitting/context.js +20 -15
- package/dist/phases/pr-splitting/index.js +1 -3
- package/dist/phases/technical-design/index.js +1 -3
- package/dist/phases/test-cases-analysis/index.js +1 -3
- package/dist/phases/user-stories-analysis/index.js +1 -3
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +4 -0
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +133 -0
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +4 -0
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +336 -0
- package/dist/services/lifecycle-agent/index.d.ts +24 -0
- package/dist/services/lifecycle-agent/index.js +25 -0
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +57 -0
- package/dist/services/lifecycle-agent/phase-criteria.js +335 -0
- package/dist/services/lifecycle-agent/transition-rules.d.ts +60 -0
- package/dist/services/lifecycle-agent/transition-rules.js +184 -0
- package/dist/services/lifecycle-agent/types.d.ts +190 -0
- package/dist/services/lifecycle-agent/types.js +12 -0
- package/package.json +1 -1
- package/.env.local +0 -12
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +0 -5
- package/dist/api/features/__tests__/regression-prevention.test.js +0 -338
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +0 -5
- package/dist/api/features/__tests__/status-updater.integration.test.js +0 -497
- package/dist/commands/workflow/pipeline-runner.d.ts +0 -17
- package/dist/commands/workflow/pipeline-runner.js +0 -393
- package/dist/commands/workflow/runner.d.ts +0 -26
- package/dist/commands/workflow/runner.js +0 -119
- package/dist/commands/workflow/workflow-runner.d.ts +0 -26
- package/dist/commands/workflow/workflow-runner.js +0 -119
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +0 -28
- package/dist/phases/code-implementation/analyzer-helpers.js +0 -177
- package/dist/phases/code-implementation/analyzer.d.ts +0 -32
- package/dist/phases/code-implementation/analyzer.js +0 -629
- package/dist/phases/code-implementation/context-fetcher.d.ts +0 -17
- package/dist/phases/code-implementation/context-fetcher.js +0 -86
- package/dist/phases/code-implementation/mcp-server.d.ts +0 -1
- package/dist/phases/code-implementation/mcp-server.js +0 -93
- package/dist/phases/code-implementation/prompts-improvement.d.ts +0 -5
- package/dist/phases/code-implementation/prompts-improvement.js +0 -108
- package/dist/phases/code-implementation-verification/verifier.d.ts +0 -31
- package/dist/phases/code-implementation-verification/verifier.js +0 -196
- package/dist/phases/code-refine/analyzer.d.ts +0 -41
- package/dist/phases/code-refine/analyzer.js +0 -561
- package/dist/phases/code-refine/context-fetcher.d.ts +0 -94
- package/dist/phases/code-refine/context-fetcher.js +0 -423
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +0 -22
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +0 -134
- package/dist/phases/code-refine-verification/verifier.d.ts +0 -47
- package/dist/phases/code-refine-verification/verifier.js +0 -597
- package/dist/phases/code-review/analyzer.d.ts +0 -29
- package/dist/phases/code-review/analyzer.js +0 -363
- package/dist/phases/code-review/context-fetcher.d.ts +0 -92
- package/dist/phases/code-review/context-fetcher.js +0 -296
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +0 -10
- package/dist/phases/feature-analysis/analyzer-helpers.js +0 -47
- package/dist/phases/feature-analysis/analyzer.d.ts +0 -11
- package/dist/phases/feature-analysis/analyzer.js +0 -208
- package/dist/phases/feature-analysis/context-fetcher.d.ts +0 -26
- package/dist/phases/feature-analysis/context-fetcher.js +0 -134
- package/dist/phases/feature-analysis/http-fallback.d.ts +0 -20
- package/dist/phases/feature-analysis/http-fallback.js +0 -95
- package/dist/phases/feature-analysis/mcp-server.d.ts +0 -1
- package/dist/phases/feature-analysis/mcp-server.js +0 -144
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +0 -8
- package/dist/phases/feature-analysis/prompts-improvement.js +0 -109
- package/dist/phases/feature-analysis-verification/verifier.d.ts +0 -37
- package/dist/phases/feature-analysis-verification/verifier.js +0 -147
- package/dist/phases/technical-design/analyzer-helpers.d.ts +0 -25
- package/dist/phases/technical-design/analyzer-helpers.js +0 -39
- package/dist/phases/technical-design/analyzer.d.ts +0 -21
- package/dist/phases/technical-design/analyzer.js +0 -461
- package/dist/phases/technical-design/context-fetcher.d.ts +0 -12
- package/dist/phases/technical-design/context-fetcher.js +0 -39
- package/dist/phases/technical-design/http-fallback.d.ts +0 -17
- package/dist/phases/technical-design/http-fallback.js +0 -151
- package/dist/phases/technical-design/mcp-server.d.ts +0 -1
- package/dist/phases/technical-design/mcp-server.js +0 -157
- package/dist/phases/technical-design/prompts-improvement.d.ts +0 -5
- package/dist/phases/technical-design/prompts-improvement.js +0 -93
- package/dist/phases/technical-design-verification/verifier.d.ts +0 -53
- package/dist/phases/technical-design-verification/verifier.js +0 -170
- package/dist/services/feature-branches.d.ts +0 -77
- package/dist/services/feature-branches.js +0 -205
- package/dist/workflow-runner/config/phase-configs.d.ts +0 -5
- package/dist/workflow-runner/config/phase-configs.js +0 -120
- package/dist/workflow-runner/core/feature-filter.d.ts +0 -16
- package/dist/workflow-runner/core/feature-filter.js +0 -46
- package/dist/workflow-runner/core/index.d.ts +0 -8
- package/dist/workflow-runner/core/index.js +0 -12
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +0 -24
- package/dist/workflow-runner/core/pipeline-evaluator.js +0 -32
- package/dist/workflow-runner/core/state-manager.d.ts +0 -24
- package/dist/workflow-runner/core/state-manager.js +0 -42
- package/dist/workflow-runner/core/workflow-logger.d.ts +0 -20
- package/dist/workflow-runner/core/workflow-logger.js +0 -65
- package/dist/workflow-runner/executors/phase-executor.d.ts +0 -8
- package/dist/workflow-runner/executors/phase-executor.js +0 -248
- package/dist/workflow-runner/feature-workflow-runner.d.ts +0 -26
- package/dist/workflow-runner/feature-workflow-runner.js +0 -119
- package/dist/workflow-runner/index.d.ts +0 -2
- package/dist/workflow-runner/index.js +0 -2
- package/dist/workflow-runner/pipeline-runner.d.ts +0 -17
- package/dist/workflow-runner/pipeline-runner.js +0 -393
- package/dist/workflow-runner/workflow-processor.d.ts +0 -54
- package/dist/workflow-runner/workflow-processor.js +0 -170
|
@@ -1,461 +0,0 @@
|
|
|
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 '../../utils/formatters.js';
|
|
7
|
-
import { createTechnicalDesignSystemPrompt, createTechnicalDesignPromptWithContext, } from './prompts.js';
|
|
8
|
-
import { formatChecklistsForContext, } from '../../services/checklist.js';
|
|
9
|
-
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
10
|
-
import { performVerificationCycle, buildDesignResult, buildVerificationFailureResult, buildNoResultsError, } from './analyzer-helpers.js';
|
|
11
|
-
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
12
|
-
function userMessage(content) {
|
|
13
|
-
return {
|
|
14
|
-
type: 'user',
|
|
15
|
-
message: { role: 'user', content: content },
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
async function* prompt(analysisPrompt) {
|
|
19
|
-
yield userMessage(analysisPrompt);
|
|
20
|
-
await new Promise((res) => setTimeout(res, 10000));
|
|
21
|
-
}
|
|
22
|
-
export const generateTechnicalDesign = async (options, config, checklistContext) => {
|
|
23
|
-
const { featureId, verbose } = options;
|
|
24
|
-
if (verbose) {
|
|
25
|
-
logInfo(`Starting technical design generation for feature ID: ${featureId}`);
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
// Fetch and prepare context
|
|
29
|
-
const context = await prepareDesignContext(featureId, checklistContext, verbose);
|
|
30
|
-
const systemPrompt = createTechnicalDesignSystemPrompt(config, featureId);
|
|
31
|
-
const initialDesignPrompt = context.designPrompt;
|
|
32
|
-
const maxIterations = options.maxVerificationIterations || 10;
|
|
33
|
-
let currentIteration = 0;
|
|
34
|
-
let currentPrompt = initialDesignPrompt;
|
|
35
|
-
let structuredDesignResult = null;
|
|
36
|
-
let verificationResult = null;
|
|
37
|
-
if (verbose) {
|
|
38
|
-
logInfo('Starting Claude Code query with pre-fetched information...');
|
|
39
|
-
}
|
|
40
|
-
// Iterative improvement loop: design → verification → improve → re-design
|
|
41
|
-
while (currentIteration < maxIterations) {
|
|
42
|
-
currentIteration++;
|
|
43
|
-
if (verbose && currentIteration > 1) {
|
|
44
|
-
logInfo(`\n🔄 Iteration ${currentIteration}/${maxIterations}: Improving design based on verification feedback...`);
|
|
45
|
-
}
|
|
46
|
-
// Log iteration start (for iterations after the first)
|
|
47
|
-
if (currentIteration > 1) {
|
|
48
|
-
await logFeaturePhaseEvent({
|
|
49
|
-
featureId,
|
|
50
|
-
eventType: 'phase_started',
|
|
51
|
-
phase: 'technical_design',
|
|
52
|
-
result: 'info',
|
|
53
|
-
metadata: {
|
|
54
|
-
iteration: currentIteration,
|
|
55
|
-
max_iterations: maxIterations,
|
|
56
|
-
re_design: true,
|
|
57
|
-
timestamp: new Date().toISOString(),
|
|
58
|
-
},
|
|
59
|
-
}, verbose);
|
|
60
|
-
}
|
|
61
|
-
// Execute design query
|
|
62
|
-
const newDesignResult = await executeDesignQuery(currentPrompt, systemPrompt, config, verbose);
|
|
63
|
-
// No result produced, break out
|
|
64
|
-
if (!newDesignResult?.technical_design) {
|
|
65
|
-
if (verbose) {
|
|
66
|
-
logError('⚠️ Design generation failed in this iteration');
|
|
67
|
-
}
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
// Update with new design result
|
|
71
|
-
structuredDesignResult = newDesignResult;
|
|
72
|
-
// Log design completion for this iteration
|
|
73
|
-
await logFeaturePhaseEvent({
|
|
74
|
-
featureId,
|
|
75
|
-
eventType: 'phase_completed',
|
|
76
|
-
phase: 'technical_design',
|
|
77
|
-
result: 'success',
|
|
78
|
-
metadata: {
|
|
79
|
-
iteration: currentIteration,
|
|
80
|
-
max_iterations: maxIterations,
|
|
81
|
-
design_step: 'completed',
|
|
82
|
-
timestamp: new Date().toISOString(),
|
|
83
|
-
},
|
|
84
|
-
}, verbose);
|
|
85
|
-
// Save technical design immediately after generation
|
|
86
|
-
if (verbose) {
|
|
87
|
-
logInfo(`💾 Saving technical design (iteration ${currentIteration})...`);
|
|
88
|
-
}
|
|
89
|
-
await saveTechnicalDesign(featureId, structuredDesignResult.technical_design, verbose);
|
|
90
|
-
// Perform verification cycle
|
|
91
|
-
const verificationCycle = await performVerificationCycle(structuredDesignResult.technical_design, checklistContext || null, context.feedbacksContext, featureId, context.featureName, context.featureDescription, config, currentIteration, maxIterations, verbose);
|
|
92
|
-
verificationResult = verificationCycle.verificationResult;
|
|
93
|
-
// If verification passed, exit
|
|
94
|
-
if (verificationCycle.passed) {
|
|
95
|
-
if (verbose) {
|
|
96
|
-
logInfo('✅ Verification passed! Technical design saved.');
|
|
97
|
-
}
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
// Verification failed
|
|
101
|
-
if (currentIteration < maxIterations && verificationCycle.nextPrompt) {
|
|
102
|
-
// We have more iterations - retry with improvement prompt
|
|
103
|
-
if (verbose) {
|
|
104
|
-
logInfo(`🔄 Will improve and save design in next iteration (${maxIterations - currentIteration} attempts remaining)`);
|
|
105
|
-
}
|
|
106
|
-
currentPrompt = verificationCycle.nextPrompt;
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// Max iterations reached or no next prompt - exit loop
|
|
110
|
-
if (verbose) {
|
|
111
|
-
logInfo('⚠️ Max iterations reached. Last design version saved.');
|
|
112
|
-
}
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Handle results
|
|
117
|
-
if (!structuredDesignResult?.technical_design) {
|
|
118
|
-
return buildNoResultsError(featureId);
|
|
119
|
-
}
|
|
120
|
-
// Check if verification failed after all iterations
|
|
121
|
-
if (verificationResult &&
|
|
122
|
-
verificationResult.rejected_count > 0 &&
|
|
123
|
-
checklistContext &&
|
|
124
|
-
checklistContext.checklists.length > 0) {
|
|
125
|
-
logError(`❌ Final result: Checklist verification FAILED after ${currentIteration} iterations`);
|
|
126
|
-
logError(` Technical design saved for manual review`);
|
|
127
|
-
return buildVerificationFailureResult(featureId, structuredDesignResult.technical_design, verificationResult, currentIteration);
|
|
128
|
-
}
|
|
129
|
-
// Return success result
|
|
130
|
-
return buildDesignResult(featureId, structuredDesignResult.technical_design, structuredDesignResult.summary ||
|
|
131
|
-
'Technical design generated successfully', currentIteration);
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
logError(`Technical design generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
135
|
-
return {
|
|
136
|
-
featureId,
|
|
137
|
-
technicalDesign: null,
|
|
138
|
-
status: 'error',
|
|
139
|
-
summary: `Generation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
/**
|
|
144
|
-
* Prepare all context information needed for design
|
|
145
|
-
*/
|
|
146
|
-
async function prepareDesignContext(featureId, checklistContext, verbose) {
|
|
147
|
-
if (verbose) {
|
|
148
|
-
logInfo('Fetching technical design context via MCP endpoints...');
|
|
149
|
-
}
|
|
150
|
-
const context = await fetchTechnicalDesignContext(featureId, verbose);
|
|
151
|
-
const { content: contextInfo, downloadedImages } = await formatTechnicalDesignContext(context);
|
|
152
|
-
if (verbose && downloadedImages.length > 0) {
|
|
153
|
-
logInfo(`Downloaded ${downloadedImages.length} images for Claude Code:`);
|
|
154
|
-
downloadedImages.forEach((img) => {
|
|
155
|
-
logInfo(` - ${img.url} -> ${img.localPath}`);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
let finalContextInfo = contextInfo;
|
|
159
|
-
let hasFeedbacks = false;
|
|
160
|
-
let feedbacksContext = null;
|
|
161
|
-
// Check if there's existing technical design
|
|
162
|
-
const existingTechnicalDesign = context.feature.technical_design;
|
|
163
|
-
const hasExistingDesign = !!existingTechnicalDesign && existingTechnicalDesign.trim().length > 0;
|
|
164
|
-
// Add existing technical design to context if it exists
|
|
165
|
-
if (hasExistingDesign && verbose) {
|
|
166
|
-
logInfo('📋 Found existing technical design - will perform incremental update if feedbacks exist');
|
|
167
|
-
}
|
|
168
|
-
// Add feedbacks context to the design prompt
|
|
169
|
-
try {
|
|
170
|
-
feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'technical-design');
|
|
171
|
-
if (verbose) {
|
|
172
|
-
logInfo(`📋 Feedbacks fetched successfully: ${feedbacksContext.feedbacks.length} feedbacks found`);
|
|
173
|
-
if (feedbacksContext.feedbacks.length > 0) {
|
|
174
|
-
logInfo('📝 Feedbacks details:');
|
|
175
|
-
feedbacksContext.feedbacks.forEach((fb, idx) => {
|
|
176
|
-
logInfo(` ${idx + 1}. [${fb.feedback_type}] ${fb.title} (priority: ${fb.priority}, resolved: ${fb.is_resolved || false})`);
|
|
177
|
-
logInfo(` Content: ${fb.content.substring(0, 150)}...`);
|
|
178
|
-
if (fb.target_type) {
|
|
179
|
-
logInfo(` 🎯 Target Type: ${fb.target_type}`);
|
|
180
|
-
}
|
|
181
|
-
if (fb.document_type) {
|
|
182
|
-
logInfo(` 📄 Document: ${fb.document_type}`);
|
|
183
|
-
}
|
|
184
|
-
if (fb.line_number) {
|
|
185
|
-
logInfo(` 📏 Line: ${fb.line_number}`);
|
|
186
|
-
}
|
|
187
|
-
else if (fb.line_range_start && fb.line_range_end) {
|
|
188
|
-
logInfo(` 📏 Lines: ${fb.line_range_start}-${fb.line_range_end}`);
|
|
189
|
-
}
|
|
190
|
-
if (fb.context_snippet) {
|
|
191
|
-
logInfo(` Referenced: ${fb.context_snippet.substring(0, 100)}...`);
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (feedbacksContext.feedbacks.length > 0) {
|
|
197
|
-
hasFeedbacks = true;
|
|
198
|
-
const feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
|
|
199
|
-
finalContextInfo = finalContextInfo + '\n\n' + feedbacksInfo;
|
|
200
|
-
if (verbose) {
|
|
201
|
-
logInfo(`✅ Added ${feedbacksContext.feedbacks.length} human feedbacks to design context`);
|
|
202
|
-
logInfo(`📄 Feedbacks section length: ${feedbacksInfo.length} characters`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
if (verbose) {
|
|
207
|
-
logInfo('ℹ️ No unresolved feedbacks found for this phase');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
// Don't fail if feedbacks fetch fails - just log and continue
|
|
213
|
-
if (verbose) {
|
|
214
|
-
logError(`❌ Failed to fetch feedbacks: ${error instanceof Error ? error.message : String(error)}`);
|
|
215
|
-
if (error instanceof Error && error.stack) {
|
|
216
|
-
logError(` Stack: ${error.stack}`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// Add checklist context to the design prompt
|
|
221
|
-
if (checklistContext && checklistContext.checklists.length > 0) {
|
|
222
|
-
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
223
|
-
finalContextInfo = finalContextInfo + '\n\n' + checklistInfo;
|
|
224
|
-
if (verbose) {
|
|
225
|
-
logInfo(`Added ${checklistContext.checklists.length} checklists to design context`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
// Decide on prompt mode based on existing design and feedbacks
|
|
229
|
-
const isIncrementalUpdate = hasExistingDesign && hasFeedbacks;
|
|
230
|
-
if (verbose) {
|
|
231
|
-
logInfo('\n📋 Design Mode Decision:');
|
|
232
|
-
logInfo(` - Has existing design: ${hasExistingDesign}`);
|
|
233
|
-
logInfo(` - Has feedbacks: ${hasFeedbacks} (${feedbacksContext?.feedbacks.length || 0} feedbacks)`);
|
|
234
|
-
logInfo(` - Mode: ${isIncrementalUpdate ? '🔄 Incremental Update' : hasExistingDesign ? '🔄 Full Redesign' : '✨ New Design'}`);
|
|
235
|
-
if (isIncrementalUpdate && feedbacksContext) {
|
|
236
|
-
logInfo('\n🎯 Feedbacks that will be addressed:');
|
|
237
|
-
feedbacksContext.feedbacks.forEach((fb, idx) => {
|
|
238
|
-
const priorityBadge = fb.priority >= 9
|
|
239
|
-
? '🔴'
|
|
240
|
-
: fb.priority >= 7
|
|
241
|
-
? '🟠'
|
|
242
|
-
: fb.priority >= 5
|
|
243
|
-
? '🟡'
|
|
244
|
-
: '🟢';
|
|
245
|
-
logInfo(` ${idx + 1}. [${fb.feedback_type}] ${fb.title} ${priorityBadge}`);
|
|
246
|
-
logInfo(` ${fb.content.substring(0, 100)}${fb.content.length > 100 ? '...' : ''}`);
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
const designPrompt = createTechnicalDesignPromptWithContext(featureId, finalContextInfo, existingTechnicalDesign, isIncrementalUpdate);
|
|
251
|
-
return {
|
|
252
|
-
featureName: context.feature.name,
|
|
253
|
-
featureDescription: context.feature.description || undefined,
|
|
254
|
-
designPrompt,
|
|
255
|
-
hasExistingDesign,
|
|
256
|
-
hasFeedbacks,
|
|
257
|
-
feedbacksContext,
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Execute design query and parse result
|
|
262
|
-
*/
|
|
263
|
-
async function executeDesignQuery(designPrompt, systemPrompt, config, verbose) {
|
|
264
|
-
let lastAssistantResponse = '';
|
|
265
|
-
let structuredDesignResult = null;
|
|
266
|
-
if (verbose) {
|
|
267
|
-
logInfo('🤖 Starting design agent query...');
|
|
268
|
-
}
|
|
269
|
-
// Use Claude Code SDK without MCP servers - all info is pre-fetched
|
|
270
|
-
for await (const message of query({
|
|
271
|
-
prompt: prompt(designPrompt),
|
|
272
|
-
options: {
|
|
273
|
-
appendSystemPrompt: systemPrompt,
|
|
274
|
-
model: config.claude.model || 'sonnet',
|
|
275
|
-
maxTurns: 1000,
|
|
276
|
-
permissionMode: 'bypassPermissions',
|
|
277
|
-
},
|
|
278
|
-
})) {
|
|
279
|
-
if (verbose) {
|
|
280
|
-
logInfo(` Received message type: ${message.type}`);
|
|
281
|
-
}
|
|
282
|
-
// Stream the technical design generation process
|
|
283
|
-
if (message.type === 'assistant' && message.message?.content) {
|
|
284
|
-
for (const content of message.message.content) {
|
|
285
|
-
if (content.type === 'text') {
|
|
286
|
-
lastAssistantResponse += content.text + '\n';
|
|
287
|
-
if (verbose) {
|
|
288
|
-
console.log(`\n🤖 ${content.text}`);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
else if (content.type === 'tool_use') {
|
|
292
|
-
if (verbose) {
|
|
293
|
-
console.log(`\n🔧 ${content.name}: ${content.input.description || 'Running...'}`);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (message.type === 'result') {
|
|
299
|
-
if (message.subtype === 'success') {
|
|
300
|
-
logInfo('\n🎨 Technical design generation completed, parsing results...');
|
|
301
|
-
try {
|
|
302
|
-
// Try to extract JSON from markdown code block or parse directly
|
|
303
|
-
const responseText = message.result || lastAssistantResponse;
|
|
304
|
-
let jsonResult = null;
|
|
305
|
-
// First try to extract JSON from markdown code block
|
|
306
|
-
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
307
|
-
if (jsonBlockMatch) {
|
|
308
|
-
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
// Try to find JSON object containing "technical_design_result"
|
|
312
|
-
let jsonStartIndex = -1;
|
|
313
|
-
// Find the position of "technical_design_result" and work backwards to find the opening brace
|
|
314
|
-
if (responseText.includes('"technical_design_result"')) {
|
|
315
|
-
const targetIndex = responseText.indexOf('"technical_design_result"');
|
|
316
|
-
// Work backwards from "technical_design_result" to find the opening '{'
|
|
317
|
-
for (let i = targetIndex; i >= 0; i--) {
|
|
318
|
-
if (responseText[i] === '{') {
|
|
319
|
-
jsonStartIndex = i;
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
if (jsonStartIndex !== -1) {
|
|
325
|
-
// Find the complete JSON object starting from this position
|
|
326
|
-
let braceCount = 0;
|
|
327
|
-
let endIndex = jsonStartIndex;
|
|
328
|
-
let inString = false;
|
|
329
|
-
let escapeNext = false;
|
|
330
|
-
for (let i = jsonStartIndex; i < responseText.length; i++) {
|
|
331
|
-
const char = responseText[i];
|
|
332
|
-
if (escapeNext) {
|
|
333
|
-
escapeNext = false;
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
if (char === '\\' && inString) {
|
|
337
|
-
escapeNext = true;
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
if (char === '"') {
|
|
341
|
-
inString = !inString;
|
|
342
|
-
continue;
|
|
343
|
-
}
|
|
344
|
-
if (!inString) {
|
|
345
|
-
if (char === '{') {
|
|
346
|
-
braceCount++;
|
|
347
|
-
}
|
|
348
|
-
else if (char === '}') {
|
|
349
|
-
braceCount--;
|
|
350
|
-
if (braceCount === 0) {
|
|
351
|
-
endIndex = i;
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
const jsonStr = responseText.substring(jsonStartIndex, endIndex + 1);
|
|
358
|
-
try {
|
|
359
|
-
jsonResult = JSON.parse(jsonStr);
|
|
360
|
-
}
|
|
361
|
-
catch (parseError) {
|
|
362
|
-
logError(`Failed to parse extracted JSON: ${parseError}`);
|
|
363
|
-
// Try to parse the entire response as JSON as fallback
|
|
364
|
-
jsonResult = JSON.parse(responseText);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
// Try to parse the entire response as JSON
|
|
369
|
-
jsonResult = JSON.parse(responseText);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (jsonResult && jsonResult.technical_design_result) {
|
|
373
|
-
structuredDesignResult = jsonResult.technical_design_result;
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
throw new Error('Invalid JSON structure');
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
logError(`Failed to parse structured design result: ${error}`);
|
|
381
|
-
// Extract technical design from response if JSON parsing fails
|
|
382
|
-
const extractedDesign = extractTechnicalDesignFromResponse(message.result || lastAssistantResponse);
|
|
383
|
-
structuredDesignResult = {
|
|
384
|
-
status: extractedDesign ? 'success' : 'error',
|
|
385
|
-
technical_design: extractedDesign,
|
|
386
|
-
summary: extractedDesign
|
|
387
|
-
? 'Technical design generated successfully'
|
|
388
|
-
: 'Failed to generate technical design',
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
logError(`\n⚠️ Technical design generation incomplete: ${message.subtype}`);
|
|
394
|
-
if (message.subtype === 'error_max_turns') {
|
|
395
|
-
logError('💡 Try increasing timeout or reducing complexity');
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return structuredDesignResult;
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* Save technical design document
|
|
404
|
-
*/
|
|
405
|
-
async function saveTechnicalDesign(featureId, technicalDesign, verbose) {
|
|
406
|
-
if (verbose) {
|
|
407
|
-
logInfo('Saving technical design...');
|
|
408
|
-
}
|
|
409
|
-
const designSaved = await updateTechnicalDesign(featureId, technicalDesign, verbose);
|
|
410
|
-
// Try HTTP fallback if direct update failed
|
|
411
|
-
if (!designSaved) {
|
|
412
|
-
if (verbose) {
|
|
413
|
-
logInfo('Direct update failed, trying HTTP fallback...');
|
|
414
|
-
}
|
|
415
|
-
const fallbackSaved = await saveTechnicalDesignViaHttp({
|
|
416
|
-
featureId,
|
|
417
|
-
technicalDesign,
|
|
418
|
-
verbose,
|
|
419
|
-
});
|
|
420
|
-
if (!fallbackSaved && verbose) {
|
|
421
|
-
logError('⚠️ Both direct update and HTTP fallback failed');
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
const extractTechnicalDesignFromResponse = (response) => {
|
|
426
|
-
// Try to extract technical design content from the response
|
|
427
|
-
// Look for markdown sections that contain technical design
|
|
428
|
-
const lines = response.split('\n');
|
|
429
|
-
let inTechnicalDesign = false;
|
|
430
|
-
const technicalDesignLines = [];
|
|
431
|
-
for (let i = 0; i < lines.length; i++) {
|
|
432
|
-
const line = lines[i].toLowerCase();
|
|
433
|
-
// Look for technical design section headers
|
|
434
|
-
if (line.includes('technical design') ||
|
|
435
|
-
line.includes('architecture') ||
|
|
436
|
-
line.includes('# design') ||
|
|
437
|
-
line.includes('## technical')) {
|
|
438
|
-
inTechnicalDesign = true;
|
|
439
|
-
technicalDesignLines.push(lines[i]);
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
if (inTechnicalDesign) {
|
|
443
|
-
// Continue until we hit another major section or JSON
|
|
444
|
-
if (line.startsWith('{') && line.includes('"technical_design_result"')) {
|
|
445
|
-
break;
|
|
446
|
-
}
|
|
447
|
-
technicalDesignLines.push(lines[i]);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
if (technicalDesignLines.length > 0) {
|
|
451
|
-
return technicalDesignLines.join('\n').trim();
|
|
452
|
-
}
|
|
453
|
-
// Ultimate fallback: return the whole response if it seems to contain design content
|
|
454
|
-
if (response.length > 100 &&
|
|
455
|
-
(response.toLowerCase().includes('architecture') ||
|
|
456
|
-
response.toLowerCase().includes('component') ||
|
|
457
|
-
response.toLowerCase().includes('database'))) {
|
|
458
|
-
return response.trim();
|
|
459
|
-
}
|
|
460
|
-
return null;
|
|
461
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
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(featureId: string, verbose?: boolean): Promise<TechnicalDesignContext>;
|
|
@@ -1,39 +0,0 @@
|
|
|
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(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(featureId, verbose),
|
|
15
|
-
getUserStories(featureId, verbose),
|
|
16
|
-
getTestCases(featureId, verbose),
|
|
17
|
-
]);
|
|
18
|
-
const product = await getProduct(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,17 +0,0 @@
|
|
|
1
|
-
export interface HttpFallbackOptions {
|
|
2
|
-
featureId: string;
|
|
3
|
-
technicalDesign: string;
|
|
4
|
-
verbose?: boolean;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Save technical design via HTTP as a fallback when MCP server fails
|
|
8
|
-
*/
|
|
9
|
-
export declare function saveTechnicalDesignViaHttp(options: HttpFallbackOptions): Promise<boolean>;
|
|
10
|
-
/**
|
|
11
|
-
* Verify that technical design was saved by retrieving it and optionally comparing content
|
|
12
|
-
*/
|
|
13
|
-
export declare function verifyTechnicalDesignSaved(featureId: string, verbose?: boolean, expectedContent?: string): Promise<boolean>;
|
|
14
|
-
/**
|
|
15
|
-
* Enhanced save with retry logic and verification
|
|
16
|
-
*/
|
|
17
|
-
export declare function saveTechnicalDesignWithRetry(options: HttpFallbackOptions, maxRetries?: number): Promise<boolean>;
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { logInfo, logError } from '../../utils/logger.js';
|
|
2
|
-
/**
|
|
3
|
-
* Save technical design via HTTP as a fallback when MCP server fails
|
|
4
|
-
*/
|
|
5
|
-
export async function saveTechnicalDesignViaHttp(options) {
|
|
6
|
-
const { featureId, technicalDesign, verbose } = options;
|
|
7
|
-
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
8
|
-
const mcpToken = process.env.MCP_TOKEN;
|
|
9
|
-
try {
|
|
10
|
-
if (verbose) {
|
|
11
|
-
logInfo('🔄 Attempting to save technical design via HTTP fallback...');
|
|
12
|
-
}
|
|
13
|
-
// Make direct HTTP call to the MCP server endpoint
|
|
14
|
-
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
15
|
-
method: 'POST',
|
|
16
|
-
headers: {
|
|
17
|
-
'Content-Type': 'application/json',
|
|
18
|
-
Authorization: `Bearer ${mcpToken}`,
|
|
19
|
-
},
|
|
20
|
-
body: JSON.stringify({
|
|
21
|
-
jsonrpc: '2.0',
|
|
22
|
-
method: 'features/update',
|
|
23
|
-
params: {
|
|
24
|
-
feature_id: featureId,
|
|
25
|
-
technical_design: technicalDesign,
|
|
26
|
-
},
|
|
27
|
-
id: Math.random().toString(36).substring(7),
|
|
28
|
-
}),
|
|
29
|
-
});
|
|
30
|
-
if (!response.ok) {
|
|
31
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
32
|
-
}
|
|
33
|
-
const data = await response.json();
|
|
34
|
-
if (data.error) {
|
|
35
|
-
throw new Error(data.error.message || 'HTTP call failed');
|
|
36
|
-
}
|
|
37
|
-
if (verbose) {
|
|
38
|
-
logInfo('✅ Technical design saved successfully via HTTP fallback');
|
|
39
|
-
}
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
if (verbose) {
|
|
44
|
-
logError(`❌ HTTP fallback failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
45
|
-
}
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Verify that technical design was saved by retrieving it and optionally comparing content
|
|
51
|
-
*/
|
|
52
|
-
export async function verifyTechnicalDesignSaved(featureId, verbose, expectedContent) {
|
|
53
|
-
try {
|
|
54
|
-
if (verbose) {
|
|
55
|
-
logInfo('🔍 Verifying technical design was saved...');
|
|
56
|
-
}
|
|
57
|
-
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
58
|
-
const mcpToken = process.env.MCP_TOKEN;
|
|
59
|
-
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
60
|
-
method: 'POST',
|
|
61
|
-
headers: {
|
|
62
|
-
'Content-Type': 'application/json',
|
|
63
|
-
Authorization: `Bearer ${mcpToken}`,
|
|
64
|
-
},
|
|
65
|
-
body: JSON.stringify({
|
|
66
|
-
jsonrpc: '2.0',
|
|
67
|
-
method: 'features/get',
|
|
68
|
-
params: {
|
|
69
|
-
feature_id: featureId,
|
|
70
|
-
},
|
|
71
|
-
id: Math.random().toString(36).substring(7),
|
|
72
|
-
}),
|
|
73
|
-
});
|
|
74
|
-
if (!response.ok) {
|
|
75
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
76
|
-
}
|
|
77
|
-
const data = await response.json();
|
|
78
|
-
if (data.error) {
|
|
79
|
-
throw new Error(data.error.message || 'Verification failed');
|
|
80
|
-
}
|
|
81
|
-
const feature = data.result?.features?.[0];
|
|
82
|
-
const actualTechnicalDesign = feature?.technical_design;
|
|
83
|
-
const hasTechnicalDesign = actualTechnicalDesign && actualTechnicalDesign.trim().length > 0;
|
|
84
|
-
// If expected content is provided, compare it with actual content
|
|
85
|
-
if (expectedContent && hasTechnicalDesign) {
|
|
86
|
-
const contentMatches = actualTechnicalDesign.trim() === expectedContent.trim();
|
|
87
|
-
if (verbose) {
|
|
88
|
-
if (contentMatches) {
|
|
89
|
-
logInfo('✅ Technical design verified - content matches expected');
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
logInfo('⚠️ Technical design exists but content differs from expected');
|
|
93
|
-
logInfo(`Expected length: ${expectedContent.length}, Actual length: ${actualTechnicalDesign.length}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return contentMatches;
|
|
97
|
-
}
|
|
98
|
-
if (verbose) {
|
|
99
|
-
if (hasTechnicalDesign) {
|
|
100
|
-
logInfo('✅ Technical design verified - successfully saved');
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
logInfo('⚠️ Technical design verification failed - not found');
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return hasTechnicalDesign;
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
if (verbose) {
|
|
110
|
-
logError(`❌ Verification failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
-
}
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Enhanced save with retry logic and verification
|
|
117
|
-
*/
|
|
118
|
-
export async function saveTechnicalDesignWithRetry(options, maxRetries = 3) {
|
|
119
|
-
const { verbose } = options;
|
|
120
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
121
|
-
if (verbose && attempt > 1) {
|
|
122
|
-
logInfo(`🔄 Retry attempt ${attempt} of ${maxRetries}...`);
|
|
123
|
-
}
|
|
124
|
-
const saved = await saveTechnicalDesignViaHttp(options);
|
|
125
|
-
if (saved) {
|
|
126
|
-
// Verify the save was successful
|
|
127
|
-
const verified = await verifyTechnicalDesignSaved(options.featureId, verbose);
|
|
128
|
-
if (verified) {
|
|
129
|
-
if (verbose) {
|
|
130
|
-
logInfo(`✅ Technical design successfully saved and verified (attempt ${attempt})`);
|
|
131
|
-
}
|
|
132
|
-
return true;
|
|
133
|
-
}
|
|
134
|
-
else if (verbose) {
|
|
135
|
-
logError(`❌ Save appeared successful but verification failed (attempt ${attempt})`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (attempt < maxRetries) {
|
|
139
|
-
// Wait before retrying
|
|
140
|
-
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); // Exponential backoff
|
|
141
|
-
if (verbose) {
|
|
142
|
-
logInfo(`⏳ Waiting ${delay}ms before retry...`);
|
|
143
|
-
}
|
|
144
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (verbose) {
|
|
148
|
-
logError(`❌ Failed to save technical design after ${maxRetries} attempts`);
|
|
149
|
-
}
|
|
150
|
-
return false;
|
|
151
|
-
}
|