edsger 0.6.2 → 0.6.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.
@@ -114,12 +114,14 @@ export function getExecutionModeDescription(mode) {
114
114
  only_technical_design: 'Execute only: technical design',
115
115
  only_code_implementation: 'Execute only: code implementation',
116
116
  only_functional_testing: 'Execute only: functional testing',
117
+ only_pull_request: 'Execute only: create pull request',
117
118
  only_code_refine: 'Execute only: code refine (address PR review feedback and verify resolution)',
118
119
  only_code_review: 'Execute only: code review (review PR code and create review comments)',
119
120
  from_feature_analysis: 'Execute from feature analysis to end: analysis → design → implementation → testing',
120
121
  from_technical_design: 'Execute from technical design to end: design → implementation → testing',
121
122
  from_code_implementation: 'Execute from code implementation to end: implementation → testing',
122
123
  from_functional_testing: 'Execute from functional testing to end: testing',
124
+ from_pull_request: 'Execute from pull request creation to end: pull-request → code-review → code-refine → code-refine-verification',
123
125
  from_code_review: 'Execute from code review to end: code-review → code-refine → code-refine-verification',
124
126
  };
125
127
  return descriptions[mode] || 'Unknown execution mode';
@@ -62,6 +62,11 @@ export const runPipelineByMode = async (options, config, executionMode) => {
62
62
  return await runOnlyFunctionalTesting(options, config);
63
63
  case 'from_functional_testing':
64
64
  return await runFromFunctionalTesting(options, config);
65
+ // Pull Request
66
+ case 'only_pull_request':
67
+ return await runOnlyPullRequest(options, config);
68
+ case 'from_pull_request':
69
+ return await runFromPullRequest(options, config);
65
70
  // Code Refine
66
71
  case 'only_code_refine':
67
72
  return await runOnlyCodeRefine(options, config);
@@ -311,6 +316,30 @@ const runFromFunctionalTesting = async (options, config) => {
311
316
  }
312
317
  return logPipelineComplete(results, verbose);
313
318
  };
319
+ /**
320
+ * Run only pull request creation phase
321
+ */
322
+ const runOnlyPullRequest = async (options, config) => {
323
+ const { featureId, verbose } = options;
324
+ logPipelineStart(featureId, verbose);
325
+ const results = [];
326
+ // Note: We create a mock testing result since this mode assumes testing already passed
327
+ const mockTestingResult = {
328
+ featureId,
329
+ phase: 'functional-testing',
330
+ status: 'success',
331
+ message: 'Functional testing assumed to have passed',
332
+ data: {},
333
+ };
334
+ // Create pull request only
335
+ await handlePullRequestCreation({
336
+ featureId,
337
+ results,
338
+ testingResult: mockTestingResult,
339
+ verbose,
340
+ });
341
+ return logPipelineComplete(results, verbose);
342
+ };
314
343
  /**
315
344
  * Run only code refine phase (refine code based on PR feedback)
316
345
  * Includes automatic retry loop for verification failures
@@ -362,6 +391,39 @@ const runFromCodeReview = async (options, config) => {
362
391
  });
363
392
  return logPipelineComplete(results, verbose);
364
393
  };
394
+ /**
395
+ * Run from pull request creation to end (pull-request → code-review → code-refine → code-refine-verification)
396
+ */
397
+ const runFromPullRequest = async (options, config) => {
398
+ const { featureId, verbose } = options;
399
+ logPipelineStart(featureId, verbose);
400
+ const results = [];
401
+ // Note: We create a mock testing result since this mode assumes testing already passed
402
+ // The PR creation handler needs this for context
403
+ const mockTestingResult = {
404
+ featureId,
405
+ phase: 'functional-testing',
406
+ status: 'success',
407
+ message: 'Functional testing assumed to have passed',
408
+ data: {},
409
+ };
410
+ // 1. Create pull request
411
+ const prCreated = await handlePullRequestCreation({
412
+ featureId,
413
+ results,
414
+ testingResult: mockTestingResult,
415
+ verbose,
416
+ });
417
+ if (!prCreated) {
418
+ if (verbose) {
419
+ logInfo('⚠️ Pull request creation failed, stopping workflow');
420
+ }
421
+ return logPipelineComplete(results, verbose);
422
+ }
423
+ // 2. Continue with code review and refine workflow
424
+ await continueWithCodeReviewAndRefine(options, config, results, verbose);
425
+ return logPipelineComplete(results, verbose);
426
+ };
365
427
  /**
366
428
  * Continue with code review and refine after PR creation
367
429
  * This is the post-PR workflow: code-review → code-refine → code-refine-verification → code-testing
@@ -15,6 +15,39 @@ const getCurrentBranch = () => {
15
15
  throw new Error(`Failed to get current branch: ${error}`);
16
16
  }
17
17
  };
18
+ /**
19
+ * Check if a branch exists
20
+ */
21
+ const branchExists = (branch) => {
22
+ try {
23
+ execSync(`git rev-parse --verify ${branch}`, { encoding: 'utf-8' });
24
+ return true;
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ };
30
+ /**
31
+ * Switch to an existing branch
32
+ */
33
+ const switchToBranch = (branch, verbose) => {
34
+ try {
35
+ // First check if branch exists
36
+ if (!branchExists(branch)) {
37
+ throw new Error(`Branch '${branch}' does not exist. The branch should have been created during code implementation phase.`);
38
+ }
39
+ if (verbose) {
40
+ console.log(`🔀 Switching to branch: ${branch}`);
41
+ }
42
+ execSync(`git checkout ${branch}`, { encoding: 'utf-8' });
43
+ if (verbose) {
44
+ console.log(`✅ Switched to branch: ${branch}`);
45
+ }
46
+ }
47
+ catch (error) {
48
+ throw new Error(`Failed to switch to branch ${branch}: ${error}`);
49
+ }
50
+ };
18
51
  /**
19
52
  * Push current branch to remote
20
53
  */
@@ -93,16 +126,18 @@ export async function createPullRequest(config, feature) {
93
126
  auth: githubToken,
94
127
  });
