edsger 0.26.0 → 0.26.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/.claude/settings.local.json +28 -0
- package/.env.local +12 -0
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
- package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
- package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
- package/dist/commands/workflow/config/phase-configs.js +5 -0
- package/dist/commands/workflow/executors/phase-executor.d.ts +2 -2
- package/dist/commands/workflow/executors/phase-executor.js +2 -2
- package/dist/commands/workflow/feature-coordinator.js +3 -1
- package/dist/commands/workflow/phase-orchestrator.js +66 -3
- package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
- package/dist/commands/workflow/pipeline-runner.js +393 -0
- package/dist/commands/workflow/runner.d.ts +26 -0
- package/dist/commands/workflow/runner.js +119 -0
- package/dist/commands/workflow/workflow-runner.d.ts +26 -0
- package/dist/commands/workflow/workflow-runner.js +119 -0
- package/dist/config/feature-status.js +3 -0
- package/dist/index.js +0 -0
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +32 -0
- package/dist/phases/code-implementation/analyzer.js +629 -0
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
- package/dist/phases/code-implementation/mcp-server.js +93 -0
- package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
- package/dist/phases/code-implementation/prompts-improvement.js +108 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/code-refine/analyzer.d.ts +41 -0
- package/dist/phases/code-refine/analyzer.js +561 -0
- package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
- package/dist/phases/code-refine/context-fetcher.js +423 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
- package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
- package/dist/phases/code-refine-verification/verifier.js +597 -0
- package/dist/phases/code-review/analyzer.d.ts +29 -0
- package/dist/phases/code-review/analyzer.js +363 -0
- package/dist/phases/code-review/context-fetcher.d.ts +92 -0
- package/dist/phases/code-review/context-fetcher.js +296 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
- package/dist/phases/feature-analysis/analyzer.js +208 -0
- package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
- package/dist/phases/feature-analysis/context-fetcher.js +134 -0
- package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
- package/dist/phases/feature-analysis/http-fallback.js +95 -0
- package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
- package/dist/phases/feature-analysis/mcp-server.js +144 -0
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
- package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/pr-execution/context.d.ts +26 -0
- package/dist/phases/pr-execution/context.js +156 -0
- package/dist/phases/pr-execution/index.d.ts +20 -0
- package/dist/phases/pr-execution/index.js +287 -0
- package/dist/phases/pr-execution/outcome.d.ts +26 -0
- package/dist/phases/pr-execution/outcome.js +34 -0
- package/dist/phases/pr-execution/pr-executor.d.ts +28 -0
- package/dist/phases/pr-execution/pr-executor.js +152 -0
- package/dist/phases/pr-execution/prompts.d.ts +17 -0
- package/dist/phases/pr-execution/prompts.js +208 -0
- package/dist/phases/pr-splitting/context.d.ts +16 -2
- package/dist/phases/pr-splitting/context.js +127 -4
- package/dist/phases/pr-splitting/index.d.ts +7 -0
- package/dist/phases/pr-splitting/index.js +58 -52
- package/dist/phases/pr-splitting/prompts.d.ts +4 -4
- package/dist/phases/pr-splitting/prompts.js +42 -30
- package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
- package/dist/phases/technical-design/analyzer-helpers.js +39 -0
- package/dist/phases/technical-design/analyzer.d.ts +21 -0
- package/dist/phases/technical-design/analyzer.js +461 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/phases/technical-design/http-fallback.d.ts +17 -0
- package/dist/phases/technical-design/http-fallback.js +151 -0
- package/dist/phases/technical-design/mcp-server.d.ts +1 -0
- package/dist/phases/technical-design/mcp-server.js +157 -0
- package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
- package/dist/phases/technical-design/prompts-improvement.js +93 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
- package/dist/phases/technical-design-verification/verifier.js +170 -0
- package/dist/services/audit-logs.d.ts +2 -2
- package/dist/services/feature-branches.d.ts +77 -0
- package/dist/services/feature-branches.js +205 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/pipeline.d.ts +1 -1
- package/dist/utils/github-repo-info.d.ts +14 -0
- package/dist/utils/github-repo-info.js +19 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +120 -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/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 +248 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +119 -0
- package/dist/workflow-runner/index.d.ts +2 -0
- package/dist/workflow-runner/index.js +2 -0
- package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
- package/dist/workflow-runner/pipeline-runner.js +393 -0
- package/dist/workflow-runner/workflow-processor.d.ts +54 -0
- package/dist/workflow-runner/workflow-processor.js +170 -0
- package/package.json +1 -1
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- package/dist/services/lifecycle-agent/types.js +0 -12
|
@@ -17,6 +17,13 @@ async function* prompt(analysisPrompt) {
|
|
|
17
17
|
yield userMessage(analysisPrompt);
|
|
18
18
|
await new Promise((res) => setTimeout(res, 10000));
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* PR Splitting Phase: Analyze diff and create PR split plan
|
|
22
|
+
*
|
|
23
|
+
* This phase analyzes the actual code diff between dev/{featureId} and main,
|
|
24
|
+
* then uses AI to produce a PR split plan saved to the database.
|
|
25
|
+
* Human review is expected before running the pr-execution phase.
|
|
26
|
+
*/
|
|
20
27
|
export const splitFeatureIntoPRs = async (options, config) => {
|
|
21
28
|
const { featureId, verbose, replaceExisting } = options;
|
|
22
29
|
if (verbose) {
|
|
@@ -34,8 +41,14 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
34
41
|
timestamp: new Date().toISOString(),
|
|
35
42
|
},
|
|
36
43
|
}, verbose);
|
|
37
|
-
// Fetch context
|
|
38
|
-
const context = await fetchPRSplittingContext(featureId, verbose);
|
|
44
|
+
// Fetch context (includes git diff from dev/{featureId} vs main)
|
|
45
|
+
const context = await fetchPRSplittingContext(featureId, verbose, replaceExisting);
|
|
46
|
+
if (context.changedFiles.length === 0) {
|
|
47
|
+
if (verbose) {
|
|
48
|
+
logInfo('No code changes detected between dev branch and main.');
|
|
49
|
+
}
|
|
50
|
+
return buildNoChangeResult(featureId, context.existing_pull_requests.length);
|
|
51
|
+
}
|
|
39
52
|
// Fetch feedbacks for pr-splitting phase
|
|
40
53
|
let feedbacksContext = null;
|
|
41
54
|
let hasFeedbacks = false;
|
|
@@ -54,32 +67,37 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
54
67
|
// Determine operation mode
|
|
55
68
|
const hasExistingPRs = context.existing_pull_requests.length > 0;
|
|
56
69
|
const isIncrementalUpdate = hasExistingPRs && hasFeedbacks && !replaceExisting;
|
|
57
|
-
if
|
|
58
|
-
logInfo('\n📋 PR Splitting Mode Decision:');
|
|
59
|
-
logInfo(` - Has existing PRs: ${hasExistingPRs} (${context.existing_pull_requests.length} PRs)`);
|
|
60
|
-
logInfo(` - Has feedbacks: ${hasFeedbacks} (${feedbacksContext?.feedbacks.length || 0} feedbacks)`);
|
|
61
|
-
logInfo(` - Replace existing: ${replaceExisting || false}`);
|
|
62
|
-
logInfo(` - Mode: ${isIncrementalUpdate ? '🔄 Incremental Update' : hasExistingPRs && !replaceExisting ? '✅ No Change Needed' : '✨ New Planning'}`);
|
|
63
|
-
}
|
|
64
|
-
// Check if there are existing PRs and no feedbacks - no change needed
|
|
70
|
+
// Check if existing PRs already planned and no feedback
|
|
65
71
|
if (hasExistingPRs && !hasFeedbacks && !replaceExisting) {
|
|
66
72
|
if (verbose) {
|
|
67
|
-
logInfo(`Feature already has ${context.existing_pull_requests.length} PRs planned
|
|
73
|
+
logInfo(`Feature already has ${context.existing_pull_requests.length} PRs planned. No feedbacks to address.`);
|
|
68
74
|
logInfo('Use replaceExisting: true to re-plan.');
|
|
69
75
|
}
|
|
70
76
|
return buildNoChangeResult(featureId, context.existing_pull_requests.length);
|
|
71
77
|
}
|
|
72
|
-
|
|
78
|
+
if (verbose) {
|
|
79
|
+
logInfo('\n📋 PR Splitting Mode:');
|
|
80
|
+
logInfo(` - Has existing PRs: ${hasExistingPRs}`);
|
|
81
|
+
logInfo(` - Has feedbacks: ${hasFeedbacks}`);
|
|
82
|
+
logInfo(` - Replace existing: ${replaceExisting || false}`);
|
|
83
|
+
logInfo(` - Mode: ${isIncrementalUpdate ? '🔄 Incremental Update' : '✨ New Planning'}`);
|
|
84
|
+
logInfo(` - Changed files: ${context.changedFiles.length}`);
|
|
85
|
+
}
|
|
86
|
+
// Clear existing PRs if replacing
|
|
73
87
|
if (replaceExisting && hasExistingPRs) {
|
|
74
88
|
if (verbose) {
|
|
75
89
|
logInfo(`Clearing ${context.existing_pull_requests.length} existing PRs for full re-plan...`);
|
|
76
90
|
}
|
|
77
91
|
await clearPullRequests({ featureId, verbose }, true);
|
|
78
92
|
}
|
|
79
|
-
//
|
|
93
|
+
// ==============================
|
|
94
|
+
// Diff Analysis with AI Agent
|
|
95
|
+
// ==============================
|
|
96
|
+
if (verbose) {
|
|
97
|
+
logInfo('\n🔍 Analyzing code diff with AI...');
|
|
98
|
+
}
|
|
80
99
|
const contextInfo = formatContextForPrompt(context.feature, context.product, context.existing_branches);
|
|
81
100
|
const existingPRsInfo = formatExistingPRsForPrompt(context.existing_pull_requests);
|
|
82
|
-
// Create prompts based on mode
|
|
83
101
|
const systemPrompt = createPRSplittingSystemPrompt(config, featureId);
|
|
84
102
|
let userPrompt;
|
|
85
103
|
if (isIncrementalUpdate && feedbacksContext) {
|
|
@@ -87,7 +105,6 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
87
105
|
logInfo('\n🎯 Feedbacks that will be addressed:');
|
|
88
106
|
feedbacksContext.feedbacks.forEach((fb, idx) => {
|
|
89
107
|
logInfo(` ${idx + 1}. [${fb.feedback_type}] ${fb.title}`);
|
|
90
|
-
logInfo(` ${fb.content.substring(0, 100)}${fb.content.length > 100 ? '...' : ''}`);
|
|
91
108
|
});
|
|
92
109
|
}
|
|
93
110
|
const feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
|
|
@@ -96,39 +113,40 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
96
113
|
userPrompt = `${userPrompt}\n\n## Feature Context\n\n${contextInfo}`;
|
|
97
114
|
}
|
|
98
115
|
else {
|
|
99
|
-
userPrompt = createPRSplittingPromptWithContext(featureId, contextInfo, existingPRsInfo);
|
|
100
|
-
}
|
|
101
|
-
if (verbose) {
|
|
102
|
-
logInfo('Starting Claude Code query for PR splitting...');
|
|
116
|
+
userPrompt = createPRSplittingPromptWithContext(featureId, contextInfo, existingPRsInfo, context.diffStat, context.changedFiles);
|
|
103
117
|
}
|
|
104
|
-
// Execute query
|
|
105
|
-
const result = await
|
|
118
|
+
// Execute agent query
|
|
119
|
+
const result = await executeAgentQuery(userPrompt, systemPrompt, config, verbose);
|
|
106
120
|
if (!result ||
|
|
107
121
|
!result.pullRequests ||
|
|
108
122
|
result.pullRequests.length === 0) {
|
|
109
|
-
|
|
110
|
-
logError(errorMsg);
|
|
111
|
-
return buildErrorResult(featureId, errorMsg);
|
|
123
|
+
return buildErrorResult(featureId, 'No pull requests were generated');
|
|
112
124
|
}
|
|
113
125
|
// Validate PRs
|
|
114
126
|
const validation = validatePlannedPRs(result.pullRequests);
|
|
115
127
|
if (!validation.valid) {
|
|
116
|
-
|
|
117
|
-
logError(errorMsg);
|
|
118
|
-
return buildErrorResult(featureId, errorMsg);
|
|
128
|
+
return buildErrorResult(featureId, `Invalid PR plan: ${validation.errors.join(', ')}`);
|
|
119
129
|
}
|
|
120
|
-
// Sort PRs by dependency
|
|
121
130
|
const sortedPRs = sortPRsByDependency(result.pullRequests);
|
|
122
|
-
|
|
131
|
+
if (verbose) {
|
|
132
|
+
logInfo(`\n✅ ${sortedPRs.length} PRs planned:`);
|
|
133
|
+
sortedPRs.forEach((pr) => {
|
|
134
|
+
logInfo(` ${pr.sequence}. ${pr.name} (${pr.branch_name})`);
|
|
135
|
+
if (pr.files) {
|
|
136
|
+
logInfo(` Files: ${pr.files.map((f) => f.path).join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// Clear existing PRs for incremental update before creating new ones
|
|
123
141
|
if (isIncrementalUpdate && hasExistingPRs) {
|
|
124
142
|
if (verbose) {
|
|
125
|
-
logInfo(`🔄 Clearing
|
|
143
|
+
logInfo(`🔄 Clearing existing PRs for incremental update...`);
|
|
126
144
|
}
|
|
127
145
|
await clearPullRequests({ featureId, verbose: false }, true);
|
|
128
146
|
}
|
|
129
|
-
//
|
|
130
|
-
const prBranchNameToId = new Map();
|
|
147
|
+
// Save PR plan to database
|
|
131
148
|
const prInputs = [];
|
|
149
|
+
const prBranchNameToId = new Map();
|
|
132
150
|
for (const pr of sortedPRs) {
|
|
133
151
|
let basePrId;
|
|
134
152
|
if (pr.depends_on_branch_name) {
|
|
@@ -143,22 +161,14 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
143
161
|
files: pr.files,
|
|
144
162
|
});
|
|
145
163
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
created.forEach((createdPR) => {
|
|
164
|
+
const createdPRRecords = await createPullRequests({ featureId, verbose: false }, prInputs);
|
|
165
|
+
createdPRRecords.forEach((createdPR) => {
|
|
149
166
|
if (createdPR.branch_name) {
|
|
150
167
|
prBranchNameToId.set(createdPR.branch_name, createdPR.id);
|
|
151
168
|
}
|
|
152
169
|
});
|
|
153
170
|
if (verbose) {
|
|
154
|
-
|
|
155
|
-
logInfo(`${modeLabel} ${sortedPRs.length} pull requests`);
|
|
156
|
-
sortedPRs.forEach((pr) => {
|
|
157
|
-
logInfo(` ${pr.sequence}. ${pr.name}`);
|
|
158
|
-
if (pr.files) {
|
|
159
|
-
logInfo(` Files: ${pr.files.map((f) => f.path).join(', ')}`);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
171
|
+
logInfo(`\n📝 Saved ${createdPRRecords.length} PR records to database. Awaiting human review before execution.`);
|
|
162
172
|
}
|
|
163
173
|
// Log phase completion
|
|
164
174
|
await logFeaturePhaseEvent({
|
|
@@ -167,23 +177,19 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
167
177
|
phase: 'pr_splitting',
|
|
168
178
|
result: 'success',
|
|
169
179
|
metadata: {
|
|
170
|
-
|
|
180
|
+
prs_planned: sortedPRs.length,
|
|
171
181
|
pr_names: sortedPRs.map((pr) => pr.name),
|
|
172
182
|
mode: isIncrementalUpdate ? 'incremental_update' : 'new_planning',
|
|
173
183
|
feedbacks_addressed: feedbacksContext?.feedbacks.length || 0,
|
|
174
184
|
timestamp: new Date().toISOString(),
|
|
175
185
|
},
|
|
176
186
|
}, verbose);
|
|
177
|
-
const summaryPrefix = isIncrementalUpdate
|
|
178
|
-
? `Updated PR plan based on ${feedbacksContext?.feedbacks.length || 0} feedbacks.`
|
|
179
|
-
: '';
|
|
180
187
|
return buildSuccessResult(featureId, sortedPRs, result.summary ||
|
|
181
|
-
|
|
188
|
+
`Split feature into ${sortedPRs.length} pull requests for review`, result.rationale);
|
|
182
189
|
}
|
|
183
190
|
catch (error) {
|
|
184
191
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
185
192
|
logError(`PR splitting failed: ${errorMessage}`);
|
|
186
|
-
// Log phase failure
|
|
187
193
|
await logFeaturePhaseEvent({
|
|
188
194
|
featureId,
|
|
189
195
|
eventType: 'phase_failed',
|
|
@@ -198,9 +204,9 @@ export const splitFeatureIntoPRs = async (options, config) => {
|
|
|
198
204
|
}
|
|
199
205
|
};
|
|
200
206
|
/**
|
|
201
|
-
* Execute
|
|
207
|
+
* Execute an agent query and parse the result
|
|
202
208
|
*/
|
|
203
|
-
async function
|
|
209
|
+
async function executeAgentQuery(userPrompt, systemPrompt, config, verbose) {
|
|
204
210
|
let lastAssistantResponse = '';
|
|
205
211
|
let structuredResult = null;
|
|
206
212
|
if (verbose) {
|
|
@@ -245,7 +251,7 @@ async function executePRSplittingQuery(userPrompt, systemPrompt, config, verbose
|
|
|
245
251
|
structuredResult = parseJsonResponse(responseText, verbose);
|
|
246
252
|
}
|
|
247
253
|
catch (error) {
|
|
248
|
-
logError(`Failed to parse
|
|
254
|
+
logError(`Failed to parse result: ${error}`);
|
|
249
255
|
}
|
|
250
256
|
}
|
|
251
257
|
else {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { EdsgerConfig } from '../../types/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Create the system prompt for PR splitting
|
|
3
|
+
* Create the system prompt for PR splitting: Diff analysis and PR planning
|
|
4
4
|
*/
|
|
5
5
|
export declare function createPRSplittingSystemPrompt(config: EdsgerConfig, featureId: string): string;
|
|
6
6
|
/**
|
|
7
|
-
* Create the user prompt with context for PR splitting
|
|
7
|
+
* Create the user prompt with diff context for PR splitting
|
|
8
8
|
*/
|
|
9
|
-
export declare function createPRSplittingPromptWithContext(featureId: string, contextInfo: string, existingPRsInfo: string): string;
|
|
9
|
+
export declare function createPRSplittingPromptWithContext(featureId: string, contextInfo: string, existingPRsInfo: string, diffStat: string, changedFiles: string[]): string;
|
|
10
10
|
/**
|
|
11
11
|
* Format the context information for the prompt
|
|
12
12
|
*/
|
|
@@ -38,6 +38,6 @@ export declare function formatExistingPRsForPrompt(pullRequests: Array<{
|
|
|
38
38
|
}> | null;
|
|
39
39
|
}>): string;
|
|
40
40
|
/**
|
|
41
|
-
* Create improvement prompt for re-planning
|
|
41
|
+
* Create improvement prompt for re-planning based on feedback
|
|
42
42
|
*/
|
|
43
43
|
export declare function createImprovementPrompt(feedback: string, currentPlan: string): string;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Create the system prompt for PR splitting
|
|
2
|
+
* Create the system prompt for PR splitting: Diff analysis and PR planning
|
|
3
3
|
*/
|
|
4
4
|
export function createPRSplittingSystemPrompt(config, featureId) {
|
|
5
|
-
return `You are an expert software architect specialized in splitting
|
|
5
|
+
return `You are an expert software architect specialized in splitting feature implementations into multiple smaller, reviewable pull requests.
|
|
6
6
|
|
|
7
|
-
Your task is to analyze the
|
|
7
|
+
Your task is to analyze the actual code changes on the \`dev/${featureId}\` branch compared to \`main\` and create a plan to split them into multiple logical PRs.
|
|
8
|
+
|
|
9
|
+
## Your Environment
|
|
10
|
+
|
|
11
|
+
You have full access to the repository. You can:
|
|
12
|
+
- Run \`git diff main...dev/${featureId}\` to see all changes
|
|
13
|
+
- Run \`git diff main...dev/${featureId} -- <path>\` to see changes for specific files
|
|
14
|
+
- Read any file in the repository to understand context
|
|
15
|
+
- Run \`git log main...dev/${featureId} --oneline\` to see commit history
|
|
8
16
|
|
|
9
17
|
## Key Principles
|
|
10
18
|
|
|
@@ -13,16 +21,15 @@ Your task is to analyze the completed code on the feature branch and split it in
|
|
|
13
21
|
3. **Dependency Order**: PRs should be ordered so each one builds on the previous (database first, then API, then UI)
|
|
14
22
|
4. **Independent Testability**: Each PR should not break the build when merged independently in order
|
|
15
23
|
5. **Clear Boundaries**: Each PR should have clear scope — one concern per PR
|
|
24
|
+
6. **Module-Based Splitting**: Split by module/domain, not just by layer. If a feature touches auth, payments, and notifications — those are separate PRs even if they're all "backend"
|
|
16
25
|
|
|
17
26
|
## PR Branch Naming Convention
|
|
18
27
|
|
|
19
|
-
Branch names
|
|
20
|
-
- \`pr
|
|
21
|
-
- \`pr
|
|
28
|
+
Branch names MUST follow this pattern:
|
|
29
|
+
- \`pr/${featureId}/1-{short-description}\`
|
|
30
|
+
- \`pr/${featureId}/2-{short-description}\`
|
|
22
31
|
- etc.
|
|
23
32
|
|
|
24
|
-
Feature ID for this feature: ${featureId}
|
|
25
|
-
|
|
26
33
|
## Output Format
|
|
27
34
|
|
|
28
35
|
You MUST respond with a valid JSON object in this exact format:
|
|
@@ -57,72 +64,77 @@ You MUST respond with a valid JSON object in this exact format:
|
|
|
57
64
|
## PR Dependencies
|
|
58
65
|
|
|
59
66
|
Use \`depends_on_branch_name\` to specify which PR must be merged before this one:
|
|
60
|
-
- First PR: \`"depends_on_branch_name": null\` (merges to main
|
|
67
|
+
- First PR: \`"depends_on_branch_name": null\` (merges directly to main)
|
|
61
68
|
- Subsequent PRs: \`"depends_on_branch_name": "pr/${featureId}/1-database"\` (depends on previous PR)
|
|
62
69
|
|
|
63
70
|
## File Assignment Guidelines
|
|
64
71
|
|
|
65
72
|
- **Database migrations and schema**: First PR
|
|
66
73
|
- **Types and interfaces**: Can go with the PR that introduces them, or in a foundational PR
|
|
67
|
-
- **Backend services and API routes**: Middle PRs
|
|
68
|
-
- **Frontend components**: Later PRs that depend on backend
|
|
74
|
+
- **Backend services and API routes**: Middle PRs, split by module/domain
|
|
75
|
+
- **Frontend components**: Later PRs that depend on backend, split by feature area
|
|
69
76
|
- **Tests**: Include with the code they test
|
|
70
77
|
- **Configuration files**: Group with the feature they configure
|
|
71
78
|
|
|
72
79
|
## Handling Existing PRs During Re-sync
|
|
73
80
|
|
|
74
81
|
When existing PRs are provided, respect their status:
|
|
75
|
-
|
|
76
|
-
- **
|
|
77
|
-
|
|
78
|
-
- **pending / branch_created / pr_opened / in_review / approved**: These can be updated — you may reassign files, update descriptions, or adjust scope.
|
|
79
|
-
- When creating new PRs to accommodate changes that can't go into merged/closed PRs, use the next available sequence number.
|
|
82
|
+
- **merged / closed**: NEVER modify these PRs. Do not reassign their files.
|
|
83
|
+
- **pending / branch_created / pr_opened / in_review / approved**: These can be updated.
|
|
84
|
+
- When creating new PRs to accommodate changes, use the next available sequence number.
|
|
80
85
|
|
|
81
86
|
## Important Notes
|
|
82
87
|
|
|
83
88
|
- Every changed file must be assigned to exactly one PR
|
|
84
89
|
- If the feature is small enough, a single PR is fine
|
|
85
90
|
- Consider the reviewer's perspective: each PR should tell a coherent story
|
|
86
|
-
- Database migrations should be in the earliest PR possible
|
|
91
|
+
- Database migrations should be in the earliest PR possible
|
|
92
|
+
- Analyze the ACTUAL diff, not just file names — understand what the changes do`;
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
89
|
-
* Create the user prompt with context for PR splitting
|
|
95
|
+
* Create the user prompt with diff context for PR splitting
|
|
90
96
|
*/
|
|
91
|
-
export function createPRSplittingPromptWithContext(featureId, contextInfo, existingPRsInfo) {
|
|
97
|
+
export function createPRSplittingPromptWithContext(featureId, contextInfo, existingPRsInfo, diffStat, changedFiles) {
|
|
92
98
|
let prompt = `# PR Splitting Task
|
|
93
99
|
|
|
94
|
-
Please analyze the
|
|
100
|
+
Please analyze the actual code changes on the \`dev/${featureId}\` branch and create a plan to split them into multiple smaller PRs for review.
|
|
95
101
|
|
|
96
102
|
## Feature Context
|
|
97
103
|
|
|
98
104
|
${contextInfo}
|
|
99
105
|
|
|
106
|
+
## Code Changes Summary
|
|
107
|
+
|
|
108
|
+
### Diff Stat
|
|
109
|
+
\`\`\`
|
|
110
|
+
${diffStat || 'No changes detected'}
|
|
111
|
+
\`\`\`
|
|
112
|
+
|
|
113
|
+
### Changed Files (${changedFiles.length} files)
|
|
114
|
+
${changedFiles.map((f) => `- ${f}`).join('\n') || 'No files changed'}
|
|
115
|
+
|
|
100
116
|
`;
|
|
101
117
|
if (existingPRsInfo) {
|
|
102
118
|
prompt += `## Existing Pull Requests
|
|
103
119
|
|
|
104
120
|
${existingPRsInfo}
|
|
105
121
|
|
|
106
|
-
**Note**:
|
|
122
|
+
**Note**: Merged/closed PRs are frozen — do not modify them or reassign their files.
|
|
107
123
|
|
|
108
124
|
`;
|
|
109
125
|
}
|
|
110
126
|
prompt += `## Your Task
|
|
111
127
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
1. **Analyze all changed files**: Understand what was implemented
|
|
115
|
-
2. **Identify logical groupings**: Find files that change together for the same reason
|
|
128
|
+
1. **Examine the actual diff**: Run \`git diff main...dev/${featureId}\` or targeted diffs for specific files to understand what changed
|
|
129
|
+
2. **Identify logical groupings**: Find files that change together for the same reason, considering module boundaries
|
|
116
130
|
3. **Determine dependencies**: Figure out which groups must be merged first
|
|
117
131
|
4. **Create PR plan**: Define PRs with clear scope, file assignments, and acceptance criteria
|
|
118
132
|
|
|
119
|
-
Please provide your PR splitting plan as a JSON response following the format specified in the system prompt.
|
|
120
|
-
|
|
121
133
|
**Remember**:
|
|
122
134
|
- Every changed file must be assigned to exactly one PR
|
|
123
135
|
- Smaller, focused PRs are better than large ones
|
|
124
|
-
-
|
|
125
|
-
-
|
|
136
|
+
- Split by module/domain, not just by layer
|
|
137
|
+
- Order PRs by their dependencies`;
|
|
126
138
|
return prompt;
|
|
127
139
|
}
|
|
128
140
|
/**
|
|
@@ -181,7 +193,7 @@ export function formatExistingPRsForPrompt(pullRequests) {
|
|
|
181
193
|
return result;
|
|
182
194
|
}
|
|
183
195
|
/**
|
|
184
|
-
* Create improvement prompt for re-planning
|
|
196
|
+
* Create improvement prompt for re-planning based on feedback
|
|
185
197
|
*/
|
|
186
198
|
export function createImprovementPrompt(feedback, currentPlan) {
|
|
187
199
|
return `# PR Splitting Improvement
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ChecklistVerificationResult } from '../technical-design-verification/agent.js';
|
|
2
|
+
export interface TechnicalDesignResult {
|
|
3
|
+
featureId: string;
|
|
4
|
+
technicalDesign: string | null;
|
|
5
|
+
status: 'success' | 'error';
|
|
6
|
+
summary: string;
|
|
7
|
+
verificationResult?: ChecklistVerificationResult;
|
|
8
|
+
iterations?: number;
|
|
9
|
+
data?: {
|
|
10
|
+
checklist_item_results?: any[];
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build successful design result
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildDesignResult(featureId: string, technicalDesign: string, summary: string, iterations: number, checklistItemResults?: any[]): TechnicalDesignResult;
|
|
18
|
+
/**
|
|
19
|
+
* Build verification failure result
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildVerificationFailureResult(featureId: string, technicalDesign: string, verificationResult: ChecklistVerificationResult, iterations: number): TechnicalDesignResult;
|
|
22
|
+
/**
|
|
23
|
+
* Build error result when no design was generated
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildNoResultsError(featureId: string): TechnicalDesignResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build successful design result
|
|
3
|
+
*/
|
|
4
|
+
export function buildDesignResult(featureId, technicalDesign, summary, iterations, checklistItemResults) {
|
|
5
|
+
return {
|
|
6
|
+
featureId,
|
|
7
|
+
technicalDesign,
|
|
8
|
+
status: 'success',
|
|
9
|
+
summary,
|
|
10
|
+
iterations,
|
|
11
|
+
data: checklistItemResults
|
|
12
|
+
? { checklist_item_results: checklistItemResults }
|
|
13
|
+
: undefined,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build verification failure result
|
|
18
|
+
*/
|
|
19
|
+
export function buildVerificationFailureResult(featureId, technicalDesign, verificationResult, iterations) {
|
|
20
|
+
return {
|
|
21
|
+
featureId,
|
|
22
|
+
technicalDesign,
|
|
23
|
+
status: 'error',
|
|
24
|
+
summary: `Checklist verification failed after ${iterations} iterations: ${verificationResult.summary}`,
|
|
25
|
+
verificationResult,
|
|
26
|
+
iterations,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build error result when no design was generated
|
|
31
|
+
*/
|
|
32
|
+
export function buildNoResultsError(featureId) {
|
|
33
|
+
return {
|
|
34
|
+
featureId,
|
|
35
|
+
technicalDesign: null,
|
|
36
|
+
status: 'error',
|
|
37
|
+
summary: 'Failed to generate technical design - no valid result received',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
import { ChecklistPhaseContext } from '../../services/checklist.js';
|
|
3
|
+
export interface TechnicalDesignOptions {
|
|
4
|
+
featureId: string;
|
|
5
|
+
verbose?: boolean;
|
|
6
|
+
maxVerificationIterations?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TechnicalDesignResult {
|
|
9
|
+
featureId: string;
|
|
10
|
+
technicalDesign: string | null;
|
|
11
|
+
status: 'success' | 'error';
|
|
12
|
+
summary: string;
|
|
13
|
+
verificationResult?: any;
|
|
14
|
+
iterations?: number;
|
|
15
|
+
savedViaHttp?: boolean;
|
|
16
|
+
data?: {
|
|
17
|
+
checklist_item_results?: any[];
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare const generateTechnicalDesign: (options: TechnicalDesignOptions, config: EdsgerConfig, checklistContext?: ChecklistPhaseContext | null) => Promise<TechnicalDesignResult>;
|