edsger 0.7.2 โ†’ 0.7.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,4 +1,4 @@
1
- import { mkdir, writeFile, access } from 'fs/promises';
1
+ import { mkdir, access } from 'fs/promises';
2
2
  import { join } from 'path';
3
3
  import { query } from '@anthropic-ai/claude-code';
4
4
  import { logInfo, logError, logSuccess } from '../../utils/logger.js';
@@ -47,12 +47,12 @@ async function edsgerDirExists(targetDir) {
47
47
  }
48
48
  /**
49
49
  * Use Claude Code SDK to analyze codebase and generate documentation
50
+ * Claude will directly write the file to .edsger/ directory
50
51
  */
51
52
  async function generateDocumentation(prompt, description, verbose) {
52
53
  if (verbose) {
53
54
  logInfo(`\n๐Ÿ” Analyzing codebase for ${description}...`);
54
55
  }
55
- let content = '';
56
56
  let hasStarted = false;
57
57
  try {
58
58
  for await (const message of query({
@@ -60,6 +60,7 @@ async function generateDocumentation(prompt, description, verbose) {
60
60
  options: {
61
61
  appendSystemPrompt: createSystemPrompt(),
62
62
  model: 'sonnet',
63
+ permissionMode: 'bypassPermissions',
63
64
  },
64
65
  })) {
65
66
  // Stream the analysis process
@@ -83,7 +84,6 @@ async function generateDocumentation(prompt, description, verbose) {
83
84
  }
84
85
  if (message.type === 'result') {
85
86
  if (message.subtype === 'success') {
86
- content = message.result || '';
87
87
  if (verbose) {
88
88
  console.log(` โœ“ ${description} generated successfully`);
89
89
  }
@@ -93,7 +93,6 @@ async function generateDocumentation(prompt, description, verbose) {
93
93
  }
94
94
  }
95
95
  }
96
- return content;
97
96
  }
98
97
  catch (error) {
99
98
  throw new Error(`Failed to generate ${description}: ${error instanceof Error ? error.message : String(error)}`);
@@ -121,12 +120,11 @@ export const runInit = async (options) => {
121
120
  await mkdir(edsgerPath, { recursive: true });
122
121
  logInfo(`\n๐Ÿ“ Created ${EDSGER_DIR}/ directory`);
123
122
  logInfo('\n๐Ÿค– Analyzing your codebase with Claude Code SDK to generate documentation...\n');
124
- // Generate and write all documentation files
123
+ // Generate all documentation files (Claude will write them directly)
125
124
  for (const doc of documentsToGenerate) {
126
- const prompt = doc.promptCreator();
127
- const content = await generateDocumentation(prompt, doc.description, options.verbose);
128
125
  const filePath = join(edsgerPath, doc.filename);
129
- await writeFile(filePath, content, 'utf-8');
126
+ const prompt = doc.promptCreator(filePath);
127
+ await generateDocumentation(prompt, doc.description, options.verbose);
130
128
  logInfo(` โœ“ ${doc.filename}`);
131
129
  }
132
130
  logSuccess('\nโœจ Successfully initialized edsger!');
@@ -2,8 +2,8 @@
2
2
  * Prompts for Claude Code SDK to analyze codebase and generate documentation
3
3
  */
4
4
  export declare function createSystemPrompt(): string;
5
- export declare function createProjectOverviewPrompt(): string;
6
- export declare function createTechStackPrompt(): string;
7
- export declare function createArchitecturePrompt(): string;
8
- export declare function createCodingGuidelinesPrompt(): string;
9
- export declare function createDevelopmentSetupPrompt(): string;
5
+ export declare function createProjectOverviewPrompt(filename: string): string;
6
+ export declare function createTechStackPrompt(filename: string): string;
7
+ export declare function createArchitecturePrompt(filename: string): string;
8
+ export declare function createCodingGuidelinesPrompt(filename: string): string;
9
+ export declare function createDevelopmentSetupPrompt(filename: string): string;
@@ -9,13 +9,12 @@ Your task is to analyze the codebase structure, code files, configuration, and d
9
9
  IMPORTANT INSTRUCTIONS:
10
10
  1. Use available tools to explore the codebase (Glob, Read, Grep, Bash)
11
11
  2. Analyze actual code, not assumptions
12
- 3. Output ONLY the final markdown documentation content
13
- 4. Do NOT include any conversational text or explanations
14
- 5. The output should be ready to save directly as a markdown file
15
- 6. Be thorough but concise - focus on what developers need to know
16
- 7. Use proper markdown formatting with headers, lists, and code blocks`;
12
+ 3. Use the Write tool to save the documentation to the specified file path
13
+ 4. Write ONLY markdown documentation content to the file - no conversational text
14
+ 5. Be thorough but concise - focus on what developers need to know
15
+ 6. Use proper markdown formatting with headers, lists, and code blocks`;
17
16
  }
18
- export function createProjectOverviewPrompt() {
17
+ export function createProjectOverviewPrompt(filename) {
19
18
  return `Analyze this codebase and generate a comprehensive project overview document.
20
19
 
21
20
  Please explore the codebase and create a markdown document covering:
@@ -32,9 +31,9 @@ Use Glob to find package.json, README, and main source directories.
32
31
  Use Read to examine key files.
33
32
  Use Grep to search for patterns if needed.
34
33
 
35
- Output ONLY the markdown content for project-overview.md - no other text.`;
34
+ When done analyzing, use the Write tool to save the markdown documentation to: ${filename}`;
36
35
  }
37
- export function createTechStackPrompt() {
36
+ export function createTechStackPrompt(filename) {
38
37
  return `Analyze this codebase and generate a comprehensive technology stack document.
39
38
 
40
39
  Please explore the codebase and create a markdown document covering:
@@ -53,9 +52,9 @@ Use Glob to find package.json, tsconfig.json, .env.example, and config files.
53
52
  Use Read to examine dependencies and configurations.
54
53
  Check for Docker, CI/CD configs, and other infrastructure files.
55
54
 
56
- Output ONLY the markdown content for tech-stack.md - no other text.`;
55
+ When done analyzing, use the Write tool to save the markdown documentation to: ${filename}`;
57
56
  }
58
- export function createArchitecturePrompt() {
57
+ export function createArchitecturePrompt(filename) {
59
58
  return `Analyze this codebase and generate a comprehensive system architecture document.
60
59
 
61
60
  Please explore the codebase and create a markdown document covering:
@@ -75,9 +74,9 @@ Use Read to examine main entry points and key files.
75
74
  Use Grep to find patterns like classes, interfaces, API endpoints.
76
75
  Look for architecture diagrams or documentation.
77
76
 
78
- Output ONLY the markdown content for architecture.md - no other text.`;
77
+ When done analyzing, use the Write tool to save the markdown documentation to: ${filename}`;
79
78
  }
80
- export function createCodingGuidelinesPrompt() {
79
+ export function createCodingGuidelinesPrompt(filename) {
81
80
  return `Analyze this codebase and generate a comprehensive coding guidelines document.
82
81
 
83
82
  Please explore the codebase and create a markdown document covering:
@@ -99,9 +98,9 @@ Use Read to examine code style, ESLint, Prettier configs.
99
98
  Use Grep to find common patterns in function declarations, imports, error handling.
100
99
  Check for CONTRIBUTING.md or similar files.
101
100
 
102
- Output ONLY the markdown content for coding-guidelines.md - no other text.`;
101
+ When done analyzing, use the Write tool to save the markdown documentation to: ${filename}`;
103
102
  }
104
- export function createDevelopmentSetupPrompt() {
103
+ export function createDevelopmentSetupPrompt(filename) {
105
104
  return `Analyze this codebase and generate a comprehensive development setup document.
106
105
 
107
106
  Please explore the codebase and create a markdown document covering:
@@ -125,5 +124,5 @@ Use Glob to find package.json, .env.example, docker-compose, and README.
125
124
  Use Read to examine package.json scripts, env variables, and setup instructions.
126
125
  Check for Docker, database migrations, or setup scripts.
127
126
 
128
- Output ONLY the markdown content for development-setup.md - no other text.`;
127
+ When done analyzing, use the Write tool to save the markdown documentation to: ${filename}`;
129
128
  }
@@ -27,6 +27,26 @@ const branchExists = (branch) => {
27
27
  return false;
28
28
  }
29
29
  };
30
+ /**
31
+ * Discard uncommitted changes in the working directory
32
+ */
33
+ const discardUncommittedChanges = (verbose) => {
34
+ try {
35
+ if (verbose) {
36
+ console.log(`๐Ÿงน Discarding uncommitted changes...`);
37
+ }
38
+ // Reset all tracked files to HEAD
39
+ execSync('git reset --hard HEAD', { encoding: 'utf-8' });
40
+ // Remove all untracked files and directories
41
+ execSync('git clean -fd', { encoding: 'utf-8' });
42
+ if (verbose) {
43
+ console.log(`โœ… Working directory cleaned`);
44
+ }
45
+ }
46
+ catch (error) {
47
+ throw new Error(`Failed to discard uncommitted changes: ${error}`);
48
+ }
49
+ };
30
50
  /**
31
51
  * Switch to an existing branch
32
52
  */
@@ -39,6 +59,8 @@ const switchToBranch = (branch, verbose) => {
39
59
  if (verbose) {
40
60
  console.log(`๐Ÿ”€ Switching to branch: ${branch}`);
41
61
  }
62
+ // Discard any uncommitted changes before switching
63
+ discardUncommittedChanges(verbose);
42
64
  execSync(`git checkout ${branch}`, { encoding: 'utf-8' });
43
65
  if (verbose) {
44
66
  console.log(`โœ… Switched to branch: ${branch}`);
@@ -73,6 +95,8 @@ const switchToMainBranch = (mainBranch = 'main', verbose) => {
73
95
  if (verbose) {
74
96
  console.log(`๐Ÿ”„ Switching to ${mainBranch} branch...`);
75
97
  }
98
+ // Discard any uncommitted changes before switching
99
+ discardUncommittedChanges(verbose);
76
100
  execSync(`git checkout ${mainBranch}`, { encoding: 'utf-8' });
77
101
  if (verbose) {
78
102
  console.log(`โœ… Switched to ${mainBranch} branch`);
@@ -91,6 +115,44 @@ const generatePRTitle = (featureName) => {
91
115
  // Convert to lowercase for conventional commits format
92
116
  return `feat: ${cleanName.toLowerCase()}`;
93
117
  };
118
+ /**
119
+ * Check if a pull request already exists from head to base
120
+ */
121
+ const findExistingPullRequest = async (octokit, owner, repo, head, base, verbose) => {
122
+ try {
123
+ if (verbose) {
124
+ console.log(`๐Ÿ” Checking for existing PR from ${head} to ${base}...`);
125
+ }
126
+ const { data: pullRequests } = await octokit.pulls.list({
127
+ owner,
128
+ repo,
129
+ head: `${owner}:${head}`,
130
+ base,
131
+ state: 'open',
132
+ });
133
+ if (pullRequests.length > 0) {
134
+ const existingPR = pullRequests[0];
135
+ if (verbose) {
136
+ console.log(`โ„น๏ธ Found existing PR #${existingPR.number}: ${existingPR.html_url}`);
137
+ }
138
+ return {
139
+ number: existingPR.number,
140
+ html_url: existingPR.html_url,
141
+ };
142
+ }
143
+ if (verbose) {
144
+ console.log(`โœ… No existing PR found`);
145
+ }
146
+ return null;
147
+ }
148
+ catch (error) {
149
+ if (verbose) {
150
+ console.log(`โš ๏ธ Error checking for existing PR: ${error}`);
151
+ }
152
+ // If we can't check, return null and proceed with creation attempt
153
+ return null;
154
+ }
155
+ };
94
156
  /**
95
157
  * Generate pull request body with feature details
96
158
  */
@@ -185,21 +247,33 @@ export async function createPullRequest(config, feature) {
185
247
  // Generate PR title and body
186
248
  const title = generatePRTitle(feature.name);
187
249
  const body = generatePRBody(feature);
188
- if (verbose) {
189
- console.log(`๐Ÿ“ Creating pull request: ${title} from ${currentBranch} to ${targetBranch}`);
250
+ // Check if PR already exists
251
+ const existingPR = await findExistingPullRequest(octokit, owner, repo, currentBranch, targetBranch, verbose);
252
+ let pullRequest;
253
+ if (existingPR) {
254
+ if (verbose) {
255
+ console.log(`โ„น๏ธ Using existing pull request: ${existingPR.html_url}`);
256
+ }
257
+ pullRequest = existingPR;
190
258
  }
191
- // Create the pull request from dev/ to feat/
192
- const { data: pullRequest } = await octokit.pulls.create({
193
- owner,
194
- repo,
195
- title,
196
- body,
197
- head: currentBranch,
198
- base: targetBranch,
199
- draft: false,
200
- });
201
- if (verbose) {
202
- console.log(`โœ… Pull request created: ${pullRequest.html_url}`);
259
+ else {
260
+ if (verbose) {
261
+ console.log(`๐Ÿ“ Creating pull request: ${title} from ${currentBranch} to ${targetBranch}`);
262
+ }
263
+ // Create the pull request from dev/ to feat/
264
+ const { data: newPullRequest } = await octokit.pulls.create({
265
+ owner,
266
+ repo,
267
+ title,
268
+ body,
269
+ head: currentBranch,
270
+ base: targetBranch,
271
+ draft: false,
272
+ });
273
+ if (verbose) {
274
+ console.log(`โœ… Pull request created: ${newPullRequest.html_url}`);
275
+ }
276
+ pullRequest = newPullRequest;
203
277
  }
204
278
  // Switch back to main branch
205
279
  switchToMainBranch(baseBranch, verbose);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"