edsger 0.41.1 → 0.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/.claude/settings.local.json +23 -3
  2. package/.env.local +12 -0
  3. package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
  4. package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
  5. package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
  6. package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
  7. package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
  8. package/dist/commands/workflow/pipeline-runner.js +393 -0
  9. package/dist/commands/workflow/runner.d.ts +26 -0
  10. package/dist/commands/workflow/runner.js +119 -0
  11. package/dist/commands/workflow/workflow-runner.d.ts +26 -0
  12. package/dist/commands/workflow/workflow-runner.js +119 -0
  13. package/dist/index.js +0 -0
  14. package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
  15. package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
  16. package/dist/phases/code-implementation/analyzer.d.ts +32 -0
  17. package/dist/phases/code-implementation/analyzer.js +629 -0
  18. package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
  19. package/dist/phases/code-implementation/context-fetcher.js +86 -0
  20. package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
  21. package/dist/phases/code-implementation/mcp-server.js +93 -0
  22. package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
  23. package/dist/phases/code-implementation/prompts-improvement.js +108 -0
  24. package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
  25. package/dist/phases/code-implementation-verification/verifier.js +196 -0
  26. package/dist/phases/code-refine/analyzer.d.ts +41 -0
  27. package/dist/phases/code-refine/analyzer.js +561 -0
  28. package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
  29. package/dist/phases/code-refine/context-fetcher.js +423 -0
  30. package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
  31. package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
  32. package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
  33. package/dist/phases/code-refine-verification/verifier.js +597 -0
  34. package/dist/phases/code-review/analyzer.d.ts +29 -0
  35. package/dist/phases/code-review/analyzer.js +363 -0
  36. package/dist/phases/code-review/context-fetcher.d.ts +92 -0
  37. package/dist/phases/code-review/context-fetcher.js +296 -0
  38. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
  39. package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
  40. package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
  41. package/dist/phases/feature-analysis/analyzer.js +208 -0
  42. package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
  43. package/dist/phases/feature-analysis/context-fetcher.js +134 -0
  44. package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
  45. package/dist/phases/feature-analysis/http-fallback.js +95 -0
  46. package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
  47. package/dist/phases/feature-analysis/mcp-server.js +144 -0
  48. package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
  49. package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
  50. package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
  51. package/dist/phases/feature-analysis-verification/verifier.js +147 -0
  52. package/dist/phases/pr-execution/file-assigner.js +20 -12
  53. package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
  54. package/dist/phases/technical-design/analyzer-helpers.js +39 -0
  55. package/dist/phases/technical-design/analyzer.d.ts +21 -0
  56. package/dist/phases/technical-design/analyzer.js +461 -0
  57. package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
  58. package/dist/phases/technical-design/context-fetcher.js +39 -0
  59. package/dist/phases/technical-design/http-fallback.d.ts +17 -0
  60. package/dist/phases/technical-design/http-fallback.js +151 -0
  61. package/dist/phases/technical-design/mcp-server.d.ts +1 -0
  62. package/dist/phases/technical-design/mcp-server.js +157 -0
  63. package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
  64. package/dist/phases/technical-design/prompts-improvement.js +93 -0
  65. package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
  66. package/dist/phases/technical-design-verification/verifier.js +170 -0
  67. package/dist/services/feature-branches.d.ts +77 -0
  68. package/dist/services/feature-branches.js +205 -0
  69. package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
  70. package/dist/workflow-runner/config/phase-configs.js +120 -0
  71. package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
  72. package/dist/workflow-runner/core/feature-filter.js +46 -0
  73. package/dist/workflow-runner/core/index.d.ts +8 -0
  74. package/dist/workflow-runner/core/index.js +12 -0
  75. package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
  76. package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
  77. package/dist/workflow-runner/core/state-manager.d.ts +24 -0
  78. package/dist/workflow-runner/core/state-manager.js +42 -0
  79. package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
  80. package/dist/workflow-runner/core/workflow-logger.js +65 -0
  81. package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
  82. package/dist/workflow-runner/executors/phase-executor.js +248 -0
  83. package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
  84. package/dist/workflow-runner/feature-workflow-runner.js +119 -0
  85. package/dist/workflow-runner/index.d.ts +2 -0
  86. package/dist/workflow-runner/index.js +2 -0
  87. package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
  88. package/dist/workflow-runner/pipeline-runner.js +393 -0
  89. package/dist/workflow-runner/workflow-processor.d.ts +54 -0
  90. package/dist/workflow-runner/workflow-processor.js +170 -0
  91. package/package.json +1 -1
  92. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
  93. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
  94. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
  95. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
  96. package/dist/services/lifecycle-agent/index.d.ts +0 -24
  97. package/dist/services/lifecycle-agent/index.js +0 -25
  98. package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
  99. package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
  100. package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
  101. package/dist/services/lifecycle-agent/transition-rules.js +0 -184
  102. package/dist/services/lifecycle-agent/types.d.ts +0 -190
  103. package/dist/services/lifecycle-agent/types.js +0 -12
