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,
|
|
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
|
|
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
|
-
|
|
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.
|
|
13
|
-
4.
|
|
14
|
-
5.
|
|
15
|
-
6.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
189
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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);
|