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
|
@@ -1,121 +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
|
-
// Pure function to create MCP request payload
|
|
7
|
-
const createMcpRequest = (method, params) => ({
|
|
8
|
-
jsonrpc: '2.0',
|
|
9
|
-
method,
|
|
10
|
-
params,
|
|
11
|
-
id: Math.random().toString(36).substring(7),
|
|
12
|
-
});
|
|
13
|
-
// Higher-order function to create MCP client
|
|
14
|
-
export const createMcpClient = (config) => {
|
|
15
|
-
const { mcpServerUrl, mcpToken } = config;
|
|
16
|
-
return {
|
|
17
|
-
call: async (method, params) => {
|
|
18
|
-
const requestBody = createMcpRequest(method, params);
|
|
19
|
-
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
20
|
-
method: 'POST',
|
|
21
|
-
headers: {
|
|
22
|
-
'Content-Type': 'application/json',
|
|
23
|
-
Authorization: `Bearer ${mcpToken}`,
|
|
24
|
-
},
|
|
25
|
-
body: JSON.stringify(requestBody),
|
|
26
|
-
});
|
|
27
|
-
if (!response.ok) {
|
|
28
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
29
|
-
}
|
|
30
|
-
const data = await response.json();
|
|
31
|
-
if (data.error) {
|
|
32
|
-
throw new Error(data.error.message || 'MCP call failed');
|
|
33
|
-
}
|
|
34
|
-
return data.result;
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
// Pure function to filter features by status
|
|
39
|
-
const filterFeaturesByStatus = (status) => (features) => features.filter((feature) => feature.status === status);
|
|
40
|
-
// Pure function to sort features by updated_at (most recent first)
|
|
41
|
-
const sortFeaturesByUpdatedAt = (features) => [...features].sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime());
|
|
42
|
-
// Curried logging function
|
|
43
|
-
const logFeatureResults = (verbose) => (features) => {
|
|
44
|
-
if (verbose) {
|
|
45
|
-
console.log(`✅ Found ${features.length} ready_for_dev features`);
|
|
46
|
-
features.forEach((feature, index) => {
|
|
47
|
-
console.log(` ${index + 1}. ${feature.name} (updated: ${feature.updated_at})`);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
return features;
|
|
51
|
-
};
|
|
52
|
-
// Composition helpers
|
|
53
|
-
const pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value);
|
|
54
|
-
const tap = (fn) => (value) => {
|
|
55
|
-
fn(value);
|
|
56
|
-
return value;
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* Fetch all features with ready_for_dev status for a product, sorted by updated_at
|
|
60
|
-
* Pure functional approach with composition
|
|
61
|
-
*/
|
|
62
|
-
export const fetchReadyForDevFeatures = (options) => {
|
|
63
|
-
const { mcpServerUrl, mcpToken, productId, verbose } = options;
|
|
64
|
-
const client = createMcpClient({ mcpServerUrl, mcpToken, verbose });
|
|
65
|
-
const logStart = () => {
|
|
66
|
-
if (verbose) {
|
|
67
|
-
console.log(`📋 Fetching ready_for_dev features for product: ${productId}`);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
const logMcpResponse = (result) => {
|
|
71
|
-
if (verbose) {
|
|
72
|
-
console.log(`📊 MCP server response:`, result);
|
|
73
|
-
}
|
|
74
|
-
return result;
|
|
75
|
-
};
|
|
76
|
-
const extractFeatures = (result) => result?.features || [];
|
|
77
|
-
const processFeatures = logFeatureResults(verbose || false);
|
|
78
|
-
return async () => {
|
|
79
|
-
try {
|
|
80
|
-
logStart();
|
|
81
|
-
const result = await client.call('features/list', {
|
|
82
|
-
product_id: productId,
|
|
83
|
-
status: 'ready_for_dev',
|
|
84
|
-
});
|
|
85
|
-
const mcpLogged = tap(logMcpResponse)(result);
|
|
86
|
-
const features = extractFeatures(mcpLogged);
|
|
87
|
-
return processFeatures(features);
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
console.error(`❌ Error fetching features:`, error);
|
|
91
|
-
throw error;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
};
|
|
95
|
-
/**
|
|
96
|
-
* Get feature details by ID
|
|
97
|
-
* Functional approach with error handling
|
|
98
|
-
*/
|
|
99
|
-
export const getFeatureDetails = (featureId, options) => {
|
|
100
|
-
const { mcpServerUrl, mcpToken, verbose } = options;
|
|
101
|
-
const client = createMcpClient({ mcpServerUrl, mcpToken, verbose });
|
|
102
|
-
const logStart = () => {
|
|
103
|
-
if (verbose) {
|
|
104
|
-
console.log(`🔍 Getting details for feature: ${featureId}`);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
const extractFeature = (result) => result?.features?.[0] || null;
|
|
108
|
-
return async () => {
|
|
109
|
-
try {
|
|
110
|
-
logStart();
|
|
111
|
-
const result = await client.call('features/get', { feature_id: featureId });
|
|
112
|
-
return extractFeature(result);
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
console.error(`❌ Error getting feature details:`, error);
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
};
|
|
120
|
-
// Export utility functions for composition
|
|
121
|
-
export { filterFeaturesByStatus, sortFeaturesByUpdatedAt };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feature fetching and status management service
|
|
3
|
-
*/
|
|
4
|
-
import { FeatureStatus } from '../types.js';
|
|
5
|
-
import { type FeatureInfo } from '../api/features.js';
|
|
6
|
-
/**
|
|
7
|
-
* Fetch features with ready_for_dev status for a product
|
|
8
|
-
*/
|
|
9
|
-
export declare function fetchReadyForDevFeatures(mcpServerUrl: string, mcpToken: string, productId: string, verbose?: boolean): Promise<FeatureInfo[]>;
|
|
10
|
-
/**
|
|
11
|
-
* Map pipeline stage to feature status
|
|
12
|
-
*/
|
|
13
|
-
export declare function getStatusForStage(stage: string): FeatureStatus;
|
|
14
|
-
/**
|
|
15
|
-
* Update feature status based on pipeline stage
|
|
16
|
-
*/
|
|
17
|
-
export declare function updateFeatureStatusForStage(mcpServerUrl: string, mcpToken: string, featureId: string, stage: string, verbose?: boolean): Promise<boolean>;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feature fetching and status management service
|
|
3
|
-
*/
|
|
4
|
-
import { logInfo, logError } from '../logger.js';
|
|
5
|
-
import { updateFeatureStatus, } from '../api/features.js';
|
|
6
|
-
import { callMcpEndpoint } from '../api/mcp-client.js';
|
|
7
|
-
/**
|
|
8
|
-
* Fetch features with ready_for_dev status for a product
|
|
9
|
-
*/
|
|
10
|
-
export async function fetchReadyForDevFeatures(mcpServerUrl, mcpToken, productId, verbose) {
|
|
11
|
-
try {
|
|
12
|
-
if (verbose) {
|
|
13
|
-
logInfo(`📋 Fetching ready_for_dev features for product: ${productId}`);
|
|
14
|
-
}
|
|
15
|
-
const result = (await callMcpEndpoint(mcpServerUrl, mcpToken, 'features/list', {
|
|
16
|
-
product_id: productId,
|
|
17
|
-
status: 'ready_for_dev',
|
|
18
|
-
}));
|
|
19
|
-
const features = result?.features || [];
|
|
20
|
-
if (verbose) {
|
|
21
|
-
logInfo(`✅ Found ${features.length} ready_for_dev features`);
|
|
22
|
-
features.forEach((feature, index) => {
|
|
23
|
-
logInfo(` ${index + 1}. ${feature.name} (${feature.id})`);
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
return features;
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
logError(`❌ Error fetching features: ${error}`);
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Map pipeline stage to feature status
|
|
35
|
-
*/
|
|
36
|
-
export function getStatusForStage(stage) {
|
|
37
|
-
switch (stage) {
|
|
38
|
-
case 'feature-analysis':
|
|
39
|
-
return 'feature_analysis';
|
|
40
|
-
case 'technical-design':
|
|
41
|
-
return 'technical_design';
|
|
42
|
-
case 'code-implementation':
|
|
43
|
-
return 'code_implementation';
|
|
44
|
-
case 'functional-testing':
|
|
45
|
-
return 'testing_in_progress';
|
|
46
|
-
case 'testing-passed':
|
|
47
|
-
return 'testing_passed';
|
|
48
|
-
case 'testing-failed':
|
|
49
|
-
return 'testing_failed';
|
|
50
|
-
default:
|
|
51
|
-
return 'backlog';
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Update feature status based on pipeline stage
|
|
56
|
-
*/
|
|
57
|
-
export async function updateFeatureStatusForStage(mcpServerUrl, mcpToken, featureId, stage, verbose) {
|
|
58
|
-
const status = getStatusForStage(stage);
|
|
59
|
-
return await updateFeatureStatus(mcpServerUrl, mcpToken, featureId, status, verbose);
|
|
60
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pipeline execution logic for feature development workflow
|
|
3
|
-
*/
|
|
4
|
-
import { EdsgerConfig } from '../types.js';
|
|
5
|
-
import { PipelineStageOptions, PipelineResult } from './types.js';
|
|
6
|
-
/**
|
|
7
|
-
* Run the complete pipeline for a feature
|
|
8
|
-
*/
|
|
9
|
-
export declare function runCompletePipeline(options: PipelineStageOptions, config: EdsgerConfig, githubConfig?: {
|
|
10
|
-
githubToken: string;
|
|
11
|
-
githubOwner: string;
|
|
12
|
-
githubRepo: string;
|
|
13
|
-
githubBaseBranch?: string;
|
|
14
|
-
}): Promise<PipelineResult[]>;
|
|
15
|
-
/**
|
|
16
|
-
* Log pipeline results summary
|
|
17
|
-
*/
|
|
18
|
-
export declare function logPipelineResults(results: readonly PipelineResult[]): void;
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pipeline execution logic for feature development workflow
|
|
3
|
-
*/
|
|
4
|
-
import { updateFeatureStatusForStage } from './feature-service.js';
|
|
5
|
-
// Import phase analyzers
|
|
6
|
-
import { analyzeFeatureWithMCP, checkFeatureAnalysisRequirements, } from '../phases/feature-analysis/analyzer.js';
|
|
7
|
-
import { generateTechnicalDesign, checkTechnicalDesignRequirements, } from '../phases/technical-design/analyzer.js';
|
|
8
|
-
import { implementFeatureCode, checkCodeImplementationRequirements, } from '../phases/code-implementation/analyzer.js';
|
|
9
|
-
import { runFunctionalTesting, checkFunctionalTestingRequirements, } from '../phases/functional-testing/analyzer.js';
|
|
10
|
-
import { fixTestFailures, checkBugFixingRequirements, } from '../phases/bug-fixing/analyzer.js';
|
|
11
|
-
import { createPullRequest, updateFeatureWithPullRequest, } from '../phases/pull-request/creator.js';
|
|
12
|
-
import { getFeature } from '../api/features.js';
|
|
13
|
-
// Common requirements error message
|
|
14
|
-
const COMMON_REQUIREMENTS_ERROR = 'Requirements not met. Install with: npm install @anthropic-ai/claude-code zod';
|
|
15
|
-
// Pipeline stage configurations
|
|
16
|
-
const stageConfigs = [
|
|
17
|
-
{
|
|
18
|
-
name: 'feature-analysis',
|
|
19
|
-
checkRequirements: checkFeatureAnalysisRequirements,
|
|
20
|
-
execute: analyzeFeatureWithMCP,
|
|
21
|
-
requirementsError: `Feature analysis ${COMMON_REQUIREMENTS_ERROR}`,
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: 'technical-design',
|
|
25
|
-
checkRequirements: checkTechnicalDesignRequirements,
|
|
26
|
-
execute: generateTechnicalDesign,
|
|
27
|
-
requirementsError: `Technical design ${COMMON_REQUIREMENTS_ERROR}`,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'code-implementation',
|
|
31
|
-
checkRequirements: checkCodeImplementationRequirements,
|
|
32
|
-
execute: implementFeatureCode,
|
|
33
|
-
requirementsError: `Code implementation ${COMMON_REQUIREMENTS_ERROR}`,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: 'functional-testing',
|
|
37
|
-
checkRequirements: checkFunctionalTestingRequirements,
|
|
38
|
-
execute: runFunctionalTesting,
|
|
39
|
-
requirementsError: `Functional testing ${COMMON_REQUIREMENTS_ERROR}`,
|
|
40
|
-
},
|
|
41
|
-
];
|
|
42
|
-
/**
|
|
43
|
-
* Execute a single pipeline stage
|
|
44
|
-
*/
|
|
45
|
-
async function executeStage(stageConfig, options, config) {
|
|
46
|
-
const { featureId } = options;
|
|
47
|
-
try {
|
|
48
|
-
// Check requirements
|
|
49
|
-
if (!(await stageConfig.checkRequirements())) {
|
|
50
|
-
return {
|
|
51
|
-
featureId,
|
|
52
|
-
stage: stageConfig.name,
|
|
53
|
-
status: 'error',
|
|
54
|
-
message: stageConfig.requirementsError,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
// Update status to indicate stage is starting
|
|
58
|
-
await updateFeatureStatusForStage(options.mcpServerUrl, options.mcpToken, featureId, stageConfig.name, options.verbose);
|
|
59
|
-
// Execute stage
|
|
60
|
-
const result = await stageConfig.execute(options, config);
|
|
61
|
-
return {
|
|
62
|
-
featureId,
|
|
63
|
-
stage: stageConfig.name,
|
|
64
|
-
status: 'success',
|
|
65
|
-
message: `${stageConfig.name} completed successfully`,
|
|
66
|
-
data: result,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
return {
|
|
71
|
-
featureId,
|
|
72
|
-
stage: stageConfig.name,
|
|
73
|
-
status: 'error',
|
|
74
|
-
message: `${stageConfig.name} failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Run the complete pipeline for a feature
|
|
80
|
-
*/
|
|
81
|
-
export async function runCompletePipeline(options, config, githubConfig) {
|
|
82
|
-
const results = [];
|
|
83
|
-
for (const stageConfig of stageConfigs) {
|
|
84
|
-
const result = await executeStage(stageConfig, options, config);
|
|
85
|
-
results.push(result);
|
|
86
|
-
// Stop pipeline if stage failed
|
|
87
|
-
if (result.status === 'error') {
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Handle testing failures with bug fixing
|
|
92
|
-
const lastResult = results[results.length - 1];
|
|
93
|
-
if (lastResult?.stage === 'functional-testing' &&
|
|
94
|
-
lastResult?.status === 'error') {
|
|
95
|
-
// Try bug fixing
|
|
96
|
-
try {
|
|
97
|
-
if (await checkBugFixingRequirements()) {
|
|
98
|
-
await updateFeatureStatusForStage(options.mcpServerUrl, options.mcpToken, options.featureId, 'bug-fixing', options.verbose);
|
|
99
|
-
const bugFixResult = await fixTestFailures({
|
|
100
|
-
...options,
|
|
101
|
-
testErrors: 'Functional testing failed',
|
|
102
|
-
}, config);
|
|
103
|
-
results.push({
|
|
104
|
-
featureId: options.featureId,
|
|
105
|
-
stage: 'bug-fixing',
|
|
106
|
-
status: 'success',
|
|
107
|
-
message: 'Bug fixing completed',
|
|
108
|
-
data: bugFixResult,
|
|
109
|
-
});
|
|
110
|
-
// Retry functional testing
|
|
111
|
-
const functionalTestingStage = stageConfigs.find(stage => stage.name === 'functional-testing');
|
|
112
|
-
if (!functionalTestingStage) {
|
|
113
|
-
throw new Error('Functional testing stage configuration not found');
|
|
114
|
-
}
|
|
115
|
-
const retestResult = await executeStage(functionalTestingStage, options, config);
|
|
116
|
-
results.push(retestResult);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
results.push({
|
|
121
|
-
featureId: options.featureId,
|
|
122
|
-
stage: 'bug-fixing',
|
|
123
|
-
status: 'error',
|
|
124
|
-
message: `Bug fixing failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// Create pull request if GitHub configuration is provided and all stages succeeded
|
|
129
|
-
const allSuccessful = results.every((r) => r.status === 'success');
|
|
130
|
-
if (githubConfig && allSuccessful) {
|
|
131
|
-
try {
|
|
132
|
-
// Get feature details for PR creation
|
|
133
|
-
const feature = await getFeature(options.mcpServerUrl, options.mcpToken, options.featureId, options.verbose);
|
|
134
|
-
if (feature) {
|
|
135
|
-
const prConfig = {
|
|
136
|
-
githubToken: githubConfig.githubToken,
|
|
137
|
-
owner: githubConfig.githubOwner,
|
|
138
|
-
repo: githubConfig.githubRepo,
|
|
139
|
-
baseBranch: githubConfig.githubBaseBranch || 'main',
|
|
140
|
-
verbose: options.verbose,
|
|
141
|
-
};
|
|
142
|
-
// Convert API FeatureInfo to PR FeatureInfo format
|
|
143
|
-
const prFeature = {
|
|
144
|
-
id: feature.id,
|
|
145
|
-
name: feature.name,
|
|
146
|
-
description: feature.description || 'No description provided',
|
|
147
|
-
productId: feature.product_id,
|
|
148
|
-
technicalDesign: feature.technical_design,
|
|
149
|
-
testResult: undefined,
|
|
150
|
-
testReportUrl: undefined,
|
|
151
|
-
};
|
|
152
|
-
const prResult = await createPullRequest(prConfig, prFeature);
|
|
153
|
-
if (prResult.success && prResult.pullRequestUrl) {
|
|
154
|
-
// Update feature with PR URL
|
|
155
|
-
await updateFeatureWithPullRequest(options.mcpServerUrl, options.mcpToken, options.featureId, prResult.pullRequestUrl, options.verbose);
|
|
156
|
-
results.push({
|
|
157
|
-
featureId: options.featureId,
|
|
158
|
-
stage: 'pull-request',
|
|
159
|
-
status: 'success',
|
|
160
|
-
message: `Pull request created: ${prResult.pullRequestUrl}`,
|
|
161
|
-
data: prResult,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
results.push({
|
|
166
|
-
featureId: options.featureId,
|
|
167
|
-
stage: 'pull-request',
|
|
168
|
-
status: 'error',
|
|
169
|
-
message: `Pull request creation failed: ${prResult.error || 'Unknown error'}`,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
results.push({
|
|
176
|
-
featureId: options.featureId,
|
|
177
|
-
stage: 'pull-request',
|
|
178
|
-
status: 'error',
|
|
179
|
-
message: `Pull request creation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return results;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Log pipeline results summary
|
|
187
|
-
*/
|
|
188
|
-
export function logPipelineResults(results) {
|
|
189
|
-
console.log('\n' + '='.repeat(60));
|
|
190
|
-
console.log('📊 Pipeline Results Summary');
|
|
191
|
-
console.log('='.repeat(60));
|
|
192
|
-
results.forEach((result, index) => {
|
|
193
|
-
const statusIcon = result.status === 'success' ? '✅' : '❌';
|
|
194
|
-
console.log(`${index + 1}. ${statusIcon} ${result.stage}: ${result.message}`);
|
|
195
|
-
});
|
|
196
|
-
console.log('='.repeat(60) + '\n');
|
|
197
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main workflow processor for continuous feature development
|
|
3
|
-
*/
|
|
4
|
-
import { EdsgerConfig } from '../types.js';
|
|
5
|
-
import { WorkflowOptions, WorkflowStats } from './types.js';
|
|
6
|
-
/**
|
|
7
|
-
* Main workflow processor class
|
|
8
|
-
*/
|
|
9
|
-
export declare class WorkflowProcessor {
|
|
10
|
-
private readonly options;
|
|
11
|
-
private readonly config;
|
|
12
|
-
private isRunning;
|
|
13
|
-
private processedFeatures;
|
|
14
|
-
private pollTimer?;
|
|
15
|
-
constructor(options: WorkflowOptions, config: EdsgerConfig);
|
|
16
|
-
/**
|
|
17
|
-
* Start the workflow processor
|
|
18
|
-
*/
|
|
19
|
-
start(): Promise<void>;
|
|
20
|
-
/**
|
|
21
|
-
* Stop the workflow processor
|
|
22
|
-
*/
|
|
23
|
-
stop(): void;
|
|
24
|
-
/**
|
|
25
|
-
* Process the next available feature
|
|
26
|
-
*/
|
|
27
|
-
private processNextFeature;
|
|
28
|
-
/**
|
|
29
|
-
* Process a single feature through the complete pipeline
|
|
30
|
-
*/
|
|
31
|
-
private processFeature;
|
|
32
|
-
/**
|
|
33
|
-
* Get current processing statistics
|
|
34
|
-
*/
|
|
35
|
-
getStats(): WorkflowStats;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Create and start a workflow processor
|
|
39
|
-
*/
|
|
40
|
-
export declare function startWorkflowProcessor(options: WorkflowOptions, config: EdsgerConfig): Promise<WorkflowProcessor>;
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main workflow processor for continuous feature development
|
|
3
|
-
*/
|
|
4
|
-
import { logInfo, logError, logSuccess } from '../logger.js';
|
|
5
|
-
import { fetchReadyForDevFeatures } from './feature-service.js';
|
|
6
|
-
import { runCompletePipeline, logPipelineResults } from './pipeline.js';
|
|
7
|
-
/**
|
|
8
|
-
* Main workflow processor class
|
|
9
|
-
*/
|
|
10
|
-
export class WorkflowProcessor {
|
|
11
|
-
options;
|
|
12
|
-
config;
|
|
13
|
-
isRunning = false;
|
|
14
|
-
processedFeatures = new Map();
|
|
15
|
-
pollTimer;
|
|
16
|
-
constructor(options, config) {
|
|
17
|
-
this.options = {
|
|
18
|
-
pollInterval: 30000, // 30 seconds default
|
|
19
|
-
maxRetries: 3,
|
|
20
|
-
verbose: false,
|
|
21
|
-
...options,
|
|
22
|
-
};
|
|
23
|
-
this.config = config;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Start the workflow processor
|
|
27
|
-
*/
|
|
28
|
-
async start() {
|
|
29
|
-
if (this.isRunning) {
|
|
30
|
-
logInfo('Workflow processor is already running');
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
this.isRunning = true;
|
|
34
|
-
logInfo('🚀 Starting workflow processor...');
|
|
35
|
-
logInfo(`📋 Product ID: ${this.options.productId}`);
|
|
36
|
-
logInfo(`🔄 Poll interval: ${this.options.pollInterval}ms`);
|
|
37
|
-
// Initial check
|
|
38
|
-
await this.processNextFeature();
|
|
39
|
-
// Set up polling for new features
|
|
40
|
-
this.pollTimer = setInterval(() => {
|
|
41
|
-
this.processNextFeature().catch((error) => {
|
|
42
|
-
logError(`Error in polling cycle: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
-
});
|
|
44
|
-
}, this.options.pollInterval);
|
|
45
|
-
logInfo('✅ Workflow processor started and monitoring for new features');
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Stop the workflow processor
|
|
49
|
-
*/
|
|
50
|
-
stop() {
|
|
51
|
-
if (!this.isRunning) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
this.isRunning = false;
|
|
55
|
-
if (this.pollTimer) {
|
|
56
|
-
clearInterval(this.pollTimer);
|
|
57
|
-
this.pollTimer = undefined;
|
|
58
|
-
}
|
|
59
|
-
logInfo('⏹️ Workflow processor stopped');
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Process the next available feature
|
|
63
|
-
*/
|
|
64
|
-
async processNextFeature() {
|
|
65
|
-
try {
|
|
66
|
-
// Skip if features are being processed
|
|
67
|
-
const processing = Array.from(this.processedFeatures.values()).filter((s) => s.status === 'processing').length;
|
|
68
|
-
if (processing > 0) {
|
|
69
|
-
if (this.options.verbose) {
|
|
70
|
-
logInfo(`⏳ Skipping - ${processing} feature(s) being processed`);
|
|
71
|
-
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
// Fetch ready features
|
|
75
|
-
const features = await fetchReadyForDevFeatures(this.options.mcpServerUrl, this.options.mcpToken, this.options.productId, this.options.verbose);
|
|
76
|
-
if (features.length === 0) {
|
|
77
|
-
if (this.options.verbose) {
|
|
78
|
-
logInfo('🔍 No ready_for_dev features found, continuing to monitor...');
|
|
79
|
-
}
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
// Find next feature to process
|
|
83
|
-
const nextFeature = features.find((feature) => {
|
|
84
|
-
const state = this.processedFeatures.get(feature.id);
|
|
85
|
-
return (!state ||
|
|
86
|
-
(state.status === 'failed' &&
|
|
87
|
-
state.retryCount < this.options.maxRetries));
|
|
88
|
-
});
|
|
89
|
-
if (!nextFeature) {
|
|
90
|
-
if (this.options.verbose) {
|
|
91
|
-
logInfo('🔄 All features processed or being processed, continuing to monitor...');
|
|
92
|
-
}
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
// Process the feature
|
|
96
|
-
await this.processFeature(nextFeature);
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
logError(`Error in processNextFeature: ${error instanceof Error ? error.message : String(error)}`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Process a single feature through the complete pipeline
|
|
104
|
-
*/
|
|
105
|
-
async processFeature(feature) {
|
|
106
|
-
const featureId = feature.id;
|
|
107
|
-
const currentState = this.processedFeatures.get(featureId);
|
|
108
|
-
// Update state to processing
|
|
109
|
-
this.processedFeatures.set(featureId, {
|
|
110
|
-
featureId,
|
|
111
|
-
retryCount: currentState ? currentState.retryCount + 1 : 1,
|
|
112
|
-
lastAttempt: new Date(),
|
|
113
|
-
status: 'processing',
|
|
114
|
-
});
|
|
115
|
-
logInfo(`🎯 Processing feature: ${feature.name} (${feature.id})`);
|
|
116
|
-
if (this.options.verbose) {
|
|
117
|
-
logInfo(` Description: ${feature.description}`);
|
|
118
|
-
logInfo(` Status: ${feature.status}`);
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
// Prepare GitHub configuration if provided
|
|
122
|
-
const githubConfig = this.options.githubToken && this.options.githubOwner && this.options.githubRepo
|
|
123
|
-
? {
|
|
124
|
-
githubToken: this.options.githubToken,
|
|
125
|
-
githubOwner: this.options.githubOwner,
|
|
126
|
-
githubRepo: this.options.githubRepo,
|
|
127
|
-
githubBaseBranch: this.options.githubBaseBranch,
|
|
128
|
-
}
|
|
129
|
-
: undefined;
|
|
130
|
-
// Run complete pipeline
|
|
131
|
-
const results = await runCompletePipeline({
|
|
132
|
-
featureId,
|
|
133
|
-
mcpServerUrl: this.options.mcpServerUrl,
|
|
134
|
-
mcpToken: this.options.mcpToken,
|
|
135
|
-
verbose: this.options.verbose,
|
|
136
|
-
}, this.config, githubConfig);
|
|
137
|
-
// Check if all stages succeeded
|
|
138
|
-
const allSuccessful = results.every((r) => r.status === 'success');
|
|
139
|
-
if (allSuccessful) {
|
|
140
|
-
this.processedFeatures.set(featureId, {
|
|
141
|
-
featureId,
|
|
142
|
-
retryCount: this.processedFeatures.get(featureId).retryCount,
|
|
143
|
-
lastAttempt: new Date(),
|
|
144
|
-
status: 'completed',
|
|
145
|
-
});
|
|
146
|
-
logSuccess(`✅ Feature ${feature.name} completed successfully!`);
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
this.processedFeatures.set(featureId, {
|
|
150
|
-
featureId,
|
|
151
|
-
retryCount: this.processedFeatures.get(featureId).retryCount,
|
|
152
|
-
lastAttempt: new Date(),
|
|
153
|
-
status: 'failed',
|
|
154
|
-
});
|
|
155
|
-
logError(`❌ Feature ${feature.name} failed in pipeline`);
|
|
156
|
-
}
|
|
157
|
-
// Log pipeline results
|
|
158
|
-
logPipelineResults(results);
|
|
159
|
-
}
|
|
160
|
-
catch (error) {
|
|
161
|
-
this.processedFeatures.set(featureId, {
|
|
162
|
-
featureId,
|
|
163
|
-
retryCount: this.processedFeatures.get(featureId).retryCount,
|
|
164
|
-
lastAttempt: new Date(),
|
|
165
|
-
status: 'failed',
|
|
166
|
-
});
|
|
167
|
-
logError(`❌ Error processing feature ${feature.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Get current processing statistics
|
|
172
|
-
*/
|
|
173
|
-
getStats() {
|
|
174
|
-
const states = Array.from(this.processedFeatures.values());
|
|
175
|
-
return {
|
|
176
|
-
totalProcessed: states.length,
|
|
177
|
-
completed: states.filter((s) => s.status === 'completed').length,
|
|
178
|
-
failed: states.filter((s) => s.status === 'failed').length,
|
|
179
|
-
processing: states.filter((s) => s.status === 'processing').length,
|
|
180
|
-
isRunning: this.isRunning,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Create and start a workflow processor
|
|
186
|
-
*/
|
|
187
|
-
export async function startWorkflowProcessor(options, config) {
|
|
188
|
-
const processor = new WorkflowProcessor(options, config);
|
|
189
|
-
await processor.start();
|
|
190
|
-
return processor;
|
|
191
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feature status updater for workflow pipeline
|
|
3
|
-
* Updates feature status at each stage of the development workflow
|
|
4
|
-
*/
|
|
5
|
-
import type { FeatureStatus } from '../types.js';
|
|
6
|
-
interface McpClientConfig {
|
|
7
|
-
readonly mcpServerUrl: string;
|
|
8
|
-
readonly mcpToken: string;
|
|
9
|
-
}
|
|
10
|
-
interface StatusUpdateOptions extends McpClientConfig {
|
|
11
|
-
readonly featureId: string;
|
|
12
|
-
readonly status: FeatureStatus;
|
|
13
|
-
readonly verbose?: boolean;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Update feature status via MCP endpoint
|
|
17
|
-
*/
|
|
18
|
-
export declare function updateFeatureStatus({ mcpServerUrl, mcpToken, featureId, status, verbose, }: StatusUpdateOptions): Promise<boolean>;
|
|
19
|
-
/**
|
|
20
|
-
* Map pipeline stage to feature status
|
|
21
|
-
*/
|
|
22
|
-
export declare const getStatusForStage: (stage: string) => FeatureStatus;
|
|
23
|
-
/**
|
|
24
|
-
* Update feature status based on pipeline stage
|
|
25
|
-
*/
|
|
26
|
-
export declare const updateFeatureStatusForStage: (mcpConfig: McpClientConfig, featureId: string, stage: string, verbose?: boolean) => Promise<boolean>;
|
|
27
|
-
export {};
|