edsger 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +17 -0
  2. package/dist/api/features/batch-operations.d.ts +16 -0
  3. package/dist/api/features/batch-operations.js +100 -0
  4. package/dist/api/features/index.d.ts +1 -0
  5. package/dist/api/features/index.js +1 -0
  6. package/dist/api/features/test-cases.d.ts +8 -0
  7. package/dist/api/features/test-cases.js +45 -0
  8. package/dist/api/features/user-stories.d.ts +8 -0
  9. package/dist/api/features/user-stories.js +45 -0
  10. package/dist/cli/commands/refactor-command.d.ts +2 -0
  11. package/dist/cli/commands/refactor-command.js +107 -0
  12. package/dist/cli/index.js +7 -0
  13. package/dist/cli.d.ts +2 -2
  14. package/dist/cli.js +4 -99
  15. package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
  16. package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
  17. package/dist/phases/code-implementation/analyzer.d.ts +2 -0
  18. package/dist/phases/code-implementation/analyzer.js +304 -175
  19. package/dist/phases/code-implementation-verification/index.d.ts +1 -0
  20. package/dist/phases/code-implementation-verification/index.js +1 -0
  21. package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
  22. package/dist/phases/code-implementation-verification/verifier.js +196 -0
  23. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +62 -0
  24. package/dist/phases/feature-analysis/analyzer-helpers.js +450 -0
  25. package/dist/phases/feature-analysis/analyzer.d.ts +1 -0
  26. package/dist/phases/feature-analysis/analyzer.js +132 -219
  27. package/dist/phases/feature-analysis-verification/index.d.ts +1 -0
  28. package/dist/phases/feature-analysis-verification/index.js +1 -0
  29. package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
  30. package/dist/phases/feature-analysis-verification/verifier.js +147 -0
  31. package/dist/phases/pull-request/creator.js +2 -1
  32. package/dist/phases/technical-design/analyzer-helpers.d.ts +37 -0
  33. package/dist/phases/technical-design/analyzer-helpers.js +144 -0
  34. package/dist/phases/technical-design/analyzer.d.ts +3 -0
  35. package/dist/phases/technical-design/analyzer.js +282 -318
  36. package/dist/phases/technical-design-verification/index.d.ts +1 -0
  37. package/dist/phases/technical-design-verification/index.js +1 -0
  38. package/dist/phases/technical-design-verification/verifier.d.ts +36 -0
  39. package/dist/phases/technical-design-verification/verifier.js +147 -0
  40. package/dist/prompts/checklist-verification.d.ts +11 -0
  41. package/dist/prompts/checklist-verification.js +153 -0
  42. package/dist/prompts/code-implementation-improvement.d.ts +5 -0
  43. package/dist/prompts/code-implementation-improvement.js +108 -0
  44. package/dist/prompts/code-implementation-verification.d.ts +3 -0
  45. package/dist/prompts/code-implementation-verification.js +176 -0
  46. package/dist/prompts/feature-analysis-improvement.d.ts +8 -0
  47. package/dist/prompts/feature-analysis-improvement.js +109 -0
  48. package/dist/prompts/feature-analysis.js +1 -1
  49. package/dist/prompts/technical-design-improvement.d.ts +5 -0
  50. package/dist/prompts/technical-design-improvement.js +93 -0
  51. package/dist/prompts/technical-design-verification.d.ts +11 -0
  52. package/dist/prompts/technical-design-verification.js +134 -0
  53. package/dist/prompts/technical-design.js +1 -1
  54. package/dist/services/audit-logs.d.ts +60 -0
  55. package/dist/services/audit-logs.js +115 -0
  56. package/dist/services/checklist.d.ts +1 -0
  57. package/dist/types/index.d.ts +19 -0
  58. package/dist/workflow-runner/executors/phase-executor.js +56 -12
  59. package/package.json +1 -1
  60. package/dist/api/features.d.ts +0 -100
  61. package/dist/api/features.js +0 -219
  62. package/dist/logger.d.ts +0 -19
  63. package/dist/logger.js +0 -52
  64. package/dist/types.d.ts +0 -99
  65. package/dist/types.js +0 -1
  66. package/dist/utils/image-processor.d.ts +0 -5
  67. package/dist/utils/image-processor.js +0 -55
  68. package/dist/workflow-runner/config/stage-configs.d.ts +0 -5
  69. package/dist/workflow-runner/config/stage-configs.js +0 -34
  70. package/dist/workflow-runner/core/feature-filter.test.d.ts +0 -4
  71. package/dist/workflow-runner/core/feature-filter.test.js +0 -127
  72. package/dist/workflow-runner/executors/stage-executor.d.ts +0 -8
  73. package/dist/workflow-runner/executors/stage-executor.js +0 -49
  74. package/dist/workflow-runner/feature-fetcher.d.ts +0 -41
  75. package/dist/workflow-runner/feature-fetcher.js +0 -121
  76. package/dist/workflow-runner/feature-service.d.ts +0 -17
  77. package/dist/workflow-runner/feature-service.js +0 -60
  78. package/dist/workflow-runner/pipeline.d.ts +0 -18
  79. package/dist/workflow-runner/pipeline.js +0 -197
  80. package/dist/workflow-runner/processor.d.ts +0 -40
  81. package/dist/workflow-runner/processor.js +0 -191
  82. package/dist/workflow-runner/status-updater.d.ts +0 -27
  83. package/dist/workflow-runner/status-updater.js +0 -80
  84. package/dist/workflow-runner/types.d.ts +0 -48
  85. package/dist/workflow-runner/types.js +0 -4
