edsger 0.2.4 → 0.2.6
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/cli/commands/refactor-command.js +43 -27
- package/dist/cli/formatters/formatter-utils.d.ts +23 -0
- package/dist/cli/formatters/formatter-utils.js +67 -0
- package/dist/cli/utils/command-handler.d.ts +23 -0
- package/dist/cli/utils/command-handler.js +39 -0
- package/dist/phases/bug-fixing/analyzer.js +25 -3
- package/dist/phases/code-implementation/analyzer.js +27 -7
- package/dist/phases/feature-analysis/analyzer.js +20 -2
- package/dist/phases/functional-testing/analyzer.js +26 -4
- package/dist/phases/technical-design/analyzer.js +43 -3
- package/dist/prompts/technical-design.d.ts +1 -1
- package/dist/prompts/technical-design.js +50 -3
- package/dist/services/feedbacks.d.ts +35 -0
- package/dist/services/feedbacks.js +142 -0
- package/package.json +1 -1
|
@@ -5,9 +5,9 @@ export const runRefactor = async (options) => {
|
|
|
5
5
|
// Load and validate configuration
|
|
6
6
|
const config = validateConfiguration(options);
|
|
7
7
|
if (options.verbose) {
|
|
8
|
-
logInfo('Starting code refactoring for current directory...');
|
|
8
|
+
logInfo('Starting automatic code refactoring for current directory...');
|
|
9
9
|
}
|
|
10
|
-
logInfo('Analyzing
|
|
10
|
+
logInfo('Analyzing and refactoring code...');
|
|
11
11
|
try {
|
|
12
12
|
const refactorPrompt = createRefactorPrompt(config);
|
|
13
13
|
const systemPrompt = createSystemPrompt();
|
|
@@ -17,6 +17,7 @@ export const runRefactor = async (options) => {
|
|
|
17
17
|
options: {
|
|
18
18
|
appendSystemPrompt: systemPrompt,
|
|
19
19
|
model: config.claude.model || 'sonnet',
|
|
20
|
+
permissionMode: 'bypassPermissions',
|
|
20
21
|
},
|
|
21
22
|
})) {
|
|
22
23
|
// Stream the refactoring process
|
|
@@ -33,7 +34,7 @@ export const runRefactor = async (options) => {
|
|
|
33
34
|
if (message.type === 'result') {
|
|
34
35
|
hasCompleted = true;
|
|
35
36
|
if (message.subtype === 'success') {
|
|
36
|
-
logSuccess('
|
|
37
|
+
logSuccess('Code refactoring completed successfully');
|
|
37
38
|
process.exit(0);
|
|
38
39
|
}
|
|
39
40
|
else {
|
|
@@ -56,52 +57,67 @@ export const runRefactor = async (options) => {
|
|
|
56
57
|
}
|
|
57
58
|
};
|
|
58
59
|
const createSystemPrompt = () => {
|
|
59
|
-
return `You are an expert code refactoring assistant using Claude Code. Your task is to analyze code in the current directory
|
|
60
|
+
return `You are an expert code refactoring assistant using Claude Code. Your task is to analyze and AUTOMATICALLY REFACTOR code in the current directory to improve quality and maintainability.
|
|
60
61
|
|
|
61
62
|
IMPORTANT INSTRUCTIONS:
|
|
62
63
|
1. Use the Bash tool to explore the project structure (ls, find, etc.)
|
|
63
64
|
2. Use the Read tool to examine file contents
|
|
64
65
|
3. Use the Grep tool to search for patterns, code smells, or duplications
|
|
65
|
-
4. Use the Edit tool to apply refactoring changes
|
|
66
|
-
5.
|
|
66
|
+
4. Use the Edit tool to DIRECTLY apply refactoring changes
|
|
67
|
+
5. You have FULL PERMISSION to make refactoring changes without asking for confirmation
|
|
67
68
|
|
|
68
|
-
REFACTORING FOCUS AREAS:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
REFACTORING FOCUS AREAS (prioritized):
|
|
70
|
+
1. Code duplication and DRY violations (HIGHEST PRIORITY)
|
|
71
|
+
2. Complex functions that need simplification
|
|
72
|
+
3. Poor naming conventions
|
|
73
|
+
4. Missing type annotations (TypeScript)
|
|
74
|
+
5. Inefficient algorithms or data structures
|
|
75
|
+
6. Code organization and structure
|
|
76
|
+
7. Missing or inadequate error handling
|
|
77
|
+
8. Opportunities for better abstraction
|
|
78
|
+
9. Performance improvements
|
|
78
79
|
|
|
79
80
|
WORKFLOW:
|
|
80
81
|
1. First, explore the project structure to understand the codebase
|
|
81
82
|
2. Identify files that would benefit from refactoring
|
|
82
|
-
3. Analyze specific issues and patterns
|
|
83
|
-
4.
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
3. Analyze specific issues and patterns (focus on high-impact issues first)
|
|
84
|
+
4. For each issue found:
|
|
85
|
+
- Explain what you're refactoring and why
|
|
86
|
+
- Apply the refactoring using the Edit tool
|
|
87
|
+
- Verify the change is correct
|
|
88
|
+
5. Continue until all high-priority refactorings are complete or you run out of turns
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
SAFETY GUIDELINES:
|
|
91
|
+
- Start with safest refactorings (extract utilities, remove duplication)
|
|
92
|
+
- Preserve existing functionality - only improve structure/quality
|
|
93
|
+
- Focus on non-breaking changes
|
|
94
|
+
- Make atomic commits for each logical refactoring
|
|
95
|
+
|
|
96
|
+
IMPORTANT: You should DIRECTLY perform refactorings without asking for permission. The user has granted you full bypass authority to improve the code.`;
|
|
88
97
|
};
|
|
89
98
|
const createRefactorPrompt = (config) => {
|
|
90
|
-
return `Please analyze the code in the current directory
|
|
99
|
+
return `Please analyze and REFACTOR the code in the current directory. You have full permission to make improvements directly.
|
|
100
|
+
|
|
101
|
+
TASK: Automatically identify and fix code quality issues
|
|
91
102
|
|
|
92
103
|
Steps to follow:
|
|
93
104
|
1. Start by running "ls -la" to see the project structure
|
|
94
105
|
2. Identify key source files (focus on patterns: ${config.patterns.join(', ')})
|
|
95
106
|
3. Read and analyze relevant source files
|
|
96
|
-
4. Look for:
|
|
97
|
-
- Code duplication
|
|
107
|
+
4. Look for HIGH-PRIORITY issues:
|
|
108
|
+
- Code duplication (MOST IMPORTANT - fix first)
|
|
98
109
|
- Complex or long functions
|
|
99
110
|
- Poor naming
|
|
100
111
|
- Missing types or documentation
|
|
101
112
|
- Error handling issues
|
|
102
113
|
- Performance bottlenecks
|
|
103
|
-
5.
|
|
104
|
-
|
|
114
|
+
5. For EACH issue found, IMMEDIATELY apply the fix:
|
|
115
|
+
- Use the Edit tool to make the change
|
|
116
|
+
- Explain what you changed and why
|
|
117
|
+
- Move to the next issue
|
|
118
|
+
6. Continue refactoring until all high-priority issues are addressed
|
|
119
|
+
|
|
120
|
+
IMPORTANT: Do NOT ask for permission. You have full bypass authority to improve the code directly. Start refactoring immediately after analysis.
|
|
105
121
|
|
|
106
|
-
Start by exploring the current directory structure.`;
|
|
122
|
+
Start by exploring the current directory structure and begin refactoring.`;
|
|
107
123
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface FormatterSection {
|
|
2
|
+
title: string;
|
|
3
|
+
content?: string;
|
|
4
|
+
items?: Array<{
|
|
5
|
+
label: string;
|
|
6
|
+
value?: string | number;
|
|
7
|
+
type?: 'success' | 'error' | 'info';
|
|
8
|
+
}>;
|
|
9
|
+
list?: Array<{
|
|
10
|
+
text: string;
|
|
11
|
+
isHighlight?: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export interface FormatterOptions {
|
|
15
|
+
title: string;
|
|
16
|
+
icon: string;
|
|
17
|
+
sections: FormatterSection[];
|
|
18
|
+
verbose?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare const formatResults: (options: FormatterOptions) => void;
|
|
21
|
+
export declare const createStatusSection: (featureId: string, status: string) => FormatterSection;
|
|
22
|
+
export declare const createSummarySection: (summary?: string) => FormatterSection | null;
|
|
23
|
+
export declare const createContentPreview: (content: string, title: string, maxLines?: number) => FormatterSection;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export const formatResults = (options) => {
|
|
2
|
+
const { title, icon, sections } = options;
|
|
3
|
+
console.log('\n' + '='.repeat(60));
|
|
4
|
+
console.log(`${icon} ${title}`);
|
|
5
|
+
console.log('='.repeat(60));
|
|
6
|
+
sections.forEach((section) => {
|
|
7
|
+
if (section.title) {
|
|
8
|
+
console.log(`\n${section.title}`);
|
|
9
|
+
}
|
|
10
|
+
if (section.content) {
|
|
11
|
+
console.log(section.content);
|
|
12
|
+
}
|
|
13
|
+
if (section.items) {
|
|
14
|
+
section.items.forEach((item) => {
|
|
15
|
+
const statusIcon = getStatusIcon(item.type);
|
|
16
|
+
const value = item.value !== undefined ? `: ${item.value}` : '';
|
|
17
|
+
console.log(`${statusIcon} ${item.label}${value}`);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (section.list) {
|
|
21
|
+
section.list.forEach((listItem, index) => {
|
|
22
|
+
const prefix = listItem.isHighlight ? ' ⭐' : ' ';
|
|
23
|
+
console.log(`${prefix}${index + 1}. ${listItem.text}`);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
console.log('\n' + '='.repeat(60));
|
|
28
|
+
};
|
|
29
|
+
export const createStatusSection = (featureId, status) => ({
|
|
30
|
+
title: '',
|
|
31
|
+
items: [
|
|
32
|
+
{ label: '📋 Feature ID', value: featureId },
|
|
33
|
+
{
|
|
34
|
+
label: '📊 Status',
|
|
35
|
+
value: status === 'success' || status === 'testing_passed' ? '✅ Success' : '❌ Failed',
|
|
36
|
+
type: status === 'success' || status === 'testing_passed' ? 'success' : 'error'
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
});
|
|
40
|
+
export const createSummarySection = (summary) => {
|
|
41
|
+
if (!summary)
|
|
42
|
+
return null;
|
|
43
|
+
return {
|
|
44
|
+
title: '📝 Summary:',
|
|
45
|
+
content: summary
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export const createContentPreview = (content, title, maxLines = 10) => {
|
|
49
|
+
const lines = content.split('\n');
|
|
50
|
+
const previewLines = lines.slice(0, maxLines);
|
|
51
|
+
let displayContent = previewLines.join('\n');
|
|
52
|
+
if (lines.length > maxLines) {
|
|
53
|
+
displayContent += `\n... (${lines.length - maxLines} more lines)`;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
title: `${title}:`,
|
|
57
|
+
content: '─'.repeat(40) + '\n' + displayContent + '\n' + '─'.repeat(40)
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
function getStatusIcon(type) {
|
|
61
|
+
switch (type) {
|
|
62
|
+
case 'success': return '✅';
|
|
63
|
+
case 'error': return '❌';
|
|
64
|
+
case 'info': return 'ℹ️';
|
|
65
|
+
default: return '📊';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CliOptions } from '../../types/index.js';
|
|
2
|
+
export interface CommandOptions {
|
|
3
|
+
featureId: string;
|
|
4
|
+
mcpServerUrl: string;
|
|
5
|
+
mcpToken: string;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface CommandResult {
|
|
9
|
+
status: 'success' | 'error' | 'testing_passed' | 'testing_failed' | 'pending';
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
export interface CommandConfig<TResult extends CommandResult> {
|
|
13
|
+
name: string;
|
|
14
|
+
getFeatureId: (options: CliOptions) => string | undefined;
|
|
15
|
+
checkRequirements: () => Promise<boolean>;
|
|
16
|
+
requirementsError: string;
|
|
17
|
+
startMessage: string;
|
|
18
|
+
successMessage: string;
|
|
19
|
+
errorMessage: string;
|
|
20
|
+
analyzer: (commandOptions: CommandOptions, config: any, ...args: any[]) => Promise<TResult>;
|
|
21
|
+
formatter: (result: TResult, verbose?: boolean) => void;
|
|
22
|
+
}
|
|
23
|
+
export declare function executeCommand<TResult extends CommandResult>(options: CliOptions, config: CommandConfig<TResult>): Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { logInfo, logError, logSuccess } from '../../utils/logger.js';
|
|
2
|
+
import { validateCommandEnvironment, validateRequirements, } from './validation.js';
|
|
3
|
+
export async function executeCommand(options, config) {
|
|
4
|
+
await validateRequirements(config.checkRequirements, config.requirementsError);
|
|
5
|
+
const { config: edsgerConfig, mcpServerUrl, mcpToken } = validateCommandEnvironment(options);
|
|
6
|
+
const featureId = config.getFeatureId(options);
|
|
7
|
+
if (!featureId) {
|
|
8
|
+
throw new Error(`Feature ID is required for ${config.name}`);
|
|
9
|
+
}
|
|
10
|
+
if (options.verbose) {
|
|
11
|
+
logInfo(`${config.startMessage}: ${featureId}`);
|
|
12
|
+
}
|
|
13
|
+
logInfo(`Starting ${config.name}...`);
|
|
14
|
+
try {
|
|
15
|
+
const result = await config.analyzer({
|
|
16
|
+
featureId,
|
|
17
|
+
mcpServerUrl,
|
|
18
|
+
mcpToken,
|
|
19
|
+
verbose: options.verbose,
|
|
20
|
+
}, edsgerConfig);
|
|
21
|
+
config.formatter(result, options.verbose);
|
|
22
|
+
if (result.status === 'success' || result.status === 'testing_passed') {
|
|
23
|
+
logSuccess(config.successMessage);
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
else if (result.status === 'error' || result.status === 'testing_failed') {
|
|
27
|
+
logError(config.errorMessage);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logError(`${config.errorMessage}: ${result.status}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
logError(`${config.errorMessage}: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { query } from '@anthropic-ai/claude-code';
|
|
2
2
|
import { logInfo, logError } from '../../utils/logger.js';
|
|
3
|
+
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
3
4
|
import { fetchBugFixingContext, formatContextForPrompt, } from './context-fetcher.js';
|
|
4
5
|
function userMessage(content) {
|
|
5
6
|
return {
|
|
@@ -23,8 +24,25 @@ export const fixTestFailures = async (options, config) => {
|
|
|
23
24
|
logInfo('Fetching bug fixing context via MCP endpoints...');
|
|
24
25
|
}
|
|
25
26
|
const context = await fetchBugFixingContext(mcpServerUrl, mcpToken, featureId, verbose);
|
|
27
|
+
// Fetch feedbacks for bug fixing phase
|
|
28
|
+
let feedbacksInfo;
|
|
29
|
+
try {
|
|
30
|
+
const feedbacksContext = await getFeedbacksForPhase({ featureId, mcpServerUrl, mcpToken, verbose }, 'bug_fixing');
|
|
31
|
+
if (feedbacksContext.feedbacks.length > 0) {
|
|
32
|
+
feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
|
|
33
|
+
if (verbose) {
|
|
34
|
+
logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to bug fixing context`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
// Don't fail if feedbacks fetch fails - just log and continue
|
|
40
|
+
if (verbose) {
|
|
41
|
+
logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
26
44
|
const systemPrompt = createSystemPrompt(config);
|
|
27
|
-
const bugFixPrompt = createBugFixPromptWithContext(featureId, testErrors, attemptNumber, context);
|
|
45
|
+
const bugFixPrompt = createBugFixPromptWithContext(featureId, testErrors, attemptNumber, context, feedbacksInfo);
|
|
28
46
|
let lastAssistantResponse = '';
|
|
29
47
|
let structuredFixResult = null;
|
|
30
48
|
if (verbose) {
|
|
@@ -208,8 +226,12 @@ You MUST end your response with a JSON object containing the bug fix results in
|
|
|
208
226
|
|
|
209
227
|
Focus on systematic bug fixing based on the provided context and test failure information.`;
|
|
210
228
|
}
|
|
211
|
-
function createBugFixPromptWithContext(featureId, testErrors, attemptNumber, context) {
|
|
212
|
-
|
|
229
|
+
function createBugFixPromptWithContext(featureId, testErrors, attemptNumber, context, feedbacksInfo) {
|
|
230
|
+
let contextInfo = formatContextForPrompt(context, testErrors);
|
|
231
|
+
// Add feedbacks context to the bug fixing prompt
|
|
232
|
+
if (feedbacksInfo) {
|
|
233
|
+
contextInfo = contextInfo + '\n\n' + feedbacksInfo;
|
|
234
|
+
}
|
|
213
235
|
return `Fix the test failures for feature: ${featureId} (Attempt ${attemptNumber})
|
|
214
236
|
|
|
215
237
|
${contextInfo}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
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
|
+
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
4
5
|
import { fetchCodeImplementationContext, formatContextForPrompt, } from './context-fetcher.js';
|
|
5
6
|
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
6
7
|
import { performVerificationCycle, buildImplementationResult, buildVerificationFailureResult, buildNoResultsError, } from './analyzer-helpers.js';
|
|
@@ -27,8 +28,25 @@ export const implementFeatureCode = async (options, config, checklistContext) =>
|
|
|
27
28
|
logInfo('Fetching code implementation context via MCP endpoints...');
|
|
28
29
|
}
|
|
29
30
|
const context = await fetchCodeImplementationContext(mcpServerUrl, mcpToken, featureId, verbose);
|
|
31
|
+
// Fetch feedbacks for code implementation phase
|
|
32
|
+
let feedbacksInfo;
|
|
33
|
+
try {
|
|
34
|
+
const feedbacksContext = await getFeedbacksForPhase({ featureId, mcpServerUrl, mcpToken, verbose }, 'code_implementation');
|
|
35
|
+
if (feedbacksContext.feedbacks.length > 0) {
|
|
36
|
+
feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
|
|
37
|
+
if (verbose) {
|
|
38
|
+
logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to implementation context`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
// Don't fail if feedbacks fetch fails - just log and continue
|
|
44
|
+
if (verbose) {
|
|
45
|
+
logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
30
48
|
const systemPrompt = createSystemPrompt(config, baseBranch, mcpServerUrl, mcpToken, featureId);
|
|
31
|
-
const initialImplementationPrompt = createImplementationPromptWithContext(featureId, context, baseBranch, checklistContext, verbose);
|
|
49
|
+
const initialImplementationPrompt = createImplementationPromptWithContext(featureId, context, baseBranch, checklistContext, verbose, feedbacksInfo);
|
|
32
50
|
const maxIterations = options.maxVerificationIterations || 10;
|
|
33
51
|
let currentIteration = 0;
|
|
34
52
|
let currentPrompt = initialImplementationPrompt;
|
|
@@ -429,14 +447,18 @@ IMPORTANT: In the checklist context, look for lines that say "ID: [UUID]" in the
|
|
|
429
447
|
|
|
430
448
|
Remember: Quality over speed. It's better to implement correctly than to rush and create bugs.`;
|
|
431
449
|
};
|
|
432
|
-
const createImplementationPromptWithContext = (featureId, context, baseBranch, checklistContext, verbose) => {
|
|
450
|
+
const createImplementationPromptWithContext = (featureId, context, baseBranch, checklistContext, verbose, feedbacksInfo) => {
|
|
433
451
|
const contextInfo = formatContextForPrompt(context);
|
|
434
|
-
// Add checklist context to the implementation prompt
|
|
435
452
|
let finalContextInfo = contextInfo;
|
|
453
|
+
// Add feedbacks context to the implementation prompt
|
|
454
|
+
if (feedbacksInfo) {
|
|
455
|
+
finalContextInfo = finalContextInfo + '\n\n' + feedbacksInfo;
|
|
456
|
+
}
|
|
457
|
+
// Add checklist context to the implementation prompt
|
|
436
458
|
let checklistInstructions = '';
|
|
437
459
|
if (checklistContext && checklistContext.checklists.length > 0) {
|
|
438
460
|
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
439
|
-
finalContextInfo =
|
|
461
|
+
finalContextInfo = finalContextInfo + '\n\n' + checklistInfo;
|
|
440
462
|
// DEBUG: Log checklist context details
|
|
441
463
|
console.log('=== DEBUG: Checklist Context for Code Implementation ===');
|
|
442
464
|
console.log('Number of checklists:', checklistContext.checklists.length);
|
|
@@ -601,9 +623,7 @@ async function pushToRemote(branchName, verbose) {
|
|
|
601
623
|
return { success: true };
|
|
602
624
|
}
|
|
603
625
|
catch (retryError) {
|
|
604
|
-
const errorMessage = retryError instanceof Error
|
|
605
|
-
? retryError.message
|
|
606
|
-
: String(retryError);
|
|
626
|
+
const errorMessage = retryError instanceof Error ? retryError.message : String(retryError);
|
|
607
627
|
return {
|
|
608
628
|
success: false,
|
|
609
629
|
error: errorMessage,
|
|
@@ -3,6 +3,7 @@ import { fetchFeatureAnalysisContext, } from './context-fetcher.js';
|
|
|
3
3
|
import { formatFeatureAnalysisContext } from '../../prompts/formatters.js';
|
|
4
4
|
import { createFeatureAnalysisSystemPrompt, createFeatureAnalysisPromptWithContext, } from '../../prompts/feature-analysis.js';
|
|
5
5
|
import { formatChecklistsForContext, } from '../../services/checklist.js';
|
|
6
|
+
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
6
7
|
import { executeAnalysisQuery, performVerificationCycle, saveAnalysisArtifactsAsDraft, updateArtifactsToReady, deleteArtifacts, buildAnalysisResult, buildVerificationFailureResult, buildNoResultsError, } from './analyzer-helpers.js';
|
|
7
8
|
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
8
9
|
export const analyzeFeatureWithMCP = async (options, config, checklistContext) => {
|
|
@@ -165,11 +166,28 @@ async function prepareAnalysisContext(mcpServerUrl, mcpToken, featureId, checkli
|
|
|
165
166
|
logInfo(` - ${img.url} -> ${img.localPath}`);
|
|
166
167
|
});
|
|
167
168
|
}
|
|
168
|
-
// Add checklist context to the analysis prompt
|
|
169
169
|
let finalContextInfo = contextInfo;
|
|
170
|
+
// Add feedbacks context to the analysis prompt
|
|
171
|
+
try {
|
|
172
|
+
const feedbacksContext = await getFeedbacksForPhase({ featureId, mcpServerUrl, mcpToken, verbose }, 'feature-analysis');
|
|
173
|
+
if (feedbacksContext.feedbacks.length > 0) {
|
|
174
|
+
const feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
|
|
175
|
+
finalContextInfo = finalContextInfo + '\n\n' + feedbacksInfo;
|
|
176
|
+
if (verbose) {
|
|
177
|
+
logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to context`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
// Don't fail if feedbacks fetch fails - just log and continue
|
|
183
|
+
if (verbose) {
|
|
184
|
+
logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Add checklist context to the analysis prompt
|
|
170
188
|
if (checklistContext && checklistContext.checklists.length > 0) {
|
|
171
189
|
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
172
|
-
finalContextInfo =
|
|
190
|
+
finalContextInfo = finalContextInfo + '\n\n' + checklistInfo;
|
|
173
191
|
if (verbose) {
|
|
174
192
|
logInfo(`Added ${checklistContext.checklists.length} checklists to analysis context`);
|
|
175
193
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
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
|
+
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
4
5
|
import { saveFunctionalTestResultsWithRetry } from './http-fallback.js';
|
|
5
6
|
import { fetchFunctionalTestingContext, formatContextForPrompt, } from './context-fetcher.js';
|
|
6
7
|
import { updateFeatureStatus } from '../../api/features/index.js';
|
|
@@ -27,8 +28,25 @@ export const runFunctionalTesting = async (options, config, checklistContext) =>
|
|
|
27
28
|
logInfo('Fetching feature testing context via MCP endpoints...');
|
|
28
29
|
}
|
|
29
30
|
const context = await fetchFunctionalTestingContext(mcpServerUrl, mcpToken, featureId, verbose);
|
|
31
|
+
// Fetch feedbacks for functional testing phase
|
|
32
|
+
let feedbacksInfo;
|
|
33
|
+
try {
|
|
34
|
+
const feedbacksContext = await getFeedbacksForPhase({ featureId, mcpServerUrl, mcpToken, verbose }, 'functional_testing');
|
|
35
|
+
if (feedbacksContext.feedbacks.length > 0) {
|
|
36
|
+
feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
|
|
37
|
+
if (verbose) {
|
|
38
|
+
logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to testing context`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
// Don't fail if feedbacks fetch fails - just log and continue
|
|
44
|
+
if (verbose) {
|
|
45
|
+
logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
30
48
|
const systemPrompt = createSystemPrompt(config, mcpServerUrl, mcpToken, featureId);
|
|
31
|
-
const testingPrompt = createTestingPromptWithContext(featureId, context, checklistContext, verbose);
|
|
49
|
+
const testingPrompt = createTestingPromptWithContext(featureId, context, checklistContext, verbose, feedbacksInfo);
|
|
32
50
|
let lastAssistantResponse = '';
|
|
33
51
|
let structuredTestResult = null;
|
|
34
52
|
let testStatus = 'testing_failed';
|
|
@@ -475,13 +493,17 @@ IMPORTANT: In the checklist context, look for lines that say "ID: [UUID]" in the
|
|
|
475
493
|
|
|
476
494
|
Focus on systematic testing based on the provided context information.${mcpInstructions}`;
|
|
477
495
|
};
|
|
478
|
-
const createTestingPromptWithContext = (featureId, context, checklistContext, verbose) => {
|
|
496
|
+
const createTestingPromptWithContext = (featureId, context, checklistContext, verbose, feedbacksInfo) => {
|
|
479
497
|
const contextInfo = formatContextForPrompt(context);
|
|
480
|
-
// Add checklist context to the testing prompt
|
|
481
498
|
let finalContextInfo = contextInfo;
|
|
499
|
+
// Add feedbacks context to the testing prompt
|
|
500
|
+
if (feedbacksInfo) {
|
|
501
|
+
finalContextInfo = finalContextInfo + '\n\n' + feedbacksInfo;
|
|
502
|
+
}
|
|
503
|
+
// Add checklist context to the testing prompt
|
|
482
504
|
if (checklistContext && checklistContext.checklists.length > 0) {
|
|
483
505
|
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
484
|
-
finalContextInfo =
|
|
506
|
+
finalContextInfo = finalContextInfo + '\n\n' + checklistInfo;
|
|
485
507
|
if (verbose) {
|
|
486
508
|
logInfo(`Added ${checklistContext.checklists.length} checklists to testing context`);
|
|
487
509
|
}
|
|
@@ -6,6 +6,7 @@ import { updateTechnicalDesign } from '../../api/features/index.js';
|
|
|
6
6
|
import { formatTechnicalDesignContext } from '../../prompts/formatters.js';
|
|
7
7
|
import { createTechnicalDesignSystemPrompt, createTechnicalDesignPromptWithContext, } from '../../prompts/technical-design.js';
|
|
8
8
|
import { formatChecklistsForContext, } from '../../services/checklist.js';
|
|
9
|
+
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
9
10
|
import { performVerificationCycle, buildDesignResult, buildVerificationFailureResult, buildNoResultsError, } from './analyzer-helpers.js';
|
|
10
11
|
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
11
12
|
function userMessage(content) {
|
|
@@ -155,20 +156,59 @@ async function prepareDesignContext(mcpServerUrl, mcpToken, featureId, checklist
|
|
|
155
156
|
logInfo(` - ${img.url} -> ${img.localPath}`);
|
|
156
157
|
});
|
|
157
158
|
}
|
|
158
|
-
// Add checklist context to the design prompt
|
|
159
159
|
let finalContextInfo = contextInfo;
|
|
160
|
+
let hasFeedbacks = false;
|
|
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
|
+
const feedbacksContext = await getFeedbacksForPhase({ featureId, mcpServerUrl, mcpToken, verbose }, 'technical-design');
|
|
171
|
+
if (feedbacksContext.feedbacks.length > 0) {
|
|
172
|
+
hasFeedbacks = true;
|
|
173
|
+
const feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
|
|
174
|
+
finalContextInfo = finalContextInfo + '\n\n' + feedbacksInfo;
|
|
175
|
+
if (verbose) {
|
|
176
|
+
logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to design context`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
// Don't fail if feedbacks fetch fails - just log and continue
|
|
182
|
+
if (verbose) {
|
|
183
|
+
logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Add checklist context to the design prompt
|
|
160
187
|
if (checklistContext && checklistContext.checklists.length > 0) {
|
|
161
188
|
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
162
|
-
finalContextInfo =
|
|
189
|
+
finalContextInfo = finalContextInfo + '\n\n' + checklistInfo;
|
|
163
190
|
if (verbose) {
|
|
164
191
|
logInfo(`Added ${checklistContext.checklists.length} checklists to design context`);
|
|
165
192
|
}
|
|
166
193
|
}
|
|
167
|
-
|
|
194
|
+
// Decide on prompt mode based on existing design and feedbacks
|
|
195
|
+
const isIncrementalUpdate = hasExistingDesign && hasFeedbacks;
|
|
196
|
+
if (isIncrementalUpdate && verbose) {
|
|
197
|
+
logInfo('🔄 Mode: Incremental Update (existing design + feedbacks)');
|
|
198
|
+
}
|
|
199
|
+
else if (hasExistingDesign && verbose) {
|
|
200
|
+
logInfo('🔄 Mode: Full Redesign (existing design but no feedbacks)');
|
|
201
|
+
}
|
|
202
|
+
else if (verbose) {
|
|
203
|
+
logInfo('✨ Mode: New Design (no existing design)');
|
|
204
|
+
}
|
|
205
|
+
const designPrompt = createTechnicalDesignPromptWithContext(featureId, finalContextInfo, existingTechnicalDesign, isIncrementalUpdate);
|
|
168
206
|
return {
|
|
169
207
|
featureName: context.feature.name,
|
|
170
208
|
featureDescription: context.feature.description || undefined,
|
|
171
209
|
designPrompt,
|
|
210
|
+
hasExistingDesign,
|
|
211
|
+
hasFeedbacks,
|
|
172
212
|
};
|
|
173
213
|
}
|
|
174
214
|
/**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { EdsgerConfig } from '../types/index.js';
|
|
2
2
|
export declare const createTechnicalDesignSystemPrompt: (_config: EdsgerConfig, mcpServerUrl?: string, mcpToken?: string, featureId?: string) => string;
|
|
3
|
-
export declare const createTechnicalDesignPromptWithContext: (featureId: string, contextInfo: string) => string;
|
|
3
|
+
export declare const createTechnicalDesignPromptWithContext: (featureId: string, contextInfo: string, existingTechnicalDesign?: string | null, isIncrementalUpdate?: boolean) => string;
|
|
@@ -89,11 +89,58 @@ IMPORTANT: In the checklist context, look for lines that say "ID: [UUID]" in the
|
|
|
89
89
|
|
|
90
90
|
Focus on systematic technical design based on the provided context information.${mcpInstructions}`;
|
|
91
91
|
};
|
|
92
|
-
export const createTechnicalDesignPromptWithContext = (featureId, contextInfo) => {
|
|
93
|
-
|
|
92
|
+
export const createTechnicalDesignPromptWithContext = (featureId, contextInfo, existingTechnicalDesign, isIncrementalUpdate = false) => {
|
|
93
|
+
// If incremental update mode (existing design + feedbacks), create focused update prompt
|
|
94
|
+
if (isIncrementalUpdate && existingTechnicalDesign) {
|
|
95
|
+
return `Update the technical design for feature ID: ${featureId} based on human feedbacks
|
|
96
|
+
|
|
97
|
+
## Current Technical Design
|
|
98
|
+
|
|
99
|
+
${existingTechnicalDesign}
|
|
100
|
+
|
|
101
|
+
## Context and Feedbacks
|
|
94
102
|
|
|
95
103
|
${contextInfo}
|
|
96
104
|
|
|
105
|
+
## IMPORTANT: Incremental Update Mode
|
|
106
|
+
|
|
107
|
+
You are in **INCREMENTAL UPDATE** mode. This means:
|
|
108
|
+
|
|
109
|
+
1. **DO NOT redesign from scratch** - The current technical design is already approved
|
|
110
|
+
2. **Focus ONLY on the feedbacks provided** - Address each feedback point specifically
|
|
111
|
+
3. **Make targeted modifications** - Only change the sections that feedbacks request
|
|
112
|
+
4. **Preserve approved sections** - Keep all parts of the design that are not mentioned in feedbacks
|
|
113
|
+
5. **Track changes** - In your summary, clearly indicate what was modified and why
|
|
114
|
+
|
|
115
|
+
## Update Instructions
|
|
116
|
+
|
|
117
|
+
Follow this focused approach:
|
|
118
|
+
|
|
119
|
+
1. **Review Current Design**: Carefully read the existing technical design above
|
|
120
|
+
2. **Analyze Feedbacks**: Understand what specific changes are requested in the feedbacks
|
|
121
|
+
3. **Make Targeted Updates**:
|
|
122
|
+
- Address each feedback point one by one
|
|
123
|
+
- Modify only the relevant sections of the design
|
|
124
|
+
- Preserve the structure and content of unchanged sections
|
|
125
|
+
4. **Verify Completeness**: Ensure all feedbacks have been addressed
|
|
126
|
+
|
|
127
|
+
## Important Notes
|
|
128
|
+
- This is NOT a full redesign - only update what feedbacks specifically request
|
|
129
|
+
- Maintain consistency with the existing design's structure and style
|
|
130
|
+
- If a feedback is unclear, make your best interpretation and note it in recommendations
|
|
131
|
+
- Keep all approved content that is not mentioned in feedbacks
|
|
132
|
+
- Your summary should list each feedback addressed and the changes made
|
|
133
|
+
|
|
134
|
+
Begin by reviewing the feedbacks and identifying which sections of the current design need updates.`;
|
|
135
|
+
}
|
|
136
|
+
// Default mode: full design (either new design or full redesign)
|
|
137
|
+
const designMode = existingTechnicalDesign
|
|
138
|
+
? 'Update and improve the existing technical design, or redesign if needed'
|
|
139
|
+
: 'Generate a comprehensive technical design';
|
|
140
|
+
return `${designMode} for feature ID: ${featureId}
|
|
141
|
+
|
|
142
|
+
${existingTechnicalDesign ? `## Existing Technical Design\n\n${existingTechnicalDesign}\n\n` : ''}${contextInfo}
|
|
143
|
+
|
|
97
144
|
## Technical Design Instructions
|
|
98
145
|
|
|
99
146
|
Follow this systematic approach:
|
|
@@ -122,7 +169,7 @@ Follow this systematic approach:
|
|
|
122
169
|
- Focus on creating detailed architectural specifications
|
|
123
170
|
- Consider the user stories to understand what needs to be built
|
|
124
171
|
- Use test cases to inform testing strategy and validation approaches
|
|
125
|
-
- Build upon existing technical design
|
|
172
|
+
${existingTechnicalDesign ? '- Build upon or improve the existing technical design provided above' : '- Create a complete new technical design from scratch'}
|
|
126
173
|
- Consider integration with existing systems and architecture
|
|
127
174
|
- Address scalability, maintainability, and performance requirements
|
|
128
175
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedbacks service for pipeline integration
|
|
3
|
+
* Provides human-guided feedbacks to influence Claude Code behavior in each phase
|
|
4
|
+
*/
|
|
5
|
+
import { PipelinePhaseOptions } from '../types/pipeline.js';
|
|
6
|
+
export type { PipelinePhaseOptions };
|
|
7
|
+
export type FeedbackType = 'requirement' | 'constraint' | 'preference' | 'context' | 'quality_criteria';
|
|
8
|
+
export interface Feedback {
|
|
9
|
+
id: string;
|
|
10
|
+
feature_id: string | null;
|
|
11
|
+
product_id: string | null;
|
|
12
|
+
phase: string;
|
|
13
|
+
feedback_type: FeedbackType;
|
|
14
|
+
title: string;
|
|
15
|
+
content: string;
|
|
16
|
+
priority: number;
|
|
17
|
+
is_active: boolean;
|
|
18
|
+
created_by: string;
|
|
19
|
+
created_at: string;
|
|
20
|
+
updated_at: string;
|
|
21
|
+
}
|
|
22
|
+
export interface FeedbacksContext {
|
|
23
|
+
phase: string;
|
|
24
|
+
feature_id: string;
|
|
25
|
+
feedbacks: Feedback[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Fetch feedbacks for a specific phase
|
|
29
|
+
* Includes both feature-level and product-level feedbacks
|
|
30
|
+
*/
|
|
31
|
+
export declare function getFeedbacksForPhase(options: PipelinePhaseOptions, phase: string): Promise<FeedbacksContext>;
|
|
32
|
+
/**
|
|
33
|
+
* Format feedbacks context as string for LLM consumption
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatFeedbacksForContext(context: FeedbacksContext): string;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedbacks service for pipeline integration
|
|
3
|
+
* Provides human-guided feedbacks to influence Claude Code behavior in each phase
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Fetch feedbacks for a specific phase
|
|
7
|
+
* Includes both feature-level and product-level feedbacks
|
|
8
|
+
*/
|
|
9
|
+
export async function getFeedbacksForPhase(options, phase) {
|
|
10
|
+
const { mcpServerUrl, mcpToken, featureId, verbose } = options;
|
|
11
|
+
// Convert phase name from hyphen to underscore format for database compatibility
|
|
12
|
+
// e.g., 'feature-analysis' -> 'feature_analysis'
|
|
13
|
+
const dbPhase = phase.replace(/-/g, '_');
|
|
14
|
+
if (verbose) {
|
|
15
|
+
console.log(`🔍 Fetching feedbacks: phase="${phase}" (db: "${dbPhase}"), feature_id="${featureId}"`);
|
|
16
|
+
}
|
|
17
|
+
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
Authorization: `Bearer ${mcpToken}`,
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
jsonrpc: '2.0',
|
|
25
|
+
id: 1,
|
|
26
|
+
method: 'feedbacks/get',
|
|
27
|
+
params: {
|
|
28
|
+
feature_id: featureId,
|
|
29
|
+
phase: dbPhase,
|
|
30
|
+
},
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const errorText = await response.text();
|
|
35
|
+
throw new Error(`Failed to fetch feedbacks for phase "${phase}": ${response.status} ${response.statusText}. Response: ${errorText}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
if (data.error) {
|
|
39
|
+
throw new Error(`MCP Error for phase "${phase}": ${data.error.message || JSON.stringify(data.error)}`);
|
|
40
|
+
}
|
|
41
|
+
// Handle empty result gracefully
|
|
42
|
+
if (!data.result) {
|
|
43
|
+
return {
|
|
44
|
+
phase,
|
|
45
|
+
feature_id: featureId,
|
|
46
|
+
feedbacks: [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return data.result;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Format feedbacks context as string for LLM consumption
|
|
53
|
+
*/
|
|
54
|
+
export function formatFeedbacksForContext(context) {
|
|
55
|
+
if (!context.feedbacks || context.feedbacks.length === 0) {
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
// Group feedbacks by type
|
|
59
|
+
const grouped = groupBy(context.feedbacks, 'feedback_type');
|
|
60
|
+
const sections = [];
|
|
61
|
+
// Requirements
|
|
62
|
+
if (grouped.requirement && grouped.requirement.length > 0) {
|
|
63
|
+
sections.push(`## 📋 Additional Requirements\n\n${formatFeedbacksList(grouped.requirement)}`);
|
|
64
|
+
}
|
|
65
|
+
// Constraints
|
|
66
|
+
if (grouped.constraint && grouped.constraint.length > 0) {
|
|
67
|
+
sections.push(`## 🚫 Constraints\n\n${formatFeedbacksList(grouped.constraint)}`);
|
|
68
|
+
}
|
|
69
|
+
// Preferences
|
|
70
|
+
if (grouped.preference && grouped.preference.length > 0) {
|
|
71
|
+
sections.push(`## 💡 Preferences\n\n${formatFeedbacksList(grouped.preference)}`);
|
|
72
|
+
}
|
|
73
|
+
// Context
|
|
74
|
+
if (grouped.context && grouped.context.length > 0) {
|
|
75
|
+
sections.push(`## 🔍 Additional Context\n\n${formatFeedbacksList(grouped.context)}`);
|
|
76
|
+
}
|
|
77
|
+
// Quality Criteria
|
|
78
|
+
if (grouped.quality_criteria && grouped.quality_criteria.length > 0) {
|
|
79
|
+
sections.push(`## ✅ Quality Criteria\n\n${formatFeedbacksList(grouped.quality_criteria)}`);
|
|
80
|
+
}
|
|
81
|
+
const phaseDisplay = context.phase.replace(/_/g, '-');
|
|
82
|
+
return `
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
# 🎯 Human Feedbacks for ${phaseDisplay} Phase
|
|
86
|
+
|
|
87
|
+
These feedbacks have been provided by the development team to guide your work in this phase. They represent domain knowledge, business constraints, and quality expectations that must be incorporated into your analysis and outputs.
|
|
88
|
+
|
|
89
|
+
${sections.join('\n\n')}
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
**IMPORTANT**: These human-provided feedbacks are MANDATORY and take precedence over default behavior. Please ensure your work:
|
|
94
|
+
- ✅ Satisfies ALL requirements listed above
|
|
95
|
+
- ✅ Respects ALL constraints
|
|
96
|
+
- ✅ Incorporates stated preferences where possible
|
|
97
|
+
- ✅ Considers the additional context provided
|
|
98
|
+
- ✅ Meets ALL quality criteria
|
|
99
|
+
|
|
100
|
+
If any feedback conflicts with checklist items or other requirements, prioritize the human feedbacks and note any conflicts in your response.
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format a list of feedbacks with priority ordering
|
|
105
|
+
*/
|
|
106
|
+
function formatFeedbacksList(feedbacks) {
|
|
107
|
+
// Sort by priority (highest first)
|
|
108
|
+
const sorted = [...feedbacks].sort((a, b) => b.priority - a.priority);
|
|
109
|
+
return sorted
|
|
110
|
+
.map((feedback, idx) => {
|
|
111
|
+
const priorityBadge = getPriorityBadge(feedback.priority);
|
|
112
|
+
return `### ${idx + 1}. ${feedback.title} ${priorityBadge}\n\n${feedback.content}\n`;
|
|
113
|
+
})
|
|
114
|
+
.join('\n');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get priority badge emoji
|
|
118
|
+
*/
|
|
119
|
+
function getPriorityBadge(priority) {
|
|
120
|
+
if (priority >= 9)
|
|
121
|
+
return '🔴'; // Critical
|
|
122
|
+
if (priority >= 7)
|
|
123
|
+
return '🟠'; // High
|
|
124
|
+
if (priority >= 5)
|
|
125
|
+
return '🟡'; // Medium
|
|
126
|
+
if (priority >= 3)
|
|
127
|
+
return '🟢'; // Low
|
|
128
|
+
return '⚪'; // Minimal
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Group array of objects by a key
|
|
132
|
+
*/
|
|
133
|
+
function groupBy(array, key) {
|
|
134
|
+
return array.reduce((result, item) => {
|
|
135
|
+
const groupKey = String(item[key]);
|
|
136
|
+
if (!result[groupKey]) {
|
|
137
|
+
result[groupKey] = [];
|
|
138
|
+
}
|
|
139
|
+
result[groupKey].push(item);
|
|
140
|
+
return result;
|
|
141
|
+
}, {});
|
|
142
|
+
}
|