edsger 0.2.1 → 0.2.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/dist/api/features/feature-utils.d.ts +13 -0
- package/dist/api/features/feature-utils.js +46 -0
- package/dist/api/features/get-feature.d.ts +5 -0
- package/dist/api/features/get-feature.js +19 -0
- package/dist/api/features/index.d.ts +7 -0
- package/dist/api/features/index.js +9 -0
- package/dist/api/features/status-updater.d.ts +27 -0
- package/dist/api/features/status-updater.js +64 -0
- package/dist/api/features/test-cases.d.ts +21 -0
- package/dist/api/features/test-cases.js +63 -0
- package/dist/api/features/update-feature.d.ts +13 -0
- package/dist/api/features/update-feature.js +31 -0
- package/dist/api/features/user-stories.d.ts +21 -0
- package/dist/api/features/user-stories.js +63 -0
- package/dist/api/features.d.ts +100 -0
- package/dist/api/features.js +219 -0
- package/dist/api/mcp-client.d.ts +18 -0
- package/dist/api/mcp-client.js +58 -0
- package/dist/api/products.d.ts +10 -0
- package/dist/api/products.js +22 -0
- package/dist/api/test-reports.d.ts +9 -0
- package/dist/api/test-reports.js +25 -0
- package/dist/cli/commands/code-implementation-command.d.ts +2 -0
- package/dist/cli/commands/code-implementation-command.js +36 -0
- package/dist/cli/commands/code-review-command.d.ts +2 -0
- package/dist/cli/commands/code-review-command.js +39 -0
- package/dist/cli/commands/feature-analysis-command.d.ts +2 -0
- package/dist/cli/commands/feature-analysis-command.js +36 -0
- package/dist/cli/commands/functional-testing-command.d.ts +2 -0
- package/dist/cli/commands/functional-testing-command.js +36 -0
- package/dist/cli/commands/technical-design-command.d.ts +2 -0
- package/dist/cli/commands/technical-design-command.js +36 -0
- package/dist/cli/commands/workflow-command.d.ts +2 -0
- package/dist/cli/commands/workflow-command.js +34 -0
- package/dist/cli/formatters/code-implementation-formatter.d.ts +9 -0
- package/dist/cli/formatters/code-implementation-formatter.js +27 -0
- package/dist/cli/formatters/feature-analysis-formatter.d.ts +2 -0
- package/dist/cli/formatters/feature-analysis-formatter.js +27 -0
- package/dist/cli/formatters/functional-testing-formatter.d.ts +15 -0
- package/dist/cli/formatters/functional-testing-formatter.js +37 -0
- package/dist/cli/formatters/technical-design-formatter.d.ts +7 -0
- package/dist/cli/formatters/technical-design-formatter.js +30 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/utils/validation.d.ts +25 -0
- package/dist/cli/utils/validation.js +58 -0
- package/dist/cli/utils/workflow-utils.d.ts +21 -0
- package/dist/cli/utils/workflow-utils.js +47 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +11 -466
- package/dist/config.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/{bug-fixing → phases/bug-fixing}/analyzer.d.ts +1 -1
- package/dist/{bug-fixing → phases/bug-fixing}/analyzer.js +1 -1
- package/dist/{bug-fixing → phases/bug-fixing}/context-fetcher.d.ts +4 -22
- package/dist/{bug-fixing → phases/bug-fixing}/context-fetcher.js +14 -58
- package/dist/{bug-fixing → phases/bug-fixing}/mcp-server.js +1 -30
- package/dist/phases/code-implementation/analyzer.d.ts +33 -0
- package/dist/{code-implementation → phases/code-implementation}/analyzer.js +174 -15
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/{code-implementation → phases/code-implementation}/mcp-server.js +1 -30
- package/dist/{code-review → phases/code-review}/reviewer.d.ts +1 -1
- package/dist/{feature-analysis → phases/feature-analysis}/analyzer.d.ts +3 -2
- package/dist/{feature-analysis → phases/feature-analysis}/analyzer.js +29 -127
- package/dist/phases/feature-analysis/context-fetcher.d.ts +18 -0
- package/dist/phases/feature-analysis/context-fetcher.js +86 -0
- package/dist/{feature-analysis → phases/feature-analysis}/http-fallback.js +1 -1
- package/dist/{feature-analysis → phases/feature-analysis}/mcp-server.js +1 -24
- package/dist/{functional-testing → phases/functional-testing}/analyzer.d.ts +17 -2
- package/dist/{functional-testing → phases/functional-testing}/analyzer.js +225 -31
- package/dist/phases/functional-testing/context-fetcher.d.ts +16 -0
- package/dist/phases/functional-testing/context-fetcher.js +81 -0
- package/dist/{functional-testing → phases/functional-testing}/http-fallback.js +1 -1
- package/dist/{functional-testing → phases/functional-testing}/index.d.ts +1 -1
- package/dist/{functional-testing → phases/functional-testing}/index.js +1 -1
- package/dist/{functional-testing → phases/functional-testing}/mcp-server.js +1 -30
- package/dist/{functional-testing → phases/functional-testing}/test-report-creator.js +1 -1
- package/dist/phases/functional-testing/test-retry-handler.d.ts +16 -0
- package/dist/phases/functional-testing/test-retry-handler.js +75 -0
- package/dist/{pull-request → phases/pull-request}/creator.js +47 -6
- package/dist/phases/pull-request/handler.d.ts +16 -0
- package/dist/phases/pull-request/handler.js +60 -0
- package/dist/{technical-design → phases/technical-design}/analyzer.d.ts +7 -2
- package/dist/phases/technical-design/analyzer.js +418 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/{technical-design → phases/technical-design}/http-fallback.js +1 -1
- package/dist/{technical-design → phases/technical-design}/mcp-server.js +1 -30
- package/dist/prompts/bug-fixing.d.ts +2 -0
- package/dist/prompts/bug-fixing.js +63 -0
- package/dist/prompts/code-implementation.d.ts +3 -0
- package/dist/prompts/code-implementation.js +132 -0
- package/dist/prompts/feature-analysis.d.ts +3 -0
- package/dist/prompts/feature-analysis.js +149 -0
- package/dist/prompts/formatters.d.ts +29 -0
- package/dist/prompts/formatters.js +139 -0
- package/dist/prompts/functional-testing.d.ts +3 -0
- package/dist/prompts/functional-testing.js +126 -0
- package/dist/prompts/index.d.ts +6 -0
- package/dist/prompts/index.js +7 -0
- package/dist/prompts/technical-design.d.ts +3 -0
- package/dist/prompts/technical-design.js +130 -0
- package/dist/services/checklist.d.ts +99 -0
- package/dist/services/checklist.js +337 -0
- package/dist/types/features.d.ts +29 -0
- package/dist/types/features.js +1 -0
- package/dist/types/index.d.ts +112 -0
- package/dist/types/index.js +1 -0
- package/dist/types/pipeline.d.ts +25 -0
- package/dist/types/pipeline.js +4 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/pipeline-logger.d.ts +8 -0
- package/dist/utils/pipeline-logger.js +35 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +34 -0
- package/dist/workflow-runner/config/stage-configs.d.ts +5 -0
- package/dist/workflow-runner/config/stage-configs.js +34 -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/feature-filter.test.d.ts +4 -0
- package/dist/workflow-runner/core/feature-filter.test.js +127 -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 +183 -0
- package/dist/workflow-runner/executors/stage-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/stage-executor.js +49 -0
- package/dist/workflow-runner/feature-service.d.ts +17 -0
- package/dist/workflow-runner/feature-service.js +60 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +113 -0
- package/dist/workflow-runner/index.d.ts +0 -1
- package/dist/workflow-runner/index.js +0 -1
- package/dist/workflow-runner/pipeline-runner.d.ts +9 -19
- package/dist/workflow-runner/pipeline-runner.js +247 -256
- package/dist/workflow-runner/pipeline.d.ts +18 -0
- package/dist/workflow-runner/pipeline.js +197 -0
- package/dist/workflow-runner/processor.d.ts +40 -0
- package/dist/workflow-runner/processor.js +191 -0
- package/dist/workflow-runner/types.d.ts +48 -0
- package/dist/workflow-runner/types.js +4 -0
- package/dist/workflow-runner/workflow-processor.d.ts +6 -23
- package/dist/workflow-runner/workflow-processor.js +38 -100
- package/package.json +1 -1
- package/dist/code-implementation/analyzer.d.ts +0 -19
- package/dist/code-implementation/context-fetcher.d.ts +0 -38
- package/dist/code-implementation/context-fetcher.js +0 -147
- package/dist/feature-analysis/context-fetcher.d.ts +0 -54
- package/dist/feature-analysis/context-fetcher.js +0 -193
- package/dist/functional-testing/context-fetcher.d.ts +0 -47
- package/dist/functional-testing/context-fetcher.js +0 -192
- package/dist/technical-design/analyzer.js +0 -338
- package/dist/technical-design/context-fetcher.d.ts +0 -42
- package/dist/technical-design/context-fetcher.js +0 -170
- /package/dist/{bug-fixing → phases/bug-fixing}/index.d.ts +0 -0
- /package/dist/{bug-fixing → phases/bug-fixing}/index.js +0 -0
- /package/dist/{bug-fixing → phases/bug-fixing}/mcp-server.d.ts +0 -0
- /package/dist/{code-implementation → phases/code-implementation}/mcp-server.d.ts +0 -0
- /package/dist/{code-review → phases/code-review}/reviewer.js +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/http-fallback.d.ts +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/index.d.ts +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/index.js +0 -0
- /package/dist/{feature-analysis → phases/feature-analysis}/mcp-server.d.ts +0 -0
- /package/dist/{functional-testing → phases/functional-testing}/http-fallback.d.ts +0 -0
- /package/dist/{functional-testing → phases/functional-testing}/mcp-server.d.ts +0 -0
- /package/dist/{functional-testing → phases/functional-testing}/test-report-creator.d.ts +0 -0
- /package/dist/{pull-request → phases/pull-request}/creator.d.ts +0 -0
- /package/dist/{technical-design → phases/technical-design}/http-fallback.d.ts +0 -0
- /package/dist/{technical-design → phases/technical-design}/mcp-server.d.ts +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature filtering utilities for workflow processor
|
|
3
|
+
* Pure functions for filtering and selecting features for processing
|
|
4
|
+
*/
|
|
5
|
+
import type { FeatureInfo } from '../../types/features.js';
|
|
6
|
+
import type { FeatureProcessingState } from './state-manager.js';
|
|
7
|
+
export declare const shouldProcessFeature: (maxRetries: number) => (feature: FeatureInfo, states: Map<string, FeatureProcessingState>) => boolean;
|
|
8
|
+
export declare const findNextFeature: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>, maxRetries: number) => FeatureInfo | undefined;
|
|
9
|
+
export declare const isFeatureProcessing: (featureId: string, states: Map<string, FeatureProcessingState>) => boolean;
|
|
10
|
+
export declare const isFeatureCompleted: (featureId: string, states: Map<string, FeatureProcessingState>) => boolean;
|
|
11
|
+
export declare const isFeatureFailed: (featureId: string, states: Map<string, FeatureProcessingState>) => boolean;
|
|
12
|
+
export declare const hasReachedMaxRetries: (featureId: string, states: Map<string, FeatureProcessingState>, maxRetries: number) => boolean;
|
|
13
|
+
export declare const filterProcessingFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>) => FeatureInfo[];
|
|
14
|
+
export declare const filterCompletedFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>) => FeatureInfo[];
|
|
15
|
+
export declare const filterFailedFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>) => FeatureInfo[];
|
|
16
|
+
export declare const filterAvailableFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>, maxRetries: number) => FeatureInfo[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature filtering utilities for workflow processor
|
|
3
|
+
* Pure functions for filtering and selecting features for processing
|
|
4
|
+
*/
|
|
5
|
+
// Feature filtering functions (pure)
|
|
6
|
+
export const shouldProcessFeature = (maxRetries) => (feature, states) => {
|
|
7
|
+
const state = states.get(feature.id);
|
|
8
|
+
// If never processed, should process
|
|
9
|
+
if (!state)
|
|
10
|
+
return true;
|
|
11
|
+
// If feature was updated after last processing attempt, should reprocess
|
|
12
|
+
// This handles cases where user manually changes status back to ready_for_dev
|
|
13
|
+
if (feature.updated_at) {
|
|
14
|
+
const featureUpdatedTime = new Date(feature.updated_at).getTime();
|
|
15
|
+
const lastAttemptTime = state.lastAttempt.getTime();
|
|
16
|
+
if (featureUpdatedTime > lastAttemptTime) {
|
|
17
|
+
// Feature has been updated since last processing, reprocess it
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// If failed and haven't exceeded retry limit, should retry
|
|
22
|
+
return state.status === 'failed' && state.retryCount < maxRetries;
|
|
23
|
+
};
|
|
24
|
+
export const findNextFeature = (features, states, maxRetries) => features.find((feature) => shouldProcessFeature(maxRetries)(feature, states));
|
|
25
|
+
// Feature status checking functions (pure)
|
|
26
|
+
export const isFeatureProcessing = (featureId, states) => {
|
|
27
|
+
const state = states.get(featureId);
|
|
28
|
+
return state?.status === 'processing';
|
|
29
|
+
};
|
|
30
|
+
export const isFeatureCompleted = (featureId, states) => {
|
|
31
|
+
const state = states.get(featureId);
|
|
32
|
+
return state?.status === 'completed';
|
|
33
|
+
};
|
|
34
|
+
export const isFeatureFailed = (featureId, states) => {
|
|
35
|
+
const state = states.get(featureId);
|
|
36
|
+
return state?.status === 'failed';
|
|
37
|
+
};
|
|
38
|
+
export const hasReachedMaxRetries = (featureId, states, maxRetries) => {
|
|
39
|
+
const state = states.get(featureId);
|
|
40
|
+
return state ? state.retryCount >= maxRetries : false;
|
|
41
|
+
};
|
|
42
|
+
// Feature collection filtering functions (pure)
|
|
43
|
+
export const filterProcessingFeatures = (features, states) => features.filter((feature) => isFeatureProcessing(feature.id, states));
|
|
44
|
+
export const filterCompletedFeatures = (features, states) => features.filter((feature) => isFeatureCompleted(feature.id, states));
|
|
45
|
+
export const filterFailedFeatures = (features, states) => features.filter((feature) => isFeatureFailed(feature.id, states));
|
|
46
|
+
export const filterAvailableFeatures = (features, states, maxRetries) => features.filter((feature) => shouldProcessFeature(maxRetries)(feature, states));
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core workflow processor modules
|
|
3
|
+
* Centralized exports for all core functionality
|
|
4
|
+
*/
|
|
5
|
+
// State management
|
|
6
|
+
export * from './state-manager.js';
|
|
7
|
+
// Feature filtering
|
|
8
|
+
export * from './feature-filter.js';
|
|
9
|
+
// Pipeline evaluation
|
|
10
|
+
export * from './pipeline-evaluator.js';
|
|
11
|
+
// Workflow logging
|
|
12
|
+
export * from './workflow-logger.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline result evaluation utilities for workflow processor
|
|
3
|
+
* Pure functions for evaluating pipeline execution results
|
|
4
|
+
*/
|
|
5
|
+
import type { PipelineResult } from '../../types/pipeline.js';
|
|
6
|
+
export declare const evaluatePipelineResults: (results: readonly PipelineResult[]) => boolean;
|
|
7
|
+
export declare const hasAnyPipelineFailures: (results: readonly PipelineResult[]) => boolean;
|
|
8
|
+
export declare const countSuccessfulPhases: (results: readonly PipelineResult[]) => number;
|
|
9
|
+
export declare const countFailedPhases: (results: readonly PipelineResult[]) => number;
|
|
10
|
+
export declare const getFailedPhases: (results: readonly PipelineResult[]) => PipelineResult[];
|
|
11
|
+
export declare const getSuccessfulPhases: (results: readonly PipelineResult[]) => PipelineResult[];
|
|
12
|
+
export declare const getFirstFailure: (results: readonly PipelineResult[]) => PipelineResult | undefined;
|
|
13
|
+
export declare const getLastPhaseResult: (results: readonly PipelineResult[]) => PipelineResult | undefined;
|
|
14
|
+
export declare const isPipelineFullySuccessful: (results: readonly PipelineResult[]) => boolean;
|
|
15
|
+
export declare const isPipelinePartiallySuccessful: (results: readonly PipelineResult[]) => boolean;
|
|
16
|
+
export declare const isPipelineCompleteFailure: (results: readonly PipelineResult[]) => boolean;
|
|
17
|
+
export declare const isPipelineEmpty: (results: readonly PipelineResult[]) => boolean;
|
|
18
|
+
export interface PipelineStats {
|
|
19
|
+
readonly total: number;
|
|
20
|
+
readonly successful: number;
|
|
21
|
+
readonly failed: number;
|
|
22
|
+
readonly successRate: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const calculatePipelineStats: (results: readonly PipelineResult[]) => PipelineStats;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline result evaluation utilities for workflow processor
|
|
3
|
+
* Pure functions for evaluating pipeline execution results
|
|
4
|
+
*/
|
|
5
|
+
// Pipeline result evaluation (pure)
|
|
6
|
+
export const evaluatePipelineResults = (results) => results.every((result) => result.status === 'success');
|
|
7
|
+
export const hasAnyPipelineFailures = (results) => results.some((result) => result.status !== 'success');
|
|
8
|
+
export const countSuccessfulPhases = (results) => results.filter((result) => result.status === 'success').length;
|
|
9
|
+
export const countFailedPhases = (results) => results.filter((result) => result.status !== 'success').length;
|
|
10
|
+
export const getFailedPhases = (results) => results.filter((result) => result.status !== 'success');
|
|
11
|
+
export const getSuccessfulPhases = (results) => results.filter((result) => result.status === 'success');
|
|
12
|
+
export const getFirstFailure = (results) => results.find((result) => result.status !== 'success');
|
|
13
|
+
export const getLastPhaseResult = (results) => results.length > 0 ? results[results.length - 1] : undefined;
|
|
14
|
+
// Pipeline completion status
|
|
15
|
+
export const isPipelineFullySuccessful = (results) => results.length > 0 && evaluatePipelineResults(results);
|
|
16
|
+
export const isPipelinePartiallySuccessful = (results) => results.length > 0 &&
|
|
17
|
+
countSuccessfulPhases(results) > 0 &&
|
|
18
|
+
hasAnyPipelineFailures(results);
|
|
19
|
+
export const isPipelineCompleteFailure = (results) => results.length > 0 && countSuccessfulPhases(results) === 0;
|
|
20
|
+
export const isPipelineEmpty = (results) => results.length === 0;
|
|
21
|
+
export const calculatePipelineStats = (results) => {
|
|
22
|
+
const total = results.length;
|
|
23
|
+
const successful = countSuccessfulPhases(results);
|
|
24
|
+
const failed = countFailedPhases(results);
|
|
25
|
+
const successRate = total > 0 ? successful / total : 0;
|
|
26
|
+
return {
|
|
27
|
+
total,
|
|
28
|
+
successful,
|
|
29
|
+
failed,
|
|
30
|
+
successRate,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State management utilities for workflow processor
|
|
3
|
+
* Pure functions for handling feature processing states
|
|
4
|
+
*/
|
|
5
|
+
export interface FeatureProcessingState {
|
|
6
|
+
readonly featureId: string;
|
|
7
|
+
readonly retryCount: number;
|
|
8
|
+
readonly lastAttempt: Date;
|
|
9
|
+
readonly status: 'processing' | 'completed' | 'failed';
|
|
10
|
+
readonly featureUpdatedAt?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface WorkflowStats {
|
|
13
|
+
readonly totalProcessed: number;
|
|
14
|
+
readonly completed: number;
|
|
15
|
+
readonly failed: number;
|
|
16
|
+
readonly processing: number;
|
|
17
|
+
readonly isRunning: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const createInitialState: () => Map<string, FeatureProcessingState>;
|
|
20
|
+
export declare const createProcessingState: (featureId: string, currentState?: FeatureProcessingState) => FeatureProcessingState;
|
|
21
|
+
export declare const createCompletedState: (featureId: string, currentState?: FeatureProcessingState) => FeatureProcessingState;
|
|
22
|
+
export declare const createFailedState: (featureId: string, currentState?: FeatureProcessingState) => FeatureProcessingState;
|
|
23
|
+
export declare const updateFeatureState: (states: Map<string, FeatureProcessingState>, featureId: string, updateFn: (currentState?: FeatureProcessingState) => FeatureProcessingState) => Map<string, FeatureProcessingState>;
|
|
24
|
+
export declare const calculateStats: (states: Map<string, FeatureProcessingState>, isRunning: boolean) => WorkflowStats;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State management utilities for workflow processor
|
|
3
|
+
* Pure functions for handling feature processing states
|
|
4
|
+
*/
|
|
5
|
+
// State creation functions (pure)
|
|
6
|
+
export const createInitialState = () => new Map();
|
|
7
|
+
export const createProcessingState = (featureId, currentState) => ({
|
|
8
|
+
featureId,
|
|
9
|
+
retryCount: currentState ? currentState.retryCount + 1 : 1,
|
|
10
|
+
lastAttempt: new Date(),
|
|
11
|
+
status: 'processing',
|
|
12
|
+
});
|
|
13
|
+
export const createCompletedState = (featureId, currentState) => ({
|
|
14
|
+
featureId,
|
|
15
|
+
retryCount: currentState ? currentState.retryCount : 1,
|
|
16
|
+
lastAttempt: new Date(),
|
|
17
|
+
status: 'completed',
|
|
18
|
+
});
|
|
19
|
+
export const createFailedState = (featureId, currentState) => ({
|
|
20
|
+
featureId,
|
|
21
|
+
retryCount: currentState ? currentState.retryCount : 1,
|
|
22
|
+
lastAttempt: new Date(),
|
|
23
|
+
status: 'failed',
|
|
24
|
+
});
|
|
25
|
+
// State update function (pure)
|
|
26
|
+
export const updateFeatureState = (states, featureId, updateFn) => {
|
|
27
|
+
const newStates = new Map(states);
|
|
28
|
+
const currentState = newStates.get(featureId);
|
|
29
|
+
newStates.set(featureId, updateFn(currentState));
|
|
30
|
+
return newStates;
|
|
31
|
+
};
|
|
32
|
+
// Statistics calculation (pure)
|
|
33
|
+
export const calculateStats = (states, isRunning) => {
|
|
34
|
+
const stateArray = Array.from(states.values());
|
|
35
|
+
return {
|
|
36
|
+
totalProcessed: stateArray.length,
|
|
37
|
+
completed: stateArray.filter((s) => s.status === 'completed').length,
|
|
38
|
+
failed: stateArray.filter((s) => s.status === 'failed').length,
|
|
39
|
+
processing: stateArray.filter((s) => s.status === 'processing').length,
|
|
40
|
+
isRunning,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for workflow processor
|
|
3
|
+
* Centralized logging functions for workflow operations
|
|
4
|
+
*/
|
|
5
|
+
import type { FeatureInfo } from '../../types/features.js';
|
|
6
|
+
import type { PipelineResult } from '../../types/pipeline.js';
|
|
7
|
+
export declare const logProcessingStart: (feature: FeatureInfo, verbose?: boolean) => void;
|
|
8
|
+
export declare const logRetryInfo: (featureName: string, retryCount: number, maxRetries: number) => void;
|
|
9
|
+
export declare const logPipelineResults: (results: readonly PipelineResult[]) => void;
|
|
10
|
+
export declare const logProcessorStart: (productId: string, pollInterval: number) => void;
|
|
11
|
+
export declare const logProcessorReady: () => void;
|
|
12
|
+
export declare const logProcessorStop: () => void;
|
|
13
|
+
export declare const logFeatureSuccess: (featureName: string) => void;
|
|
14
|
+
export declare const logFeatureFailed: (featureName: string) => void;
|
|
15
|
+
export declare const logFeatureError: (featureName: string, error: unknown) => void;
|
|
16
|
+
export declare const logNoFeaturesFound: () => void;
|
|
17
|
+
export declare const logAllFeaturesProcessed: () => void;
|
|
18
|
+
export declare const logSkippingProcessing: (processingCount: number) => void;
|
|
19
|
+
export declare const logPollingError: (error: unknown) => void;
|
|
20
|
+
export declare const logProcessNextFeatureError: (error: unknown) => void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for workflow processor
|
|
3
|
+
* Centralized logging functions for workflow operations
|
|
4
|
+
*/
|
|
5
|
+
import { logInfo, logError, logSuccess } from '../../utils/logger.js';
|
|
6
|
+
export const logProcessingStart = (feature, verbose) => {
|
|
7
|
+
logInfo(`🎯 Processing feature: ${feature.name} (${feature.id})`);
|
|
8
|
+
if (verbose) {
|
|
9
|
+
logInfo(` Description: ${feature.description}`);
|
|
10
|
+
logInfo(` Last updated: ${feature.updated_at}`);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const logRetryInfo = (featureName, retryCount, maxRetries) => {
|
|
14
|
+
if (retryCount < maxRetries) {
|
|
15
|
+
logInfo(`🔄 Will retry feature ${featureName} (attempt ${retryCount + 1}/${maxRetries})`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
logError(`⛔ Max retries reached for feature ${featureName}, marking as permanently failed`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
export const logPipelineResults = (results) => {
|
|
22
|
+
console.log('\n' + '='.repeat(60));
|
|
23
|
+
console.log('📊 Pipeline Results Summary');
|
|
24
|
+
console.log('='.repeat(60));
|
|
25
|
+
results.forEach((result, index) => {
|
|
26
|
+
const statusIcon = result.status === 'success' ? '✅' : '❌';
|
|
27
|
+
console.log(`${index + 1}. ${statusIcon} ${result.phase}: ${result.message}`);
|
|
28
|
+
});
|
|
29
|
+
console.log('='.repeat(60) + '\n');
|
|
30
|
+
};
|
|
31
|
+
export const logProcessorStart = (productId, pollInterval) => {
|
|
32
|
+
logInfo('🚀 Starting workflow processor...');
|
|
33
|
+
logInfo(`📋 Product ID: ${productId}`);
|
|
34
|
+
logInfo(`🔄 Poll interval: ${pollInterval}ms`);
|
|
35
|
+
};
|
|
36
|
+
export const logProcessorReady = () => {
|
|
37
|
+
logInfo('✅ Workflow processor started and monitoring for new features');
|
|
38
|
+
};
|
|
39
|
+
export const logProcessorStop = () => {
|
|
40
|
+
logInfo('⏹️ Workflow processor stopped');
|
|
41
|
+
};
|
|
42
|
+
export const logFeatureSuccess = (featureName) => {
|
|
43
|
+
logSuccess(`✅ Feature ${featureName} completed successfully!`);
|
|
44
|
+
};
|
|
45
|
+
export const logFeatureFailed = (featureName) => {
|
|
46
|
+
logError(`❌ Feature ${featureName} failed in pipeline`);
|
|
47
|
+
};
|
|
48
|
+
export const logFeatureError = (featureName, error) => {
|
|
49
|
+
logError(`❌ Error processing feature ${featureName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
};
|
|
51
|
+
export const logNoFeaturesFound = () => {
|
|
52
|
+
logInfo('🔍 No ready_for_dev features found, continuing to monitor...');
|
|
53
|
+
};
|
|
54
|
+
export const logAllFeaturesProcessed = () => {
|
|
55
|
+
logInfo('🔄 All current features are processed or being processed, continuing to monitor...');
|
|
56
|
+
};
|
|
57
|
+
export const logSkippingProcessing = (processingCount) => {
|
|
58
|
+
logInfo(`⏳ Skipping feature fetching as ${processingCount} feature(s) are currently being processed`);
|
|
59
|
+
};
|
|
60
|
+
export const logPollingError = (error) => {
|
|
61
|
+
logError(`Error in polling cycle: ${error instanceof Error ? error.message : String(error)}`);
|
|
62
|
+
};
|
|
63
|
+
export const logProcessNextFeatureError = (error) => {
|
|
64
|
+
logError(`Error in processNextFeature: ${error instanceof Error ? error.message : String(error)}`);
|
|
65
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase execution logic for pipeline runner
|
|
3
|
+
*/
|
|
4
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
5
|
+
import { PipelinePhaseOptions, PipelineResult, PhaseConfig } from '../../types/pipeline.js';
|
|
6
|
+
export declare const createPhaseRunner: (phaseConfig: PhaseConfig) => (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
7
|
+
declare const runFeatureAnalysisPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
8
|
+
export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, };
|