edsger 0.19.2 ā 0.19.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.
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
2
2
|
import { logInfo, logError } from '../../utils/logger.js';
|
|
3
3
|
import { fetchBranchPlanningContext } from './context.js';
|
|
4
|
-
import { createBranchPlanningSystemPrompt, createBranchPlanningPromptWithContext, formatContextForPrompt, formatExistingBranchesForPrompt, } from './prompts.js';
|
|
4
|
+
import { createBranchPlanningSystemPrompt, createBranchPlanningPromptWithContext, createImprovementPrompt, formatContextForPrompt, formatExistingBranchesForPrompt, } from './prompts.js';
|
|
5
5
|
import { buildSuccessResult, buildErrorResult, buildNoChangeResult, validatePlannedBranches, sortBranchesByDependency, } from './outcome.js';
|
|
6
6
|
import { createFeatureBranches, clearFeatureBranches, } from '../../services/feature-branches.js';
|
|
7
7
|
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
8
|
+
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
8
9
|
function userMessage(content) {
|
|
9
10
|
return {
|
|
10
11
|
type: 'user',
|
|
@@ -34,27 +35,71 @@ export const planFeatureBranches = async (options, config) => {
|
|
|
34
35
|
}, verbose);
|
|
35
36
|
// Fetch context
|
|
36
37
|
const context = await fetchBranchPlanningContext(featureId, verbose);
|
|
37
|
-
//
|
|
38
|
-
|
|
38
|
+
// Fetch feedbacks for branch_planning phase
|
|
39
|
+
let feedbacksContext = null;
|
|
40
|
+
let hasFeedbacks = false;
|
|
41
|
+
try {
|
|
42
|
+
feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'branch-planning');
|
|
43
|
+
hasFeedbacks = feedbacksContext.feedbacks.length > 0;
|
|
44
|
+
if (verbose) {
|
|
45
|
+
logInfo(`š Feedbacks fetched: ${feedbacksContext.feedbacks.length} feedbacks found`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (verbose) {
|
|
50
|
+
logError(`Failed to fetch feedbacks: ${error instanceof Error ? error.message : String(error)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Determine operation mode
|
|
54
|
+
const hasExistingBranches = context.existing_branches.length > 0;
|
|
55
|
+
const isIncrementalUpdate = hasExistingBranches && hasFeedbacks && !replaceExisting;
|
|
56
|
+
if (verbose) {
|
|
57
|
+
logInfo('\nš Branch Planning Mode Decision:');
|
|
58
|
+
logInfo(` - Has existing branches: ${hasExistingBranches} (${context.existing_branches.length} branches)`);
|
|
59
|
+
logInfo(` - Has feedbacks: ${hasFeedbacks} (${feedbacksContext?.feedbacks.length || 0} feedbacks)`);
|
|
60
|
+
logInfo(` - Replace existing: ${replaceExisting || false}`);
|
|
61
|
+
logInfo(` - Mode: ${isIncrementalUpdate ? 'š Incremental Update' : hasExistingBranches && !replaceExisting ? 'ā
No Change Needed' : '⨠New Planning'}`);
|
|
62
|
+
}
|
|
63
|
+
// Check if there are existing branches and no feedbacks - no change needed
|
|
64
|
+
if (hasExistingBranches && !hasFeedbacks && !replaceExisting) {
|
|
39
65
|
if (verbose) {
|
|
40
|
-
logInfo(`Feature already has ${context.existing_branches.length} branches planned.`);
|
|
66
|
+
logInfo(`Feature already has ${context.existing_branches.length} branches planned and no feedbacks to address.`);
|
|
41
67
|
logInfo('Use replaceExisting: true to re-plan.');
|
|
42
68
|
}
|
|
43
69
|
return buildNoChangeResult(featureId, context.existing_branches.length);
|
|
44
70
|
}
|
|
45
|
-
// Clear existing branches if requested
|
|
46
|
-
if (replaceExisting &&
|
|
71
|
+
// Clear existing branches if requested (full re-plan)
|
|
72
|
+
if (replaceExisting && hasExistingBranches) {
|
|
47
73
|
if (verbose) {
|
|
48
|
-
logInfo(`Clearing ${context.existing_branches.length} existing branches...`);
|
|
74
|
+
logInfo(`Clearing ${context.existing_branches.length} existing branches for full re-plan...`);
|
|
49
75
|
}
|
|
50
76
|
await clearFeatureBranches({ featureId, verbose }, true);
|
|
51
77
|
}
|
|
52
78
|
// Format context for prompt
|
|
53
79
|
const contextInfo = formatContextForPrompt(context.feature, context.product, context.user_stories, context.test_cases);
|
|
54
80
|
const existingBranchesInfo = formatExistingBranchesForPrompt(context.existing_branches);
|
|
55
|
-
// Create prompts
|
|
81
|
+
// Create prompts based on mode
|
|
56
82
|
const systemPrompt = createBranchPlanningSystemPrompt(config, featureId);
|
|
57
|
-
|
|
83
|
+
let userPrompt;
|
|
84
|
+
if (isIncrementalUpdate && feedbacksContext) {
|
|
85
|
+
// Incremental update mode: adjust existing branches based on feedbacks
|
|
86
|
+
if (verbose) {
|
|
87
|
+
logInfo('\nšÆ Feedbacks that will be addressed:');
|
|
88
|
+
feedbacksContext.feedbacks.forEach((fb, idx) => {
|
|
89
|
+
logInfo(` ${idx + 1}. [${fb.feedback_type}] ${fb.title}`);
|
|
90
|
+
logInfo(` ${fb.content.substring(0, 100)}${fb.content.length > 100 ? '...' : ''}`);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
|
|
94
|
+
const currentPlanInfo = existingBranchesInfo || 'No existing branch plan documented.';
|
|
95
|
+
userPrompt = createImprovementPrompt(feedbacksInfo, currentPlanInfo);
|
|
96
|
+
// Add context info to the improvement prompt
|
|
97
|
+
userPrompt = `${userPrompt}\n\n## Feature Context\n\n${contextInfo}`;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// New planning mode
|
|
101
|
+
userPrompt = createBranchPlanningPromptWithContext(featureId, contextInfo, existingBranchesInfo);
|
|
102
|
+
}
|
|
58
103
|
if (verbose) {
|
|
59
104
|
logInfo('Starting Claude Code query for branch planning...');
|
|
60
105
|
}
|
|
@@ -74,6 +119,14 @@ export const planFeatureBranches = async (options, config) => {
|
|
|
74
119
|
}
|
|
75
120
|
// Sort branches by dependency
|
|
76
121
|
const sortedBranches = sortBranchesByDependency(result.branches);
|
|
122
|
+
// For incremental update mode, clear existing branches before creating new ones
|
|
123
|
+
// This is because the AI may have reorganized the branch structure
|
|
124
|
+
if (isIncrementalUpdate && hasExistingBranches) {
|
|
125
|
+
if (verbose) {
|
|
126
|
+
logInfo(`š Clearing ${context.existing_branches.length} existing branches for incremental update...`);
|
|
127
|
+
}
|
|
128
|
+
await clearFeatureBranches({ featureId, verbose: false }, true);
|
|
129
|
+
}
|
|
77
130
|
// Create branches in database with proper dependencies
|
|
78
131
|
// We need to create them one by one to get IDs for base_branch_id
|
|
79
132
|
const createdBranches = [];
|
|
@@ -104,7 +157,8 @@ export const planFeatureBranches = async (options, config) => {
|
|
|
104
157
|
}
|
|
105
158
|
}
|
|
106
159
|
if (verbose) {
|
|
107
|
-
|
|
160
|
+
const modeLabel = isIncrementalUpdate ? 'š Updated' : 'ā
Created';
|
|
161
|
+
logInfo(`${modeLabel} ${sortedBranches.length} feature branches`);
|
|
108
162
|
sortedBranches.forEach((b, idx) => {
|
|
109
163
|
logInfo(` ${idx + 1}. ${b.name}`);
|
|
110
164
|
if (b.scope) {
|
|
@@ -121,11 +175,16 @@ export const planFeatureBranches = async (options, config) => {
|
|
|
121
175
|
metadata: {
|
|
122
176
|
branches_created: sortedBranches.length,
|
|
123
177
|
branch_names: sortedBranches.map((b) => b.name),
|
|
178
|
+
mode: isIncrementalUpdate ? 'incremental_update' : 'new_planning',
|
|
179
|
+
feedbacks_addressed: feedbacksContext?.feedbacks.length || 0,
|
|
124
180
|
timestamp: new Date().toISOString(),
|
|
125
181
|
},
|
|
126
182
|
}, verbose);
|
|
183
|
+
const summaryPrefix = isIncrementalUpdate
|
|
184
|
+
? `Updated branch plan based on ${feedbacksContext?.feedbacks.length || 0} feedbacks.`
|
|
185
|
+
: '';
|
|
127
186
|
return buildSuccessResult(featureId, sortedBranches, result.summary ||
|
|
128
|
-
|
|
187
|
+
`${summaryPrefix} ${sortedBranches.length} branches for incremental development`.trim(), result.rationale);
|
|
129
188
|
}
|
|
130
189
|
catch (error) {
|
|
131
190
|
const errorMessage = error instanceof Error ? error.message : String(error);
|