edsger 0.45.1 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +3 -23
- package/dist/api/__tests__/app-store.test.d.ts +7 -0
- package/dist/api/__tests__/app-store.test.js +60 -0
- package/dist/api/__tests__/intelligence.test.d.ts +11 -0
- package/dist/api/__tests__/intelligence.test.js +315 -0
- package/dist/api/features/__tests__/feature-utils.test.d.ts +4 -0
- package/dist/api/features/__tests__/feature-utils.test.js +370 -0
- package/dist/api/features/__tests__/status-updater.test.d.ts +4 -0
- package/dist/api/features/__tests__/status-updater.test.js +88 -0
- package/dist/commands/build/__tests__/build.test.d.ts +5 -0
- package/dist/commands/build/__tests__/build.test.js +206 -0
- package/dist/commands/build/__tests__/detect-project.test.d.ts +6 -0
- package/dist/commands/build/__tests__/detect-project.test.js +160 -0
- package/dist/commands/build/__tests__/run-build.test.d.ts +6 -0
- package/dist/commands/build/__tests__/run-build.test.js +433 -0
- package/dist/commands/intelligence/__tests__/command.test.d.ts +4 -0
- package/dist/commands/intelligence/__tests__/command.test.js +48 -0
- package/dist/commands/run-sheet/index.js +6 -0
- package/dist/commands/workflow/core/__tests__/feature-filter.test.d.ts +5 -0
- package/dist/commands/workflow/core/__tests__/feature-filter.test.js +316 -0
- package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.d.ts +4 -0
- package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.js +397 -0
- package/dist/commands/workflow/core/__tests__/state-manager.test.d.ts +4 -0
- package/dist/commands/workflow/core/__tests__/state-manager.test.js +384 -0
- package/dist/commands/workflow/executors/phase-executor.js +3 -1
- package/dist/commands/workflow/phase-orchestrator.js +1 -2
- package/dist/config/__tests__/config.test.d.ts +4 -0
- package/dist/config/__tests__/config.test.js +286 -0
- package/dist/config/__tests__/feature-status.test.d.ts +4 -0
- package/dist/config/__tests__/feature-status.test.js +111 -0
- package/dist/errors/__tests__/index.test.d.ts +4 -0
- package/dist/errors/__tests__/index.test.js +349 -0
- package/dist/index.js +0 -0
- package/dist/phases/app-store-generation/__tests__/agent.test.d.ts +5 -0
- package/dist/phases/app-store-generation/__tests__/agent.test.js +142 -0
- package/dist/phases/app-store-generation/__tests__/context.test.d.ts +4 -0
- package/dist/phases/app-store-generation/__tests__/context.test.js +284 -0
- package/dist/phases/app-store-generation/__tests__/prompts.test.d.ts +4 -0
- package/dist/phases/app-store-generation/__tests__/prompts.test.js +122 -0
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.d.ts +5 -0
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.js +826 -0
- package/dist/phases/app-store-generation/index.js +1 -2
- package/dist/phases/branch-planning/index.js +1 -2
- package/dist/phases/bug-fixing/analyzer.js +1 -2
- package/dist/phases/code-implementation/index.js +1 -2
- package/dist/phases/code-refine/index.js +1 -2
- package/dist/phases/code-review/__tests__/diff-utils.test.d.ts +1 -0
- package/dist/phases/code-review/__tests__/diff-utils.test.js +101 -0
- package/dist/phases/code-review/index.js +1 -2
- package/dist/phases/code-testing/analyzer.js +1 -2
- package/dist/phases/feature-analysis/index.js +1 -2
- package/dist/phases/functional-testing/analyzer.js +1 -2
- package/dist/phases/growth-analysis/index.js +1 -2
- package/dist/phases/intelligence-analysis/__tests__/context.test.d.ts +4 -0
- package/dist/phases/intelligence-analysis/__tests__/context.test.js +192 -0
- package/dist/phases/intelligence-analysis/__tests__/matching.test.d.ts +13 -0
- package/dist/phases/intelligence-analysis/__tests__/matching.test.js +154 -0
- package/dist/phases/intelligence-analysis/__tests__/orchestration.test.d.ts +5 -0
- package/dist/phases/intelligence-analysis/__tests__/orchestration.test.js +378 -0
- package/dist/phases/intelligence-analysis/__tests__/prompts.test.d.ts +4 -0
- package/dist/phases/intelligence-analysis/__tests__/prompts.test.js +33 -0
- package/dist/phases/pr-execution/__tests__/file-assigner.test.d.ts +1 -0
- package/dist/phases/pr-execution/__tests__/file-assigner.test.js +303 -0
- package/dist/phases/pr-execution/index.js +1 -0
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.js +157 -0
- package/dist/phases/pr-resolve/__tests__/prompts.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/prompts.test.js +116 -0
- package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.js +138 -0
- package/dist/phases/pr-resolve/__tests__/types.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/types.test.js +43 -0
- package/dist/phases/pr-resolve/__tests__/workspace.test.d.ts +1 -0
- package/dist/phases/pr-resolve/__tests__/workspace.test.js +111 -0
- package/dist/phases/pr-review/__tests__/prompts.test.d.ts +1 -0
- package/dist/phases/pr-review/__tests__/prompts.test.js +49 -0
- package/dist/phases/pr-review/__tests__/review-comments.test.d.ts +1 -0
- package/dist/phases/pr-review/__tests__/review-comments.test.js +110 -0
- package/dist/phases/pr-shared/__tests__/agent-utils.test.d.ts +1 -0
- package/dist/phases/pr-shared/__tests__/agent-utils.test.js +91 -0
- package/dist/phases/pr-shared/__tests__/context.test.d.ts +1 -0
- package/dist/phases/pr-shared/__tests__/context.test.js +94 -0
- package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.d.ts +1 -0
- package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.js +331 -0
- package/dist/phases/pr-splitting/index.js +1 -2
- package/dist/phases/release-sync/github.d.ts +12 -0
- package/dist/phases/release-sync/github.js +39 -0
- package/dist/phases/release-sync/snapshot.js +0 -1
- package/dist/phases/run-sheet/index.d.ts +15 -0
- package/dist/phases/run-sheet/index.js +161 -29
- package/dist/phases/run-sheet/render.d.ts +23 -5
- package/dist/phases/run-sheet/render.js +195 -31
- package/dist/phases/smoke-test/__tests__/agent.test.d.ts +4 -0
- package/dist/phases/smoke-test/__tests__/agent.test.js +84 -0
- package/dist/phases/smoke-test/__tests__/github.test.d.ts +9 -0
- package/dist/phases/smoke-test/__tests__/github.test.js +120 -0
- package/dist/phases/smoke-test/__tests__/snapshot.test.d.ts +8 -0
- package/dist/phases/smoke-test/__tests__/snapshot.test.js +93 -0
- package/dist/phases/smoke-test/agent.js +2 -4
- package/dist/phases/smoke-test/github.d.ts +54 -0
- package/dist/phases/smoke-test/github.js +101 -0
- package/dist/phases/smoke-test/index.js +11 -6
- package/dist/phases/smoke-test/snapshot.d.ts +27 -0
- package/dist/phases/smoke-test/snapshot.js +157 -0
- package/dist/phases/technical-design/index.js +1 -2
- package/dist/phases/test-cases-analysis/index.js +1 -2
- package/dist/phases/user-stories-analysis/index.js +1 -2
- package/dist/services/coaching/__tests__/coaching-agent.test.d.ts +1 -0
- package/dist/services/coaching/__tests__/coaching-agent.test.js +74 -0
- package/dist/services/coaching/__tests__/coaching-loop.test.d.ts +1 -0
- package/dist/services/coaching/__tests__/coaching-loop.test.js +59 -0
- package/dist/services/coaching/__tests__/self-rating.test.d.ts +1 -0
- package/dist/services/coaching/__tests__/self-rating.test.js +188 -0
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +4 -0
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +133 -0
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +4 -0
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +336 -0
- package/dist/services/lifecycle-agent/index.d.ts +24 -0
- package/dist/services/lifecycle-agent/index.js +25 -0
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +57 -0
- package/dist/services/lifecycle-agent/phase-criteria.js +335 -0
- package/dist/services/lifecycle-agent/transition-rules.d.ts +60 -0
- package/dist/services/lifecycle-agent/transition-rules.js +184 -0
- package/dist/services/lifecycle-agent/types.d.ts +190 -0
- package/dist/services/lifecycle-agent/types.js +12 -0
- package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.d.ts +1 -0
- package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.js +122 -0
- package/dist/services/phase-hooks/__tests__/hook-executor.test.d.ts +1 -0
- package/dist/services/phase-hooks/__tests__/hook-executor.test.js +321 -0
- package/dist/services/phase-hooks/__tests__/hook-runner.test.d.ts +1 -0
- package/dist/services/phase-hooks/__tests__/hook-runner.test.js +261 -0
- package/dist/services/phase-hooks/__tests__/plugin-loader.test.d.ts +1 -0
- package/dist/services/phase-hooks/__tests__/plugin-loader.test.js +158 -0
- package/dist/services/video/__tests__/video-pipeline.test.d.ts +6 -0
- package/dist/services/video/__tests__/video-pipeline.test.js +249 -0
- package/dist/workspace/__tests__/workspace-manager.test.d.ts +7 -0
- package/dist/workspace/__tests__/workspace-manager.test.js +52 -0
- package/dist/workspace/workspace-manager.js +17 -4
- package/package.json +1 -1
- package/.env.local +0 -12
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for workflow state management utilities
|
|
3
|
+
*/
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import { calculateStats, createCompletedState, createFailedState, createInitialState, createProcessingState, updateFeatureState, } from '../state-manager.js';
|
|
7
|
+
void describe('State Manager', () => {
|
|
8
|
+
void describe('createInitialState', () => {
|
|
9
|
+
void it('should return an empty Map', () => {
|
|
10
|
+
const state = createInitialState();
|
|
11
|
+
assert.ok(state instanceof Map, 'Should return a Map instance');
|
|
12
|
+
assert.strictEqual(state.size, 0, 'Map should be empty');
|
|
13
|
+
});
|
|
14
|
+
void it('should return a new Map on each call', () => {
|
|
15
|
+
const state1 = createInitialState();
|
|
16
|
+
const state2 = createInitialState();
|
|
17
|
+
assert.notStrictEqual(state1, state2, 'Each call should return a distinct Map');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
void describe('createProcessingState', () => {
|
|
21
|
+
void it('should create a new processing state with retryCount 1 when no current state', () => {
|
|
22
|
+
const state = createProcessingState('feat-1');
|
|
23
|
+
assert.strictEqual(state.featureId, 'feat-1');
|
|
24
|
+
assert.strictEqual(state.retryCount, 1);
|
|
25
|
+
assert.strictEqual(state.status, 'processing');
|
|
26
|
+
assert.ok(state.lastAttempt instanceof Date, 'lastAttempt should be a Date');
|
|
27
|
+
});
|
|
28
|
+
void it('should increment retryCount when current state is provided', () => {
|
|
29
|
+
const currentState = {
|
|
30
|
+
featureId: 'feat-1',
|
|
31
|
+
retryCount: 2,
|
|
32
|
+
lastAttempt: new Date('2024-01-01'),
|
|
33
|
+
status: 'failed',
|
|
34
|
+
};
|
|
35
|
+
const state = createProcessingState('feat-1', currentState);
|
|
36
|
+
assert.strictEqual(state.retryCount, 3, 'Should increment retryCount by 1');
|
|
37
|
+
assert.strictEqual(state.status, 'processing');
|
|
38
|
+
});
|
|
39
|
+
void it('should set a recent lastAttempt date', () => {
|
|
40
|
+
const before = new Date();
|
|
41
|
+
const state = createProcessingState('feat-1');
|
|
42
|
+
const after = new Date();
|
|
43
|
+
assert.ok(state.lastAttempt.getTime() >= before.getTime(), 'lastAttempt should be at or after the call');
|
|
44
|
+
assert.ok(state.lastAttempt.getTime() <= after.getTime(), 'lastAttempt should be at or before now');
|
|
45
|
+
});
|
|
46
|
+
void it('should increment from retryCount 1 to 2', () => {
|
|
47
|
+
const currentState = {
|
|
48
|
+
featureId: 'feat-1',
|
|
49
|
+
retryCount: 1,
|
|
50
|
+
lastAttempt: new Date('2024-01-01'),
|
|
51
|
+
status: 'completed',
|
|
52
|
+
};
|
|
53
|
+
const state = createProcessingState('feat-1', currentState);
|
|
54
|
+
assert.strictEqual(state.retryCount, 2);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
void describe('createCompletedState', () => {
|
|
58
|
+
void it('should create a completed state with retryCount 1 when no current state', () => {
|
|
59
|
+
const state = createCompletedState('feat-2');
|
|
60
|
+
assert.strictEqual(state.featureId, 'feat-2');
|
|
61
|
+
assert.strictEqual(state.retryCount, 1);
|
|
62
|
+
assert.strictEqual(state.status, 'completed');
|
|
63
|
+
assert.ok(state.lastAttempt instanceof Date);
|
|
64
|
+
});
|
|
65
|
+
void it('should preserve retryCount from current state', () => {
|
|
66
|
+
const currentState = {
|
|
67
|
+
featureId: 'feat-2',
|
|
68
|
+
retryCount: 5,
|
|
69
|
+
lastAttempt: new Date('2024-01-01'),
|
|
70
|
+
status: 'processing',
|
|
71
|
+
};
|
|
72
|
+
const state = createCompletedState('feat-2', currentState);
|
|
73
|
+
assert.strictEqual(state.retryCount, 5, 'Should preserve the existing retryCount');
|
|
74
|
+
assert.strictEqual(state.status, 'completed');
|
|
75
|
+
});
|
|
76
|
+
void it('should not increment retryCount (unlike createProcessingState)', () => {
|
|
77
|
+
const currentState = {
|
|
78
|
+
featureId: 'feat-2',
|
|
79
|
+
retryCount: 3,
|
|
80
|
+
lastAttempt: new Date('2024-01-01'),
|
|
81
|
+
status: 'processing',
|
|
82
|
+
};
|
|
83
|
+
const state = createCompletedState('feat-2', currentState);
|
|
84
|
+
assert.strictEqual(state.retryCount, 3, 'retryCount should stay the same, not increment');
|
|
85
|
+
});
|
|
86
|
+
void it('should update lastAttempt to current time', () => {
|
|
87
|
+
const oldDate = new Date('2024-01-01');
|
|
88
|
+
const currentState = {
|
|
89
|
+
featureId: 'feat-2',
|
|
90
|
+
retryCount: 1,
|
|
91
|
+
lastAttempt: oldDate,
|
|
92
|
+
status: 'processing',
|
|
93
|
+
};
|
|
94
|
+
const state = createCompletedState('feat-2', currentState);
|
|
95
|
+
assert.ok(state.lastAttempt.getTime() > oldDate.getTime(), 'lastAttempt should be newer than the old date');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
void describe('createFailedState', () => {
|
|
99
|
+
void it('should create a failed state with retryCount 1 when no current state', () => {
|
|
100
|
+
const state = createFailedState('feat-3');
|
|
101
|
+
assert.strictEqual(state.featureId, 'feat-3');
|
|
102
|
+
assert.strictEqual(state.retryCount, 1);
|
|
103
|
+
assert.strictEqual(state.status, 'failed');
|
|
104
|
+
assert.ok(state.lastAttempt instanceof Date);
|
|
105
|
+
});
|
|
106
|
+
void it('should preserve retryCount from current state', () => {
|
|
107
|
+
const currentState = {
|
|
108
|
+
featureId: 'feat-3',
|
|
109
|
+
retryCount: 4,
|
|
110
|
+
lastAttempt: new Date('2024-01-01'),
|
|
111
|
+
status: 'processing',
|
|
112
|
+
};
|
|
113
|
+
const state = createFailedState('feat-3', currentState);
|
|
114
|
+
assert.strictEqual(state.retryCount, 4, 'Should preserve the existing retryCount');
|
|
115
|
+
assert.strictEqual(state.status, 'failed');
|
|
116
|
+
});
|
|
117
|
+
void it('should not increment retryCount (unlike createProcessingState)', () => {
|
|
118
|
+
const currentState = {
|
|
119
|
+
featureId: 'feat-3',
|
|
120
|
+
retryCount: 2,
|
|
121
|
+
lastAttempt: new Date('2024-01-01'),
|
|
122
|
+
status: 'processing',
|
|
123
|
+
};
|
|
124
|
+
const state = createFailedState('feat-3', currentState);
|
|
125
|
+
assert.strictEqual(state.retryCount, 2);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
void describe('updateFeatureState', () => {
|
|
129
|
+
void it('should return a new Map (immutability)', () => {
|
|
130
|
+
const original = new Map();
|
|
131
|
+
const updated = updateFeatureState(original, 'feat-1', () => createProcessingState('feat-1'));
|
|
132
|
+
assert.notStrictEqual(updated, original, 'Should return a different Map instance');
|
|
133
|
+
});
|
|
134
|
+
void it('should not mutate the original Map', () => {
|
|
135
|
+
const original = new Map();
|
|
136
|
+
updateFeatureState(original, 'feat-1', () => createProcessingState('feat-1'));
|
|
137
|
+
assert.strictEqual(original.size, 0, 'Original Map should remain empty');
|
|
138
|
+
});
|
|
139
|
+
void it('should add a new feature to the Map', () => {
|
|
140
|
+
const states = new Map();
|
|
141
|
+
const updated = updateFeatureState(states, 'feat-1', () => createProcessingState('feat-1'));
|
|
142
|
+
assert.strictEqual(updated.size, 1, 'Map should have one entry');
|
|
143
|
+
assert.strictEqual(updated.get('feat-1')?.status, 'processing');
|
|
144
|
+
});
|
|
145
|
+
void it('should update an existing feature in the Map', () => {
|
|
146
|
+
const initial = new Map([
|
|
147
|
+
[
|
|
148
|
+
'feat-1',
|
|
149
|
+
{
|
|
150
|
+
featureId: 'feat-1',
|
|
151
|
+
retryCount: 1,
|
|
152
|
+
lastAttempt: new Date('2024-01-01'),
|
|
153
|
+
status: 'processing',
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
]);
|
|
157
|
+
const updated = updateFeatureState(initial, 'feat-1', (current) => createCompletedState('feat-1', current));
|
|
158
|
+
assert.strictEqual(updated.get('feat-1')?.status, 'completed');
|
|
159
|
+
assert.strictEqual(updated.get('feat-1')?.retryCount, 1, 'retryCount should be preserved');
|
|
160
|
+
});
|
|
161
|
+
void it('should pass current state to the update function', () => {
|
|
162
|
+
const existingState = {
|
|
163
|
+
featureId: 'feat-1',
|
|
164
|
+
retryCount: 3,
|
|
165
|
+
lastAttempt: new Date('2024-01-01'),
|
|
166
|
+
status: 'processing',
|
|
167
|
+
};
|
|
168
|
+
const states = new Map([
|
|
169
|
+
['feat-1', existingState],
|
|
170
|
+
]);
|
|
171
|
+
let receivedState;
|
|
172
|
+
updateFeatureState(states, 'feat-1', (current) => {
|
|
173
|
+
receivedState = current;
|
|
174
|
+
return createCompletedState('feat-1', current);
|
|
175
|
+
});
|
|
176
|
+
assert.deepStrictEqual(receivedState, existingState, 'Update function should receive the current state');
|
|
177
|
+
});
|
|
178
|
+
void it('should pass undefined for non-existent feature', () => {
|
|
179
|
+
const states = new Map();
|
|
180
|
+
let receivedState = {
|
|
181
|
+
featureId: 'sentinel',
|
|
182
|
+
retryCount: 999,
|
|
183
|
+
lastAttempt: new Date(),
|
|
184
|
+
status: 'completed',
|
|
185
|
+
};
|
|
186
|
+
updateFeatureState(states, 'feat-new', (current) => {
|
|
187
|
+
receivedState = current;
|
|
188
|
+
return createProcessingState('feat-new', current);
|
|
189
|
+
});
|
|
190
|
+
assert.strictEqual(receivedState, undefined, 'Update function should receive undefined for non-existent feature');
|
|
191
|
+
});
|
|
192
|
+
void it('should preserve other features in the Map', () => {
|
|
193
|
+
const states = new Map([
|
|
194
|
+
[
|
|
195
|
+
'feat-1',
|
|
196
|
+
{
|
|
197
|
+
featureId: 'feat-1',
|
|
198
|
+
retryCount: 1,
|
|
199
|
+
lastAttempt: new Date('2024-01-01'),
|
|
200
|
+
status: 'completed',
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
[
|
|
204
|
+
'feat-2',
|
|
205
|
+
{
|
|
206
|
+
featureId: 'feat-2',
|
|
207
|
+
retryCount: 2,
|
|
208
|
+
lastAttempt: new Date('2024-01-02'),
|
|
209
|
+
status: 'processing',
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
]);
|
|
213
|
+
const updated = updateFeatureState(states, 'feat-2', (current) => createFailedState('feat-2', current));
|
|
214
|
+
assert.strictEqual(updated.size, 2, 'Map should still have two entries');
|
|
215
|
+
assert.strictEqual(updated.get('feat-1')?.status, 'completed', 'feat-1 should remain unchanged');
|
|
216
|
+
assert.strictEqual(updated.get('feat-2')?.status, 'failed', 'feat-2 should be updated');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
void describe('calculateStats', () => {
|
|
220
|
+
void it('should return zeros for an empty Map', () => {
|
|
221
|
+
const states = new Map();
|
|
222
|
+
const stats = calculateStats(states, false);
|
|
223
|
+
assert.deepStrictEqual(stats, {
|
|
224
|
+
totalProcessed: 0,
|
|
225
|
+
completed: 0,
|
|
226
|
+
failed: 0,
|
|
227
|
+
processing: 0,
|
|
228
|
+
isRunning: false,
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
void it('should count all completed features', () => {
|
|
232
|
+
const states = new Map([
|
|
233
|
+
[
|
|
234
|
+
'feat-1',
|
|
235
|
+
{
|
|
236
|
+
featureId: 'feat-1',
|
|
237
|
+
retryCount: 1,
|
|
238
|
+
lastAttempt: new Date(),
|
|
239
|
+
status: 'completed',
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
[
|
|
243
|
+
'feat-2',
|
|
244
|
+
{
|
|
245
|
+
featureId: 'feat-2',
|
|
246
|
+
retryCount: 1,
|
|
247
|
+
lastAttempt: new Date(),
|
|
248
|
+
status: 'completed',
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
]);
|
|
252
|
+
const stats = calculateStats(states, true);
|
|
253
|
+
assert.strictEqual(stats.totalProcessed, 2);
|
|
254
|
+
assert.strictEqual(stats.completed, 2);
|
|
255
|
+
assert.strictEqual(stats.failed, 0);
|
|
256
|
+
assert.strictEqual(stats.processing, 0);
|
|
257
|
+
assert.strictEqual(stats.isRunning, true);
|
|
258
|
+
});
|
|
259
|
+
void it('should count mixed states correctly', () => {
|
|
260
|
+
const states = new Map([
|
|
261
|
+
[
|
|
262
|
+
'feat-1',
|
|
263
|
+
{
|
|
264
|
+
featureId: 'feat-1',
|
|
265
|
+
retryCount: 1,
|
|
266
|
+
lastAttempt: new Date(),
|
|
267
|
+
status: 'completed',
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
[
|
|
271
|
+
'feat-2',
|
|
272
|
+
{
|
|
273
|
+
featureId: 'feat-2',
|
|
274
|
+
retryCount: 2,
|
|
275
|
+
lastAttempt: new Date(),
|
|
276
|
+
status: 'failed',
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
[
|
|
280
|
+
'feat-3',
|
|
281
|
+
{
|
|
282
|
+
featureId: 'feat-3',
|
|
283
|
+
retryCount: 1,
|
|
284
|
+
lastAttempt: new Date(),
|
|
285
|
+
status: 'processing',
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
[
|
|
289
|
+
'feat-4',
|
|
290
|
+
{
|
|
291
|
+
featureId: 'feat-4',
|
|
292
|
+
retryCount: 1,
|
|
293
|
+
lastAttempt: new Date(),
|
|
294
|
+
status: 'completed',
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
]);
|
|
298
|
+
const stats = calculateStats(states, true);
|
|
299
|
+
assert.strictEqual(stats.totalProcessed, 4);
|
|
300
|
+
assert.strictEqual(stats.completed, 2);
|
|
301
|
+
assert.strictEqual(stats.failed, 1);
|
|
302
|
+
assert.strictEqual(stats.processing, 1);
|
|
303
|
+
assert.strictEqual(stats.isRunning, true);
|
|
304
|
+
});
|
|
305
|
+
void it('should reflect isRunning as false when stopped', () => {
|
|
306
|
+
const states = new Map([
|
|
307
|
+
[
|
|
308
|
+
'feat-1',
|
|
309
|
+
{
|
|
310
|
+
featureId: 'feat-1',
|
|
311
|
+
retryCount: 1,
|
|
312
|
+
lastAttempt: new Date(),
|
|
313
|
+
status: 'completed',
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
]);
|
|
317
|
+
const stats = calculateStats(states, false);
|
|
318
|
+
assert.strictEqual(stats.isRunning, false);
|
|
319
|
+
});
|
|
320
|
+
void it('should count all failed features', () => {
|
|
321
|
+
const states = new Map([
|
|
322
|
+
[
|
|
323
|
+
'feat-1',
|
|
324
|
+
{
|
|
325
|
+
featureId: 'feat-1',
|
|
326
|
+
retryCount: 3,
|
|
327
|
+
lastAttempt: new Date(),
|
|
328
|
+
status: 'failed',
|
|
329
|
+
},
|
|
330
|
+
],
|
|
331
|
+
[
|
|
332
|
+
'feat-2',
|
|
333
|
+
{
|
|
334
|
+
featureId: 'feat-2',
|
|
335
|
+
retryCount: 1,
|
|
336
|
+
lastAttempt: new Date(),
|
|
337
|
+
status: 'failed',
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
]);
|
|
341
|
+
const stats = calculateStats(states, false);
|
|
342
|
+
assert.strictEqual(stats.totalProcessed, 2);
|
|
343
|
+
assert.strictEqual(stats.completed, 0);
|
|
344
|
+
assert.strictEqual(stats.failed, 2);
|
|
345
|
+
assert.strictEqual(stats.processing, 0);
|
|
346
|
+
});
|
|
347
|
+
void it('should count all processing features', () => {
|
|
348
|
+
const states = new Map([
|
|
349
|
+
[
|
|
350
|
+
'feat-1',
|
|
351
|
+
{
|
|
352
|
+
featureId: 'feat-1',
|
|
353
|
+
retryCount: 1,
|
|
354
|
+
lastAttempt: new Date(),
|
|
355
|
+
status: 'processing',
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
[
|
|
359
|
+
'feat-2',
|
|
360
|
+
{
|
|
361
|
+
featureId: 'feat-2',
|
|
362
|
+
retryCount: 1,
|
|
363
|
+
lastAttempt: new Date(),
|
|
364
|
+
status: 'processing',
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
[
|
|
368
|
+
'feat-3',
|
|
369
|
+
{
|
|
370
|
+
featureId: 'feat-3',
|
|
371
|
+
retryCount: 1,
|
|
372
|
+
lastAttempt: new Date(),
|
|
373
|
+
status: 'processing',
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
]);
|
|
377
|
+
const stats = calculateStats(states, true);
|
|
378
|
+
assert.strictEqual(stats.totalProcessed, 3);
|
|
379
|
+
assert.strictEqual(stats.completed, 0);
|
|
380
|
+
assert.strictEqual(stats.failed, 0);
|
|
381
|
+
assert.strictEqual(stats.processing, 3);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
});
|
|
@@ -130,7 +130,9 @@ async function validateAndLogChecklists(options, name, checklistContext, feature
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
// Higher-order function for phase execution
|
|
133
|
-
export const createPhaseRunner = (phaseConfig) =>
|
|
133
|
+
export const createPhaseRunner = (phaseConfig) =>
|
|
134
|
+
// eslint-disable-next-line complexity
|
|
135
|
+
async (options, config) => {
|
|
134
136
|
const { featureId, verbose } = options;
|
|
135
137
|
const { name, execute } = phaseConfig;
|
|
136
138
|
// Track phase duration for logging
|
|
@@ -36,9 +36,8 @@ const logAndMarkPhaseCompleted = async (result, verbose) => {
|
|
|
36
36
|
* Orchestrate phase execution based on execution mode
|
|
37
37
|
* Routes to appropriate phase sequence based on mode (only_*, from_*, full_pipeline)
|
|
38
38
|
*/
|
|
39
|
-
export const runPipelineByMode = async (options, config, executionMode
|
|
40
39
|
// eslint-disable-next-line complexity
|
|
41
|
-
) => {
|
|
40
|
+
export const runPipelineByMode = async (options, config, executionMode) => {
|
|
42
41
|
const { featureId, verbose } = options;
|
|
43
42
|
if (verbose) {
|
|
44
43
|
logInfo(`🚀 Starting pipeline with mode: ${executionMode} for feature: ${featureId}`);
|