Skip to content

Commit 8721662

Browse files
semsem
authored andcommitted
Merge pull request #1 from feature/retrofit-projects
feat: Add analyze command for retrofitting existing projects - Smart project analysis with tech stack detection - Interactive retrofit flow with future planning prompts - CLAUDE.md append mode preserves existing content - Generate PRPs for planned features - Comprehensive file tree summary - Secure API key management
2 parents ecc5fd7 + ac48628 commit 8721662

File tree

26 files changed

+5611
-13
lines changed

26 files changed

+5611
-13
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,7 @@ tmp/
6363
# Documentation development files
6464
context-engineering-prompts-starter.md
6565
context-forge-descriptions.md
66-
prd-forge-plan.md
66+
prd-forge-plan.md
67+
68+
# Context Forge API keys
69+
.context-forge-api

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ Need help understanding how each IDE uses its configuration? Check out our detai
127127
- 📁 **Structured Output** - Organized documentation following each IDE's conventions
128128
-**Fast Setup** - Go from zero to AI-ready project in minutes
129129
- 🔄 **Format Conversion** - Convert between different IDE formats (coming soon)
130+
- 🔧 **Retrofit Existing Projects** - NEW: Analyze and upgrade existing codebases with AI documentation
130131

131132
### Advanced Features
132133

@@ -201,6 +202,9 @@ context-forge init --config ./context-forge.json
201202

202203
# Run validation on existing project
203204
context-forge validate
205+
206+
# NEW: Retrofit existing projects with AI-optimized documentation
207+
context-forge analyze
204208
```
205209

206210
## 💡 Usage Examples
@@ -379,6 +383,62 @@ npx context-forge init --preset hackathon
379383
# CLAUDE.md has simplified rules for rapid development
380384
```
381385

386+
## 🔧 Retrofitting Existing Projects
387+
388+
**NEW in v3.1.3**: The `analyze` command allows you to retrofit existing codebases with AI-optimized documentation. This is perfect for:
389+
390+
- Adding AI assistance to legacy projects
391+
- Upgrading existing projects with modern context engineering
392+
- Planning new features for established codebases
393+
- Generating PRPs for upcoming development work
394+
395+
### How it Works
396+
397+
1. **Smart Analysis**: Automatically detects your tech stack, project structure, and existing documentation
398+
2. **Interactive Setup**: Asks about your future development plans
399+
3. **Non-Destructive**: Never overwrites existing files (appends to CLAUDE.md with clear markers)
400+
4. **Feature PRPs**: Generates individual PRP files for each planned feature
401+
5. **Comprehensive Summary**: Creates a detailed retrofit summary with file tree visualization
402+
403+
### Usage
404+
405+
```bash
406+
# Run in your existing project directory
407+
cd /path/to/your/project
408+
context-forge analyze
409+
410+
# Specify output directory
411+
context-forge analyze --output ./ai-docs
412+
413+
# Target specific IDEs
414+
context-forge analyze --ide claude,cursor
415+
416+
# Skip AI analysis for faster setup
417+
context-forge analyze --no-ai
418+
```
419+
420+
### Example Output
421+
422+
```
423+
📁 Generated Files:
424+
├── CLAUDE.md (UPDATED - appended retrofit section)
425+
├── Docs/
426+
│ ├── Implementation.md
427+
│ ├── project_structure.md
428+
│ ├── UI_UX_doc.md
429+
│ └── Bug_tracking.md
430+
└── PRPs/
431+
├── user-authentication-prp.md
432+
├── payment-integration-prp.md
433+
└── api-v2-prp.md
434+
```
435+
436+
The analyze command is intelligent enough to:
437+
- Detect if you're using TypeScript, Python, or other languages
438+
- Identify frameworks like React, Next.js, Express, FastAPI
439+
- Find existing documentation to use as context
440+
- Ask about your future plans to generate relevant PRPs
441+
382442
## 📚 Documentation
383443

384444
### Generated Files Structure

docs/ide-configs/cline/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ onAddToCart: (product: Product) => void;
273273

