edsger 0.22.4 → 0.23.1

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.
@@ -10,6 +10,7 @@ import { writeCodeTests } from '../../../phases/code-testing/analyzer.js';
10
10
  import { refineCodeFromPRFeedback } from '../../../phases/code-refine/index.js';
11
11
  import { verifyAndResolveComments } from '../../../phases/code-refine-verification/index.js';
12
12
  import { reviewPullRequest } from '../../../phases/code-review/index.js';
13
+ import { runAutonomousDevelopment } from '../../../phases/autonomous/index.js';
13
14
  import { getGitHubConfig } from '../../../api/github.js';
14
15
  /**
15
16
  * Wrapper for code-refine phase to inject GitHub token
@@ -104,4 +105,8 @@ export const phaseConfigs = [
104
105
  name: 'code-review',
105
106
  execute: executeCodeReview,
106
107
  },
108
+ {
109
+ name: 'autonomous',
110
+ execute: runAutonomousDevelopment,
111
+ },
107
112
  ];
@@ -18,3 +18,6 @@ export declare const logAllFeaturesProcessed: () => void;
18
18
  export declare const logSkippingProcessing: (processingCount: number) => void;
19
19
  export declare const logPollingError: (error: unknown) => void;
20
20
  export declare const logProcessNextFeatureError: (error: unknown) => void;
21
+ export declare const logAutonomousIterationStart: (iteration: number, remainingHours: number) => void;
22
+ export declare const logAutonomousIterationComplete: (iteration: number, summary: string, prUrl?: string) => void;
23
+ export declare const logAutonomousPhaseComplete: (totalIterations: number, elapsedHours: number) => void;
@@ -63,3 +63,15 @@ export const logPollingError = (error) => {
63
63
  export const logProcessNextFeatureError = (error) => {
64
64
  logError(`Error in processNextFeature: ${error instanceof Error ? error.message : String(error)}`);
65
65
  };
66
+ export const logAutonomousIterationStart = (iteration, remainingHours) => {
67
+ logInfo(`🔄 Autonomous iteration ${iteration} (${remainingHours.toFixed(1)}h remaining)`);
68
+ };
69
+ export const logAutonomousIterationComplete = (iteration, summary, prUrl) => {
70
+ logSuccess(`✅ Iteration ${iteration}: ${summary}`);
71
+ if (prUrl) {
72
+ logInfo(` PR: ${prUrl}`);
73
+ }
74
+ };
75
+ export const logAutonomousPhaseComplete = (totalIterations, elapsedHours) => {
76
+ logSuccess(`🏁 Autonomous development completed: ${totalIterations} iterations in ${elapsedHours.toFixed(2)} hours`);
77
+ };
@@ -4,5 +4,5 @@
4
4
  import { EdsgerConfig } from '../../../types/index.js';
5
5
  import { PipelinePhaseOptions, PipelineResult, PhaseConfig } from '../../../types/pipeline.js';
6
6
  export declare const createPhaseRunner: (phaseConfig: PhaseConfig) => (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
7
- declare const runFeatureAnalysisPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runBranchPlanningPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefinePhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefineVerificationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeReviewPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
8
- export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
7
+ declare const runFeatureAnalysisPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runBranchPlanningPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefinePhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefineVerificationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeReviewPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runAutonomousPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
8
+ export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, runAutonomousPhase, };
@@ -262,6 +262,6 @@ export const createPhaseRunner = (phaseConfig) => async (options, config) => {
262
262
  }
263
263
  };
264
264
  // Create phase runners using the configuration
265
- const [runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase,] = phaseConfigs.map(createPhaseRunner);
265
+ const [runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, runAutonomousPhase,] = phaseConfigs.map(createPhaseRunner);
266
266
  // Export individual phase runners for granular control
267
- export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
267
+ export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, runAutonomousPhase, };
@@ -13,7 +13,7 @@ import { getFeature } from '../../api/features/get-feature.js';
13
13
  import { markWorkflowPhaseCompleted } from '../../api/features/update-feature.js';
14
14
  import { logError, logInfo, logWarning } from '../../utils/logger.js';
15
15
  import { logPhaseResult } from '../../utils/pipeline-logger.js';
16
- import { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeRefinePhase, runCodeReviewPhase, } from './executors/phase-executor.js';
16
+ import { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeRefinePhase, runCodeReviewPhase, runAutonomousPhase, } from './executors/phase-executor.js';
17
17
  /**
18
18
  * Map workflow phase names (underscore format) to phase runner functions
19
19
  * Note: code_refine includes built-in verification loop (similar to technical_design)
@@ -26,6 +26,7 @@ const PHASE_RUNNERS = {
26
26
  functional_testing: runFunctionalTestingPhase,
27
27
  code_review: runCodeReviewPhase,
28
28
  code_refine: runCodeRefinePhase,
29
+ autonomous: runAutonomousPhase,
29
30
  };
30
31
  /**
31
32
  * Get all pending phases from workflow in order
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Autonomous Development Phase
3
+ *
4
+ * Runs a time-limited loop where Claude Code SDK analyzes the codebase,
5
+ * decides the next actionable step toward the feature's objective (description),
6
+ * implements it, and commits. All iterations build on the same branch.
7
+ * A PR is created after the first iteration; subsequent pushes update it.
8
+ */
9
+ import { EdsgerConfig } from '../../types/index.js';
10
+ import { ChecklistPhaseContext } from '../../services/checklist.js';
11
+ import { PipelinePhaseOptions } from '../../types/pipeline.js';
12
+ export interface AutonomousResult {
13
+ featureId: string;
14
+ status: 'success' | 'error';
15
+ message: string;
16
+ branchName: string;
17
+ totalIterations: number;
18
+ elapsedHours: number;
19
+ prUrl?: string;
20
+ }
21
+ /**
22
+ * Main entry point for autonomous development phase
23
+ */
24
+ export declare function runAutonomousDevelopment(options: PipelinePhaseOptions, config: EdsgerConfig, _checklistContext?: ChecklistPhaseContext | null): Promise<any>;
@@ -0,0 +1,404 @@
1
+ /**
2
+ * Autonomous Development Phase
3
+ *
4
+ * Runs a time-limited loop where Claude Code SDK analyzes the codebase,
5
+ * decides the next actionable step toward the feature's objective (description),
6
+ * implements it, and commits. All iterations build on the same branch.
7
+ * A PR is created after the first iteration; subsequent pushes update it.
8
+ */
9
+ import { query } from '@anthropic-ai/claude-agent-sdk';
10
+ import { DEFAULT_MODEL } from '../../constants.js';
11
+ import { logInfo, logError } from '../../utils/logger.js';
12
+ import { getFeature } from '../../api/features/get-feature.js';
13
+ import { createBranches, getCurrentBranch, updateBranch, } from '../../services/branches.js';
14
+ import { prepareCustomBranchGitEnvironmentAsync, resetUncommittedChanges, } from '../../utils/git-branch-manager.js';
15
+ import { createBranchPullRequest, } from '../code-implementation/branch-pr-creator.js';
16
+ import { getGitHubConfig } from '../../api/github.js';
17
+ import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
18
+ import { createAutonomousSystemPrompt, createAutonomousUserPrompt, } from './prompts.js';
19
+ /**
20
+ * Truncate text to a maximum length, adding ellipsis if truncated
21
+ */
22
+ function truncateText(text, maxLength) {
23
+ if (text.length <= maxLength) {
24
+ return text;
25
+ }
26
+ return text.slice(0, maxLength - 3) + '...';
27
+ }
28
+ function userMessage(content) {
29
+ return {
30
+ type: 'user',
31
+ message: { role: 'user', content: content },
32
+ };
33
+ }
34
+ async function* prompt(userPrompt) {
35
+ yield userMessage(userPrompt);
36
+ await new Promise((res) => setTimeout(res, 10000));
37
+ }
38
+ /**
39
+ * Push branch to remote repository
40
+ */
41
+ async function pushToRemote(branchName, verbose) {
42
+ try {
43
+ const { execSync } = await import('child_process');
44
+ if (verbose) {
45
+ logInfo(`📤 Pushing branch ${branchName} to remote...`);
46
+ }
47
+ try {
48
+ execSync(`git push -u origin ${branchName}`, {
49
+ encoding: 'utf-8',
50
+ stdio: verbose ? 'inherit' : 'pipe',
51
+ });
52
+ return { success: true };
53
+ }
54
+ catch {
55
+ try {
56
+ execSync(`git push origin ${branchName}`, {
57
+ encoding: 'utf-8',
58
+ stdio: verbose ? 'inherit' : 'pipe',
59
+ });
60
+ return { success: true };
61
+ }
62
+ catch {
63
+ if (verbose) {
64
+ logInfo(`⚠️ Push rejected, attempting force push with lease...`);
65
+ }
66
+ try {
67
+ execSync(`git push --force-with-lease origin ${branchName}`, {
68
+ encoding: 'utf-8',
69
+ stdio: verbose ? 'inherit' : 'pipe',
70
+ });
71
+ return { success: true };
72
+ }
73
+ catch (forceError) {
74
+ return {
75
+ success: false,
76
+ error: forceError instanceof Error
77
+ ? forceError.message
78
+ : String(forceError),
79
+ };
80
+ }
81
+ }
82
+ }
83
+ }
84
+ catch (error) {
85
+ return {
86
+ success: false,
87
+ error: error instanceof Error ? error.message : String(error),
88
+ };
89
+ }
90
+ }
91
+ /**
92
+ * Run a single autonomous iteration using Claude Code SDK
93
+ */
94
+ async function runIteration(featureId, featureDescription, config, verbose) {
95
+ const systemPrompt = createAutonomousSystemPrompt(config, featureId);
96
+ const userPromptText = createAutonomousUserPrompt(featureDescription);
97
+ let lastAssistantResponse = '';
98
+ for await (const message of query({
99
+ prompt: prompt(userPromptText),
100
+ options: {
101
+ systemPrompt: {
102
+ type: 'preset',
103
+ preset: 'claude_code',
104
+ append: systemPrompt,
105
+ },
106
+ model: DEFAULT_MODEL,
107
+ maxTurns: 3000,
108
+ permissionMode: 'bypassPermissions',
109
+ },
110
+ })) {
111
+ if (verbose) {
112
+ logInfo(`Received message type: ${message.type}`);
113
+ }
114
+ if (message.type === 'assistant' && message.message?.content) {
115
+ for (const content of message.message.content) {
116
+ if (content.type === 'text') {
117
+ lastAssistantResponse += content.text + '\n';
118
+ if (verbose) {
119
+ console.log(`\n🤖 ${content.text}`);
120
+ }
121
+ }
122
+ else if (content.type === 'tool_use') {
123
+ if (verbose) {
124
+ console.log(`\n🔧 ${content.name}: ${content.input.description || 'Running...'}`);
125
+ }
126
+ }
127
+ }
128
+ }
129
+ if (message.type === 'result') {
130
+ if (message.subtype === 'success') {
131
+ try {
132
+ const responseText = message.result || lastAssistantResponse;
133
+ const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
134
+ let jsonResult = null;
135
+ if (jsonBlockMatch) {
136
+ jsonResult = JSON.parse(jsonBlockMatch[1]);
137
+ }
138
+ else {
139
+ jsonResult = JSON.parse(responseText);
140
+ }
141
+ if (jsonResult?.autonomous_result) {
142
+ const result = jsonResult.autonomous_result;
143
+ return {
144
+ success: true,
145
+ summary: result.summary,
146
+ taskType: result.task_type,
147
+ filesModified: result.files_modified,
148
+ commitHash: result.commit_hash,
149
+ };
150
+ }
151
+ // JSON parsed but missing autonomous_result key
152
+ logInfo('⚠️ JSON result missing autonomous_result key, treating as success');
153
+ return {
154
+ success: true,
155
+ summary: 'Autonomous iteration completed (missing result key)',
156
+ };
157
+ }
158
+ catch {
159
+ // JSON parsing failed - still consider it a success if Claude did work
160
+ logInfo('⚠️ Could not parse structured result, treating as success');
161
+ return {
162
+ success: true,
163
+ summary: 'Autonomous iteration completed (unstructured result)',
164
+ };
165
+ }
166
+ }
167
+ else {
168
+ logError(`⚠️ Autonomous iteration incomplete: ${message.subtype}`);
169
+ return { success: false };
170
+ }
171
+ }
172
+ }
173
+ return { success: false };
174
+ }
175
+ /**
176
+ * Main entry point for autonomous development phase
177
+ */
178
+ export async function runAutonomousDevelopment(options, config, _checklistContext) {
179
+ const { featureId, verbose } = options;
180
+ const startTime = Date.now();
181
+ logInfo(`\n🤖 Starting autonomous development for feature: ${featureId}`);
182
+ // 1. Fetch feature info to get description (= objective) and autonomous_hours
183
+ const feature = await getFeature(featureId, verbose);
184
+ const featureDescription = feature.description || '';
185
+ const autonomousHours = feature.autonomous_hours || 4;
186
+ if (!featureDescription) {
187
+ return {
188
+ featureId,
189
+ status: 'error',
190
+ message: 'Feature description is required for autonomous mode (it serves as the objective)',
191
+ };
192
+ }
193
+ const endTime = startTime + autonomousHours * 3600000;
194
+ logInfo(`⏰ Autonomous mode will run for ${autonomousHours} hour(s)`);
195
+ logInfo(`🎯 Objective: ${truncateText(featureDescription.replace(/<[^>]*>/g, ''), 200)}`);
196
+ // 2. Get or create branch
197
+ let currentBranch = null;
198
+ try {
199
+ currentBranch = await getCurrentBranch({ featureId, verbose });
200
+ }
201
+ catch {
202
+ if (verbose) {
203
+ logInfo('No existing branch found, will create one');
204
+ }
205
+ }
206
+ if (!currentBranch) {
207
+ const featureName = truncateText(feature.name || 'Autonomous Development', 100);
208
+ const defaultBranchName = `dev/${featureId}`;
209
+ const createdBranches = await createBranches({ featureId, verbose }, [
210
+ {
211
+ name: featureName,
212
+ description: `Autonomous development branch for: ${featureName}`,
213
+ branch_name: defaultBranchName,
214
+ status: 'pending',
215
+ },
216
+ ]);
217
+ if (createdBranches.length > 0) {
218
+ currentBranch = createdBranches[0];
219
+ if (verbose) {
220
+ logInfo(`✅ Created branch: ${currentBranch.branch_name}`);
221
+ }
222
+ }
223
+ }
224
+ if (!currentBranch) {
225
+ return {
226
+ featureId,
227
+ status: 'error',
228
+ message: 'Failed to create or find a branch for autonomous development',
229
+ };
230
+ }
231
+ const devBranchName = currentBranch.branch_name || `dev/${featureId}`;
232
+ // 3. Update branch status to in_progress
233
+ if (currentBranch.status === 'pending') {
234
+ try {
235
+ await updateBranch(currentBranch.id, { status: 'in_progress' }, verbose);
236
+ }
237
+ catch (error) {
238
+ if (verbose) {
239
+ logError(`Failed to update branch status: ${error}`);
240
+ }
241
+ }
242
+ }
243
+ // 4. Prepare git environment (checkout branch + rebase with main)
244
+ const { cleanup: cleanupGit } = await prepareCustomBranchGitEnvironmentAsync({
245
+ featureBranch: devBranchName,
246
+ baseBranch: 'main',
247
+ verbose,
248
+ resolveConflicts: true,
249
+ conflictResolverConfig: {
250
+ model: DEFAULT_MODEL,
251
+ },
252
+ });
253
+ let totalIterations = 0;
254
+ let prUrl;
255
+ let prNumber;
256
+ try {
257
+ // 5. Main autonomous loop
258
+ while (Date.now() < endTime) {
259
+ totalIterations++;
260
+ const iterationStart = Date.now();
261
+ logInfo(`\n${'='.repeat(60)}\n🔄 Autonomous iteration ${totalIterations}\n${'='.repeat(60)}`);
262
+ // Run iteration
263
+ const iterationResult = await runIteration(featureId, featureDescription, config, verbose);
264
+ const iterationDuration = Date.now() - iterationStart;
265
+ logInfo(`⏱️ Iteration ${totalIterations} took ${(iterationDuration / 1000).toFixed(0)}s`);
266
+ if (iterationResult.success) {
267
+ logInfo(`✅ Iteration ${totalIterations}: ${iterationResult.summary || 'completed'}`);
268
+ // Push to remote
269
+ const pushResult = await pushToRemote(devBranchName, verbose);
270
+ if (!pushResult.success && verbose) {
271
+ logError(`⚠️ Failed to push: ${pushResult.error}`);
272
+ }
273
+ // Create PR after first successful iteration
274
+ if (!prUrl) {
275
+ const githubConfig = await getGitHubConfig(featureId, verbose);
276
+ if (githubConfig.configured &&
277
+ githubConfig.token &&
278
+ githubConfig.owner &&
279
+ githubConfig.repo) {
280
+ const prConfig = {
281
+ githubToken: githubConfig.token,
282
+ owner: githubConfig.owner,
283
+ repo: githubConfig.repo,
284
+ verbose,
285
+ };
286
+ logInfo(`📝 Creating pull request for autonomous work...`);
287
+ const prResult = await createBranchPullRequest(prConfig, devBranchName, currentBranch.name, currentBranch.description ||
288
+ 'Autonomous development implementation', 'main');
289
+ if (prResult.success) {
290
+ prUrl = prResult.pullRequestUrl;
291
+ prNumber = prResult.pullRequestNumber;
292
+ logInfo(`✅ Pull request created: ${prUrl}`);
293
+ }
294
+ else if (verbose) {
295
+ logError(`⚠️ Failed to create pull request: ${prResult.error}`);
296
+ }
297
+ }
298
+ else if (verbose) {
299
+ logInfo('⚠️ GitHub not configured, skipping PR creation');
300
+ }
301
+ }
302
+ // Log iteration completion to audit logs
303
+ await logFeaturePhaseEvent({
304
+ featureId,
305
+ eventType: 'autonomous_iteration_completed',
306
+ phase: 'autonomous',
307
+ result: 'success',
308
+ metadata: {
309
+ iteration: totalIterations,
310
+ task_type: iterationResult.taskType,
311
+ summary: iterationResult.summary,
312
+ files_modified: iterationResult.filesModified || [],
313
+ commit_hash: iterationResult.commitHash || '',
314
+ duration_ms: iterationDuration,
315
+ pr_url: prUrl || null,
316
+ elapsed_hours: ((Date.now() - startTime) / 3600000).toFixed(2),
317
+ remaining_hours: ((endTime - Date.now()) / 3600000).toFixed(2),
318
+ timestamp: new Date().toISOString(),
319
+ },
320
+ }, verbose);
321
+ }
322
+ else {
323
+ logError(`❌ Iteration ${totalIterations} failed`);
324
+ // Reset any uncommitted changes before next iteration
325
+ try {
326
+ resetUncommittedChanges(verbose);
327
+ }
328
+ catch {
329
+ // Ignore cleanup errors
330
+ }
331
+ // Log iteration failure to audit logs
332
+ await logFeaturePhaseEvent({
333
+ featureId,
334
+ eventType: 'autonomous_iteration_failed',
335
+ phase: 'autonomous',
336
+ result: 'error',
337
+ metadata: {
338
+ iteration: totalIterations,
339
+ duration_ms: iterationDuration,
340
+ elapsed_hours: ((Date.now() - startTime) / 3600000).toFixed(2),
341
+ remaining_hours: ((endTime - Date.now()) / 3600000).toFixed(2),
342
+ timestamp: new Date().toISOString(),
343
+ },
344
+ errorMessage: 'Autonomous iteration failed',
345
+ }, verbose);
346
+ }
347
+ // Check time before starting next iteration
348
+ if (Date.now() >= endTime) {
349
+ logInfo(`\n⏰ Time limit reached after ${totalIterations} iterations`);
350
+ break;
351
+ }
352
+ }
353
+ // 6. Update branch status to ready_for_review
354
+ try {
355
+ await updateBranch(currentBranch.id, {
356
+ status: 'ready_for_review',
357
+ pull_request_url: prUrl || null,
358
+ pull_request_number: prNumber || null,
359
+ }, verbose);
360
+ if (verbose) {
361
+ logInfo(`✅ Updated branch status to ready_for_review`);
362
+ }
363
+ }
364
+ catch (error) {
365
+ if (verbose) {
366
+ logError(`Failed to update branch status: ${error}`);
367
+ }
368
+ }
369
+ const elapsedHours = (Date.now() - startTime) / 3600000;
370
+ logInfo(`\n${'='.repeat(60)}`);
371
+ logInfo(`🏁 Autonomous development completed`);
372
+ logInfo(` Total iterations: ${totalIterations}`);
373
+ logInfo(` Elapsed time: ${elapsedHours.toFixed(2)} hours`);
374
+ logInfo(` Branch: ${devBranchName}`);
375
+ if (prUrl) {
376
+ logInfo(` PR: ${prUrl}`);
377
+ }
378
+ logInfo(`${'='.repeat(60)}\n`);
379
+ return {
380
+ featureId,
381
+ status: 'success',
382
+ message: `Autonomous development completed: ${totalIterations} iterations in ${elapsedHours.toFixed(2)} hours`,
383
+ branchName: devBranchName,
384
+ totalIterations,
385
+ elapsedHours,
386
+ prUrl,
387
+ };
388
+ }
389
+ catch (error) {
390
+ const elapsedHours = (Date.now() - startTime) / 3600000;
391
+ logError(`Autonomous development failed: ${error instanceof Error ? error.message : String(error)}`);
392
+ return {
393
+ featureId,
394
+ status: 'error',
395
+ message: `Autonomous development failed: ${error instanceof Error ? error.message : String(error)}`,
396
+ branchName: devBranchName,
397
+ totalIterations,
398
+ elapsedHours,
399
+ };
400
+ }
401
+ finally {
402
+ cleanupGit();
403
+ }
404
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Prompts for the autonomous development phase
3
+ */
4
+ import { EdsgerConfig } from '../../types/index.js';
5
+ export declare function createAutonomousSystemPrompt(_config: EdsgerConfig, featureId: string): string;
6
+ export declare function createAutonomousUserPrompt(featureDescription: string): string;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Prompts for the autonomous development phase
3
+ */
4
+ export function createAutonomousSystemPrompt(_config, featureId) {
5
+ return `You are an autonomous developer working toward a specific objective. Your role is to analyze the current state of the codebase, decide the next most valuable step toward the objective, implement it, and commit your changes.
6
+
7
+ **Your Role**: Analyze the codebase, identify the next actionable improvement, implement it, and commit.
8
+
9
+ **Available Tools**:
10
+ - Bash: Git operations, running commands, tests, and builds
11
+ - Glob: Find files and understand project structure
12
+ - Read: Examine existing code, configuration, and documentation files
13
+ - Edit: Modify existing files
14
+ - Write: Create new files
15
+ - TodoWrite: Track implementation tasks
16
+
17
+ **WORKFLOW - Follow these steps**:
18
+
19
+ 1. **ANALYZE**: Use Glob and Read to understand the current state of the code
20
+ 2. **DECIDE**: Based on the objective, determine the single most impactful next step
21
+ 3. **IMPLEMENT**: Make the changes using Edit/Write tools
22
+ 4. **TEST**: Run relevant tests or builds to verify your changes work
23
+ 5. **COMMIT**: Commit your changes with a conventional commit message (feat:, fix:, refactor:, docs:, test:, chore:)
24
+
25
+ **Types of work you may do**:
26
+ - Implement new feature code toward the objective
27
+ - Fix bugs discovered during analysis
28
+ - Refactor code to improve quality or maintainability
29
+ - Add or improve tests
30
+ - Update documentation
31
+ - Improve error handling or validation
32
+
33
+ **Important Rules**:
34
+ 1. You are already on the correct branch - do NOT create or switch branches
35
+ 2. Focus on ONE coherent change per iteration
36
+ 3. Use conventional commit messages that describe what and why
37
+ 4. Follow existing code patterns and conventions in the repository
38
+ 5. Ensure proper TypeScript types and interfaces
39
+ 6. Add appropriate error handling and validation
40
+ 7. Handle pre-commit hooks properly:
41
+ - If lint-staged fails: Fix formatting and linting issues, then retry commit
42
+ - If AI code review fails: Use SKIP_REVIEW=1 git commit -m "message"
43
+ - Last resort: git commit --no-verify -m "message"
44
+
45
+ **CRITICAL - Result Format**:
46
+ You MUST end your response with a JSON object in this EXACT format:
47
+
48
+ \`\`\`json
49
+ {
50
+ "autonomous_result": {
51
+ "feature_id": "${featureId}",
52
+ "task_type": "feature|bugfix|refactor|test|docs|chore",
53
+ "summary": "Brief description of what was done",
54
+ "files_modified": ["file1.ts", "file2.tsx"],
55
+ "commit_hash": "abc123..."
56
+ }
57
+ }
58
+ \`\`\`
59
+
60
+ Remember: Focus on making real, meaningful progress toward the objective. Quality over quantity.`;
61
+ }
62
+ export function createAutonomousUserPrompt(featureDescription) {
63
+ return `## Objective
64
+
65
+ ${featureDescription}
66
+
67
+ ## Instructions
68
+
69
+ Analyze the current state of the codebase. Based on the objective above, decide the next most valuable step to move toward the goal. Implement the change, verify it works, and commit it.
70
+
71
+ Focus on ONE coherent, well-scoped change. Make real progress toward the objective.
72
+
73
+ Begin by analyzing the codebase to understand the current state and decide your next step.`;
74
+ }
@@ -5,14 +5,11 @@ import { executeAnalysisQuery } from './agent.js';
5
5
  import { performVerificationCycle } from '../feature-analysis-verification/index.js';
6
6
  import { deleteArtifacts, deleteSpecificArtifacts, updateArtifactsToReady, saveAnalysisArtifactsAsDraft, buildAnalysisResult, } from './outcome.js';
7
7
  import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
8
- import { preparePhaseGitEnvironment } from '../../utils/git-branch-manager.js';
9
8
  export const analyseFeature = async (options, config, checklistContext) => {
10
9
  const { featureId, verbose } = options;
11
10
  if (verbose) {
12
11
  logInfo(`Starting feature analysis for feature ID: ${featureId}`);
13
12
  }
14
- // Prepare git environment: switch to feature branch and rebase with main
15
- const cleanupGit = preparePhaseGitEnvironment(featureId, 'main', verbose);
16
13
  try {
17
14
  const context = await prepareAnalysisContext(featureId, checklistContext, verbose);
18
15
  const systemPrompt = createFeatureAnalysisSystemPrompt();
@@ -157,8 +154,4 @@ export const analyseFeature = async (options, config, checklistContext) => {
157
154
  status: 'error',
158
155
  };
159
156
  }
160
- finally {
161
- // Always return to main branch after phase completion
162
- cleanupGit();
163
- }
164
157
  };
@@ -4,8 +4,8 @@
4
4
  */
5
5
  export interface LogPhaseEventParams {
6
6
  featureId: string;
7
- eventType: 'phase_started' | 'phase_completed' | 'phase_failed';
8
- phase: 'feature_analysis' | 'technical_design' | 'branch_planning' | 'code_implementation' | 'functional_testing' | 'pull_request' | 'code_review' | 'code_refine' | 'code_refine_verification';
7
+ eventType: 'phase_started' | 'phase_completed' | 'phase_failed' | 'autonomous_iteration_completed' | 'autonomous_iteration_failed';
8
+ phase: 'feature_analysis' | 'technical_design' | 'branch_planning' | 'code_implementation' | 'functional_testing' | 'pull_request' | 'code_review' | 'code_refine' | 'code_refine_verification' | 'autonomous';
9
9
  result?: 'success' | 'error' | 'warning' | 'info';
10
10
  metadata?: Record<string, any>;
11
11
  errorMessage?: string;
@@ -8,6 +8,7 @@ export interface FeatureInfo {
8
8
  product_id: string;
9
9
  execution_mode?: string;
10
10
  workflow?: FeatureWorkflow | null;
11
+ autonomous_hours?: number;
11
12
  created_at?: string;
12
13
  updated_at?: string;
13
14
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { EdsgerConfig } from './index.js';
5
5
  import { ChecklistPhaseContext } from '../services/checklist.js';
6
- export type ExecutionMode = 'full_pipeline' | 'only_feature_analysis' | 'only_technical_design' | 'only_branch_planning' | 'only_code_implementation' | 'only_functional_testing' | 'only_code_refine' | 'only_code_review' | 'from_feature_analysis' | 'from_technical_design' | 'from_branch_planning' | 'from_code_implementation' | 'from_functional_testing' | 'from_code_review' | 'custom';
6
+ export type ExecutionMode = 'full_pipeline' | 'only_feature_analysis' | 'only_technical_design' | 'only_branch_planning' | 'only_code_implementation' | 'only_functional_testing' | 'only_code_refine' | 'only_code_review' | 'from_feature_analysis' | 'from_technical_design' | 'from_branch_planning' | 'from_code_implementation' | 'from_functional_testing' | 'from_code_review' | 'custom' | 'autonomous';
7
7
  export type WorkflowPhaseStatus = 'pending' | 'completed';
8
8
  export interface WorkflowPhase {
9
9
  phase: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.22.4",
3
+ "version": "0.23.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"