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.
- package/.claude/settings.local.json +23 -3
- package/.env.local +12 -0
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
- package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
- package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
- package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
- package/dist/commands/workflow/pipeline-runner.js +393 -0
- package/dist/commands/workflow/runner.d.ts +26 -0
- package/dist/commands/workflow/runner.js +119 -0
- package/dist/commands/workflow/workflow-runner.d.ts +26 -0
- package/dist/commands/workflow/workflow-runner.js +119 -0
- package/dist/index.js +0 -0
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +32 -0
- package/dist/phases/code-implementation/analyzer.js +629 -0
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
- package/dist/phases/code-implementation/mcp-server.js +93 -0
- package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
- package/dist/phases/code-implementation/prompts-improvement.js +108 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/code-refine/analyzer.d.ts +41 -0
- package/dist/phases/code-refine/analyzer.js +561 -0
- package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
- package/dist/phases/code-refine/context-fetcher.js +423 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
- package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
- package/dist/phases/code-refine-verification/verifier.js +597 -0
- package/dist/phases/code-review/analyzer.d.ts +29 -0
- package/dist/phases/code-review/analyzer.js +363 -0
- package/dist/phases/code-review/context-fetcher.d.ts +92 -0
- package/dist/phases/code-review/context-fetcher.js +296 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
- package/dist/phases/feature-analysis/analyzer.js +208 -0
- package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
- package/dist/phases/feature-analysis/context-fetcher.js +134 -0
- package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
- package/dist/phases/feature-analysis/http-fallback.js +95 -0
- package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
- package/dist/phases/feature-analysis/mcp-server.js +144 -0
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
- package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/pr-execution/file-assigner.js +20 -12
- package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
- package/dist/phases/technical-design/analyzer-helpers.js +39 -0
- package/dist/phases/technical-design/analyzer.d.ts +21 -0
- package/dist/phases/technical-design/analyzer.js +461 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/phases/technical-design/http-fallback.d.ts +17 -0
- package/dist/phases/technical-design/http-fallback.js +151 -0
- package/dist/phases/technical-design/mcp-server.d.ts +1 -0
- package/dist/phases/technical-design/mcp-server.js +157 -0
- package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
- package/dist/phases/technical-design/prompts-improvement.js +93 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
- package/dist/phases/technical-design-verification/verifier.js +170 -0
- package/dist/services/feature-branches.d.ts +77 -0
- package/dist/services/feature-branches.js +205 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +120 -0
- package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
- package/dist/workflow-runner/core/feature-filter.js +46 -0
- package/dist/workflow-runner/core/index.d.ts +8 -0
- package/dist/workflow-runner/core/index.js +12 -0
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
- package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
- package/dist/workflow-runner/core/state-manager.d.ts +24 -0
- package/dist/workflow-runner/core/state-manager.js +42 -0
- package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
- package/dist/workflow-runner/core/workflow-logger.js +65 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/phase-executor.js +248 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +119 -0
- package/dist/workflow-runner/index.d.ts +2 -0
- package/dist/workflow-runner/index.js +2 -0
- package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
- package/dist/workflow-runner/pipeline-runner.js +393 -0
- package/dist/workflow-runner/workflow-processor.d.ts +54 -0
- package/dist/workflow-runner/workflow-processor.js +170 -0
- package/package.json +1 -1
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- 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>;
|