UNPKG

context-forge

Version:

AI orchestration platform with autonomous teams, enhancement planning, migration tools, 25+ slash commands, checkpoints & hooks. Multi-IDE: Claude, Cursor, Windsurf, Cline, Copilot

146 lines (136 loc) • 7.03 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateDocumentation = generateDocumentation; const path_1 = __importDefault(require("path")); const fs_extra_1 = __importDefault(require("fs-extra")); const ora_1 = __importDefault(require("ora")); const chalk_1 = __importDefault(require("chalk")); const adapters_1 = require("../adapters"); const hooks_1 = require("./hooks"); async function generateDocumentation(config, outputPath) { // Ensure output directory exists await fs_extra_1.default.ensureDir(outputPath); // Default to Claude if no IDEs specified const targetIDEs = config.targetIDEs || ['claude']; console.log(chalk_1.default.blue(`\nšŸ“ Generating documentation for ${targetIDEs.length} IDE(s)...\n`)); // Generate files for each selected IDE for (const ide of targetIDEs) { const ideInfo = (0, adapters_1.getIDEInfo)(ide); console.log(chalk_1.default.cyan(`\nGenerating ${ideInfo.name} configuration...`)); try { const adapter = (0, adapters_1.createAdapter)(ide, config); const files = await adapter.generateFiles(outputPath); // Create necessary directories and write files for (const file of files) { const spinner = (0, ora_1.default)(`Creating ${path_1.default.basename(file.path)}...`).start(); try { await fs_extra_1.default.ensureDir(path_1.default.dirname(file.path)); // Check if file already exists if (await fs_extra_1.default.pathExists(file.path)) { // Special handling for CLAUDE.md in retrofit mode if (config.isRetrofit && path_1.default.basename(file.path) === 'CLAUDE.md') { spinner.info(`Appending to existing ${path_1.default.basename(file.path)}...`); const existingContent = await fs_extra_1.default.readFile(file.path, 'utf-8'); const retrofitSection = `\n\n<!-- ===== APPENDED BY CONTEXT FORGE RETROFIT - ${new Date().toLocaleDateString()} ===== -->\n\n## Retrofit Updates - ${new Date().toLocaleDateString()}\n\n${file.content}`; await fs_extra_1.default.writeFile(file.path, existingContent + retrofitSection, 'utf-8'); spinner.succeed(`Updated ${path_1.default.basename(file.path)}`); } else { spinner.warn(`Skipped ${path_1.default.basename(file.path)} - file already exists`); } continue; } await fs_extra_1.default.writeFile(file.path, file.content, 'utf-8'); spinner.succeed(`Created ${path_1.default.basename(file.path)}`); } catch (error) { spinner.fail(`Failed to create ${path_1.default.basename(file.path)}`); throw error; } } console.log(chalk_1.default.green(`āœ“ ${ideInfo.name} configuration complete`)); } catch (error) { if (error.message.includes('not yet implemented')) { console.log(chalk_1.default.yellow(`āš ļø ${ideInfo.name} adapter coming soon`)); } else { throw error; } } } // Generate common directories if needed if (config.extras.aiDocs) { await fs_extra_1.default.ensureDir(path_1.default.join(outputPath, 'ai_docs')); const aiDocsContent = await generateAIDocsReadme(config); await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'ai_docs', 'README.md'), aiDocsContent, 'utf-8'); } // Generate hooks if enabled if (config.extras.hooks) { console.log(chalk_1.default.cyan('\nšŸŖ Generating Claude Code hooks...')); const hooksFiles = await (0, hooks_1.generateHooks)(config); for (const file of hooksFiles) { const spinner = (0, ora_1.default)(`Creating ${path_1.default.basename(file.path)}...`).start(); try { await fs_extra_1.default.ensureDir(path_1.default.dirname(file.path)); await fs_extra_1.default.writeFile(path_1.default.join(outputPath, file.path), file.content, 'utf-8'); // Make Python hooks executable if (file.path.endsWith('.py')) { await fs_extra_1.default.chmod(path_1.default.join(outputPath, file.path), 0o755); } spinner.succeed(`Created ${path_1.default.basename(file.path)}`); } catch (error) { spinner.fail(`Failed to create ${path_1.default.basename(file.path)}`); throw error; } } console.log(chalk_1.default.green('āœ“ Claude Code hooks generated')); } console.log(chalk_1.default.green('\nāœ… All documentation files generated successfully!')); } async function generateAIDocsReadme(config) { return `# AI Documentation This directory contains curated documentation for AI-assisted development with Claude Code. ## Purpose Place library documentation, API references, and other technical documentation here that should be included in the AI's context when working on this project. ## Usage 1. Add markdown files with relevant documentation 2. Reference these files in your PRPs using: \`\`\`yaml - docfile: ai_docs/library-name.md why: Specific sections or methods needed \`\`\` ## Recommended Documentation Based on your tech stack (${Object.values(config.techStack).filter(Boolean).join(', ')}), consider adding: ${generateRecommendedDocs(config.techStack)} ## File Naming Convention - Use lowercase with hyphens: \`library-name.md\` - Be descriptive: \`fastapi-security-best-practices.md\` - Version if needed: \`react-19-hooks.md\` `; } function generateRecommendedDocs(techStack) { const recommendations = []; if (techStack.frontend === 'nextjs') { recommendations.push('- Next.js 15 App Router patterns'); recommendations.push('- React Server Components guide'); } if (techStack.backend === 'fastapi') { recommendations.push('- FastAPI async patterns'); recommendations.push('- Pydantic v2 migration guide'); } if (techStack.database === 'postgresql') { recommendations.push('- PostgreSQL optimization tips'); recommendations.push('- Common SQL patterns'); } if (techStack.auth === 'jwt') { recommendations.push('- JWT best practices'); recommendations.push('- Security considerations'); } return recommendations.join('\n') || '- Add relevant documentation for your tech stack'; } //# sourceMappingURL=index.js.map