edsger 0.2.5 → 0.2.7

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.
@@ -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
- const contextInfo = formatContextForPrompt(context, testErrors);
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 = contextInfo + '\n\n' + checklistInfo;
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 = contextInfo + '\n\n' + checklistInfo;
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 = contextInfo + '\n\n' + checklistInfo;
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 = contextInfo + '\n\n' + checklistInfo;
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
- const designPrompt = createTechnicalDesignPromptWithContext(featureId, finalContextInfo);
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
- return `Generate a comprehensive technical design for feature ID: ${featureId}
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 if available, or create from scratch
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {