edsger 0.10.3 → 0.12.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.
@@ -11,21 +11,21 @@ describe('Feature Utils', () => {
11
11
  {
12
12
  id: '1',
13
13
  name: 'Feature 1',
14
- status: 'ready_for_dev',
14
+ status: 'ready_for_ai',
15
15
  product_id: 'test-product',
16
16
  updated_at: '2024-01-15T10:00:00Z',
17
17
  },
18
18
  {
19
19
  id: '2',
20
20
  name: 'Feature 2',
21
- status: 'ready_for_dev',
21
+ status: 'ready_for_ai',
22
22
  product_id: 'test-product',
23
23
  updated_at: '2024-01-10T10:00:00Z',
24
24
  },
25
25
  {
26
26
  id: '3',
27
27
  name: 'Feature 3',
28
- status: 'ready_for_dev',
28
+ status: 'ready_for_ai',
29
29
  product_id: 'test-product',
30
30
  updated_at: '2024-01-20T10:00:00Z',
31
31
  },
@@ -41,21 +41,21 @@ describe('Feature Utils', () => {
41
41
  {
42
42
  id: '1',
43
43
  name: 'Feature 1',
44
- status: 'ready_for_dev',
44
+ status: 'ready_for_ai',
45
45
  product_id: 'test-product',
46
46
  updated_at: '2024-01-15T10:00:00Z',
47
47
  },
48
48
  {
49
49
  id: '2',
50
50
  name: 'Feature 2',
51
- status: 'ready_for_dev',
51
+ status: 'ready_for_ai',
52
52
  product_id: 'test-product',
53
53
  // Missing updated_at
54
54
  },
55
55
  {
56
56
  id: '3',
57
57
  name: 'Feature 3',
58
- status: 'ready_for_dev',
58
+ status: 'ready_for_ai',
59
59
  product_id: 'test-product',
60
60
  updated_at: '2024-01-10T10:00:00Z',
61
61
  },
@@ -77,7 +77,7 @@ describe('Feature Utils', () => {
77
77
  {
78
78
  id: '1',
79
79
  name: 'Feature 1',
80
- status: 'ready_for_dev',
80
+ status: 'ready_for_ai',
81
81
  product_id: 'test-product',
82
82
  updated_at: '2024-01-15T10:00:00Z',
83
83
  },
@@ -91,14 +91,14 @@ describe('Feature Utils', () => {
91
91
  {
92
92
  id: '1',
93
93
  name: 'Feature 1',
94
- status: 'ready_for_dev',
94
+ status: 'ready_for_ai',
95
95
  product_id: 'test-product',
96
96
  updated_at: '2024-01-15T10:00:00Z',
97
97
  },
98
98
  {
99
99
  id: '2',
100
100
  name: 'Feature 2',
101
- status: 'ready_for_dev',
101
+ status: 'ready_for_ai',
102
102
  product_id: 'test-product',
103
103
  updated_at: '2024-01-10T10:00:00Z',
104
104
  },
@@ -117,21 +117,21 @@ describe('Feature Utils', () => {
117
117
  {
118
118
  id: '1',
119
119
  name: 'Feature 1',
120
- status: 'ready_for_dev',
120
+ status: 'ready_for_ai',
121
121
  product_id: 'test-product',
122
122
  updated_at: sameTimestamp,
123
123
  },
124
124
  {
125
125
  id: '2',
126
126
  name: 'Feature 2',
127
- status: 'ready_for_dev',
127
+ status: 'ready_for_ai',
128
128
  product_id: 'test-product',
129
129
  updated_at: sameTimestamp,
130
130
  },
131
131
  {
132
132
  id: '3',
133
133
  name: 'Feature 3',
134
- status: 'ready_for_dev',
134
+ status: 'ready_for_ai',
135
135
  product_id: 'test-product',
136
136
  updated_at: sameTimestamp,
137
137
  },
@@ -146,21 +146,21 @@ describe('Feature Utils', () => {
146
146
  {
147
147
  id: '1',
148
148
  name: 'Feature 1',
149
- status: 'ready_for_dev',
149
+ status: 'ready_for_ai',
150
150
  product_id: 'test-product',
151
151
  updated_at: '2024-01-15', // Date only
152
152
  },
153
153
  {
154
154
  id: '2',
155
155
  name: 'Feature 2',
156
- status: 'ready_for_dev',
156
+ status: 'ready_for_ai',
157
157
  product_id: 'test-product',
158
158
  updated_at: '2024-01-10T10:00:00.000Z', // Full ISO format
159
159
  },
160
160
  {
161
161
  id: '3',
162
162
  name: 'Feature 3',
163
- status: 'ready_for_dev',
163
+ status: 'ready_for_ai',
164
164
  product_id: 'test-product',
165
165
  updated_at: '2024-01-20T15:30:00Z', // ISO with time
166
166
  },
@@ -178,7 +178,7 @@ describe('Feature Utils', () => {
178
178
  {
179
179
  id: '1',
180
180
  name: 'Feature 1',
181
- status: 'ready_for_dev',
181
+ status: 'ready_for_ai',
182
182
  product_id: 'test-product',
183
183
  },
184
184
  {
@@ -190,12 +190,12 @@ describe('Feature Utils', () => {
190
190
  {
191
191
  id: '3',
192
192
  name: 'Feature 3',
193
- status: 'ready_for_dev',
193
+ status: 'ready_for_ai',
194
194
  product_id: 'test-product',
195
195
  },
196
196
  ];
197
- const filtered = filterFeaturesByStatus(features, 'ready_for_dev');
198
- assert.strictEqual(filtered.length, 2, 'Should return 2 ready_for_dev features');
197
+ const filtered = filterFeaturesByStatus(features, 'ready_for_ai');
198
+ assert.strictEqual(filtered.length, 2, 'Should return 2 ready_for_ai features');
199
199
  assert.strictEqual(filtered[0].id, '1', 'Should include Feature 1');
200
200
  assert.strictEqual(filtered[1].id, '3', 'Should include Feature 3');
201
201
  });
@@ -214,12 +214,12 @@ describe('Feature Utils', () => {
214
214
  product_id: 'test-product',
215
215
  },
216
216
  ];
217
- const filtered = filterFeaturesByStatus(features, 'ready_for_dev');
217
+ const filtered = filterFeaturesByStatus(features, 'ready_for_ai');
218
218
  assert.strictEqual(filtered.length, 0, 'Should return empty array');
219
219
  });
220
220
  it('should handle empty input array', () => {
221
221
  const features = [];
222
- const filtered = filterFeaturesByStatus(features, 'ready_for_dev');
222
+ const filtered = filterFeaturesByStatus(features, 'ready_for_ai');
223
223
  assert.strictEqual(filtered.length, 0, 'Should return empty array');
224
224
  });
225
225
  });
@@ -230,21 +230,21 @@ describe('Feature Utils', () => {
230
230
  {
231
231
  id: 'urgent-feature',
232
232
  name: 'Urgent Feature',
233
- status: 'ready_for_dev',
233
+ status: 'ready_for_ai',
234
234
  product_id: 'test-product',
235
235
  updated_at: '2024-01-01T08:00:00Z', // Very old - should be processed first
236
236
  },
237
237
  {
238
238
  id: 'recent-feature',
239
239
  name: 'Recent Feature',
240
- status: 'ready_for_dev',
240
+ status: 'ready_for_ai',
241
241
  product_id: 'test-product',
242
242
  updated_at: '2024-01-20T10:00:00Z', // Recent - should be processed last
243
243
  },
244
244
  {
245
245
  id: 'medium-feature',
246
246
  name: 'Medium Feature',
247
- status: 'ready_for_dev',
247
+ status: 'ready_for_ai',
248
248
  product_id: 'test-product',
249
249
  updated_at: '2024-01-10T12:00:00Z', // Medium age - should be processed second
250
250
  },
@@ -265,21 +265,21 @@ describe('Feature Utils', () => {
265
265
  {
266
266
  id: '1',
267
267
  name: 'Feature 1',
268
- status: 'ready_for_dev',
268
+ status: 'ready_for_ai',
269
269
  product_id: 'test-product',
270
270
  updated_at: '2024-01-15T10:00:00Z',
271
271
  },
272
272
  {
273
273
  id: '2',
274
274
  name: 'Feature 2',
275
- status: 'ready_for_dev',
275
+ status: 'ready_for_ai',
276
276
  product_id: 'test-product',
277
277
  updated_at: '2024-01-10T10:00:00Z',
278
278
  },
279
279
  {
280
280
  id: '3',
281
281
  name: 'Feature 3',
282
- status: 'ready_for_dev',
282
+ status: 'ready_for_ai',
283
283
  product_id: 'test-product',
284
284
  updated_at: '2024-01-20T10:00:00Z',
285
285
  },
@@ -298,21 +298,21 @@ describe('Feature Utils', () => {
298
298
  {
299
299
  id: 'very-old-bug',
300
300
  name: 'Critical Bug Fix',
301
- status: 'ready_for_dev',
301
+ status: 'ready_for_ai',
302
302
  product_id: 'test-product',
303
303
  updated_at: '2024-01-01T00:00:00Z', // Very old, should be highest priority
304
304
  },
305
305
  {
306
306
  id: 'new-enhancement',
307
307
  name: 'Nice to Have Feature',
308
- status: 'ready_for_dev',
308
+ status: 'ready_for_ai',
309
309
  product_id: 'test-product',
310
310
  updated_at: '2024-01-25T00:00:00Z', // Recent, should be lowest priority
311
311
  },
312
312
  {
313
313
  id: 'medium-priority',
314
314
  name: 'Important Feature',
315
- status: 'ready_for_dev',
315
+ status: 'ready_for_ai',
316
316
  product_id: 'test-product',
317
317
  updated_at: '2024-01-15T00:00:00Z', // Medium age, should be middle priority
318
318
  },
@@ -328,36 +328,36 @@ describe('Feature Utils', () => {
328
328
  assert.ok(ages[0] <= ages[1] && ages[1] <= ages[2], 'Features should be processed in age order (oldest first)');
329
329
  });
330
330
  });
331
- describe('getReadyForDevFeatures integration behavior', () => {
331
+ describe('getReadyForAIFeatures integration behavior', () => {
332
332
  it('should use sortFeaturesByUpdatedAt to ensure oldest-first processing', () => {
333
- // This test verifies the integration between getReadyForDevFeatures and sortFeaturesByUpdatedAt
334
- // We can test this indirectly by testing the sorting function that getReadyForDevFeatures uses
333
+ // This test verifies the integration between getReadyForAIFeatures and sortFeaturesByUpdatedAt
334
+ // We can test this indirectly by testing the sorting function that getReadyForAIFeatures uses
335
335
  const mockApiResponse = [
336
336
  {
337
337
  id: 'feat-1',
338
338
  name: 'Feature Added Last Week',
339
- status: 'ready_for_dev',
339
+ status: 'ready_for_ai',
340
340
  product_id: 'product-123',
341
341
  updated_at: '2024-01-18T10:00:00Z',
342
342
  },
343
343
  {
344
344
  id: 'feat-2',
345
345
  name: 'Feature Added Yesterday',
346
- status: 'ready_for_dev',
346
+ status: 'ready_for_ai',
347
347
  product_id: 'product-123',
348
348
  updated_at: '2024-01-24T15:30:00Z',
349
349
  },
350
350
  {
351
351
  id: 'feat-3',
352
352
  name: 'Feature Added Last Month',
353
- status: 'ready_for_dev',
353
+ status: 'ready_for_ai',
354
354
  product_id: 'product-123',
355
355
  updated_at: '2024-01-05T08:00:00Z',
356
356
  },
357
357
  ];
358
- // This simulates what getReadyForDevFeatures does internally
358
+ // This simulates what getReadyForAIFeatures does internally
359
359
  const sortedForWorkflow = sortFeaturesByUpdatedAt(mockApiResponse);
360
- // Verify oldest-first ordering that getReadyForDevFeatures should provide
360
+ // Verify oldest-first ordering that getReadyForAIFeatures should provide
361
361
  assert.strictEqual(sortedForWorkflow[0].id, 'feat-3', 'Oldest feature should be first');
362
362
  assert.strictEqual(sortedForWorkflow[1].id, 'feat-1', 'Second oldest should be second');
363
363
  assert.strictEqual(sortedForWorkflow[2].id, 'feat-2', 'Newest feature should be last');
@@ -8,7 +8,7 @@ import { isForwardProgression } from '../status-updater.js';
8
8
  describe('Status Progression Logic', () => {
9
9
  describe('isForwardProgression', () => {
10
10
  it('should allow forward progression', () => {
11
- assert.strictEqual(isForwardProgression('backlog', 'ready_for_dev'), true, 'Should allow progression from backlog to ready_for_dev');
11
+ assert.strictEqual(isForwardProgression('backlog', 'ready_for_ai'), true, 'Should allow progression from backlog to ready_for_ai');
12
12
  assert.strictEqual(isForwardProgression('feature_analysis', 'technical_design'), true, 'Should allow progression from feature_analysis to technical_design');
13
13
  assert.strictEqual(isForwardProgression('code_implementation', 'shipped'), true, 'Should allow progression from code_implementation to shipped');
14
14
  });
@@ -18,7 +18,7 @@ describe('Status Progression Logic', () => {
18
18
  assert.strictEqual(isForwardProgression('shipped', 'shipped'), true, 'Should allow staying at shipped status');
19
19
  });
20
20
  it('should prevent backward progression', () => {
21
- assert.strictEqual(isForwardProgression('ready_for_dev', 'backlog'), false, 'Should prevent regression from ready_for_dev to backlog');
21
+ assert.strictEqual(isForwardProgression('ready_for_ai', 'backlog'), false, 'Should prevent regression from ready_for_ai to backlog');
22
22
  assert.strictEqual(isForwardProgression('technical_design', 'feature_analysis'), false, 'Should prevent regression from technical_design to feature_analysis');
23
23
  assert.strictEqual(isForwardProgression('shipped', 'code_implementation'), false, 'Should prevent regression from shipped to code_implementation');
24
24
  });
@@ -42,7 +42,7 @@ describe('Status Progression Logic', () => {
42
42
  it('should contain all expected statuses', () => {
43
43
  const expectedStatuses = [
44
44
  'backlog',
45
- 'ready_for_dev',
45
+ 'ready_for_ai',
46
46
  'feature_analysis',
47
47
  'feature_analysis_verification',
48
48
  'technical_design',
@@ -68,13 +68,13 @@ describe('Status Progression Logic', () => {
68
68
  });
69
69
  it('should have correct ordering for key workflow phases', () => {
70
70
  const backlogIndex = STATUS_PROGRESSION_ORDER.indexOf('backlog');
71
- const readyForDevIndex = STATUS_PROGRESSION_ORDER.indexOf('ready_for_dev');
71
+ const readyForDevIndex = STATUS_PROGRESSION_ORDER.indexOf('ready_for_ai');
72
72
  const featureAnalysisIndex = STATUS_PROGRESSION_ORDER.indexOf('feature_analysis');
73
73
  const technicalDesignIndex = STATUS_PROGRESSION_ORDER.indexOf('technical_design');
74
74
  const codeImplementationIndex = STATUS_PROGRESSION_ORDER.indexOf('code_implementation');
75
75
  const shippedIndex = STATUS_PROGRESSION_ORDER.indexOf('shipped');
76
- assert.ok(backlogIndex < readyForDevIndex, 'backlog should come before ready_for_dev');
77
- assert.ok(readyForDevIndex < featureAnalysisIndex, 'ready_for_dev should come before feature_analysis');
76
+ assert.ok(backlogIndex < readyForDevIndex, 'backlog should come before ready_for_ai');
77
+ assert.ok(readyForDevIndex < featureAnalysisIndex, 'ready_for_ai should come before feature_analysis');
78
78
  assert.ok(featureAnalysisIndex < technicalDesignIndex, 'feature_analysis should come before technical_design');
79
79
  assert.ok(technicalDesignIndex < codeImplementationIndex, 'technical_design should come before code_implementation');
80
80
  assert.ok(codeImplementationIndex < shippedIndex, 'code_implementation should come before shipped');
@@ -1,11 +1,12 @@
1
+ import { UserStoryStatus, TestCaseStatus } from '../../types/index.js';
1
2
  /**
2
3
  * Batch update user story statuses
3
4
  */
4
- export declare function batchUpdateUserStoryStatus(userStoryIds: string[], status: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled', verbose?: boolean): Promise<boolean>;
5
+ export declare function batchUpdateUserStoryStatus(userStoryIds: string[], status: UserStoryStatus, verbose?: boolean): Promise<boolean>;
5
6
  /**
6
7
  * Batch update test case statuses
7
8
  */
8
- export declare function batchUpdateTestCaseStatus(testCaseIds: string[], status: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled', verbose?: boolean): Promise<boolean>;
9
+ export declare function batchUpdateTestCaseStatus(testCaseIds: string[], status: TestCaseStatus, verbose?: boolean): Promise<boolean>;
9
10
  /**
10
11
  * Batch delete user stories
11
12
  */
@@ -8,6 +8,6 @@ export declare function filterFeaturesByStatus(features: FeatureInfo[], status:
8
8
  */
9
9
  export declare function sortFeaturesByUpdatedAt(features: FeatureInfo[]): FeatureInfo[];
10
10
  /**
11
- * Get features with ready_for_dev status for a product
11
+ * Get features with ready_for_ai status for a product
12
12
  */
13
- export declare function getReadyForDevFeatures(productId: string, verbose?: boolean): Promise<FeatureInfo[]>;
13
+ export declare function getReadyForAIFeatures(productId: string, verbose?: boolean): Promise<FeatureInfo[]>;
@@ -17,21 +17,21 @@ export function sortFeaturesByUpdatedAt(features) {
17
17
  });
18
18
  }
19
19
  /**
20
- * Get features with ready_for_dev status for a product
20
+ * Get features with ready_for_ai status for a product
21
21
  */
22
- export async function getReadyForDevFeatures(productId, verbose) {
22
+ export async function getReadyForAIFeatures(productId, verbose) {
23
23
  if (verbose) {
24
- logInfo(`Fetching ready_for_dev features for product: ${productId}`);
24
+ logInfo(`Fetching ready_for_ai features for product: ${productId}`);
25
25
  }
26
26
  try {
27
27
  const result = (await callMcpEndpoint('features/list', {
28
28
  product_id: productId,
29
- status: 'ready_for_dev',
29
+ status: 'ready_for_ai',
30
30
  }));
31
31
  const features = result.features || [];
32
32
  const sortedFeatures = sortFeaturesByUpdatedAt(features);
33
33
  if (verbose) {
34
- logInfo(`✅ Found ${sortedFeatures.length} ready_for_dev features (oldest first)`);
34
+ logInfo(`✅ Found ${sortedFeatures.length} ready_for_ai features (oldest first)`);
35
35
  sortedFeatures.forEach((feature, index) => {
36
36
  logInfo(` ${index + 1}. ${feature.name} (updated: ${feature.updated_at})`);
37
37
  });
@@ -40,7 +40,7 @@ export async function getReadyForDevFeatures(productId, verbose) {
40
40
  }
41
41
  catch (error) {
42
42
  const errorMessage = error instanceof Error ? error.message : String(error);
43
- logError(`Failed to fetch ready_for_dev features: ${errorMessage}`);
43
+ logError(`Failed to fetch ready_for_ai features: ${errorMessage}`);
44
44
  throw error;
45
45
  }
46
46
  }
@@ -1,4 +1,4 @@
1
- import { TestCase } from '../../types/features.js';
1
+ import { TestCase, TestCaseStatus } from '../../types/features.js';
2
2
  /**
3
3
  * Get test cases for a feature
4
4
  */
@@ -26,4 +26,4 @@ export declare function deleteTestCase(testCaseId: string, verbose?: boolean): P
26
26
  /**
27
27
  * Update test case status
28
28
  */
29
- export declare function updateTestCaseStatus(testCaseId: string, status: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled', verbose?: boolean): Promise<boolean>;
29
+ export declare function updateTestCaseStatus(testCaseId: string, status: TestCaseStatus, verbose?: boolean): Promise<boolean>;
@@ -1,4 +1,4 @@
1
- import { UserStory } from '../../types/features.js';
1
+ import { UserStory, UserStoryStatus } from '../../types/features.js';
2
2
  /**
3
3
  * Get user stories for a feature
4
4
  */
@@ -11,14 +11,6 @@ export declare function createUserStory(featureId: string, userStory: {
11
11
  description: string;
12
12
  status?: string;
13
13
  }, verbose?: boolean): Promise<boolean>;
14
- /**
15
- * Create multiple user stories for a feature
16
- */
17
- export declare function createUserStories(mcpServerUrl: string, mcpToken: string, featureId: string, userStories: Array<{
18
- title: string;
19
- description: string;
20
- status?: string;
21
- }>, verbose?: boolean): Promise<boolean>;
22
14
  /**
23
15
  * Delete a user story
24
16
  */
@@ -26,4 +18,4 @@ export declare function deleteUserStory(userStoryId: string, verbose?: boolean):
26
18
  /**
27
19
  * Update user story status
28
20
  */
29
- export declare function updateUserStoryStatus(userStoryId: string, status: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled', verbose?: boolean): Promise<boolean>;
21
+ export declare function updateUserStoryStatus(userStoryId: string, status: UserStoryStatus, verbose?: boolean): Promise<boolean>;
@@ -41,28 +41,6 @@ export async function createUserStory(featureId, userStory, verbose) {
41
41
  return false;
42
42
  }
43
43
  }
44
- /**
45
- * Create multiple user stories for a feature
46
- */
47
- export async function createUserStories(mcpServerUrl, mcpToken, featureId, userStories, verbose) {
48
- try {
49
- if (verbose) {
50
- logInfo(`Creating ${userStories.length} user stories for feature: ${featureId}`);
51
- }
52
- for (const story of userStories) {
53
- await createUserStory(featureId, story, false);
54
- }
55
- if (verbose) {
56
- logInfo('✅ All user stories created successfully');
57
- }
58
- return true;
59
- }
60
- catch (error) {
61
- const errorMessage = error instanceof Error ? error.message : String(error);
62
- logError(`Failed to create user stories: ${errorMessage}`);
63
- return false;
64
- }
65
- }
66
44
  /**
67
45
  * Delete a user story
68
46
  */
@@ -9,7 +9,7 @@ export const shouldProcessFeature = (maxRetries) => (feature, states) => {
9
9
  if (!state)
10
10
  return true;
11
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
12
+ // This handles cases where user manually changes status back to ready_for_ai
13
13
  if (feature.updated_at) {
14
14
  const featureUpdatedTime = new Date(feature.updated_at).getTime();
15
15
  const lastAttemptTime = state.lastAttempt.getTime();
@@ -49,7 +49,7 @@ export const logFeatureError = (featureName, error) => {
49
49
  logError(`❌ Error processing feature ${featureName}: ${error instanceof Error ? error.message : String(error)}`);
50
50
  };
51
51
  export const logNoFeaturesFound = () => {
52
- logInfo('🔍 No ready_for_dev features found, continuing to monitor...');
52
+ logInfo('🔍 No ready_for_ai features found, continuing to monitor...');
53
53
  };
54
54
  export const logAllFeaturesProcessed = () => {
55
55
  logInfo('🔄 All current features are processed or being processed, continuing to monitor...');
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Main workflow processor for continuous feature development
3
- * Monitors for ready_for_dev features and processes them through the complete pipeline
3
+ * Monitors for ready_for_ai features and processes them through the complete pipeline
4
4
  * Uses functional programming principles
5
5
  */
6
6
  import { EdsgerConfig } from '../../types/index.js';
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Main workflow processor for continuous feature development
3
- * Monitors for ready_for_dev features and processes them through the complete pipeline
3
+ * Monitors for ready_for_ai features and processes them through the complete pipeline
4
4
  * Uses functional programming principles
5
5
  */
6
- import { getReadyForDevFeatures } from '../../api/features/index.js';
6
+ import { getReadyForAIFeatures } from '../../api/features/index.js';
7
7
  import { runFeatureWorkflow } from './feature-coordinator.js';
8
8
  import { logInfo } from '../../utils/logger.js';
9
9
  // Import core modules
@@ -77,7 +77,7 @@ export class WorkflowProcessor {
77
77
  return;
78
78
  }
79
79
  // Fetch features using unified API
80
- const features = await getReadyForDevFeatures(this.options.productId, this.options.verbose);
80
+ const features = await getReadyForAIFeatures(this.options.productId, this.options.verbose);
81
81
  if (features.length === 0) {
82
82
  if (this.options.verbose) {
83
83
  logNoFeaturesFound();
@@ -19,7 +19,7 @@ describe('Feature Status Configuration', () => {
19
19
  it('should maintain logical workflow order', () => {
20
20
  const criticalOrder = [
21
21
  'backlog',
22
- 'ready_for_dev',
22
+ 'ready_for_ai',
23
23
  'feature_analysis',
24
24
  'technical_design',
25
25
  'code_implementation',
@@ -22,7 +22,7 @@
22
22
  */
23
23
  export const STATUS_PROGRESSION_ORDER = [
24
24
  'backlog',
25
- 'ready_for_dev',
25
+ 'ready_for_ai',
26
26
  'feature_analysis',
27
27
  'feature_analysis_verification',
28
28
  'technical_design',
@@ -1,4 +1,3 @@
1
- import { createUserStories, createTestCases } from '../../api/features/index.js';
2
1
  import type { FeatureInfo, UserStory, TestCase } from '../../types/features.js';
3
2
  import { type ProductInfo } from '../../api/products.js';
4
3
  import { ChecklistPhaseContext } from '../../services/checklist.js';
@@ -12,7 +11,6 @@ export interface FeatureAnalysisContext {
12
11
  * Fetch all feature analysis context information via MCP endpoints
13
12
  */
14
13
  export declare function fetchFeatureAnalysisContext(featureId: string, verbose?: boolean): Promise<FeatureAnalysisContext>;
15
- export { createUserStories, createTestCases };
16
14
  /**
17
15
  * Format the context into a readable string for Claude Code
18
16
  */
@@ -1,5 +1,5 @@
1
1
  import { logInfo, logError } from '../../utils/logger.js';
2
- import { getFeature, getUserStories, createUserStories, getTestCases, createTestCases, } from '../../api/features/index.js';
2
+ import { getFeature, getUserStories, getTestCases, } from '../../api/features/index.js';
3
3
  import { getProduct } from '../../api/products.js';
4
4
  import { formatChecklistsForContext, } from '../../services/checklist.js';
5
5
  import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
@@ -40,8 +40,6 @@ export async function fetchFeatureAnalysisContext(featureId, verbose) {
40
40
  throw new Error(`Context fetch failed: ${errorMessage}`);
41
41
  }
42
42
  }
43
- // Re-export the create functions for convenience
44
- export { createUserStories, createTestCases };
45
43
  /**
46
44
  * Format the context into a readable string for Claude Code
47
45
  */
@@ -180,7 +180,7 @@ export function buildAnalysisResult(featureId, context, structuredAnalysisResult
180
180
  featureInfo: context.feature,
181
181
  existingUserStories: context.existing_user_stories.map((story) => ({
182
182
  ...story,
183
- status: story.status,
183
+ status: (story.status === 'ready' ? 'ready' : 'draft'),
184
184
  created_at: story.created_at || new Date().toISOString(),
185
185
  updated_at: story.updated_at || new Date().toISOString(),
186
186
  })),
@@ -193,7 +193,7 @@ export function buildAnalysisResult(featureId, context, structuredAnalysisResult
193
193
  id: '',
194
194
  title: story.title,
195
195
  description: story.description,
196
- status: story.status || 'draft',
196
+ status: 'draft',
197
197
  created_at: new Date().toISOString(),
198
198
  updated_at: new Date().toISOString(),
199
199
  })),
@@ -88,14 +88,16 @@ You MUST return ONLY a JSON object with your analysis results. Do NOT include an
88
88
  {
89
89
  "title": "User story title",
90
90
  "description": "As a [user], I want [goal] so that [benefit]",
91
- "status": "draft"
91
+ "status": "draft",
92
+ "differentiation": "REQUIRED: Explain how this differs from existing user stories. Reference specific existing story titles and explain what new scenario/user type/workflow this covers that is NOT already addressed."
92
93
  }
93
94
  ],
94
95
  "created_test_cases": [
95
96
  {
96
97
  "name": "Test case name",
97
98
  "description": "Detailed test case description with steps and expected outcomes",
98
- "is_critical": true
99
+ "is_critical": true,
100
+ "differentiation": "REQUIRED: Explain how this differs from existing test cases. Reference specific existing test case names and explain what new scenario/edge case this covers that is NOT already tested."
99
101
  }
100
102
  ],
101
103
  "deleted_user_story_ids": [
@@ -141,6 +143,14 @@ deletion_reasons: {"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d": "Duplicate of test ca
141
143
  **EXAMPLE - WRONG (DO NOT DO THIS)**:
142
144
  deleted_test_case_ids: ["Duplicate test case", "Similar test"] // WRONG - these are text, not UUIDs
143
145
 
146
+ **CRITICAL - Differentiation Requirement**:
147
+ - The "differentiation" field is MANDATORY for every new user story and test case
148
+ - You MUST explain WHY this item is NOT a duplicate of existing items
149
+ - Reference specific existing item titles/names when explaining the difference
150
+ - If there are no existing items, write: "First item for this feature - no existing items to compare"
151
+ - If you cannot clearly articulate the difference, DO NOT create the item - it is likely a duplicate
152
+ - Generic explanations like "covers different scenario" are NOT acceptable - be specific
153
+
144
154
  **Quality Guidelines**:
145
155
  - User stories should be clear, concise, and user-focused
146
156
  - Test cases should be comprehensive and cover all scenarios
@@ -300,10 +310,20 @@ You MUST return ONLY the JSON object below. Do NOT include any explanatory text,
300
310
  "status": "success",
301
311
  "summary": "Improved analysis based on verification feedback",
302
312
  "created_user_stories": [
303
- // Include ALL user stories (existing + new)
313
+ {
314
+ "title": "User story title",
315
+ "description": "As a [user], I want [goal] so that [benefit]",
316
+ "status": "draft",
317
+ "differentiation": "REQUIRED: Explain how this differs from existing user stories"
318
+ }
304
319
  ],
305
320
  "created_test_cases": [
306
- // Include ALL test cases (existing + new)
321
+ {
322
+ "name": "Test case name",
323
+ "description": "Detailed test case description",
324
+ "is_critical": true,
325
+ "differentiation": "REQUIRED: Explain how this differs from existing test cases"
326
+ }
307
327
  ],
308
328
  "deleted_user_story_ids": [
309
329
  // UUIDs of user stories to delete
@@ -327,6 +347,11 @@ You MUST return ONLY the JSON object below. Do NOT include any explanatory text,
327
347
  }
328
348
  \`\`\`
329
349
 
350
+ **CRITICAL - Differentiation Requirement**:
351
+ - The "differentiation" field is MANDATORY for every user story and test case
352
+ - You MUST explain WHY each item is NOT a duplicate of existing items
353
+ - If you cannot clearly articulate the difference, DO NOT include the item
354
+
330
355
  MANDATORY: You MUST include checklist_item_results for ALL checklist items in your response. Every checklist item ID must be addressed - either passed or with explanation in notes why it cannot be satisfied. Missing any checklist item will cause the pipeline to fail again.
331
356
 
332
357
  IMPORTANT: Return ONLY the JSON above. Do not add any text explaining what you did or how you improved the analysis. The JSON should be the complete and only content of your response.`;
@@ -10,11 +10,13 @@ export interface FeatureInfo {
10
10
  created_at?: string;
11
11
  updated_at?: string;
12
12
  }
13
+ export type UserStoryStatus = 'draft' | 'ready';
14
+ export type TestCaseStatus = 'draft' | 'ready';
13
15
  export interface UserStory {
14
16
  id: string;
15
17
  title: string;
16
18
  description: string;
17
- status: string;
19
+ status: UserStoryStatus;
18
20
  created_at?: string;
19
21
  updated_at?: string;
20
22
  [key: string]: any;
@@ -24,6 +26,7 @@ export interface TestCase {
24
26
  name: string;
25
27
  description: string;
26
28
  is_critical: boolean;
29
+ status?: TestCaseStatus;
27
30
  created_at?: string;
28
31
  updated_at?: string;
29
32
  [key: string]: any;
@@ -97,11 +97,13 @@ export interface FeatureData {
97
97
  };
98
98
  };
99
99
  }
100
+ export type UserStoryStatus = 'draft' | 'ready';
101
+ export type TestCaseStatus = 'draft' | 'ready';
100
102
  export interface UserStory {
101
103
  id: string;
102
104
  title: string;
103
105
  description: string;
104
- status: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled';
106
+ status: UserStoryStatus;
105
107
  created_at: string;
106
108
  updated_at: string;
107
109
  }
@@ -110,7 +112,7 @@ export interface TestCase {
110
112
  name: string;
111
113
  description: string;
112
114
  is_critical: boolean;
113
- status?: 'draft' | 'ready' | 'in_progress' | 'done' | 'cancelled';
115
+ status?: TestCaseStatus;
114
116
  created_at: string;
115
117
  updated_at: string;
116
118
  }
@@ -128,4 +130,4 @@ export interface FeatureAnalysisDisplayResult {
128
130
  createdUserStories?: DisplayUserStory[];
129
131
  createdTestCases?: DisplayTestCase[];
130
132
  }
131
- export type FeatureStatus = 'backlog' | 'ready_for_dev' | 'feature_analysis' | 'feature_analysis_verification' | 'technical_design' | 'technical_design_verification' | 'code_implementation' | 'code_implementation_verification' | 'code_refine' | 'code_refine_verification' | 'bug_fixing' | 'code_review' | 'pull_request' | 'functional_testing' | 'ready_for_review' | 'shipped' | 'testing_in_progress' | 'testing_passed' | 'testing_failed';
133
+ export type FeatureStatus = 'backlog' | 'ready_for_ai' | 'feature_analysis' | 'feature_analysis_verification' | 'technical_design' | 'technical_design_verification' | 'code_implementation' | 'code_implementation_verification' | 'code_refine' | 'code_refine_verification' | 'bug_fixing' | 'code_review' | 'pull_request' | 'functional_testing' | 'ready_for_review' | 'shipped' | 'testing_in_progress' | 'testing_passed' | 'testing_failed';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.10.3",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"