274274
export function ProductCard({ product, onAddToCart }: ProductCardProps) {
275275
return (
276+
276277
<div className="product-card">
277278
<img src={product.image} alt={product.name} />
278279
<h3>{product.name}</h3>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "context-forge",
3-
"version": "3.1.2",
3+
"version": "3.1.3",
44
"description": "Universal AI IDE configuration generator - Optimized setups for Claude Code, Cursor, Windsurf, Cline, Copilot, Gemini, and more",
55
"main": "dist/index.js",
66
"bin": {

src/adapters/claude.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,39 @@ export class ClaudeAdapter extends IDEAdapter {
6969
const prpPath = path.join(outputPath, 'PRPs');
7070
const projectSlug = this.config.projectName.toLowerCase().replace(/\s+/g, '-');
7171

72-
files.push({
73-
path: path.join(prpPath, `${projectSlug}-prp.md`),
74-
content: await generatePRP(this.config, 'base'),
75-
description: 'Base implementation PRP',
76-
});
77-
78-
// Add planning PRP for complex projects
79-
if (this.config.timeline === 'enterprise' || this.config.teamSize !== 'solo') {
72+
// In retrofit mode, generate PRPs for planned features
73+
if (this.config.isRetrofit && this.config.plannedFeatures && this.config.plannedFeatures.length > 0) {
74+
// Generate a PRP for each planned feature
75+
for (const feature of this.config.plannedFeatures) {
76+
const featureName = feature.split(':')[0].toLowerCase().replace(/\s+/g, '-');
77+
files.push({
78+
path: path.join(prpPath, `${featureName}-prp.md`),
79+
content: await generatePRP({
80+
...this.config,
81+
prd: {
82+
...this.config.prd,
83+
content: `Feature: ${feature}`,
84+
}
85+
}, 'base'),
86+
description: `PRP for: ${feature}`,
87+
});
88+
}
89+
} else {
90+
// Regular mode - generate base PRP
8091
files.push({
81-
path: path.join(prpPath, `${projectSlug}-planning.md`),
82-
content: await generatePRP(this.config, 'planning'),
83-
description: 'Architecture planning PRP',
92+
path: path.join(prpPath, `${projectSlug}-prp.md`),
93+
content: await generatePRP(this.config, 'base'),
94+
description: 'Base implementation PRP',
8495
});
96+
97+
// Add planning PRP for complex projects
98+
if (this.config.timeline === 'enterprise' || this.config.teamSize !== 'solo') {
99+
files.push({
100+
path: path.join(prpPath, `${projectSlug}-planning.md`),
101+
content: await generatePRP(this.config, 'planning'),
102+
description: 'Architecture planning PRP',
103+
});
104+
}
85105
}
86106
}
87107

src/cli/commands/analyze.ts

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import { Command } from 'commander';
2+
import chalk from 'chalk';
3+
import ora from 'ora';
4+
import path from 'path';
5+
import fs from 'fs-extra';
6+
import { ProjectConfig, SupportedIDE } from '../../types';
7+
import { getSupportedIDEs } from '../../adapters';
8+
import { ProjectAnalyzer } from '../../services/projectAnalyzer';
9+
import { ApiKeyManager } from '../../services/apiKeyManager';
10+
import { runRetrofitPrompts } from '../prompts/retrofit';
11+
import { generateDocumentation } from '../../generators';
12+
import { version } from '../../../package.json';
13+
14+
export const analyzeCommand = new Command('analyze')
15+
.description('Analyze existing project and generate AI-optimized documentation')
16+
.option('-o, --output <path>', 'output directory for generated files', '.')
17+
.option(
18+
'-i, --ide <ide>',
19+
'target IDE (claude, cursor, windsurf, cline, roo, gemini, copilot)',
20+
(value) => {
21+
const validIDEs = getSupportedIDEs();
22+
const ides = value.split(',').map((ide) => ide.trim());
23+
for (const ide of ides) {
24+
if (!validIDEs.includes(ide as SupportedIDE)) {
25+
throw new Error(`Invalid IDE: ${ide}. Valid options: ${validIDEs.join(', ')}`);
26+
}
27+
}
28+
return ides as SupportedIDE[];
29+
}
30+
)
31+
.option('--no-ai', 'skip AI analysis and use pattern-based analysis only')
32+
.option('--config-only', 'generate configuration file only without documentation')
33+
.action(async (options) => {
34+
console.log(chalk.blue.bold('\n🔍 Context Forge Analyzer\n'));
35+
console.log(
36+
chalk.gray("Let's analyze your existing project and create AI-optimized documentation.\n")
37+
);
38+
39+
const spinner = ora();
40+
const projectPath = process.cwd();
41+
const outputPath = path.resolve(options.output);
42+
43+
try {
44+
// Initialize services
45+
const analyzer = new ProjectAnalyzer(projectPath);
46+
const apiKeyManager = new ApiKeyManager(projectPath);
47+
48+
// Step 1: Basic Project Analysis
49+
spinner.start('Analyzing project structure...');
50+
const basicAnalysis = await analyzer.analyzeBasic();
51+
spinner.succeed(`Detected: ${basicAnalysis.summary}`);
52+
53+
console.log(chalk.cyan('\n📊 Project Overview:'));
54+
console.log(` • Type: ${basicAnalysis.projectType}`);
55+
console.log(` • Tech Stack: ${basicAnalysis.techStack.join(', ')}`);
56+
console.log(` • Components: ${basicAnalysis.fileStats.components} files`);
57+
console.log(` • API Routes: ${basicAnalysis.fileStats.routes} files`);
58+
if (basicAnalysis.existingDocs.length > 0) {
59+
console.log(` • Documentation: ${basicAnalysis.existingDocs.join(', ')}`);
60+
}
61+
62+
let detailedAnalysis = null;
63+
let apiConfig = null;
64+
65+
// Step 2: AI Analysis (if requested)
66+
if (options.ai !== false) {
67+
const useAI = await analyzer.shouldUseAI();
68+
69+
if (useAI) {
70+
apiConfig = await apiKeyManager.setupApiKey();
71+
if (apiConfig) {
72+
spinner.start('Analyzing with AI...');
73+
detailedAnalysis = await analyzer.analyzeDeep(apiConfig);
74+
spinner.succeed('AI analysis complete');
75+
76+
if (detailedAnalysis.insights.length > 0) {
77+
console.log(chalk.cyan('\n🤖 AI Insights:'));
78+
detailedAnalysis.insights.forEach((insight) => {
79+
console.log(` • ${insight}`);
80+
});
81+
}
82+
}
83+
}
84+
}
85+
86+
// Step 3: Retrofit Questions
87+
spinner.stop(); // Stop spinner before interactive prompts
88+
const config: ProjectConfig = await runRetrofitPrompts(
89+
basicAnalysis,
90+
detailedAnalysis,
91+
options.ide
92+
);
93+
console.log(chalk.green('✔ Configuration complete'));
94+
95+
// Step 4: Generate Documentation
96+
if (!options.configOnly) {
97+
spinner.start('Generating AI-optimized documentation...');
98+
await generateDocumentation(config, outputPath);
99+
spinner.succeed('Documentation generated successfully!');
100+
101+
console.log(chalk.green('\n✅ Analysis and generation complete!'));
102+
103+
// Show comprehensive summary
104+
console.log(chalk.blue.bold('\n📋 Summary of Changes:\n'));
105+
106+
// API Configuration
107+
if (apiConfig) {
108+
console.log(chalk.cyan('🔑 API Configuration:'));
109+
console.log(` • API key stored in: ${chalk.green('.context-forge-api')}`);
110+
console.log(` • Provider: ${chalk.green(apiConfig.provider)}`);
111+
console.log(` • Added to .gitignore: ${chalk.green('✓')}\n`);
112+
}
113+
114+
// Generated Files
115+
console.log(chalk.cyan('📁 Generated Files:'));
116+
console.log(chalk.gray(' ' + outputPath + '/'));
117+
118+
// CLAUDE.md status
119+
const claudeMdPath = path.join(outputPath, 'CLAUDE.md');
120+
if (await fs.pathExists(claudeMdPath)) {
121+
console.log(chalk.yellow(' ├── CLAUDE.md (UPDATED - appended retrofit section)'));
122+
}
123+
124+
// Docs folder
125+
const docsPath = path.join(outputPath, 'Docs');
126+
if (await fs.pathExists(docsPath)) {
127+
console.log(' ├── Docs/');
128+
const docFiles = await fs.readdir(docsPath);
129+
docFiles.forEach((file, index) => {
130+
const isLast = index === docFiles.length - 1;
131+
console.log(` │ ${isLast ? '└──' : '├──'} ${chalk.green(file)}`);
132+
});
133+
}
134+
135+
// PRPs folder
136+
const prpsPath = path.join(outputPath, 'PRPs');
137+
if (await fs.pathExists(prpsPath)) {
138+
console.log(' └── PRPs/');
139+
const prpFiles = await fs.readdir(prpsPath);
140+
prpFiles.forEach((file, index) => {
141+
const isLast = index === prpFiles.length - 1;
142+
console.log(` ${isLast ? '└──' : '├──'} ${chalk.green(file)}`);
143+
});
144+
}
145+
146+
console.log(chalk.gray('\n💡 Next steps:'));
147+
console.log(chalk.gray(' 1. Review the updated CLAUDE.md file'));
148+
console.log(chalk.gray(' 2. Check the PRPs folder for feature-specific implementations'));
149+
console.log(chalk.gray(' 3. Use these files with Claude Code for development'));
150+
151+
// Save summary to file
152+
let summaryContent = `# Context Forge Retrofit Summary
153+
Generated on: ${new Date().toLocaleString()}
154+
155+
## Project Analysis
156+
- **Type**: ${config.projectType}
157+
- **Tech Stack**: ${Object.values(config.techStack).filter(Boolean).join(', ')}
158+
- **Components**: ${basicAnalysis.fileStats.components} files
159+
- **API Routes**: ${basicAnalysis.fileStats.routes} files
160+
- **Test Coverage**: ${basicAnalysis.fileStats.tests} test files
161+
162+
## API Configuration
163+
${apiConfig ? `- **Provider**: ${apiConfig.provider}
164+
- **Key Location**: .context-forge-api
165+
- **Added to .gitignore**: ✓` : 'No API configuration used'}
166+
167+
## Generated Files
168+
169+
### Updated Files
170+
- **CLAUDE.md**: Appended retrofit section with date marker
171+
172+
### New Files Created
173+
`;
174+
175+
// Add Docs files
176+
if (await fs.pathExists(docsPath)) {
177+
summaryContent += '\n#### Docs/\n';
178+
const docFiles = await fs.readdir(docsPath);
179+
docFiles.forEach(file => {
180+
summaryContent += `- ${file}\n`;
181+
});
182+
}
183+
184+
// Add PRP files
185+
if (await fs.pathExists(prpsPath)) {
186+
summaryContent += '\n#### PRPs/\n';
187+
const prpFiles = await fs.readdir(prpsPath);
188+
prpFiles.forEach(file => {
189+
summaryContent += `- ${file}\n`;
190+
});
191+
}
192+
193+
summaryContent += `\n## Planned Features
194+
${config.plannedFeatures && config.plannedFeatures.length > 0
195+
? config.plannedFeatures.map(f => `- ${f}`).join('\n')
196+
: 'No specific features documented'}
197+
198+
## Next Steps
199+
1. Review the updated CLAUDE.md file
200+
2. Check the PRPs folder for feature-specific implementations
201+
3. Use these files with Claude Code for development
202+
203+
---
204+
*Generated by Context Forge v${version}*
205+
`;
206+
207+
const summaryPath = path.join(outputPath, 'retrofit-summary.md');
208+
await fs.writeFile(summaryPath, summaryContent);
209+
console.log(chalk.gray(`\n📄 Summary saved to: ${chalk.green('retrofit-summary.md')}`));
210+
}
211+
} catch (error) {
212+
spinner.fail('Analysis failed');
213+
throw error;
214+
}
215+
});

src/cli/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Command } from 'commander';
22
import chalk from 'chalk';
33
import { initCommand } from './commands/init';
4+
import { analyzeCommand } from './commands/analyze';
45
import { validateCommand } from '../commands/validate';
56
import { version } from '../../package.json';
67

@@ -16,6 +17,7 @@ program
1617

1718
// Add commands
1819
program.addCommand(initCommand);
20+
program.addCommand(analyzeCommand);
1921
program.addCommand(validateCommand);
2022

2123
// Error handling wrapper

0 commit comments

Comments
 (0)