@@ -0,0 +1,134 @@
1
+ import { logInfo, logError } from '../../utils/logger.js';
2
+ import { getFeature, getUserStories, createUserStories, getTestCases, createTestCases, } from '../../api/features/index.js';
3
+ import { getProduct } from '../../api/products.js';
4
+ import { formatChecklistsForContext, } from '../../services/checklist.js';
5
+ import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
6
+ import { formatFeatureAnalysisContext } from '../../utils/formatters.js';
7
+ import { createFeatureAnalysisPromptWithContext, } from './prompts.js';
8
+ /**
9
+ * Fetch all feature analysis context information via MCP endpoints
10
+ */
11
+ export async function fetchFeatureAnalysisContext(featureId, verbose) {
12
+ try {
13
+ if (verbose) {
14
+ logInfo(`Fetching complete feature analysis context for feature: ${featureId}`);
15
+ }
16
+ // Fetch all required data in parallel for better performance
17
+ const [feature, existing_user_stories, existing_test_cases] = await Promise.all([
18
+ getFeature(featureId, verbose),
19
+ getUserStories(featureId, verbose),
20
+ getTestCases(featureId, verbose),
21
+ ]);
22
+ const product = await getProduct(feature.product_id, verbose);
23
+ if (verbose) {
24
+ logInfo(`✅ Feature analysis context fetched successfully:`);
25
+ logInfo(` Feature: ${feature.name}`);
26
+ logInfo(` Product: ${product.name}`);
27
+ logInfo(` Existing User Stories: ${existing_user_stories.length}`);
28
+ logInfo(` Existing Test Cases: ${existing_test_cases.length}`);
29
+ }
30
+ return {
31
+ feature,
32
+ product,
33
+ existing_user_stories,
34
+ existing_test_cases,
35
+ };
36
+ }
37
+ catch (error) {
38
+ const errorMessage = error instanceof Error ? error.message : String(error);
39
+ logError(`Failed to fetch feature analysis context: ${errorMessage}`);
40
+ throw new Error(`Context fetch failed: ${errorMessage}`);
41
+ }
42
+ }
43
+ // Re-export the create functions for convenience
44
+ export { createUserStories, createTestCases };
45
+ /**
46
+ * Format the context into a readable string for Claude Code
47
+ */
48
+ export function formatContextForPrompt(context) {
49
+ const formatUserStories = (stories) => {
50
+ if (stories.length === 0)
51
+ return 'No user stories defined.';
52
+ return stories
53
+ .map((story, index) => `${index + 1}. **${story.title}** (Status: ${story.status})
54
+ ${story.description}`)
55
+ .join('\n\n');
56
+ };
57
+ const formatTestCases = (cases) => {
58
+ if (cases.length === 0)
59
+ return 'No test cases defined.';
60
+ return cases
61
+ .map((testCase, index) => `${index + 1}. **${testCase.name}** ${testCase.is_critical ? '[CRITICAL]' : '[OPTIONAL]'}
62
+ ${testCase.description}`)
63
+ .join('\n\n');
64
+ };
65
+ return `# Feature Analysis Context
66
+
67
+ ## Feature Information
68
+ - **ID**: ${context.feature.id}
69
+ - **Name**: ${context.feature.name}
70
+ - **Description**: ${context.feature.description || 'No description provided'}
71
+ - **Current Status**: ${context.feature.status}
72
+
73
+ ## Product Information
74
+ - **Product**: ${context.product.name}
75
+ - **Product ID**: ${context.product.id}
76
+ - **Description**: ${context.product.description || 'No product description'}
77
+
78
+ ## Existing User Stories (${context.existing_user_stories.length})
79
+ ${formatUserStories(context.existing_user_stories)}
80
+
81
+ ## Existing Test Cases (${context.existing_test_cases.length})
82
+ ${formatTestCases(context.existing_test_cases)}
83
+
84
+ ## Current Technical Design
85
+ ${context.feature.technical_design || 'No technical design available yet'}
86
+
87
+ ---
88
+
89
+ **Analysis Instructions**: Based on the above feature information and existing user stories/test cases, conduct comprehensive business analysis to identify gaps and create additional user stories and test cases that add business value.`;
90
+ }
91
+ /**
92
+ * Prepare all context information needed for analysis
93
+ */
94
+ export async function prepareAnalysisContext(featureId, checklistContext, verbose) {
95
+ if (verbose) {
96
+ logInfo('Fetching feature analysis context via MCP endpoints...');
97
+ }
98
+ const featureContext = await fetchFeatureAnalysisContext(featureId, verbose);
99
+ const { content: contextInfo, downloadedImages } = await formatFeatureAnalysisContext(featureContext);
100
+ if (verbose && downloadedImages.length > 0) {
101
+ logInfo(`Downloaded ${downloadedImages.length} images for Claude Code:`);
102
+ downloadedImages.forEach((img) => {
103
+ logInfo(` - ${img.url} -> ${img.localPath}`);
104
+ });
105
+ }
106
+ let finalContextInfo = contextInfo;
107
+ // Add feedbacks context to the analysis prompt
108
+ try {
109
+ const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'feature-analysis');
110
+ if (feedbacksContext.feedbacks.length > 0) {
111
+ const feedbacksInfo = formatFeedbacksForContext(feedbacksContext);
112
+ finalContextInfo = finalContextInfo + '\n\n' + feedbacksInfo;
113
+ if (verbose) {
114
+ logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to context`);
115
+ }
116
+ }
117
+ }
118
+ catch (error) {
119
+ // Don't fail if feedbacks fetch fails - just log and continue
120
+ if (verbose) {
121
+ logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
122
+ }
123
+ }
124
+ // Add checklist context to the analysis prompt
125
+ if (checklistContext && checklistContext.checklists.length > 0) {
126
+ const checklistInfo = formatChecklistsForContext(checklistContext);
127
+ finalContextInfo = finalContextInfo + '\n\n' + checklistInfo;
128
+ if (verbose) {
129
+ logInfo(`Added ${checklistContext.checklists.length} checklists to analysis context`);
130
+ }
131
+ }
132
+ const analysisPrompt = createFeatureAnalysisPromptWithContext(featureId, finalContextInfo);
133
+ return { featureContext, analysisPrompt };
134
+ }
@@ -0,0 +1,20 @@
1
+ export interface UserStory {
2
+ title: string;
3
+ description: string;
4
+ status: string;
5
+ }
6
+ export interface TestCase {
7
+ name: string;
8
+ description: string;
9
+ is_critical: boolean;
10
+ }
11
+ export interface HttpFallbackOptions {
12
+ mcpServerUrl: string;
13
+ mcpToken: string;
14
+ featureId: string;
15
+ userStories: UserStory[];
16
+ testCases: TestCase[];
17
+ verbose?: boolean;
18
+ }
19
+ export declare function saveDataViaHttp(options: HttpFallbackOptions): Promise<boolean>;
20
+ export declare function checkMcpServerHealth(mcpServerUrl: string, mcpToken: string): Promise<boolean>;
@@ -0,0 +1,95 @@
1
+ import { logInfo, logError } from '../../utils/logger.js';
2
+ export async function saveDataViaHttp(options) {
3
+ const { mcpServerUrl, mcpToken, featureId, userStories, testCases, verbose } = options;
4
+ if (verbose) {
5
+ logInfo('Using HTTP fallback to save analysis data...');
6
+ logInfo(`Feature ID: ${featureId}`);
7
+ logInfo(`User Stories to save: ${userStories.length}`);
8
+ logInfo(`Test Cases to save: ${testCases.length}`);
9
+ }
10
+ try {
11
+ // Save user stories via HTTP using MCP protocol
12
+ if (userStories.length > 0) {
13
+ const userStoriesResponse = await fetch(`${mcpServerUrl}/mcp`, {
14
+ method: 'POST',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ Authorization: `Bearer ${mcpToken}`,
18
+ },
19
+ body: JSON.stringify({
20
+ jsonrpc: '2.0',
21
+ method: 'user_stories/create',
22
+ params: {
23
+ feature_id: featureId,
24
+ user_stories: userStories,
25
+ },
26
+ id: Math.random().toString(36).substring(7),
27
+ }),
28
+ });
29
+ if (!userStoriesResponse.ok) {
30
+ const errorText = await userStoriesResponse.text();
31
+ logError(`Failed to save user stories via HTTP: ${userStoriesResponse.status} - ${errorText}`);
32
+ return false;
33
+ }
34
+ const userStoriesResult = await userStoriesResponse.json();
35
+ if (userStoriesResult.error) {
36
+ logError(`MCP error creating user stories: ${userStoriesResult.error.message}`);
37
+ return false;
38
+ }
39
+ if (verbose) {
40
+ logInfo(`✅ Successfully saved ${userStories.length} user stories via HTTP`);
41
+ }
42
+ }
43
+ // Save test cases via HTTP using MCP protocol
44
+ if (testCases.length > 0) {
45
+ const testCasesResponse = await fetch(`${mcpServerUrl}/mcp`, {
46
+ method: 'POST',
47
+ headers: {
48
+ 'Content-Type': 'application/json',
49
+ Authorization: `Bearer ${mcpToken}`,
50
+ },
51
+ body: JSON.stringify({
52
+ jsonrpc: '2.0',
53
+ method: 'test_cases/create',
54
+ params: {
55
+ feature_id: featureId,
56
+ test_cases: testCases,
57
+ },
58
+ id: Math.random().toString(36).substring(7),
59
+ }),
60
+ });
61
+ if (!testCasesResponse.ok) {
62
+ const errorText = await testCasesResponse.text();
63
+ logError(`Failed to save test cases via HTTP: ${testCasesResponse.status} - ${errorText}`);
64
+ return false;
65
+ }
66
+ const testCasesResult = await testCasesResponse.json();
67
+ if (testCasesResult.error) {
68
+ logError(`MCP error creating test cases: ${testCasesResult.error.message}`);
69
+ return false;
70
+ }
71
+ if (verbose) {
72
+ logInfo(`✅ Successfully saved ${testCases.length} test cases via HTTP`);
73
+ }
74
+ }
75
+ return true;
76
+ }
77
+ catch (error) {
78
+ logError(`HTTP fallback failed: ${error instanceof Error ? error.message : String(error)}`);
79
+ return false;
80
+ }
81
+ }
82
+ export async function checkMcpServerHealth(mcpServerUrl, mcpToken) {
83
+ try {
84
+ const response = await fetch(`${mcpServerUrl}/health`, {
85
+ method: 'GET',
86
+ headers: {
87
+ Authorization: `Bearer ${mcpToken}`,
88
+ },
89
+ });
90
+ return response.ok;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
@@ -0,0 +1 @@
1
+ export declare const createFeatureAnalysisMcpServer: () => import("@anthropic-ai/claude-code").McpSdkServerConfigWithInstance;
@@ -0,0 +1,144 @@
1
+ import { createSdkMcpServer, tool } from '@anthropic-ai/claude-code';
2
+ import { z } from 'zod';
3
+ import { callMcpEndpoint } from '../../api/mcp-client.js';
4
+ // Create an SDK MCP server with custom tools for feature analysis
5
+ export const createFeatureAnalysisMcpServer = () => {
6
+ return createSdkMcpServer({
7
+ name: 'edsger-feature-analysis-mcp',
8
+ version: '1.0.0',
9
+ tools: [
10
+ tool('get_feature_info', 'Get comprehensive feature and product information', {
11
+ feature_id: z.string().describe('Feature ID to analyze'),
12
+ }, async (args) => {
13
+ try {
14
+ // Get feature details using the features/get endpoint
15
+ const featureResult = (await callMcpEndpoint('features/get', {
16
+ feature_id: args.feature_id,
17
+ }));
18
+ if (!featureResult.features ||
19
+ featureResult.features.length === 0) {
20
+ throw new Error('Feature not found');
21
+ }
22
+ const feature = featureResult.features[0];
23
+ // Get product details
24
+ const productResult = (await callMcpEndpoint('resources/read', {
25
+ uri: `product://${feature.product_id}`,
26
+ }));
27
+ const productText = productResult.contents?.[0]?.text || '{}';
28
+ let productInfo;
29
+ try {
30
+ productInfo = JSON.parse(productText);
31
+ }
32
+ catch {
33
+ productInfo = {
34
+ id: feature.product_id,
35
+ name: 'Unknown Product',
36
+ };
37
+ }
38
+ const featureInfo = {
39
+ feature,
40
+ product: productInfo,
41
+ };
42
+ return {
43
+ content: [
44
+ {
45
+ type: 'text',
46
+ text: JSON.stringify(featureInfo, null, 2),
47
+ },
48
+ ],
49
+ };
50
+ }
51
+ catch (error) {
52
+ console.error('Error in get_feature_info:', error);
53
+ throw error;
54
+ }
55
+ }),
56
+ tool('get_existing_user_stories', 'Get existing user stories for a feature to avoid duplication', {
57
+ feature_id: z.string().describe('Feature ID to get user stories for'),
58
+ }, async (args) => {
59
+ const result = await callMcpEndpoint('user_stories/list', {
60
+ feature_id: args.feature_id,
61
+ });
62
+ return {
63
+ content: [
64
+ {
65
+ type: 'text',
66
+ text: JSON.stringify(result, null, 2),
67
+ },
68
+ ],
69
+ };
70
+ }),
71
+ tool('get_existing_test_cases', 'Get existing test cases for a feature to avoid duplication', {
72
+ feature_id: z.string().describe('Feature ID to get test cases for'),
73
+ }, async (args) => {
74
+ const result = await callMcpEndpoint('test_cases/list', {
75
+ feature_id: args.feature_id,
76
+ });
77
+ return {
78
+ content: [
79
+ {
80
+ type: 'text',
81
+ text: JSON.stringify(result, null, 2),
82
+ },
83
+ ],
84
+ };
85
+ }),
86
+ tool('create_user_stories', 'Create new user stories for a feature', {
87
+ feature_id: z
88
+ .string()
89
+ .describe('Feature ID to create user stories for'),
90
+ user_stories: z
91
+ .array(z.object({
92
+ title: z.string().describe('User story title'),
93
+ description: z.string().describe('User story description'),
94
+ status: z
95
+ .enum(['draft', 'ready', 'in_progress', 'done', 'cancelled'])
96
+ .default('draft')
97
+ .describe('User story status'),
98
+ }))
99
+ .describe('Array of user stories to create'),
100
+ }, async (args) => {
101
+ const result = await callMcpEndpoint('user_stories/create', {
102
+ feature_id: args.feature_id,
103
+ user_stories: args.user_stories,
104
+ });
105
+ return {
106
+ content: [
107
+ {
108
+ type: 'text',
109
+ text: JSON.stringify(result, null, 2),
110
+ },
111
+ ],
112
+ };
113
+ }),
114
+ tool('create_test_cases', 'Create new test cases for a feature', {
115
+ feature_id: z
116
+ .string()
117
+ .describe('Feature ID to create test cases for'),
118
+ test_cases: z
119
+ .array(z.object({
120
+ name: z.string().describe('Test case name'),
121
+ description: z.string().describe('Test case description'),
122
+ is_critical: z
123
+ .boolean()
124
+ .default(false)
125
+ .describe('Whether this is a critical test case'),
126
+ }))
127
+ .describe('Array of test cases to create'),
128
+ }, async (args) => {
129
+ const result = await callMcpEndpoint('test_cases/create', {
130
+ feature_id: args.feature_id,
131
+ test_cases: args.test_cases,
132
+ });
133
+ return {
134
+ content: [
135
+ {
136
+ type: 'text',
137
+ text: JSON.stringify(result, null, 2),
138
+ },
139
+ ],
140
+ };
141
+ }),
142
+ ],
143
+ });
144
+ };
@@ -0,0 +1,8 @@
1
+ import { ChecklistVerificationResult } from '../feature-analysis-verification/agent.js';
2
+ /**
3
+ * Create a prompt for the analysis agent to improve based on verification feedback
4
+ */
5
+ export declare const createImprovementPrompt: (verificationResult: ChecklistVerificationResult, previousAnalysis: {
6
+ created_user_stories: any[];
7
+ created_test_cases: any[];
8
+ }) => string;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Create a prompt for the analysis agent to improve based on verification feedback
3
+ */
4
+ export const createImprovementPrompt = (verificationResult, previousAnalysis) => {
5
+ // Format rejected items with specific feedback and improvement suggestions
6
+ const rejectedItemsSection = verificationResult.item_verifications
7
+ .filter((v) => v.verification_status === 'rejected')
8
+ .map((v, index) => {
9
+ return `### Rejected Requirement ${index + 1}
10
+ **Checklist Item ID**: ${v.checklist_item_id}
11
+ **Satisfaction Status**: ${v.is_satisfied ? '✅ Satisfied' : '❌ Not Satisfied'}
12
+ **Verification Result**: ❌ REJECTED
13
+ **Reason**: ${v.verification_reason}
14
+ ${v.concerns && v.concerns.length > 0 ? `**Specific Concerns**:\n${v.concerns.map((c) => `- ${c}`).join('\n')}` : ''}
15
+ ${v.improvement_suggestions && v.improvement_suggestions.length > 0 ? `\n**💡 Improvement Suggestions**:\n${v.improvement_suggestions.map((s) => `- ${s}`).join('\n')}` : ''}
16
+ `;
17
+ })
18
+ .join('\n---\n');
19
+ // Format uncertain items with improvement suggestions
20
+ const uncertainItemsSection = verificationResult.item_verifications
21
+ .filter((v) => v.verification_status === 'uncertain')
22
+ .map((v, index) => {
23
+ return `### Uncertain Requirement ${index + 1}
24
+ **Checklist Item ID**: ${v.checklist_item_id}
25
+ **Satisfaction Status**: ${v.is_satisfied ? '✅ Satisfied' : '⚠️ Partially Satisfied'}
26
+ **Verification Result**: ⚠️ UNCERTAIN
27
+ **Reason**: ${v.verification_reason}
28
+ ${v.concerns && v.concerns.length > 0 ? `**Specific Concerns**:\n${v.concerns.map((c) => `- ${c}`).join('\n')}` : ''}
29
+ ${v.improvement_suggestions && v.improvement_suggestions.length > 0 ? `\n**💡 Improvement Suggestions**:\n${v.improvement_suggestions.map((s) => `- ${s}`).join('\n')}` : ''}
30
+ `;
31
+ })
32
+ .join('\n---\n');
33
+ return `# Verification Feedback - Improvements Required
34
+
35
+ Your previous analysis was verified, and **${verificationResult.rejected_count} checklist requirements were NOT SATISFIED** and **${verificationResult.uncertain_count} requirements are PARTIALLY SATISFIED**.
36
+
37
+ ## Verification Summary
38
+ ${verificationResult.summary}
39
+
40
+ ## Results Breakdown
41
+ - ✅ Satisfied: ${verificationResult.confirmed_count}
42
+ - ❌ Not Satisfied: ${verificationResult.rejected_count}
43
+ - ⚠️ Partially Satisfied: ${verificationResult.uncertain_count}
44
+
45
+ ${verificationResult.overall_suggestions && verificationResult.overall_suggestions.length > 0 ? `## 💡 Overall Improvement Suggestions\n\n${verificationResult.overall_suggestions.map((s) => `- ${s}`).join('\n')}\n\n` : ''}
46
+
47
+ ${verificationResult.rejected_count > 0 ? `## ❌ Unsatisfied Requirements\n\n${rejectedItemsSection}` : ''}
48
+
49
+ ${verificationResult.uncertain_count > 0 ? `## ⚠️ Partially Satisfied Requirements\n\n${uncertainItemsSection}` : ''}
50
+
51
+ ## Your Previous Work
52
+
53
+ ### User Stories You Created (${previousAnalysis.created_user_stories.length})
54
+ ${previousAnalysis.created_user_stories
55
+ .map((story, index) => `${index + 1}. **${story.title}**
56
+ ${story.description}
57
+ Status: ${story.status || 'draft'}`)
58
+ .join('\n\n')}
59
+
60
+ ### Test Cases You Created (${previousAnalysis.created_test_cases.length})
61
+ ${previousAnalysis.created_test_cases
62
+ .map((tc, index) => `${index + 1}. **${tc.name}** ${tc.is_critical ? '[CRITICAL]' : '[OPTIONAL]'}
63
+ ${tc.description}`)
64
+ .join('\n\n')}
65
+
66
+ ---
67
+
68
+ ## Your Task: Improve Your Artifacts
69
+
70
+ You need to **revise and improve** your user stories and test cases to satisfy the checklist requirements.
71
+
72
+ **What You Should Do**:
73
+
74
+ 1. **Review the improvement suggestions** provided above for each rejected/uncertain requirement
75
+ 2. **Follow the specific, actionable suggestions** - they tell you exactly what to add or modify
76
+ 3. **Add NEW user stories and test cases** as suggested by the verifier
77
+ 4. **Improve the quality and specificity** of your artifacts
78
+ 5. **Ensure each requirement is adequately covered** based on the feedback
79
+
80
+ **IMPORTANT Guidelines**:
81
+ - **Pay close attention to the 💡 Improvement Suggestions** - these are specific actions you should take
82
+ - You can **keep your existing user stories and test cases** that are good
83
+ - **Add NEW items** exactly as suggested to satisfy the unsatisfied requirements
84
+ - **Make your artifacts concrete and specific** - they will be verified again
85
+ - The suggestions are your roadmap - follow them to ensure verification passes
86
+ - Ensure your artifacts directly address the checklist requirements
87
+
88
+ **CRITICAL - Output Format**:
89
+ You MUST return ONLY the JSON object below. Do NOT include any explanatory text, commentary, or markdown before or after the JSON. Return ONLY the JSON in this exact format:
90
+
91
+ \`\`\`json
92
+ {
93
+ "analysis": {
94
+ "feature_id": "...",
95
+ "status": "success",
96
+ "summary": "Improved analysis based on verification feedback",
97
+ "created_user_stories": [
98
+ // Include ALL user stories (existing + new)
99
+ ],
100
+ "created_test_cases": [
101
+ // Include ALL test cases (existing + new)
102
+ ],
103
+ "recommendations": "..."
104
+ }
105
+ }
106
+ \`\`\`
107
+
108
+ IMPORTANT: Return ONLY the JSON above. Do not add any text explaining what you did or how you improved the analysis. The JSON should be the complete and only content of your response.`;
109
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Checklist verification agent for feature analysis
3
+ * This agent independently reviews checklist compliance to ensure objectivity
4
+ */
5
+ import { EdsgerConfig } from '../../types/index.js';
6
+ import { ChecklistPhaseContext } from '../../services/checklist.js';
7
+ import { FeatureAnalysisContext } from '../feature-analysis/context-fetcher.js';
8
+ export interface ChecklistItemVerificationResult {
9
+ checklist_item_id: string;
10
+ is_satisfied: boolean;
11
+ verification_status: 'confirmed' | 'rejected' | 'uncertain';
12
+ verification_reason: string;
13
+ concerns?: string[];
14
+ improvement_suggestions?: string[];
15
+ }
16
+ export interface ChecklistVerificationResult {
17
+ all_verified: boolean;
18
+ total_items: number;
19
+ confirmed_count: number;
20
+ rejected_count: number;
21
+ uncertain_count: number;
22
+ item_verifications: ChecklistItemVerificationResult[];
23
+ summary: string;
24
+ overall_suggestions?: string[];
25
+ }
26
+ export interface VerifyChecklistOptions {
27
+ checklistContext: ChecklistPhaseContext;
28
+ analysisContext: FeatureAnalysisContext;
29
+ createdUserStories: any[];
30
+ createdTestCases: any[];
31
+ verbose?: boolean;
32
+ }
33
+ /**
34
+ * Verify checklist compliance using an independent AI agent
35
+ * This agent acts as a "challenger" to validate the claims made by the analysis agent
36
+ */
37
+ export declare function verifyChecklistCompliance(options: VerifyChecklistOptions, config: EdsgerConfig): Promise<ChecklistVerificationResult>;