UNPKG

wonder-ai-docs

Version:

AI-assisted documentation management for developers, designed to work seamlessly with Cursor

1,386 lines (1,218 loc) • 56.7 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const inquirer = require('inquirer'); const { execSync } = require('child_process'); const packageJson = require('./package.json'); const Anthropic = require('@anthropic-ai/sdk'); // Define the Wonder directory structure const WONDER_DIRS = [ '.cursor/checkpoints', 'templates/architecture', 'templates/constraints', 'templates/decisions', 'templates/documentation', 'templates/environment', 'templates/issue-tracking', 'templates/project', 'templates/references', 'templates/requirements', 'templates/user-stories' ]; // Configuration management const CONFIG_FILE = path.join(process.env.HOME || process.env.USERPROFILE, '.wonder', 'config.json'); function loadConfig() { try { if (fs.existsSync(CONFIG_FILE)) { const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); // Set default values if not present return { llmApiKey: config.llmApiKey, maxTokens: config.maxTokens || 4000, // Default to 4K tokens (safe for Claude) ...config }; } } catch (error) { console.error('Error loading config:', error.message); } return { maxTokens: 4000 // Default value }; } function saveConfig(config) { try { fs.mkdirSync(path.dirname(CONFIG_FILE), { recursive: true }); fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2)); return true; } catch (error) { console.error('Error saving config:', error.message); return false; } } async function handleConfig(args) { const config = loadConfig(); if (args.length === 0 || args[0] === 'status') { // Show current config console.log('\nCurrent Wonder configuration:'); console.log('----------------------------'); const llmApiKey = config.llmApiKey || process.env.WONDER_LLM_API_KEY; const hasApiKey = !!llmApiKey; console.log('LLM Status:'); console.log(` API Key: ${hasApiKey ? 'Set' : 'Not set'}`); if (hasApiKey) { console.log(` Source: ${config.llmApiKey ? 'Config file' : 'Environment variable'}`); console.log(` Key: ********${llmApiKey.slice(-4)}`); } else { console.log(' Note: An Anthropic API key is required for LLM features'); console.log(' Get your key at: https://console.anthropic.com/'); console.log(' Set it using: wonder config set llmApiKey your-anthropic-api-key'); } console.log('\nAnalysis Settings:'); console.log(` Max Tokens: ${config.maxTokens}`); console.log(' Note: Higher token limits allow for larger documents and more context'); console.log(' Set using: wonder config set maxTokens <number>'); return; } const command = args[0]; let key, value, unsetKey; switch (command) { case 'set': if (args.length !== 3) { console.log('Usage: wonder config set <key> <value>'); return; } key = args[1]; value = args[2]; if (key === 'llmApiKey') { config.llmApiKey = value; if (saveConfig(config)) { console.log('Anthropic API key set successfully'); console.log('Note: You may need to restart your terminal for changes to take effect'); } } else if (key === 'maxTokens') { const numValue = parseInt(value, 10); if (isNaN(numValue) || numValue < 1000 || numValue > 8192) { console.log('Error: maxTokens must be a number between 1000 and 8192'); return; } config.maxTokens = numValue; if (saveConfig(config)) { console.log(`Max tokens set to ${numValue}`); } } else { console.log('Unknown configuration key'); } break; case 'unset': if (args.length !== 2) { console.log('Usage: wonder config unset <key>'); return; } unsetKey = args[1]; if (unsetKey in config) { delete config[unsetKey]; if (saveConfig(config)) { console.log(`${unsetKey} unset successfully`); } } else { console.log('Configuration key not found'); } break; default: console.log('Unknown config command'); console.log('Available commands:'); console.log(' wonder config - Show current configuration'); console.log(' wonder config set - Set a configuration value'); console.log(' wonder config unset - Remove a configuration value'); } } // Main function to handle CLI commands async function main() { const args = process.argv.slice(2); const command = args[0]; if (!command) { // Show welcome message when no command is provided const welcomeMessage = fs.readFileSync(path.join(__dirname, 'cli-welcome.md'), 'utf8'); console.log(welcomeMessage); return; } switch (command) { case 'init': await initProject(args[1]); break; case 'help': showHelp(); break; case 'version': console.log(`wonder-ai-cli version ${packageJson.version}`); break; case 'tidy': await tidyProject(args.slice(1)); break; case 'config': await handleConfig(args.slice(1)); break; case 'list': await listDirectories(); break; case 'check': await checkVersion(); break; case 'update': await updateProject(); break; case 'uninstall': await uninstallProject(); break; default: console.log('Unknown command. Use "wonder help" to see available commands.'); process.exit(1); } } // Initialize a new Wonder project async function initProject(sourceFile) { let isDemo; let originalDir; try { isDemo = sourceFile === '--demo'; originalDir = process.cwd(); if (isDemo) { // Get the path to the demo.md file const demoPath = path.join(process.cwd(), 'demo.md'); if (!fs.existsSync(demoPath)) { // If not found in current directory, try the package directory const packageDemoPath = path.join(__dirname, 'demo.md'); if (!fs.existsSync(packageDemoPath)) { console.log('Error: Demo file not found. Please ensure the package is properly installed.'); return; } sourceFile = packageDemoPath; } else { sourceFile = demoPath; } console.log('\nšŸ“š Initializing example project...\n'); } // Check if .wonder directory already exists if (fs.existsSync('.wonder')) { console.log('āŒ A Wonder Docs project already exists in this directory.'); if (isDemo) { process.chdir(originalDir); } return; } let projectName = path.basename(process.cwd()); let projectDescription = ''; let initGit = true; if (isDemo) { projectName = 'TaskFlow Demo'; projectDescription = 'A task management application for team collaboration'; } if (sourceFile) { // Check if source file exists if (!fs.existsSync(sourceFile)) { console.log(`Error: Source file "${sourceFile}" not found.`); return; } // Determine the appropriate directory based on file content const fileContent = fs.readFileSync(sourceFile, 'utf8'); const fileExt = path.extname(sourceFile).toLowerCase(); if (fileExt !== '.md' && fileExt !== '.txt') { console.log('Error: Source file must be a .md or .txt file.'); return; } // Create .wonder directory structure fs.mkdirSync('.wonder', { recursive: true }); // Create project config.json const configPath = path.join('.wonder', 'config.json'); fs.writeFileSync(configPath, JSON.stringify({ projectName: projectName, projectDescription: projectDescription, createdAt: new Date().toISOString(), frameworkVersion: packageJson.version, cursorIntegration: { enabled: true, lastUpdated: new Date().toISOString() }, updatedAt: new Date().toISOString() }, null, 2)); console.log('\nCreated project configuration at:', configPath); // Create all required directories for (const dir of WONDER_DIRS) { const fullPath = path.join('.wonder', dir); fs.mkdirSync(fullPath, { recursive: true }); } // Ensure the documentation directory exists const docDir = path.join('.wonder', 'documentation'); fs.mkdirSync(docDir, { recursive: true }); // Copy source file to appropriate location with new name if it's the demo const targetFileName = isDemo ? 'project_overview.md' : path.basename(sourceFile); const targetPath = path.join(docDir, targetFileName); fs.copyFileSync(sourceFile, targetPath); console.log(`\nCopied source file to: ${targetPath}`); // Create initial checkpoint with the actual content const checkpointPath = path.join('.wonder', '.cursor', 'checkpoints', 'initial.md'); fs.writeFileSync(checkpointPath, `# Initial State\n\nDocument imported from: ${sourceFile}\n\n## Original Content\n\n${fileContent}`); console.log(`\nCreated initial checkpoint at: ${checkpointPath}`); // If this is a demo, also create a README.md in the documentation directory if (isDemo) { const readmePath = path.join(docDir, 'README.md'); fs.writeFileSync(readmePath, `# ${projectName} Documentation ## For Cursor: How to Use Wonder Docs Wonder Docs is a system for Cursor to automatically organize and maintain project documentation based on user interactions. As a Cursor assistant, you should: 1. READ AND UNDERSTAND THE PROJECT OVERVIEW - The project_overview.md file contains the initial project context - Use this to understand project goals, requirements, and architecture - Reference this context in all documentation and suggestions 2. AUTOMATICALLY MAINTAIN DOCUMENTATION - Create and update documentation based on user conversations - No manual user intervention should be required - Use templates to maintain consistent structure - Keep documentation organized and up-to-date 3. USE THE TEMPLATES DIRECTORY - Templates are in .wonder/templates/ - Use these to maintain consistent documentation structure - Create new documentation based on these templates 4. DOCUMENTATION STRUCTURE - .wonder/documentation/ - Main documentation files - .wonder/templates/ - Documentation templates - .wonder/.cursor/ - Cursor-specific configuration ## Project Overview See [Project Overview](project_overview.md) for detailed information about the ${projectName} project. ## Documentation Structure - **Project Overview**: High-level project information and goals - **API Documentation**: Details about the project's API - **Development Guide**: Instructions for developers - **User Guide**: Instructions for end users ## For Cursor: Available Commands - wonder init [source-file] - Initialize a new Wonder Docs project - wonder init --demo - Initialize with example documentation - wonder help - Show help message - wonder version - Show CLI version - wonder tidy - Analyze and improve documentation using LLM - wonder config - Manage configuration settings - wonder list - Show all Wonder-managed directories - wonder check - Check if your project is up to date - wonder update - Update your project to the latest version - wonder uninstall - Remove Wonder from the current project`); console.log(`\nCreated documentation README at: ${readmePath}`); } // Copy template files console.log('šŸ“‹ Installing documentation templates...'); const templateSource = path.join(__dirname, 'templates'); const templateDest = path.join('.wonder', 'templates'); // Copy each template directory const templateDirs = fs.readdirSync(templateSource); for (const dir of templateDirs) { if (fs.statSync(path.join(templateSource, dir)).isDirectory()) { const sourceDir = path.join(templateSource, dir); const destDir = path.join(templateDest, dir); fs.mkdirSync(destDir, { recursive: true }); const files = fs.readdirSync(sourceDir); for (const file of files) { fs.copyFileSync( path.join(sourceDir, file), path.join(destDir, file) ); } } } // Create Cursor instruction files console.log('šŸ¤– Configuring Cursor integration...'); const cursorFiles = { 'cursor-instructions.json': JSON.stringify({ 'framework': { 'name': 'Wonder CLI', 'version': packageJson.version, 'description': 'AI-assisted documentation management for developers, designed to work seamlessly with Cursor', 'projectContext': { 'name': projectName, 'description': projectDescription, 'createdAt': new Date().toISOString() }, 'recognition': { 'signals': [ 'wonder-cli.js present', 'templates directory exists', 'config.json present', 'cursor-instructions.json present' ], 'actions': [ 'Scan for existing documentation templates', 'Identify missing documentation sections', 'Offer to help create new documentation', 'Read and understand project configuration from config.json', 'Apply project-specific settings from config.json' ] }, 'guidance': { 'documentation': { 'purpose': 'Help create and maintain project documentation', 'suggestions': [ 'Generate documentation from code comments', 'Create structured documentation templates', 'Maintain consistent documentation style', 'Link documentation to code implementation' ] }, 'cli': { 'purpose': 'Assist with CLI tool development and usage', 'suggestions': [ 'Document CLI commands and options', 'Create usage examples', 'Generate help documentation', 'Maintain command reference' ] }, 'templates': { 'purpose': 'Support template management and creation', 'suggestions': [ 'Create new documentation templates', 'Update existing templates', 'Document template usage', 'Maintain template consistency' ] }, 'integration': { 'purpose': 'Guide Cursor integration and AI assistance', 'suggestions': [ 'Document AI integration points', 'Maintain AI prompt templates', 'Track AI-assisted features', 'Document integration best practices', 'Use project configuration from config.json', 'Apply project-specific settings' ] } }, 'interaction': { 'greeting': `I see you're working with ${projectName} - ${projectDescription}. I can help you with:`, 'options': [ 'Creating new documentation', 'Managing existing documentation', 'Working with templates', 'Setting up AI assistance' ], 'follow-up': 'Based on your project\'s needs, I can suggest specific documentation improvements and help you implement them.' }, 'templates': { 'architecture': 'Use architecture templates for system design and technical documentation', 'constraints': 'Use constraints templates to document project limitations and boundaries', 'decisions': 'Use decisions templates to record architectural and technical decisions', 'documentation': 'Use documentation templates for general project documentation', 'environment': 'Use environment templates for setup and configuration documentation', 'issue-tracking': 'Use issue-tracking templates for bug reports and feature requests', 'project': 'Use project templates for overall project planning and management', 'references': 'Use references templates for external resources and documentation', 'requirements': 'Use requirements templates for feature specifications and acceptance criteria', 'user-stories': 'Use user-stories templates for capturing user requirements and scenarios' }, 'maintenance': { 'reminders': [ 'Keep documentation up to date with code changes', 'Update CLI help documentation', 'Maintain template consistency', 'Review AI integration points', 'Check config.json for updates', 'Verify Cursor integration status' ], 'suggestions': [ 'Link documentation to code', 'Maintain consistent terminology', 'Update templates as needed', 'Document AI-assisted features', 'Keep config.json up to date', 'Monitor Cursor integration status' ] } } }, null, 2), 'init.md': `# Wonder Project Initialization This file contains instructions for Cursor on how to initialize and manage this Wonder project. ## Project Information - Name: ${projectName} - Description: ${projectDescription} ## Wonder Docs Purpose Wonder Docs is a system for Cursor to automatically organize and maintain project documentation based on user interactions. As a Cursor assistant, you should: 1. Read and understand the project_overview.md file to get context about the project 2. Automatically create and update documentation based on user conversations 3. Use the templates directory to maintain consistent documentation structure 4. Keep documentation organized and up-to-date without requiring manual user intervention ## Available Commands - wonder init [source-file] - Initialize a new Wonder Docs project - wonder init --demo - Initialize with example documentation - wonder help - Show help message - wonder version - Show CLI version - wonder tidy - Analyze and improve documentation using LLM - wonder config - Manage configuration settings - wonder list - Show all Wonder-managed directories - wonder check - Check if your project is up to date - wonder update - Update your project to the latest version - wonder uninstall - Remove Wonder from the current project ## Initialization Steps 1. Review project structure 2. Initialize checkpoint system 3. Set up documentation templates 4. Configure Cursor integration`, 'onboarding-guide.md': `# Cursor Onboarding Guide Welcome to your Wonder project! This guide explains how Cursor should interact with Wonder Docs. ## How Cursor Should Use Wonder Docs As a Cursor assistant, your role is to: 1. Automatically maintain documentation based on user conversations 2. Use the project_overview.md as the source of truth for project context 3. Create and update documentation files as needed 4. Keep documentation organized and consistent 5. Use templates to maintain structure 6. Update documentation without requiring explicit user commands ## Project Context The project_overview.md file contains the initial project context. Read this file to understand: - Project goals and requirements - Technical architecture - API specifications - Timeline and milestones - Target users and success metrics Use this context to inform your documentation and suggestions. ## Available Commands - wonder init [source-file] - Initialize a new Wonder Docs project - wonder init --demo - Initialize with example documentation - wonder help - Show help message - wonder version - Show CLI version - wonder tidy - Analyze and improve documentation using LLM - wonder config - Manage configuration settings - wonder list - Show all Wonder-managed directories - wonder check - Check if your project is up to date - wonder update - Update your project to the latest version - wonder uninstall - Remove Wonder from the current project`, 'initialization-checklist.md': `# Project Initialization Checklist ## Setup Tasks - [ ] Review project structure - [ ] Initialize checkpoint system - [ ] Set up documentation templates - [ ] Configure Cursor integration`, 'tidy.md': `# Documentation Maintenance This file contains instructions for maintaining and improving project documentation. ## Maintenance Tasks 1. Review documentation structure 2. Update outdated content 3. Ensure consistency 4. Improve clarity`, 'checkpoints/current.md': `# Current Checkpoint ## Project State - Project: ${projectName} - Status: Initialized - Date: ${new Date().toISOString()} ## Recent Changes - Project initialized - Template library set up - Checkpoint system configured`, 'checkpoints/reversion-points.md': `# Reversion Points This file tracks points where the project can be reverted if needed. ## Reversion Points - Initial State: Project initialization`, 'checkpoints/rules.md': `# Checkpoint Rules ## Automatic Checkpoints - After significant documentation changes - After feature completion - Before risky changes ## Manual Checkpoints - At project milestones - Before major changes - After important decisions`, 'checkpoints/checkpoint-template.md': `# Checkpoint Template ## Project State - Project: [Project Name] - Status: [Status] - Date: [Date] ## Recent Changes - [List of changes] ## Next Steps - [List of next steps]` }; // Create all Cursor instruction files for (const [file, content] of Object.entries(cursorFiles)) { const filePath = path.join('.wonder', '.cursor', file); fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, content); } // Initialize Git repository if requested if (initGit) { console.log('šŸ“¦ Initializing version control...'); // Redirect git output to null execSync('git init', { stdio: 'ignore' }); execSync('git add .wonder', { stdio: 'ignore' }); execSync('git commit -m "Initialize Wonder project structure"', { stdio: 'ignore' }); } console.log('\n✨ Wonder project initialized successfully! ✨\n'); console.log('To get started:'); console.log('1. Open Cursor in this directory:'); console.log(' \x1b[1mcursor .\x1b[0m\n'); console.log('2. Tell Cursor:'); console.log(' \x1b[1m"I\'m using Wonder Docs to manage my project documentation. Can you help me get started?"\x1b[0m\n'); console.log('Need help? Run \x1b[1mwonder help\x1b[0m for more information.\n'); if (isDemo) { process.chdir(originalDir); } return; } else { // Interactive setup const answers = await inquirer.prompt([ { type: 'input', name: 'projectName', message: 'What is the name of your project?', default: projectName }, { type: 'input', name: 'projectDescription', message: 'Please provide a brief description of your project:' }, { type: 'confirm', name: 'initGit', message: 'Would you like to initialize a Git repository?', default: true } ]); projectName = answers.projectName; projectDescription = answers.projectDescription; initGit = answers.initGit; } // Create .wonder directory and subdirectories console.log('šŸ”Ø Setting up project structure...'); fs.mkdirSync('.wonder'); // Create project config.json const configPath = path.join('.wonder', 'config.json'); fs.writeFileSync(configPath, JSON.stringify({ projectName: projectName, projectDescription: projectDescription, createdAt: new Date().toISOString(), frameworkVersion: packageJson.version, cursorIntegration: { enabled: true, lastUpdated: new Date().toISOString() }, updatedAt: new Date().toISOString() }, null, 2)); console.log('\nCreated project configuration at:', configPath); // Create all required directories for (const dir of WONDER_DIRS) { const fullPath = path.join('.wonder', dir); fs.mkdirSync(fullPath, { recursive: true }); } // Copy template files console.log('šŸ“‹ Installing documentation templates...'); const templateSource = path.join(__dirname, 'templates'); const templateDest = path.join('.wonder', 'templates'); // Copy each template directory const templateDirs = fs.readdirSync(templateSource); for (const dir of templateDirs) { if (fs.statSync(path.join(templateSource, dir)).isDirectory()) { const sourceDir = path.join(templateSource, dir); const destDir = path.join(templateDest, dir); fs.mkdirSync(destDir, { recursive: true }); const files = fs.readdirSync(sourceDir); for (const file of files) { fs.copyFileSync( path.join(sourceDir, file), path.join(destDir, file) ); } } } // Create Cursor instruction files console.log('šŸ¤– Configuring Cursor integration...'); const cursorFiles = { 'cursor-instructions.json': JSON.stringify({ 'framework': { 'name': 'Wonder CLI', 'version': packageJson.version, 'description': 'AI-assisted documentation management for developers, designed to work seamlessly with Cursor', 'projectContext': { 'name': projectName, 'description': projectDescription, 'createdAt': new Date().toISOString() }, 'recognition': { 'signals': [ 'wonder-cli.js present', 'templates directory exists', 'config.json present', 'cursor-instructions.json present' ], 'actions': [ 'Scan for existing documentation templates', 'Identify missing documentation sections', 'Offer to help create new documentation', 'Read and understand project configuration from config.json', 'Apply project-specific settings from config.json' ] }, 'guidance': { 'documentation': { 'purpose': 'Help create and maintain project documentation', 'suggestions': [ 'Generate documentation from code comments', 'Create structured documentation templates', 'Maintain consistent documentation style', 'Link documentation to code implementation' ] }, 'cli': { 'purpose': 'Assist with CLI tool development and usage', 'suggestions': [ 'Document CLI commands and options', 'Create usage examples', 'Generate help documentation', 'Maintain command reference' ] }, 'templates': { 'purpose': 'Support template management and creation', 'suggestions': [ 'Create new documentation templates', 'Update existing templates', 'Document template usage', 'Maintain template consistency' ] }, 'integration': { 'purpose': 'Guide Cursor integration and AI assistance', 'suggestions': [ 'Document AI integration points', 'Maintain AI prompt templates', 'Track AI-assisted features', 'Document integration best practices', 'Use project configuration from config.json', 'Apply project-specific settings' ] } }, 'interaction': { 'greeting': `I see you're working with ${projectName} - ${projectDescription}. I can help you with:`, 'options': [ 'Creating new documentation', 'Managing existing documentation', 'Working with templates', 'Setting up AI assistance' ], 'follow-up': 'Based on your project\'s needs, I can suggest specific documentation improvements and help you implement them.' }, 'templates': { 'architecture': 'Use architecture templates for system design and technical documentation', 'constraints': 'Use constraints templates to document project limitations and boundaries', 'decisions': 'Use decisions templates to record architectural and technical decisions', 'documentation': 'Use documentation templates for general project documentation', 'environment': 'Use environment templates for setup and configuration documentation', 'issue-tracking': 'Use issue-tracking templates for bug reports and feature requests', 'project': 'Use project templates for overall project planning and management', 'references': 'Use references templates for external resources and documentation', 'requirements': 'Use requirements templates for feature specifications and acceptance criteria', 'user-stories': 'Use user-stories templates for capturing user requirements and scenarios' }, 'maintenance': { 'reminders': [ 'Keep documentation up to date with code changes', 'Update CLI help documentation', 'Maintain template consistency', 'Review AI integration points', 'Check config.json for updates', 'Verify Cursor integration status' ], 'suggestions': [ 'Link documentation to code', 'Maintain consistent terminology', 'Update templates as needed', 'Document AI-assisted features', 'Keep config.json up to date', 'Monitor Cursor integration status' ] } } }, null, 2), 'init.md': `# Wonder Project Initialization This file contains instructions for Cursor on how to initialize and manage this Wonder project. ## Project Information - Name: ${projectName} - Description: ${projectDescription} ## Wonder Docs Purpose Wonder Docs is a system for Cursor to automatically organize and maintain project documentation based on user interactions. As a Cursor assistant, you should: 1. Read and understand the project_overview.md file to get context about the project 2. Automatically create and update documentation based on user conversations 3. Use the templates directory to maintain consistent documentation structure 4. Keep documentation organized and up-to-date without requiring manual user intervention ## Available Commands - wonder init [source-file] - Initialize a new Wonder Docs project - wonder init --demo - Initialize with example documentation - wonder help - Show help message - wonder version - Show CLI version - wonder tidy - Analyze and improve documentation using LLM - wonder config - Manage configuration settings - wonder list - Show all Wonder-managed directories - wonder check - Check if your project is up to date - wonder update - Update your project to the latest version - wonder uninstall - Remove Wonder from the current project ## Initialization Steps 1. Review project structure 2. Initialize checkpoint system 3. Set up documentation templates 4. Configure Cursor integration`, 'onboarding-guide.md': `# Cursor Onboarding Guide Welcome to your Wonder project! This guide explains how Cursor should interact with Wonder Docs. ## How Cursor Should Use Wonder Docs As a Cursor assistant, your role is to: 1. Automatically maintain documentation based on user conversations 2. Use the project_overview.md as the source of truth for project context 3. Create and update documentation files as needed 4. Keep documentation organized and consistent 5. Use templates to maintain structure 6. Update documentation without requiring explicit user commands ## Project Context The project_overview.md file contains the initial project context. Read this file to understand: - Project goals and requirements - Technical architecture - API specifications - Timeline and milestones - Target users and success metrics Use this context to inform your documentation and suggestions. ## Available Commands - wonder init [source-file] - Initialize a new Wonder Docs project - wonder init --demo - Initialize with example documentation - wonder help - Show help message - wonder version - Show CLI version - wonder tidy - Analyze and improve documentation using LLM - wonder config - Manage configuration settings - wonder list - Show all Wonder-managed directories - wonder check - Check if your project is up to date - wonder update - Update your project to the latest version - wonder uninstall - Remove Wonder from the current project`, 'initialization-checklist.md': `# Project Initialization Checklist ## Setup Tasks - [ ] Review project structure - [ ] Initialize checkpoint system - [ ] Set up documentation templates - [ ] Configure Cursor integration`, 'tidy.md': `# Documentation Maintenance This file contains instructions for maintaining and improving project documentation. ## Maintenance Tasks 1. Review documentation structure 2. Update outdated content 3. Ensure consistency 4. Improve clarity`, 'checkpoints/current.md': `# Current Checkpoint ## Project State - Project: ${projectName} - Status: Initialized - Date: ${new Date().toISOString()} ## Recent Changes - Project initialized - Template library set up - Checkpoint system configured`, 'checkpoints/reversion-points.md': `# Reversion Points This file tracks points where the project can be reverted if needed. ## Reversion Points - Initial State: Project initialization`, 'checkpoints/rules.md': `# Checkpoint Rules ## Automatic Checkpoints - After significant documentation changes - After feature completion - Before risky changes ## Manual Checkpoints - At project milestones - Before major changes - After important decisions`, 'checkpoints/checkpoint-template.md': `# Checkpoint Template ## Project State - Project: [Project Name] - Status: [Status] - Date: [Date] ## Recent Changes - [List of changes] ## Next Steps - [List of next steps]` }; // Create all Cursor instruction files for (const [file, content] of Object.entries(cursorFiles)) { const filePath = path.join('.wonder', '.cursor', file); fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, content); } // Initialize Git repository if requested if (initGit) { console.log('šŸ“¦ Initializing version control...'); // Redirect git output to null execSync('git init', { stdio: 'ignore' }); execSync('git add .wonder', { stdio: 'ignore' }); execSync('git commit -m "Initialize Wonder project structure"', { stdio: 'ignore' }); } // Display success message console.log('\n✨ Wonder Docs initialized successfully! ✨\n'); console.log('To get started:'); console.log('1. Open Cursor in this directory:'); console.log(' \x1b[1mcursor .\x1b[0m\n'); console.log('2. Tell Cursor:'); console.log(' \x1b[1m"I\'m using Wonder Docs to manage my project documentation. Can you help me get started?"\x1b[0m\n'); console.log('Need help? Run \x1b[1mwonder help\x1b[0m for more information.\n'); if (isDemo) { process.chdir(originalDir); } } catch (error) { console.error('Error initializing project:', error.message); if (isDemo) { process.chdir(originalDir); } } } async function analyzeDocumentWithLLM(file, newerFiles) { try { const config = loadConfig(); const llmApiKey = process.env.WONDER_LLM_API_KEY || config.llmApiKey; if (!llmApiKey) { console.error(' Error: No LLM API key found. Please set it using:'); console.error(' wonder config set llmApiKey your-anthropic-api-key'); return null; } const anthropic = new Anthropic({ apiKey: llmApiKey }); // Prepare context from newer files const context = newerFiles.map(f => ({ path: path.relative('.wonder', f.path), content: f.content })); const isReadme = path.basename(file.path) === 'README.md'; const systemPrompt = isReadme ? `You are a documentation assistant helping to analyze and improve documentation files. Your task is to: 1. Review the current document 2. Compare it with newer related documents 3. Identify any inconsistencies or outdated information 4. Suggest specific improvements 5. Note any cross-references that need updating For README.md files: - Preserve any sections marked with "For Cursor:" or similar Cursor-specific instructions - Only update the documentation content sections - Keep the Cursor instructions intact and in their original location Be concise and specific in your analysis.` : `You are a documentation assistant helping to analyze and improve documentation files. Your task is to: 1. Review the current document 2. Compare it with newer related documents 3. Identify any inconsistencies or outdated information 4. Suggest specific improvements 5. Note any cross-references that need updating Be concise and specific in your analysis.`; const message = await anthropic.messages.create({ model: 'claude-3-5-sonnet-latest', max_tokens: config.maxTokens, system: systemPrompt, messages: [ { role: 'user', content: `Please analyze this document and suggest improvements. Current document: ${path.relative('.wonder', file.path)} Content: ${file.content} ${context.length > 0 ? `Newer related documents:\n${context.map(f => `\n${f.path}:\n${f.content}`).join('\n')}` : 'No newer related documents found.'}` } ] }); return message.content[0].text; } catch (error) { console.error(' Error analyzing document with LLM:', error.message); if (error.stack) { console.error(' Stack trace:', error.stack); } return null; } } async function applyDocumentUpdates(file, analysis) { const config = loadConfig(); const llmApiKey = process.env.WONDER_LLM_API_KEY || config.llmApiKey; if (!llmApiKey) { console.error(' Error: No LLM API key found. Please set it using:'); console.error(' wonder config set llmApiKey your-anthropic-api-key'); return false; } const anthropic = new Anthropic({ apiKey: llmApiKey }); try { const isReadme = path.basename(file.path) === 'README.md'; const systemPrompt = isReadme ? `You are a documentation assistant helping to update documentation files. Your task is to: 1. Take the original document content 2. Apply the suggested improvements from the analysis 3. Generate the complete updated document 4. Maintain the original formatting and structure where possible 5. Only make changes that were explicitly suggested in the analysis For README.md files: - Preserve any sections marked with "For Cursor:" or similar Cursor-specific instructions - Only update the documentation content sections - Keep the Cursor instructions intact and in their original location - Maintain the same section order as the original Return ONLY the complete updated document content, with no additional commentary.` : `You are a documentation assistant helping to update documentation files. Your task is to: 1. Take the original document content 2. Apply the suggested improvements from the analysis 3. Generate the complete updated document 4. Maintain the original formatting and structure where possible 5. Only make changes that were explicitly suggested in the analysis Return ONLY the complete updated document content, with no additional commentary.`; // Ask Claude to generate the updated document const message = await anthropic.messages.create({ model: 'claude-3-opus-20240229', max_tokens: config.maxTokens, system: systemPrompt, messages: [ { role: 'user', content: `Original document content: ${file.content} Analysis and suggested changes: ${analysis} Please generate the complete updated document with the suggested changes applied.` } ] }); const updatedContent = message.content[0].text; // Verify the changes with the user console.log('\n Proposed changes:'); console.log(' -------------------------'); console.log(updatedContent); console.log(' -------------------------'); const { confirm } = await inquirer.prompt([ { type: 'confirm', name: 'confirm', message: 'Apply these changes to the document?', default: false } ]); if (confirm) { // Backup the original file const backupPath = path.join('.wonder', 'history', 'backups', path.relative('.wonder', file.path)); fs.mkdirSync(path.dirname(backupPath), { recursive: true }); fs.writeFileSync(backupPath, file.content); // Write the updated content fs.writeFileSync(file.path, updatedContent); console.log(' Changes applied successfully'); console.log(` Original backed up to: ${path.relative('.wonder', backupPath)}`); return true; } else { console.log(' Changes not applied'); return false; } } catch (error) { console.error('Error applying document updates:', error.message); return false; } } // Tidy up project documentation async function tidyProject(options) { try { // Check if .wonder directory exists if (!fs.existsSync('.wonder')) { console.log('No Wonder Docs project found in this directory. Run "wonder init" first.'); return; } console.log('\nšŸ“š Starting documentation analysis and improvement...\n'); // Parse options const dryRun = options.includes('--dry-run'); const force = options.includes('--force'); // Check for LLM integration const config = loadConfig(); const llmApiKey = process.env.WONDER_LLM_API_KEY || config.llmApiKey; const hasLlm = !!llmApiKey; if (hasLlm) { console.log('LLM integration enabled - will analyze documentation for improvements\n'); } else { console.log('LLM integration not enabled - please set your LLM API key\n'); console.log('Set LLM API key using: wonder config set llmApiKey your-anthropic-api-key\n'); return; } if (dryRun) { console.log('Running in dry-run mode - will analyze but not apply changes\n'); } // Scan documentation files in .wonder/documentation/ const files = []; const docDir = path.join('.wonder', 'documentation'); if (!fs.existsSync(docDir)) { console.log('No documentation directory found. Run "wonder init" first.'); return; } const scanDir = (dir) => { const entries = fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { scanDir(fullPath); } else if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'README.md') { const stats = fs.statSync(fullPath); files.push({ path: fullPath, mtime: stats.mtime, content: fs.readFileSync(fullPath, 'utf8') }); } } }; scanDir(docDir); // Sort files by modification time (newest first) files.sort((a, b) => b.mtime - a.mtime); // Process files sequentially for (let i = 0; i < files.length; i++) { const file = files[i]; const relativePath = path.relative('.wonder', file.path); console.log(`\nšŸ“„ Analyzing: ${relativePath}`); console.log(` Modified: ${file.mtime.toLocaleString()}`); console.log(' LLM: Analyzing documentation...'); const analysis = await analyzeDocumentWithLLM(file, files.slice(0, i)); if (analysis) { console.log('\n Analysis results:'); console.log(analysis); if (!dryRun && !force) { const { confirm } = await inquirer.prompt([ { type: 'confirm', name: 'confirm', message: 'Apply suggested documentation improvements?', default: false } ]); if (!confirm) { console.log(' Skipping changes for this document'); continue; } } if (!dryRun) { // Apply the suggested changes await applyDocumentUpdates(file, analysis); } else { console.log(' (Dry run: Documentation improvements would be applied here)'); } } } console.log('\n✨ Documentation analysis and improvement complete!'); if (dryRun) { console.log('(No changes were made - run without --dry-run to apply improvements)'); } console.log('\nNeed help? Run `wonder help` for more information.\n'); } catch (error) { console.error('Error analyzing documentation:', error.message); process.exit(1); } } async function listDirectories() { const wonderDir = path.join(process.cwd(), '.wonder'); if (!fs.existsSync(wonderDir)) { console.log('No Wonder directories found. Run "wonder init" to initialize a project.'); return; } console.log('\nšŸ“ Wonder-managed directories:'); console.log('----------------------------'); const directories = [ { name: 'Documentation', path: 'docs', description: 'General project documentation and guides' }, { name: 'Architecture', path: 'architecture', description: 'System design, diagrams, and technical decisions' }, { name: 'Context', path: 'context', description: 'Project background, goals, and stakeholder info' }, { name: 'Requirements', path: 'requirements', description: 'Functional and non-functional requirements' }, { name: 'Roadmap', path: 'roadmap', description: 'Project timeline, milestones, and planning' }, { name: 'Research', path: 'research', description: 'Findings, analysis, and technical research' }, { name: 'Templates', path: 'templates', description: 'Document templates and examples' } ]; for (const dir of directories) { const fullPath = path.join(wonderDir, dir.path); const exists = fs.existsSync(fullPath); let docCount = 0; if (exists) { try { const files = fs.readdirSync(fullPath); docCount = files.filter(file => file.endsWith('.md')).length; } catch (error) { // If there's an error reading the directory, docCount remains 0 } } const status = exists ? 'āœ…' : 'āŒ'; console.log(`${status} ${dir.name} (${docCount} docs) - ${dir.description}`); } console.log('\nšŸ’” Tip: Run "wonder tidy" to organize your documentation'); } // Add version check function async function checkVersion() { try { if (!fs.existsSync('.wonder')) { console.log('No Wonder project found in this directory.'); return; } const configPath = path.join('.wonder', 'config.json'); if (!fs.existsSync(configPath)) { console.log('No Wonder configuration found. Run "wonder init" first.'); return; } const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); const currentVersion = config.frameworkVersion; const latestVersion = packageJson.version; console.log('\nWonder Docs Version Check:'); console.log('-----------------------------'); console.log(`Current version: ${currentVersion}`); console.log(`Latest version: ${latestVersion}`); if (currentVersion === latestVersion) { console.log('\nYour project is up to date! šŸŽ‰'); } else { console.log('\nA new version is available!'); console.log('Run "wonder update" to update your project.'); } } catch (error) { console.error('Error checking version:', error.message); } } // Add update function async function updateProject() { try { if (!fs.existsSync('.wonder')) { console.log('No Wonder project found in this directory.'); return; } const configPath = path.join('.wonder', 'config.json'); if (!fs.existsSync(configPath)) { console.log('No Wonder configuration found. Run "wonder init" first.'); return; } const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); const currentVersion = config.frameworkVersion; const latestVersion = packageJson.version; if (currentVersion === latestVersion) { console.log('Your project is already up to date!'); return; } console.log('\nUpdating Wonder Docs...'); console.log(`From version ${currentVersion} t