@@ -1,22 +1,10 @@
1
- import { query } from '@anthropic-ai/claude-code';
2
1
  import { logInfo, logError } from '../../utils/logger.js';
3
- import { saveDataViaHttp } from './http-fallback.js';
4
2
  import { fetchFeatureAnalysisContext, } from './context-fetcher.js';
5
- import { createUserStories } from '../../api/features/index.js';
6
- import { createTestCases } from '../../api/features/index.js';
7
3
  import { formatFeatureAnalysisContext } from '../../prompts/formatters.js';
8
4
  import { createFeatureAnalysisSystemPrompt, createFeatureAnalysisPromptWithContext, } from '../../prompts/feature-analysis.js';
9
5
  import { formatChecklistsForContext, } from '../../services/checklist.js';
10
- function userMessage(content) {
11
- return {
12
- type: 'user',
13
- message: { role: 'user', content: content },
14
- };
15
- }
16
- async function* prompt(analysisPrompt) {
17
- yield userMessage(analysisPrompt);
18
- await new Promise((res) => setTimeout(res, 10000));
19
- }
6
+ import { executeAnalysisQuery, performVerificationCycle, saveAnalysisArtifactsAsDraft, updateArtifactsToReady, deleteArtifacts, buildAnalysisResult, buildVerificationFailureResult, buildNoResultsError, } from './analyzer-helpers.js';
7
+ import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
20
8
  export const analyzeFeatureWithMCP = async (options, config, checklistContext) => {
21
9
  const { featureId, mcpServerUrl, mcpToken, verbose } = options;
22
10
  if (verbose) {
@@ -24,230 +12,128 @@ export const analyzeFeatureWithMCP = async (options, config, checklistContext) =
24
12
  logInfo(`Using MCP server: ${mcpServerUrl}`);
25
13
  }
26
14
  try {
27
- // Fetch all required context information via MCP endpoints
28
- if (verbose) {
29
- logInfo('Fetching feature analysis context via MCP endpoints...');
30
- }
31
- const context = await fetchFeatureAnalysisContext(mcpServerUrl, mcpToken, featureId, verbose);
15
+ // Fetch and prepare context
16
+ const context = await prepareAnalysisContext(mcpServerUrl, mcpToken, featureId, checklistContext, verbose);
32
17
  const systemPrompt = createFeatureAnalysisSystemPrompt(config, mcpServerUrl, mcpToken, featureId);
33
- const { content: contextInfo, downloadedImages } = await formatFeatureAnalysisContext(context);
34
- if (verbose && downloadedImages.length > 0) {
35
- logInfo(`Downloaded ${downloadedImages.length} images for Claude Code:`);
36
- downloadedImages.forEach((img) => {
37
- logInfo(` - ${img.url} -> ${img.localPath}`);
38
- });
39
- }
40
- // Add checklist context to the analysis prompt
41
- let finalContextInfo = contextInfo;
42
- if (checklistContext && checklistContext.checklists.length > 0) {
43
- const checklistInfo = formatChecklistsForContext(checklistContext);
44
- finalContextInfo = contextInfo + '\n\n' + checklistInfo;
45
- if (verbose) {
46
- logInfo(`Added ${checklistContext.checklists.length} checklists to analysis context`);
47
- }
48
- }
49
- const analysisPrompt = createFeatureAnalysisPromptWithContext(featureId, finalContextInfo);
50
- let lastAssistantResponse = '';
18
+ const initialAnalysisPrompt = context.analysisPrompt;
19
+ const maxIterations = options.maxVerificationIterations || 10;
20
+ let currentIteration = 0;
21
+ let currentPrompt = initialAnalysisPrompt;
51
22
  let structuredAnalysisResult = null;
23
+ let verificationResult = null;
52
24
  if (verbose) {
53
25
  logInfo('Starting Claude Code query with pre-fetched information...');
54
26
  }
55
- // Use Claude Code SDK without MCP servers - all info is pre-fetched
56
- for await (const message of query({
57
- prompt: prompt(analysisPrompt),
58
- options: {
59
- appendSystemPrompt: systemPrompt,
60
- model: config.claude.model || 'sonnet',
61
- maxTurns: 1000,
62
- permissionMode: 'bypassPermissions',
63
- },
64
- })) {
65
- if (verbose) {
66
- logInfo(`Received message type: ${message.type}`);
27
+ // Iterative improvement loop: analysis → save draft → verification → update ready or delete → re-analysis
28
+ let currentDraftUserStoryIds = [];
29
+ let currentDraftTestCaseIds = [];
30
+ while (currentIteration < maxIterations) {
31
+ currentIteration++;
32
+ if (verbose && currentIteration > 1) {
33
+ logInfo(`\nšŸ”„ Iteration ${currentIteration}/${maxIterations}: Improving analysis based on verification feedback...`);
67
34
  }
68
- // Stream the analysis process and capture assistant responses
69
- if (message.type === 'assistant' && message.message?.content) {
70
- for (const content of message.message.content) {
71
- if (content.type === 'text') {
72
- lastAssistantResponse += content.text + '\n';
73
- if (verbose) {
74
- console.log(`\nšŸ¤– ${content.text}`);
75
- }
76
- }
77
- else if (content.type === 'tool_use') {
78
- if (verbose) {
79
- console.log(`\nšŸ”§ ${content.name}: ${content.input.description || 'Running...'}`);
80
- }
81
- }
82
- }
35
+ // Log iteration start (for iterations after the first)
36
+ if (currentIteration > 1) {
37
+ await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
38
+ featureId,
39
+ eventType: 'phase_started',
40
+ phase: 'feature_analysis',
41
+ result: 'info',
42
+ metadata: {
43
+ iteration: currentIteration,
44
+ max_iterations: maxIterations,
45
+ re_analysis: true,
46
+ timestamp: new Date().toISOString(),
47
+ },
48
+ }, verbose);
83
49
  }
84
- if (message.type === 'result') {
85
- if (message.subtype === 'success') {
86
- logInfo('\nšŸ“Š Feature analysis completed, parsing results...');
87
- try {
88
- // Try to extract JSON from markdown code block or parse directly
89
- const responseText = message.result || lastAssistantResponse;
90
- let jsonResult = null;
91
- // First try to extract JSON from markdown code block
92
- const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
93
- if (jsonBlockMatch) {
94
- jsonResult = JSON.parse(jsonBlockMatch[1]);
95
- }
96
- else {
97
- // Try to parse the entire response as JSON
98
- jsonResult = JSON.parse(responseText);
99
- }
100
- if (jsonResult && jsonResult.analysis) {
101
- structuredAnalysisResult = jsonResult.analysis;
102
- }
103
- else {
104
- throw new Error('Invalid JSON structure');
105
- }
106
- }
107
- catch (error) {
108
- logError(`Failed to parse structured analysis result: ${error}`);
109
- structuredAnalysisResult = {
110
- status: 'error',
111
- summary: 'Failed to parse analysis results from Claude Code response',
112
- created_user_stories: [],
113
- created_test_cases: [],
114
- };
115
- }
116
- }
117
- else {
118
- logError(`\nāš ļø Analysis incomplete: ${message.subtype}`);
119
- if (message.subtype === 'error_max_turns') {
120
- logError('šŸ’” Try increasing timeout or reducing complexity');
121
- }
122
- // Try to parse results from the last assistant response
123
- if (lastAssistantResponse) {
124
- try {
125
- const responseText = lastAssistantResponse;
126
- let jsonResult = null;
127
- const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
128
- if (jsonBlockMatch) {
129
- jsonResult = JSON.parse(jsonBlockMatch[1]);
130
- if (jsonResult && jsonResult.analysis) {
131
- structuredAnalysisResult = jsonResult.analysis;
132
- }
133
- }
134
- }
135
- catch (error) {
136
- logError(`Failed to parse assistant response: ${error}`);
137
- }
138
- }
139
- }
50
+ // Execute analysis query
51
+ structuredAnalysisResult = await executeAnalysisQuery(currentPrompt, systemPrompt, config, verbose);
52
+ // No result produced, break out
53
+ if (!structuredAnalysisResult) {
54
+ break;
140
55
  }
141
- }
142
- // Save the analysis results if we have them
143
- if (structuredAnalysisResult) {
144
- const { created_user_stories, created_test_cases, status, checklist_results, checklist_item_results, } = structuredAnalysisResult;
145
- if (created_user_stories && created_user_stories.length > 0) {
56
+ // Log analysis completion for this iteration
57
+ await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
58
+ featureId,
59
+ eventType: 'phase_completed',
60
+ phase: 'feature_analysis',
61
+ result: 'success',
62
+ metadata: {
63
+ iteration: currentIteration,
64
+ max_iterations: maxIterations,
65
+ analysis_step: 'completed',
66
+ user_stories_count: structuredAnalysisResult.created_user_stories?.length || 0,
67
+ test_cases_count: structuredAnalysisResult.created_test_cases?.length || 0,
68
+ timestamp: new Date().toISOString(),
69
+ },
70
+ }, verbose);
71
+ // Save artifacts as draft and get their IDs
72
+ const { userStoryIds, testCaseIds } = await saveAnalysisArtifactsAsDraft(mcpServerUrl, mcpToken, featureId, structuredAnalysisResult.created_user_stories || [], structuredAnalysisResult.created_test_cases || [], verbose);
73
+ currentDraftUserStoryIds = userStoryIds;
74
+ currentDraftTestCaseIds = testCaseIds;
75
+ // Perform verification cycle
76
+ const verificationCycle = await performVerificationCycle(structuredAnalysisResult, checklistContext || null, context.featureContext, config, currentIteration, maxIterations, mcpServerUrl, mcpToken, featureId, verbose);
77
+ verificationResult = verificationCycle.verificationResult;
78
+ // If verification passed, update artifacts to ready and exit
79
+ if (verificationCycle.passed) {
146
80
  if (verbose) {
147
- logInfo('Saving created user stories...');
148
- }
149
- const userStoriesCreated = await createUserStories(mcpServerUrl, mcpToken, featureId, created_user_stories, verbose);
150
- if (!userStoriesCreated && verbose) {
151
- logError('āš ļø Failed to save user stories');
81
+ logInfo('āœ… Verification passed! Updating artifacts to ready status...');
152
82
  }
83
+ await updateArtifactsToReady(mcpServerUrl, mcpToken, currentDraftUserStoryIds, currentDraftTestCaseIds, verbose);
84
+ break;
153
85
  }
154
- if (created_test_cases && created_test_cases.length > 0) {
86
+ // Verification failed
87
+ if (currentIteration < maxIterations && verificationCycle.nextPrompt) {
88
+ // We have more iterations - delete draft artifacts and retry
155
89
  if (verbose) {
156
- logInfo('Saving created test cases...');
157
- }
158
- const testCasesCreated = await createTestCases(mcpServerUrl, mcpToken, featureId, created_test_cases, verbose);
159
- if (!testCasesCreated && verbose) {
160
- logError('āš ļø Failed to save test cases');
90
+ logInfo('šŸ—‘ļø Deleting draft artifacts for re-analysis...');
161
91
  }
92
+ await deleteArtifacts(mcpServerUrl, mcpToken, currentDraftUserStoryIds, currentDraftTestCaseIds, verbose);
93
+ // Continue with improvement prompt
94
+ currentPrompt = verificationCycle.nextPrompt;
162
95
  }
163
- // Try HTTP fallback if direct save failed
164
- if (status === 'error' &&
165
- (created_user_stories?.length > 0 || created_test_cases?.length > 0)) {
96
+ else {
97
+ // Max iterations reached or no next prompt - exit loop
98
+ // Draft artifacts remain in database for manual review
166
99
  if (verbose) {
167
- logInfo('Direct save failed, trying HTTP fallback...');
168
- }
169
- const httpSuccess = await saveDataViaHttp({
170
- mcpServerUrl,
171
- mcpToken,
172
- featureId,
173
- userStories: created_user_stories || [],
174
- testCases: created_test_cases || [],
175
- verbose,
176
- });
177
- if (httpSuccess) {
178
- logInfo('āœ… Successfully saved data via HTTP fallback');
179
- structuredAnalysisResult.status = 'success';
180
- structuredAnalysisResult.summary =
181
- (structuredAnalysisResult.summary || '') +
182
- ' (saved via HTTP fallback)';
100
+ logInfo('āš ļø Max iterations reached. Draft artifacts kept for manual review.');
183
101
  }
184
- else if (verbose) {
185
- logError('āŒ HTTP fallback also failed');
102
+ break;
103
+ }
104
+ }
105
+ // Handle results
106
+ if (!structuredAnalysisResult) {
107
+ return buildNoResultsError(featureId, context.featureContext);
108
+ }
109
+ const { created_user_stories, created_test_cases, status, checklist_results, checklist_item_results, } = structuredAnalysisResult;
110
+ // If no checklist was used, update draft artifacts to ready now
111
+ if (!checklistContext ||
112
+ checklistContext.checklists.length === 0 ||
113
+ !verificationResult) {
114
+ if (currentDraftUserStoryIds.length > 0 ||
115
+ currentDraftTestCaseIds.length > 0) {
116
+ if (verbose) {
117
+ logInfo('āœ… No checklist verification needed. Updating artifacts to ready status...');
186
118
  }
119
+ await updateArtifactsToReady(mcpServerUrl, mcpToken, currentDraftUserStoryIds, currentDraftTestCaseIds, verbose);
187
120
  }
188
- return {
189
- featureId,
190
- productInfo: context.product,
191
- featureInfo: context.feature,
192
- existingUserStories: context.existing_user_stories.map((story) => ({
193
- ...story,
194
- status: story.status,
195
- created_at: story.created_at || new Date().toISOString(),
196
- updated_at: story.updated_at || new Date().toISOString(),
197
- })),
198
- existingTestCases: context.existing_test_cases.map((testCase) => ({
199
- ...testCase,
200
- created_at: testCase.created_at || new Date().toISOString(),
201
- updated_at: testCase.updated_at || new Date().toISOString(),
202
- })),
203
- createdUserStories: (created_user_stories || []).map((story) => ({
204
- id: '',
205
- title: story.title,
206
- description: story.description,
207
- status: story.status || 'draft',
208
- created_at: new Date().toISOString(),
209
- updated_at: new Date().toISOString(),
210
- })),
211
- createdTestCases: (created_test_cases || []).map((testCase) => ({
212
- id: '',
213
- name: testCase.name,
214
- description: testCase.description,
215
- is_critical: testCase.is_critical || false,
216
- created_at: new Date().toISOString(),
217
- updated_at: new Date().toISOString(),
218
- })),
219
- summary: structuredAnalysisResult.summary || 'Analysis completed',
220
- status: structuredAnalysisResult.status === 'success' ? 'success' : 'error',
221
- data: {
222
- checklist_results,
223
- checklist_item_results,
224
- },
225
- };
226
121
  }
227
- return {
228
- featureId,
229
- productInfo: context.product,
230
- featureInfo: context.feature,
231
- existingUserStories: context.existing_user_stories.map((story) => ({
232
- ...story,
233
- status: story.status,
234
- created_at: story.created_at || new Date().toISOString(),
235
- updated_at: story.updated_at || new Date().toISOString(),
236
- })),
237
- existingTestCases: context.existing_test_cases.map((testCase) => ({
238
- ...testCase,
239
- created_at: testCase.created_at || new Date().toISOString(),
240
- updated_at: testCase.updated_at || new Date().toISOString(),
241
- })),
242
- createdUserStories: [],
243
- createdTestCases: [],
244
- summary: 'No analysis results received',
245
- status: 'error',
246
- data: {
247
- checklist_results: undefined,
248
- checklist_item_results: undefined,
249
- },
250
- };
122
+ // Check if verification failed after all iterations
123
+ // Note: Artifacts are already saved as draft in the database
124
+ // If verification failed, they remain as draft for manual review
125
+ if (verificationResult &&
126
+ verificationResult.rejected_count > 0 &&
127
+ checklistContext &&
128
+ checklistContext.checklists.length > 0) {
129
+ logError(`āŒ Final result: Checklist verification FAILED after ${currentIteration} iterations`);
130
+ logError(` Draft artifacts (${currentDraftUserStoryIds.length} user stories, ${currentDraftTestCaseIds.length} test cases) kept for manual review`);
131
+ return buildVerificationFailureResult(featureId, context.featureContext, verificationResult, checklist_results, checklist_item_results, currentIteration);
132
+ }
133
+ // Return success result
134
+ // Note: Artifacts have already been saved and updated to 'ready' status (if verification passed)
135
+ // or remain as draft (if verification failed)
136
+ return buildAnalysisResult(featureId, context.featureContext, structuredAnalysisResult, currentIteration);
251
137
  }
252
138
  catch (error) {
253
139
  logError(`Feature analysis failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -264,6 +150,33 @@ export const analyzeFeatureWithMCP = async (options, config, checklistContext) =
264
150
  };
265
151
  }
266
152
  };
153
+ /**
154
+ * Prepare all context information needed for analysis
155
+ */
156
+ async function prepareAnalysisContext(mcpServerUrl, mcpToken, featureId, checklistContext, verbose) {
157
+ if (verbose) {
158
+ logInfo('Fetching feature analysis context via MCP endpoints...');
159
+ }
160
+ const featureContext = await fetchFeatureAnalysisContext(mcpServerUrl, mcpToken, featureId, verbose);
161
+ const { content: contextInfo, downloadedImages } = await formatFeatureAnalysisContext(featureContext);
162
+ if (verbose && downloadedImages.length > 0) {
163
+ logInfo(`Downloaded ${downloadedImages.length} images for Claude Code:`);
164
+ downloadedImages.forEach((img) => {
165
+ logInfo(` - ${img.url} -> ${img.localPath}`);
166
+ });
167
+ }
168
+ // Add checklist context to the analysis prompt
169
+ let finalContextInfo = contextInfo;
170
+ if (checklistContext && checklistContext.checklists.length > 0) {
171
+ const checklistInfo = formatChecklistsForContext(checklistContext);
172
+ finalContextInfo = contextInfo + '\n\n' + checklistInfo;
173
+ if (verbose) {
174
+ logInfo(`Added ${checklistContext.checklists.length} checklists to analysis context`);
175
+ }
176
+ }
177
+ const analysisPrompt = createFeatureAnalysisPromptWithContext(featureId, finalContextInfo);
178
+ return { featureContext, analysisPrompt };
179
+ }
267
180
  export const checkFeatureAnalysisRequirements = async () => {
268
181
  try {
269
182
  // Check if Claude Code SDK is available
@@ -0,0 +1 @@
1
+ export { verifyChecklistCompliance, type ChecklistItemVerificationResult, type ChecklistVerificationResult, type VerifyChecklistOptions, } from './verifier.js';
@@ -0,0 +1 @@
1
+ export { verifyChecklistCompliance, } from './verifier.js';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Checklist verification agent for feature analysis
3
+ * This agent independently reviews checklist compliance to ensure objectivity
4
+ */
5
+ import { EdsgerConfig } from '../../types/index.js';
6
+ import { ChecklistPhaseContext } from '../../services/checklist.js';
7
+ import { FeatureAnalysisContext } from '../feature-analysis/context-fetcher.js';
8
+ export interface ChecklistItemVerificationResult {
9
+ checklist_item_id: string;
10
+ is_satisfied: boolean;
11
+ verification_status: 'confirmed' | 'rejected' | 'uncertain';
12
+ verification_reason: string;
13
+ concerns?: string[];
14
+ improvement_suggestions?: string[];
15
+ }
16
+ export interface ChecklistVerificationResult {
17
+ all_verified: boolean;
18
+ total_items: number;
19
+ confirmed_count: number;
20
+ rejected_count: number;
21
+ uncertain_count: number;
22
+ item_verifications: ChecklistItemVerificationResult[];
23
+ summary: string;
24
+ overall_suggestions?: string[];
25
+ }
26
+ export interface VerifyChecklistOptions {
27
+ checklistContext: ChecklistPhaseContext;
28
+ analysisContext: FeatureAnalysisContext;
29
+ createdUserStories: any[];
30
+ createdTestCases: any[];
31
+ verbose?: boolean;
32
+ }
33
+ /**
34
+ * Verify checklist compliance using an independent AI agent
35
+ * This agent acts as a "challenger" to validate the claims made by the analysis agent
36
+ */
37
+ export declare function verifyChecklistCompliance(options: VerifyChecklistOptions, config: EdsgerConfig): Promise<ChecklistVerificationResult>;
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Checklist verification agent for feature analysis
3
+ * This agent independently reviews checklist compliance to ensure objectivity
4
+ */
5
+ import { query } from '@anthropic-ai/claude-code';
6
+ import { logInfo, logError } from '../../utils/logger.js';
7
+ import { createChecklistVerificationPrompt, createChecklistVerificationSystemPrompt, } from '../../prompts/checklist-verification.js';
8
+ function userMessage(content) {
9
+ return {
10
+ type: 'user',
11
+ message: { role: 'user', content: content },
12
+ };
13
+ }
14
+ async function* prompt(verificationPrompt) {
15
+ yield userMessage(verificationPrompt);
16
+ }
17
+ /**
18
+ * Verify checklist compliance using an independent AI agent
19
+ * This agent acts as a "challenger" to validate the claims made by the analysis agent
20
+ */
21
+ export async function verifyChecklistCompliance(options, config) {
22
+ const { checklistContext, analysisContext, createdUserStories, createdTestCases, verbose, } = options;
23
+ const totalChecklistItems = checklistContext.checklists.reduce((sum, checklist) => sum + checklist.items.length, 0);
24
+ if (verbose) {
25
+ logInfo('šŸ” Starting checklist verification...');
26
+ logInfo(` Verifying ${totalChecklistItems} checklist items`);
27
+ }
28
+ try {
29
+ const systemPrompt = createChecklistVerificationSystemPrompt(config);
30
+ const verificationPrompt = createChecklistVerificationPrompt({
31
+ checklistContext,
32
+ analysisContext,
33
+ createdUserStories,
34
+ createdTestCases,
35
+ });
36
+ let lastAssistantResponse = '';
37
+ let verificationResult = null;
38
+ if (verbose) {
39
+ logInfo('šŸ¤– Starting verification agent query...');
40
+ }
41
+ // Use Claude Code SDK for verification
42
+ for await (const message of query({
43
+ prompt: prompt(verificationPrompt),
44
+ options: {
45
+ appendSystemPrompt: systemPrompt,
46
+ model: config.claude.model || 'sonnet',
47
+ maxTurns: 100,
48
+ permissionMode: 'bypassPermissions',
49
+ },
50
+ })) {
51
+ if (verbose) {
52
+ logInfo(` Received message type: ${message.type}`);
53
+ }
54
+ // Capture assistant responses
55
+ if (message.type === 'assistant' && message.message?.content) {
56
+ for (const content of message.message.content) {
57
+ if (content.type === 'text') {
58
+ lastAssistantResponse += content.text + '\n';
59
+ if (verbose) {
60
+ console.log(`\nšŸ” ${content.text}`);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ if (message.type === 'result') {
66
+ if (message.subtype === 'success') {
67
+ logInfo('\nāœ… Verification completed, parsing results...');
68
+ try {
69
+ const responseText = message.result || lastAssistantResponse;
70
+ // Try to extract JSON from markdown code block
71
+ const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
72
+ let jsonResult = null;
73
+ if (jsonBlockMatch) {
74
+ jsonResult = JSON.parse(jsonBlockMatch[1]);
75
+ }
76
+ else {
77
+ jsonResult = JSON.parse(responseText);
78
+ }
79
+ if (jsonResult && jsonResult.verification) {
80
+ verificationResult = jsonResult.verification;
81
+ }
82
+ else {
83
+ throw new Error('Invalid verification JSON structure');
84
+ }
85
+ }
86
+ catch (error) {
87
+ logError(`Failed to parse verification result: ${error}`);
88
+ // Return default "uncertain" result
89
+ verificationResult = createUncertainVerificationResult(checklistContext, 'Failed to parse verification response');
90
+ }
91
+ }
92
+ else {
93
+ logError(`\nāš ļø Verification incomplete: ${message.subtype}`);
94
+ verificationResult = createUncertainVerificationResult(checklistContext, `Verification incomplete: ${message.subtype}`);
95
+ }
96
+ }
97
+ }
98
+ if (!verificationResult) {
99
+ verificationResult = createUncertainVerificationResult(checklistContext, 'No verification result received');
100
+ }
101
+ if (verbose) {
102
+ logInfo('\nšŸ“Š Verification Summary:');
103
+ logInfo(` Total items: ${verificationResult.total_items}`);
104
+ logInfo(` āœ… Confirmed: ${verificationResult.confirmed_count}`);
105
+ logInfo(` āŒ Rejected: ${verificationResult.rejected_count}`);
106
+ logInfo(` āš ļø Uncertain: ${verificationResult.uncertain_count}`);
107
+ logInfo(` Summary: ${verificationResult.summary}`);
108
+ if (verificationResult.rejected_count > 0) {
109
+ logInfo('\nāŒ Rejected items:');
110
+ verificationResult.item_verifications
111
+ .filter((v) => v.verification_status === 'rejected')
112
+ .forEach((v) => {
113
+ logInfo(` - ${v.checklist_item_id}`);
114
+ logInfo(` Reason: ${v.verification_reason}`);
115
+ });
116
+ }
117
+ }
118
+ return verificationResult;
119
+ }
120
+ catch (error) {
121
+ logError(`Checklist verification failed: ${error instanceof Error ? error.message : String(error)}`);
122
+ return createUncertainVerificationResult(checklistContext, `Verification error: ${error instanceof Error ? error.message : String(error)}`);
123
+ }
124
+ }
125
+ /**
126
+ * Create a default "uncertain" verification result when verification fails
127
+ */
128
+ function createUncertainVerificationResult(checklistContext, reason) {
129
+ // Get all checklist items
130
+ const allItems = checklistContext.checklists.flatMap((checklist) => checklist.items.map((item) => ({
131
+ checklist_item_id: item.id,
132
+ })));
133
+ return {
134
+ all_verified: false,
135
+ total_items: allItems.length,
136
+ confirmed_count: 0,
137
+ rejected_count: 0,
138
+ uncertain_count: allItems.length,
139
+ item_verifications: allItems.map((item) => ({
140
+ checklist_item_id: item.checklist_item_id,
141
+ is_satisfied: false,
142
+ verification_status: 'uncertain',
143
+ verification_reason: reason,
144
+ })),
145
+ summary: `Verification could not be completed: ${reason}`,
146
+ };
147
+ }
@@ -55,7 +55,8 @@ const switchToMainBranch = (mainBranch = 'main', verbose) => {
55
55
  const generatePRTitle = (featureName) => {
56
56
  // Remove feature ID prefix if present (e.g., "FEAT-123: Feature Name" -> "Feature Name")
57
57
  const cleanName = featureName.replace(/^[A-Z]+-\d+:\s*/, '');
58
- return `feat: ${cleanName}`;
58
+ // Convert to lowercase for conventional commits format
59
+ return `feat: ${cleanName.toLowerCase()}`;
59
60
  };
60
61
  /**
61
62
  * Generate pull request body with feature details
@@ -0,0 +1,37 @@
1
+ import { EdsgerConfig } from '../../types/index.js';
2
+ import { ChecklistPhaseContext } from '../../services/checklist.js';
3
+ import { type ChecklistVerificationResult } from '../technical-design-verification/index.js';
4
+ export interface TechnicalDesignResult {
5
+ featureId: string;
6
+ technicalDesign: string | null;
7
+ status: 'success' | 'error';
8
+ summary: string;
9
+ verificationResult?: ChecklistVerificationResult;
10
+ iterations?: number;
11
+ data?: {
12
+ checklist_item_results?: any[];
13
+ [key: string]: any;
14
+ };
15
+ }
16
+ interface VerificationCycleResult {
17
+ passed: boolean;
18
+ verificationResult: ChecklistVerificationResult | null;
19
+ nextPrompt?: string;
20
+ }
21
+ /**
22
+ * Perform verification and determine if iteration should continue
23
+ */
24
+ export declare function performVerificationCycle(technicalDesign: string, checklistContext: ChecklistPhaseContext | null, featureId: string, featureName: string, featureDescription: string | undefined, config: EdsgerConfig, currentIteration: number, maxIterations: number, mcpServerUrl: string, mcpToken: string, verbose?: boolean): Promise<VerificationCycleResult>;
25
+ /**
26
+ * Build successful design result
27
+ */
28
+ export declare function buildDesignResult(featureId: string, technicalDesign: string, summary: string, iterations: number, checklistItemResults?: any[]): TechnicalDesignResult;
29
+ /**
30
+ * Build verification failure result
31
+ */
32
+ export declare function buildVerificationFailureResult(featureId: string, technicalDesign: string, verificationResult: ChecklistVerificationResult, iterations: number): TechnicalDesignResult;
33
+ /**
34
+ * Build error result when no design was generated
35
+ */
36
+ export declare function buildNoResultsError(featureId: string): TechnicalDesignResult;
37
+ export {};