95
128
  // Get current branch (should be dev/feature-id)
96
- const currentBranch = getCurrentBranch();
129
+ let currentBranch = getCurrentBranch();
97
130
  if (verbose) {
98
131
  console.log(`🔍 Current branch: ${currentBranch}`);
99
132
  }
100
- // Don't create PR if we're on the base branch
133
+ // If we're on the base branch, switch to dev branch (should already exist)
101
134
  if (currentBranch === baseBranch) {
102
- return {
103
- success: false,
104
- error: `Cannot create PR: already on ${baseBranch} branch`,
105
- };
135
+ const devBranch = `dev/${feature.id}`;
136
+ if (verbose) {
137
+ console.log(`⚠️ Currently on ${baseBranch} branch, switching to ${devBranch}`);
138
+ }
139
+ switchToBranch(devBranch, verbose);
140
+ currentBranch = devBranch;
106
141
  }
107
142
  // Extract feature ID from current branch (dev/feature-id)
108
143
  let targetBranch = baseBranch;
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { getFeature } from '../../api/features/index.js';
5
5
  import { createPullRequest, updateFeatureWithPullRequest } from './creator.js';
6
+ import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
6
7
  /**
7
8
  * Create pull request for successful feature implementation
8
9
  * Returns true if PR was successfully created, false otherwise
@@ -11,12 +12,33 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
11
12
  if (verbose) {
12
13
  console.log('🔄 Creating pull request for successful feature...');
13
14
  }
15
+ // Log phase start
16
+ await logFeaturePhaseEvent({
17
+ featureId,
18
+ eventType: 'phase_started',
19
+ phase: 'pull_request',
20
+ result: 'info',
21
+ metadata: {
22
+ timestamp: new Date().toISOString(),
23
+ },
24
+ }, verbose);
14
25
  // Get feature details for PR creation
15
26
  const feature = await getFeature(featureId, verbose);
16
27
  if (!feature) {
17
28
  if (verbose) {
18
29
  console.log('⚠️ Could not fetch feature details for pull request creation');
19
30
  }
31
+ // Log phase failure
32
+ await logFeaturePhaseEvent({
33
+ featureId,
34
+ eventType: 'phase_failed',
35
+ phase: 'pull_request',
36
+ result: 'error',
37
+ errorMessage: 'Could not fetch feature details',
38
+ metadata: {
39
+ timestamp: new Date().toISOString(),
40
+ },
41
+ }, verbose);
20
42
  return false;
21
43
  }
22
44
  // Get GitHub configuration from environment
@@ -28,6 +50,22 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
28
50
  console.log('⚠️ GitHub configuration not found. Skipping pull request creation.');
29
51
  console.log(' Set GITHUB_TOKEN, GITHUB_OWNER, and GITHUB_REPO environment variables.');
30
52
  }
53
+ // Log phase failure
54
+ await logFeaturePhaseEvent({
55
+ featureId,
56
+ eventType: 'phase_failed',
57
+ phase: 'pull_request',
58
+ result: 'error',
59
+ errorMessage: 'GitHub configuration not found',
60
+ metadata: {
61
+ missing_vars: [
62
+ !githubToken && 'GITHUB_TOKEN',
63
+ !githubOwner && 'GITHUB_OWNER',
64
+ !githubRepo && 'GITHUB_REPO',
65
+ ].filter(Boolean),
66
+ timestamp: new Date().toISOString(),
67
+ },
68
+ }, verbose);
31
69
  return false;
32
70
  }
33
71
  const prResult = await createPullRequest({
@@ -49,6 +87,18 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
49
87
  if (prResult.success && prResult.pullRequestUrl) {
50
88
  // Update feature with PR URL and status
51
89
  await updateFeatureWithPullRequest(featureId, prResult.pullRequestUrl, verbose);
90
+ // Log phase completion
91
+ await logFeaturePhaseEvent({
92
+ featureId,
93
+ eventType: 'phase_completed',
94
+ phase: 'pull_request',
95
+ result: 'success',
96
+ metadata: {
97
+ pull_request_url: prResult.pullRequestUrl,
98
+ pull_request_number: prResult.pullRequestNumber,
99
+ timestamp: new Date().toISOString(),
100
+ },
101
+ }, verbose);
52
102
  if (verbose) {
53
103
  console.log(`✅ Pull request created and feature updated to ready_for_review`);
54
104
  }
@@ -58,6 +108,17 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
58
108
  if (verbose) {
59
109
  console.log(`⚠️ Pull request creation failed: ${prResult.error}`);
60
110
  }
111
+ // Log phase failure
112
+ await logFeaturePhaseEvent({
113
+ featureId,
114
+ eventType: 'phase_failed',
115
+ phase: 'pull_request',
116
+ result: 'error',
117
+ errorMessage: prResult.error,
118
+ metadata: {
119
+ timestamp: new Date().toISOString(),
120
+ },
121
+ }, verbose);
61
122
  return false;
62
123
  }
63
124
  }
@@ -5,7 +5,7 @@
5
5
  export interface LogPhaseEventParams {
6
6
  featureId: string;
7
7
  eventType: 'phase_started' | 'phase_completed' | 'phase_failed';
8
- phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | 'code_refine' | 'code_refine_verification' | 'code_review';
8
+ phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | 'pull_request' | 'code_review' | 'code_refine' | 'code_refine_verification';
9
9
  result?: 'success' | 'error' | 'warning' | 'info';
10
10
  metadata?: Record<string, any>;
11
11
  errorMessage?: string;
@@ -19,7 +19,7 @@ export interface LogChecklistEventParams {
19
19
  }
20
20
  export interface LogVerificationEventParams {
21
21
  featureId: string;
22
- phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | 'code_refine' | 'code_refine_verification' | 'code_review';
22
+ phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | 'pull_request' | 'code_review' | 'code_refine' | 'code_refine_verification';
23
23
  iteration: number;
24
24
  result: 'success' | 'error';
25
25
  verificationData: {
@@ -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_code_implementation' | 'only_functional_testing' | 'only_code_refine' | 'only_code_review' | 'from_feature_analysis' | 'from_technical_design' | 'from_code_implementation' | 'from_functional_testing' | 'from_code_review';
6
+ export type ExecutionMode = 'full_pipeline' | 'only_feature_analysis' | 'only_technical_design' | 'only_code_implementation' | 'only_functional_testing' | 'only_pull_request' | 'only_code_refine' | 'only_code_review' | 'from_feature_analysis' | 'from_technical_design' | 'from_code_implementation' | 'from_functional_testing' | 'from_code_review' | 'from_pull_request';
7
7
  export interface PipelinePhaseOptions {
8
8
  readonly featureId: string;
9
9
  readonly verbose?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"