edsger 0.2.2 → 0.2.4
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/README.md +17 -0
- package/dist/api/features/batch-operations.d.ts +16 -0
- package/dist/api/features/batch-operations.js +100 -0
- package/dist/api/features/index.d.ts +1 -0
- package/dist/api/features/index.js +1 -0
- package/dist/api/features/test-cases.d.ts +8 -0
- package/dist/api/features/test-cases.js +45 -0
- package/dist/api/features/user-stories.d.ts +8 -0
- package/dist/api/features/user-stories.js +45 -0
- package/dist/cli/commands/refactor-command.d.ts +2 -0
- package/dist/cli/commands/refactor-command.js +107 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +4 -99
- 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 +2 -0
- package/dist/phases/code-implementation/analyzer.js +308 -179
- package/dist/phases/code-implementation-verification/index.d.ts +1 -0
- package/dist/phases/code-implementation-verification/index.js +1 -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/feature-analysis/analyzer-helpers.d.ts +62 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +450 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +1 -0
- package/dist/phases/feature-analysis/analyzer.js +132 -213
- package/dist/phases/feature-analysis-verification/index.d.ts +1 -0
- package/dist/phases/feature-analysis-verification/index.js +1 -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/pull-request/creator.js +10 -9
- package/dist/phases/technical-design/analyzer-helpers.d.ts +37 -0
- package/dist/phases/technical-design/analyzer-helpers.js +144 -0
- package/dist/phases/technical-design/analyzer.d.ts +3 -0
- package/dist/phases/technical-design/analyzer.js +282 -312
- package/dist/phases/technical-design-verification/index.d.ts +1 -0
- package/dist/phases/technical-design-verification/index.js +1 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +36 -0
- package/dist/phases/technical-design-verification/verifier.js +147 -0
- package/dist/prompts/checklist-verification.d.ts +11 -0
- package/dist/prompts/checklist-verification.js +153 -0
- package/dist/prompts/code-implementation-improvement.d.ts +5 -0
- package/dist/prompts/code-implementation-improvement.js +108 -0
- package/dist/prompts/code-implementation-verification.d.ts +3 -0
- package/dist/prompts/code-implementation-verification.js +176 -0
- package/dist/prompts/feature-analysis-improvement.d.ts +8 -0
- package/dist/prompts/feature-analysis-improvement.js +109 -0
- package/dist/prompts/feature-analysis.js +1 -1
- package/dist/prompts/formatters.d.ts +17 -4
- package/dist/prompts/formatters.js +41 -12
- package/dist/prompts/technical-design-improvement.d.ts +5 -0
- package/dist/prompts/technical-design-improvement.js +93 -0
- package/dist/prompts/technical-design-verification.d.ts +11 -0
- package/dist/prompts/technical-design-verification.js +134 -0
- package/dist/prompts/technical-design.js +1 -1
- package/dist/services/audit-logs.d.ts +60 -0
- package/dist/services/audit-logs.js +115 -0
- package/dist/services/checklist.d.ts +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/utils/image-downloader.d.ts +32 -0
- package/dist/utils/image-downloader.js +144 -0
- package/dist/workflow-runner/executors/phase-executor.js +56 -12
- package/package.json +1 -1
- package/dist/api/features.d.ts +0 -100
- package/dist/api/features.js +0 -219
- package/dist/logger.d.ts +0 -19
- package/dist/logger.js +0 -52
- package/dist/types.d.ts +0 -99
- package/dist/types.js +0 -1
- package/dist/workflow-runner/config/stage-configs.d.ts +0 -5
- package/dist/workflow-runner/config/stage-configs.js +0 -34
- package/dist/workflow-runner/core/feature-filter.test.d.ts +0 -4
- package/dist/workflow-runner/core/feature-filter.test.js +0 -127
- package/dist/workflow-runner/executors/stage-executor.d.ts +0 -8
- package/dist/workflow-runner/executors/stage-executor.js +0 -49
- package/dist/workflow-runner/feature-fetcher.d.ts +0 -41
- package/dist/workflow-runner/feature-fetcher.js +0 -121
- package/dist/workflow-runner/feature-service.d.ts +0 -17
- package/dist/workflow-runner/feature-service.js +0 -60
- package/dist/workflow-runner/pipeline.d.ts +0 -18
- package/dist/workflow-runner/pipeline.js +0 -197
- package/dist/workflow-runner/processor.d.ts +0 -40
- package/dist/workflow-runner/processor.js +0 -191
- package/dist/workflow-runner/status-updater.d.ts +0 -27
- package/dist/workflow-runner/status-updater.js +0 -80
- package/dist/workflow-runner/types.d.ts +0 -48
- package/dist/workflow-runner/types.js +0 -4
package/dist/api/features.js
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import { logInfo, logError } from '../logger.js';
|
|
2
|
-
import { callMcpEndpoint } from './mcp-client.js';
|
|
3
|
-
/**
|
|
4
|
-
* Get feature details by ID
|
|
5
|
-
*/
|
|
6
|
-
export async function getFeature(mcpServerUrl, mcpToken, featureId, verbose) {
|
|
7
|
-
if (verbose) {
|
|
8
|
-
logInfo(`Fetching feature details for: ${featureId}`);
|
|
9
|
-
}
|
|
10
|
-
const result = (await callMcpEndpoint(mcpServerUrl, mcpToken, 'features/get', { feature_id: featureId }));
|
|
11
|
-
if (!result.features || result.features.length === 0) {
|
|
12
|
-
throw new Error(`Feature not found: ${featureId}`);
|
|
13
|
-
}
|
|
14
|
-
return result.features[0];
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Update feature with new data
|
|
18
|
-
*/
|
|
19
|
-
export async function updateFeature(mcpServerUrl, mcpToken, featureId, updates, verbose) {
|
|
20
|
-
try {
|
|
21
|
-
if (verbose) {
|
|
22
|
-
logInfo(`Updating feature: ${featureId}`);
|
|
23
|
-
}
|
|
24
|
-
await callMcpEndpoint(mcpServerUrl, mcpToken, 'features/update', {
|
|
25
|
-
feature_id: featureId,
|
|
26
|
-
...updates,
|
|
27
|
-
});
|
|
28
|
-
if (verbose) {
|
|
29
|
-
logInfo('✅ Feature updated successfully');
|
|
30
|
-
}
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
35
|
-
logError(`Failed to update feature: ${errorMessage}`);
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Update technical design for a feature
|
|
41
|
-
*/
|
|
42
|
-
export async function updateTechnicalDesign(mcpServerUrl, mcpToken, featureId, technicalDesign, verbose) {
|
|
43
|
-
return updateFeature(mcpServerUrl, mcpToken, featureId, { technical_design: technicalDesign }, verbose);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Update feature status
|
|
47
|
-
*/
|
|
48
|
-
export async function updateFeatureStatus(mcpServerUrl, mcpToken, featureId, status, verbose) {
|
|
49
|
-
return updateFeature(mcpServerUrl, mcpToken, featureId, { status }, verbose);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Get user stories for a feature
|
|
53
|
-
*/
|
|
54
|
-
export async function getUserStories(mcpServerUrl, mcpToken, featureId, verbose) {
|
|
55
|
-
if (verbose) {
|
|
56
|
-
logInfo(`Fetching user stories for feature: ${featureId}`);
|
|
57
|
-
}
|
|
58
|
-
const result = (await callMcpEndpoint(mcpServerUrl, mcpToken, 'user_stories/list', { feature_id: featureId }));
|
|
59
|
-
return (result.user_stories || []);
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Create a new user story for a feature
|
|
63
|
-
*/
|
|
64
|
-
export async function createUserStory(mcpServerUrl, mcpToken, featureId, userStory, verbose) {
|
|
65
|
-
try {
|
|
66
|
-
if (verbose) {
|
|
67
|
-
logInfo(`Creating user story for feature: ${featureId}`);
|
|
68
|
-
}
|
|
69
|
-
await callMcpEndpoint(mcpServerUrl, mcpToken, 'user_stories/create', {
|
|
70
|
-
feature_id: featureId,
|
|
71
|
-
user_stories: [
|
|
72
|
-
{
|
|
73
|
-
title: userStory.title,
|
|
74
|
-
description: userStory.description,
|
|
75
|
-
status: userStory.status || 'draft',
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
});
|
|
79
|
-
if (verbose) {
|
|
80
|
-
logInfo('✅ User story created successfully');
|
|
81
|
-
}
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
86
|
-
logError(`Failed to create user story: ${errorMessage}`);
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Create multiple user stories for a feature
|
|
92
|
-
*/
|
|
93
|
-
export async function createUserStories(mcpServerUrl, mcpToken, featureId, userStories, verbose) {
|
|
94
|
-
try {
|
|
95
|
-
if (verbose) {
|
|
96
|
-
logInfo(`Creating ${userStories.length} user stories for feature: ${featureId}`);
|
|
97
|
-
}
|
|
98
|
-
for (const story of userStories) {
|
|
99
|
-
await createUserStory(mcpServerUrl, mcpToken, featureId, story, false);
|
|
100
|
-
}
|
|
101
|
-
if (verbose) {
|
|
102
|
-
logInfo('✅ All user stories created successfully');
|
|
103
|
-
}
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
108
|
-
logError(`Failed to create user stories: ${errorMessage}`);
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Get test cases for a feature
|
|
114
|
-
*/
|
|
115
|
-
export async function getTestCases(mcpServerUrl, mcpToken, featureId, verbose) {
|
|
116
|
-
if (verbose) {
|
|
117
|
-
logInfo(`Fetching test cases for feature: ${featureId}`);
|
|
118
|
-
}
|
|
119
|
-
const result = (await callMcpEndpoint(mcpServerUrl, mcpToken, 'test_cases/list', { feature_id: featureId }));
|
|
120
|
-
return (result.test_cases || []);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Create a new test case for a feature
|
|
124
|
-
*/
|
|
125
|
-
export async function createTestCase(mcpServerUrl, mcpToken, featureId, testCase, verbose) {
|
|
126
|
-
try {
|
|
127
|
-
if (verbose) {
|
|
128
|
-
logInfo(`Creating test case for feature: ${featureId}`);
|
|
129
|
-
}
|
|
130
|
-
await callMcpEndpoint(mcpServerUrl, mcpToken, 'test_cases/create', {
|
|
131
|
-
feature_id: featureId,
|
|
132
|
-
test_cases: [
|
|
133
|
-
{
|
|
134
|
-
name: testCase.name,
|
|
135
|
-
description: testCase.description,
|
|
136
|
-
is_critical: testCase.is_critical || false,
|
|
137
|
-
},
|
|
138
|
-
],
|
|
139
|
-
});
|
|
140
|
-
if (verbose) {
|
|
141
|
-
logInfo('✅ Test case created successfully');
|
|
142
|
-
}
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
147
|
-
logError(`Failed to create test case: ${errorMessage}`);
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Create multiple test cases for a feature
|
|
153
|
-
*/
|
|
154
|
-
export async function createTestCases(mcpServerUrl, mcpToken, featureId, testCases, verbose) {
|
|
155
|
-
try {
|
|
156
|
-
if (verbose) {
|
|
157
|
-
logInfo(`Creating ${testCases.length} test cases for feature: ${featureId}`);
|
|
158
|
-
}
|
|
159
|
-
for (const testCase of testCases) {
|
|
160
|
-
await createTestCase(mcpServerUrl, mcpToken, featureId, testCase, false);
|
|
161
|
-
}
|
|
162
|
-
if (verbose) {
|
|
163
|
-
logInfo('✅ All test cases created successfully');
|
|
164
|
-
}
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
169
|
-
logError(`Failed to create test cases: ${errorMessage}`);
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// ============================================================================
|
|
174
|
-
// FEATURE UTILITY FUNCTIONS
|
|
175
|
-
// ============================================================================
|
|
176
|
-
/**
|
|
177
|
-
* Filter features by status
|
|
178
|
-
*/
|
|
179
|
-
export function filterFeaturesByStatus(features, status) {
|
|
180
|
-
return features.filter(feature => feature.status === status);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Sort features by updated_at (most recent first)
|
|
184
|
-
*/
|
|
185
|
-
export function sortFeaturesByUpdatedAt(features) {
|
|
186
|
-
return [...features].sort((a, b) => {
|
|
187
|
-
const dateA = new Date(a.updated_at || 0).getTime();
|
|
188
|
-
const dateB = new Date(b.updated_at || 0).getTime();
|
|
189
|
-
return dateB - dateA;
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Get features with ready_for_dev status for a product
|
|
194
|
-
*/
|
|
195
|
-
export async function getReadyForDevFeatures(mcpServerUrl, mcpToken, productId, verbose) {
|
|
196
|
-
if (verbose) {
|
|
197
|
-
logInfo(`Fetching ready_for_dev features for product: ${productId}`);
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
const result = await callMcpEndpoint(mcpServerUrl, mcpToken, 'features/list', {
|
|
201
|
-
product_id: productId,
|
|
202
|
-
status: 'ready_for_dev',
|
|
203
|
-
});
|
|
204
|
-
const features = result.features || [];
|
|
205
|
-
const sortedFeatures = sortFeaturesByUpdatedAt(features);
|
|
206
|
-
if (verbose) {
|
|
207
|
-
logInfo(`✅ Found ${sortedFeatures.length} ready_for_dev features`);
|
|
208
|
-
sortedFeatures.forEach((feature, index) => {
|
|
209
|
-
logInfo(` ${index + 1}. ${feature.name} (updated: ${feature.updated_at})`);
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
return sortedFeatures;
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
216
|
-
logError(`Failed to fetch ready_for_dev features: ${errorMessage}`);
|
|
217
|
-
throw error;
|
|
218
|
-
}
|
|
219
|
-
}
|
package/dist/logger.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ReviewResult } from './types.js';
|
|
2
|
-
export declare const colors: {
|
|
3
|
-
reset: string;
|
|
4
|
-
bright: string;
|
|
5
|
-
red: string;
|
|
6
|
-
green: string;
|
|
7
|
-
yellow: string;
|
|
8
|
-
blue: string;
|
|
9
|
-
magenta: string;
|
|
10
|
-
cyan: string;
|
|
11
|
-
gray: string;
|
|
12
|
-
};
|
|
13
|
-
export declare const colorize: (text: string, color: keyof typeof colors) => string;
|
|
14
|
-
export declare const logInfo: (message: string) => void;
|
|
15
|
-
export declare const logSuccess: (message: string) => void;
|
|
16
|
-
export declare const logWarning: (message: string) => void;
|
|
17
|
-
export declare const logError: (message: string) => void;
|
|
18
|
-
export declare const logProgress: (current: number, total: number, file: string) => void;
|
|
19
|
-
export declare const logResults: (results: ReviewResult[], verbose?: boolean) => void;
|
package/dist/logger.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export const colors = {
|
|
2
|
-
reset: '\x1b[0m',
|
|
3
|
-
bright: '\x1b[1m',
|
|
4
|
-
red: '\x1b[31m',
|
|
5
|
-
green: '\x1b[32m',
|
|
6
|
-
yellow: '\x1b[33m',
|
|
7
|
-
blue: '\x1b[34m',
|
|
8
|
-
magenta: '\x1b[35m',
|
|
9
|
-
cyan: '\x1b[36m',
|
|
10
|
-
gray: '\x1b[90m'
|
|
11
|
-
};
|
|
12
|
-
export const colorize = (text, color) => {
|
|
13
|
-
return `${colors[color]}${text}${colors.reset}`;
|
|
14
|
-
};
|
|
15
|
-
export const logInfo = (message) => {
|
|
16
|
-
console.log(colorize(`ℹ ${message}`, 'blue'));
|
|
17
|
-
};
|
|
18
|
-
export const logSuccess = (message) => {
|
|
19
|
-
console.log(colorize(`✓ ${message}`, 'green'));
|
|
20
|
-
};
|
|
21
|
-
export const logWarning = (message) => {
|
|
22
|
-
console.log(colorize(`⚠ ${message}`, 'yellow'));
|
|
23
|
-
};
|
|
24
|
-
export const logError = (message) => {
|
|
25
|
-
console.error(colorize(`✗ ${message}`, 'red'));
|
|
26
|
-
};
|
|
27
|
-
export const logProgress = (current, total, file) => {
|
|
28
|
-
const percentage = Math.round((current / total) * 100);
|
|
29
|
-
const progress = `[${current}/${total}] ${percentage}%`;
|
|
30
|
-
console.log(colorize(`${progress} Reviewing ${file}`, 'gray'));
|
|
31
|
-
};
|
|
32
|
-
export const logResults = (results, verbose = false) => {
|
|
33
|
-
const okCount = results.filter(r => r.status === 'OK').length;
|
|
34
|
-
const warnCount = results.filter(r => r.status === 'WARN').length;
|
|
35
|
-
const blockCount = results.filter(r => r.status === 'BLOCK').length;
|
|
36
|
-
console.log('\n' + colorize('='.repeat(60), 'gray'));
|
|
37
|
-
console.log(colorize('Review Results', 'bright'));
|
|
38
|
-
console.log(colorize('='.repeat(60), 'gray'));
|
|
39
|
-
results.forEach(result => {
|
|
40
|
-
const icon = result.status === 'OK' ? '✓' : result.status === 'WARN' ? '⚠' : '✗';
|
|
41
|
-
const color = result.status === 'OK' ? 'green' : result.status === 'WARN' ? 'yellow' : 'red';
|
|
42
|
-
console.log(colorize(`${icon} ${result.file}: ${result.message}`, color));
|
|
43
|
-
if (verbose && result.details && result.status !== 'OK') {
|
|
44
|
-
console.log(colorize(` Details: ${result.details}`, 'gray'));
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
console.log('\n' + colorize('Summary:', 'bright'));
|
|
48
|
-
console.log(colorize(` ✓ Passed: ${okCount}`, 'green'));
|
|
49
|
-
console.log(colorize(` ⚠ Warnings: ${warnCount}`, 'yellow'));
|
|
50
|
-
console.log(colorize(` ✗ Blocked: ${blockCount}`, 'red'));
|
|
51
|
-
console.log(colorize(` Total: ${results.length} files reviewed`, 'gray'));
|
|
52
|
-
};
|
package/dist/types.d.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
export interface EdsgerConfig {
|
|
2
|
-
patterns: string[];
|
|
3
|
-
exclude: string[];
|
|
4
|
-
severity: 'error' | 'warning';
|
|
5
|
-
maxFiles: number;
|
|
6
|
-
claude: {
|
|
7
|
-
model?: string;
|
|
8
|
-
timeout?: number;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
export interface GitFile {
|
|
12
|
-
path: string;
|
|
13
|
-
content: string;
|
|
14
|
-
status: 'modified' | 'added' | 'deleted' | 'renamed';
|
|
15
|
-
}
|
|
16
|
-
export interface ReviewResult {
|
|
17
|
-
file: string;
|
|
18
|
-
status: 'OK' | 'WARN' | 'BLOCK';
|
|
19
|
-
message: string;
|
|
20
|
-
details?: string;
|
|
21
|
-
}
|
|
22
|
-
export interface CliOptions {
|
|
23
|
-
review?: boolean;
|
|
24
|
-
staged?: boolean;
|
|
25
|
-
files?: string[];
|
|
26
|
-
config?: string;
|
|
27
|
-
verbose?: boolean;
|
|
28
|
-
featureAnalysis?: string;
|
|
29
|
-
technicalDesign?: string;
|
|
30
|
-
implement?: string;
|
|
31
|
-
test?: string;
|
|
32
|
-
workflow?: boolean;
|
|
33
|
-
}
|
|
34
|
-
export type ReviewSeverity = 'error' | 'warning';
|
|
35
|
-
export type ExitCode = 0 | 1;
|
|
36
|
-
export interface FeatureAnalysisResult {
|
|
37
|
-
featureId: string;
|
|
38
|
-
productInfo: unknown;
|
|
39
|
-
featureInfo: unknown;
|
|
40
|
-
existingUserStories: UserStory[];
|
|
41
|
-
existingTestCases: TestCase[];
|
|
42
|
-
createdUserStories: UserStory[];
|
|
43
|
-
createdTestCases: TestCase[];
|
|
44
|
-
summary: string;
|
|
45
|
-
status: 'pending' | 'success' | 'error';
|
|
46
|
-
}
|
|
47
|
-
export interface FeatureData {
|
|
48
|
-
feature: {
|
|
49
|
-
id: string;
|
|
50
|
-
name: string;
|
|
51
|
-
description: string;
|
|
52
|
-
status: string;
|
|
53
|
-
product_id: string;
|
|
54
|
-
created_at: string;
|
|
55
|
-
updated_at: string;
|
|
56
|
-
};
|
|
57
|
-
product: {
|
|
58
|
-
id: string;
|
|
59
|
-
name: string;
|
|
60
|
-
description: string;
|
|
61
|
-
status: string;
|
|
62
|
-
features: unknown[];
|
|
63
|
-
metadata: {
|
|
64
|
-
created_at: string;
|
|
65
|
-
updated_at: string;
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export interface UserStory {
|
|
70
|
-
id: string;
|
|
71
|
-
title: string;
|
|
72
|
-
description: string;
|
|
73
|
-
status: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled';
|
|
74
|
-
created_at: string;
|
|
75
|
-
updated_at: string;
|
|
76
|
-
}
|
|
77
|
-
export interface TestCase {
|
|
78
|
-
id: string;
|
|
79
|
-
name: string;
|
|
80
|
-
description: string;
|
|
81
|
-
is_critical: boolean;
|
|
82
|
-
created_at: string;
|
|
83
|
-
updated_at: string;
|
|
84
|
-
}
|
|
85
|
-
export interface DisplayUserStory {
|
|
86
|
-
title: string;
|
|
87
|
-
}
|
|
88
|
-
export interface DisplayTestCase {
|
|
89
|
-
name: string;
|
|
90
|
-
is_critical?: boolean;
|
|
91
|
-
}
|
|
92
|
-
export interface FeatureAnalysisDisplayResult {
|
|
93
|
-
featureId: string;
|
|
94
|
-
status: string;
|
|
95
|
-
summary?: string;
|
|
96
|
-
createdUserStories?: DisplayUserStory[];
|
|
97
|
-
createdTestCases?: DisplayTestCase[];
|
|
98
|
-
}
|
|
99
|
-
export type FeatureStatus = 'backlog' | 'ready_for_dev' | 'feature_analysis' | 'technical_design' | 'code_implementation' | 'code_review' | 'ready_for_review' | 'shipped' | 'testing_in_progress' | 'testing_passed' | 'testing_failed';
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stage configurations for the pipeline runner
|
|
3
|
-
*/
|
|
4
|
-
import { analyzeFeatureWithMCP, checkFeatureAnalysisRequirements, } from '../../phases/feature-analysis/analyzer.js';
|
|
5
|
-
import { generateTechnicalDesign, checkTechnicalDesignRequirements, } from '../../phases/technical-design/analyzer.js';
|
|
6
|
-
import { implementFeatureCode, checkCodeImplementationRequirements, } from '../../phases/code-implementation/analyzer.js';
|
|
7
|
-
import { runFunctionalTesting, checkFunctionalTestingRequirements, } from '../../phases/functional-testing/analyzer.js';
|
|
8
|
-
// Pipeline stage configurations
|
|
9
|
-
export const stageConfigs = [
|
|
10
|
-
{
|
|
11
|
-
name: 'feature-analysis',
|
|
12
|
-
checkRequirements: checkFeatureAnalysisRequirements,
|
|
13
|
-
execute: analyzeFeatureWithMCP,
|
|
14
|
-
requirementsError: 'Feature analysis requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
name: 'technical-design',
|
|
18
|
-
checkRequirements: checkTechnicalDesignRequirements,
|
|
19
|
-
execute: generateTechnicalDesign,
|
|
20
|
-
requirementsError: 'Technical design requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: 'code-implementation',
|
|
24
|
-
checkRequirements: checkCodeImplementationRequirements,
|
|
25
|
-
execute: implementFeatureCode,
|
|
26
|
-
requirementsError: 'Code implementation requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: 'functional-testing',
|
|
30
|
-
checkRequirements: checkFunctionalTestingRequirements,
|
|
31
|
-
execute: runFunctionalTesting,
|
|
32
|
-
requirementsError: 'Functional testing requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
33
|
-
},
|
|
34
|
-
];
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for feature filtering with timestamp-based reprocessing
|
|
3
|
-
*/
|
|
4
|
-
import { shouldProcessFeature } from './feature-filter.js';
|
|
5
|
-
describe('shouldProcessFeature with timestamp checking', () => {
|
|
6
|
-
const maxRetries = 3;
|
|
7
|
-
it('should process feature that has never been processed', () => {
|
|
8
|
-
const feature = {
|
|
9
|
-
id: 'feature-1',
|
|
10
|
-
name: 'Test Feature',
|
|
11
|
-
status: 'ready_for_dev',
|
|
12
|
-
product_id: 'product-1',
|
|
13
|
-
updated_at: '2024-01-01T10:00:00Z',
|
|
14
|
-
};
|
|
15
|
-
const states = new Map();
|
|
16
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
17
|
-
expect(result).toBe(true);
|
|
18
|
-
});
|
|
19
|
-
it('should reprocess completed feature if updated after last attempt', () => {
|
|
20
|
-
const feature = {
|
|
21
|
-
id: 'feature-1',
|
|
22
|
-
name: 'Test Feature',
|
|
23
|
-
status: 'ready_for_dev',
|
|
24
|
-
product_id: 'product-1',
|
|
25
|
-
updated_at: '2024-01-01T12:00:00Z', // Updated at noon
|
|
26
|
-
};
|
|
27
|
-
const states = new Map();
|
|
28
|
-
states.set('feature-1', {
|
|
29
|
-
featureId: 'feature-1',
|
|
30
|
-
retryCount: 1,
|
|
31
|
-
lastAttempt: new Date('2024-01-01T10:00:00Z'), // Processed at 10 AM
|
|
32
|
-
status: 'completed',
|
|
33
|
-
});
|
|
34
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
35
|
-
expect(result).toBe(true); // Should reprocess because updated after last attempt
|
|
36
|
-
});
|
|
37
|
-
it('should not reprocess completed feature if not updated after last attempt', () => {
|
|
38
|
-
const feature = {
|
|
39
|
-
id: 'feature-1',
|
|
40
|
-
name: 'Test Feature',
|
|
41
|
-
status: 'ready_for_dev',
|
|
42
|
-
product_id: 'product-1',
|
|
43
|
-
updated_at: '2024-01-01T10:00:00Z', // Updated at 10 AM
|
|
44
|
-
};
|
|
45
|
-
const states = new Map();
|
|
46
|
-
states.set('feature-1', {
|
|
47
|
-
featureId: 'feature-1',
|
|
48
|
-
retryCount: 1,
|
|
49
|
-
lastAttempt: new Date('2024-01-01T12:00:00Z'), // Processed at noon
|
|
50
|
-
status: 'completed',
|
|
51
|
-
});
|
|
52
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
53
|
-
expect(result).toBe(false); // Should not reprocess because not updated after last attempt
|
|
54
|
-
});
|
|
55
|
-
it('should reprocess failed feature if updated after last attempt', () => {
|
|
56
|
-
const feature = {
|
|
57
|
-
id: 'feature-1',
|
|
58
|
-
name: 'Test Feature',
|
|
59
|
-
status: 'ready_for_dev',
|
|
60
|
-
product_id: 'product-1',
|
|
61
|
-
updated_at: '2024-01-01T12:00:00Z', // Updated at noon
|
|
62
|
-
};
|
|
63
|
-
const states = new Map();
|
|
64
|
-
states.set('feature-1', {
|
|
65
|
-
featureId: 'feature-1',
|
|
66
|
-
retryCount: 2,
|
|
67
|
-
lastAttempt: new Date('2024-01-01T10:00:00Z'), // Failed at 10 AM
|
|
68
|
-
status: 'failed',
|
|
69
|
-
});
|
|
70
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
71
|
-
expect(result).toBe(true); // Should reprocess because updated after last attempt
|
|
72
|
-
});
|
|
73
|
-
it('should reprocess failed feature within retry limit even without update', () => {
|
|
74
|
-
const feature = {
|
|
75
|
-
id: 'feature-1',
|
|
76
|
-
name: 'Test Feature',
|
|
77
|
-
status: 'ready_for_dev',
|
|
78
|
-
product_id: 'product-1',
|
|
79
|
-
updated_at: '2024-01-01T09:00:00Z', // Not updated
|
|
80
|
-
};
|
|
81
|
-
const states = new Map();
|
|
82
|
-
states.set('feature-1', {
|
|
83
|
-
featureId: 'feature-1',
|
|
84
|
-
retryCount: 2, // Less than maxRetries (3)
|
|
85
|
-
lastAttempt: new Date('2024-01-01T10:00:00Z'),
|
|
86
|
-
status: 'failed',
|
|
87
|
-
});
|
|
88
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
89
|
-
expect(result).toBe(true); // Should retry because within retry limit
|
|
90
|
-
});
|
|
91
|
-
it('should not reprocess failed feature beyond retry limit without update', () => {
|
|
92
|
-
const feature = {
|
|
93
|
-
id: 'feature-1',
|
|
94
|
-
name: 'Test Feature',
|
|
95
|
-
status: 'ready_for_dev',
|
|
96
|
-
product_id: 'product-1',
|
|
97
|
-
updated_at: '2024-01-01T09:00:00Z', // Not updated
|
|
98
|
-
};
|
|
99
|
-
const states = new Map();
|
|
100
|
-
states.set('feature-1', {
|
|
101
|
-
featureId: 'feature-1',
|
|
102
|
-
retryCount: 3, // Equal to maxRetries
|
|
103
|
-
lastAttempt: new Date('2024-01-01T10:00:00Z'),
|
|
104
|
-
status: 'failed',
|
|
105
|
-
});
|
|
106
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
107
|
-
expect(result).toBe(false); // Should not retry because exceeded retry limit
|
|
108
|
-
});
|
|
109
|
-
it('should handle feature without updated_at timestamp', () => {
|
|
110
|
-
const feature = {
|
|
111
|
-
id: 'feature-1',
|
|
112
|
-
name: 'Test Feature',
|
|
113
|
-
status: 'ready_for_dev',
|
|
114
|
-
product_id: 'product-1',
|
|
115
|
-
// No updated_at field
|
|
116
|
-
};
|
|
117
|
-
const states = new Map();
|
|
118
|
-
states.set('feature-1', {
|
|
119
|
-
featureId: 'feature-1',
|
|
120
|
-
retryCount: 1,
|
|
121
|
-
lastAttempt: new Date('2024-01-01T10:00:00Z'),
|
|
122
|
-
status: 'completed',
|
|
123
|
-
});
|
|
124
|
-
const result = shouldProcessFeature(maxRetries)(feature, states);
|
|
125
|
-
expect(result).toBe(false); // Should not reprocess without timestamp info
|
|
126
|
-
});
|
|
127
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stage execution logic for pipeline runner
|
|
3
|
-
*/
|
|
4
|
-
import { EdsgerConfig } from '../../types/index.js';
|
|
5
|
-
import { PipelineStageOptions, PipelineResult, StageConfig } from '../../types/pipeline.js';
|
|
6
|
-
export declare const createStageRunner: (stageConfig: StageConfig) => (options: PipelineStageOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
7
|
-
declare const runFeatureAnalysisStage: (options: PipelineStageOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignStage: (options: PipelineStageOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationStage: (options: PipelineStageOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingStage: (options: PipelineStageOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
8
|
-
export { runFeatureAnalysisStage, runTechnicalDesignStage, runCodeImplementationStage, runFunctionalTestingStage, };
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stage execution logic for pipeline runner
|
|
3
|
-
*/
|
|
4
|
-
import { updateFeatureStatusForStage } from '../../api/features/index.js';
|
|
5
|
-
import { stageConfigs } from '../config/stage-configs.js';
|
|
6
|
-
// Higher-order function for stage execution
|
|
7
|
-
export const createStageRunner = (stageConfig) => async (options, config) => {
|
|
8
|
-
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
9
|
-
const { name, checkRequirements, execute, requirementsError } = stageConfig;
|
|
10
|
-
try {
|
|
11
|
-
// Check requirements
|
|
12
|
-
const hasRequirements = await checkRequirements();
|
|
13
|
-
if (!hasRequirements) {
|
|
14
|
-
return {
|
|
15
|
-
featureId,
|
|
16
|
-
stage: name,
|
|
17
|
-
status: 'error',
|
|
18
|
-
message: requirementsError,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
// Update feature status to reflect current stage
|
|
22
|
-
await updateFeatureStatusForStage({ mcpServerUrl, mcpToken }, featureId, name, verbose);
|
|
23
|
-
if (verbose) {
|
|
24
|
-
console.log(`🎯 Starting ${name} for: ${featureId}`);
|
|
25
|
-
}
|
|
26
|
-
const result = await execute(options, config);
|
|
27
|
-
return {
|
|
28
|
-
featureId,
|
|
29
|
-
stage: name,
|
|
30
|
-
status: result.status === 'success' ? 'success' : 'error',
|
|
31
|
-
message: result.status === 'success'
|
|
32
|
-
? `${name.replace('-', ' ')} completed successfully`
|
|
33
|
-
: `${name.replace('-', ' ')} failed`,
|
|
34
|
-
data: result,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
return {
|
|
39
|
-
featureId,
|
|
40
|
-
stage: name,
|
|
41
|
-
status: 'error',
|
|
42
|
-
message: `${name.replace('-', ' ')} failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
// Create stage runners using the configuration
|
|
47
|
-
const [runFeatureAnalysisStage, runTechnicalDesignStage, runCodeImplementationStage, runFunctionalTestingStage,] = stageConfigs.map(createStageRunner);
|
|
48
|
-
// Export individual stage runners for granular control
|
|
49
|
-
export { runFeatureAnalysisStage, runTechnicalDesignStage, runCodeImplementationStage, runFunctionalTestingStage, };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feature fetcher module for workflow processing
|
|
3
|
-
* Fetches features with ready_for_dev status and handles product queries via MCP
|
|
4
|
-
* Uses functional programming principles
|
|
5
|
-
*/
|
|
6
|
-
export interface McpClientConfig {
|
|
7
|
-
readonly mcpServerUrl: string;
|
|
8
|
-
readonly mcpToken: string;
|
|
9
|
-
readonly verbose?: boolean;
|
|
10
|
-
}
|
|
11
|
-
export declare const createMcpClient: (config: McpClientConfig) => {
|
|
12
|
-
call: <T>(method: string, params: unknown) => Promise<T>;
|
|
13
|
-
};
|
|
14
|
-
export interface FeatureInfo {
|
|
15
|
-
readonly id: string;
|
|
16
|
-
readonly name: string;
|
|
17
|
-
readonly description: string;
|
|
18
|
-
readonly status: string;
|
|
19
|
-
readonly product_id: string;
|
|
20
|
-
readonly created_at: string;
|
|
21
|
-
readonly updated_at: string;
|
|
22
|
-
}
|
|
23
|
-
export interface FetchFeaturesOptions {
|
|
24
|
-
readonly mcpServerUrl: string;
|
|
25
|
-
readonly mcpToken: string;
|
|
26
|
-
readonly productId: string;
|
|
27
|
-
readonly verbose?: boolean;
|
|
28
|
-
}
|
|
29
|
-
declare const filterFeaturesByStatus: (status: string) => (features: FeatureInfo[]) => FeatureInfo[];
|
|
30
|
-
declare const sortFeaturesByUpdatedAt: (features: FeatureInfo[]) => FeatureInfo[];
|
|
31
|
-
/**
|
|
32
|
-
* Fetch all features with ready_for_dev status for a product, sorted by updated_at
|
|
33
|
-
* Pure functional approach with composition
|
|
34
|
-
*/
|
|
35
|
-
export declare const fetchReadyForDevFeatures: (options: FetchFeaturesOptions) => () => Promise<FeatureInfo[]>;
|
|
36
|
-
/**
|
|
37
|
-
* Get feature details by ID
|
|
38
|
-
* Functional approach with error handling
|
|
39
|
-
*/
|
|
40
|
-
export declare const getFeatureDetails: (featureId: string, options: Omit<FetchFeaturesOptions, "productId">) => () => Promise<FeatureInfo | null>;
|
|
41
|
-
export { filterFeaturesByStatus, sortFeaturesByUpdatedAt };
|