diff --git a/.github/AUTOMATION.md b/.github/AUTOMATION.md new file mode 100644 index 0000000..d91fbde --- /dev/null +++ b/.github/AUTOMATION.md @@ -0,0 +1,196 @@ +# Automation Overview + +This document describes the automated workflows in the AutoReadMe project. + +## Workflows + +### 1. AutoReadMe Generation (`autoreadme.yml`) + +**Purpose:** Automatically regenerate README.md when code changes + +**Trigger:** Push to `main` branch + +**Steps:** +1. Checkout repository +2. Install dependencies +3. Build the CLI tool +4. Run `autoreadme generate` +5. Commit updated README.md + +**Use case:** Keeps README synchronized with package.json and project structure + +--- + +### 2. AGENTS.md Changelog (`update-agents.yml`) + +**Purpose:** Automatically track significant changes in AGENTS.md + +**Trigger:** Push to `main` branch (excluding AGENTS.md changes) + +**Steps:** +1. Checkout full git history +2. Run update script on latest commit +3. Parse commit message and files +4. Update AGENTS.md if significant +5. Commit changes back + +**Significant commit types:** +- `feat:` - New features +- `fix:` - Bug fixes +- `refactor:` - Code refactoring +- `perf:` - Performance improvements +- `breaking:` - Breaking changes +- `docs:` - Major documentation (with add/create/implement keywords) + +**Significant files:** +- Anything in `src/` +- `package.json` +- `.github/workflows/` + +--- + +## Update Script Details + +### Script: `.github/scripts/update-agents.mjs` + +**Language:** Node.js (ESM) + +**Key Functions:** + +1. **`isSignificantCommit(message, files)`** + - Filters commits by type and changed files + - Returns boolean + +2. **`getCommitDetails(commitHash)`** + - Extracts subject, body, author, date, files + - Returns commit object + +3. **`categorizeCommit(message)`** + - Categorizes by type: feature, fix, refactor, etc. + - Returns category string + +4. **`extractKeyChanges(commit)`** + - Parses commit body for bullet points + - Infers changes from files if no body + - Returns array of changes + +5. **`formatCommitEntry(commit)`** + - Creates formatted markdown entry + - Includes commit hash, date, changes + - Returns formatted string + +6. **`updateAgentsFile(commitHash)`** + - Main function orchestrating the update + - Creates/finds month section + - Inserts entry and updates timestamp + - Writes to AGENTS.md + +### Best Practices for Commits + +To get the best automated changelog entries: + +#### ✅ Good commit format: +``` +feat: add Python project detection + +- Scan for requirements.txt file +- Extract dependencies from pip format +- Generate Python-specific README template +``` + +#### ✅ Another good example: +``` +fix: handle missing package.json gracefully + +Scanner now returns default values when package.json is missing +instead of throwing an error. +``` + +#### ❌ Poor commit format: +``` +update stuff +``` + +#### ❌ Too vague: +``` +feat: improvements +``` + +### Manual Testing + +Test the script locally before pushing: + +```bash +# Test with specific commit +node .github/scripts/update-agents.mjs abc1234 + +# Test with HEAD +node .github/scripts/update-agents.mjs HEAD + +# Test with previous commit +node .github/scripts/update-agents.mjs HEAD~1 +``` + +--- + +## Workflow Coordination + +Both workflows run independently but are coordinated: + +1. **Paths exclusion** prevents infinite loops +2. **`update-agents.yml`** ignores changes to `AGENTS.md` +3. **`autoreadme.yml`** runs on all main branch pushes +4. Both use same bot credentials for commits + +## Maintenance + +### Updating the script + +1. Edit `.github/scripts/update-agents.mjs` +2. Test locally with sample commits +3. Commit with clear message +4. Workflow will use updated script on next run + +### Adjusting filters + +Edit `isSignificantCommit()` function to change: +- Which commit types are tracked +- Which files trigger updates +- Additional filtering logic + +### Customizing format + +Edit `formatCommitEntry()` function to change: +- Entry structure +- Markdown formatting +- What information is included + +--- + +## Troubleshooting + +### Script fails silently +- Check `continue-on-error: true` in workflow +- Review GitHub Actions logs for script output +- Test locally with same commit hash + +### Entries not appearing +- Verify commit type matches significant types +- Check that significant files were changed +- Ensure commit isn't self-referential + +### Formatting issues +- Check `formatCommitEntry()` function +- Verify markdown syntax in output +- Test with sample commit locally + +### Merge conflicts +- Script updates AGENTS.md atomically +- Conflicts should be rare +- Manually resolve if needed, script will continue + +--- + +**Maintained by:** AutoReadMe project +**Last Updated:** 2025-11-19 +**License:** MIT diff --git a/.github/scripts/README.md b/.github/scripts/README.md new file mode 100644 index 0000000..92b1999 --- /dev/null +++ b/.github/scripts/README.md @@ -0,0 +1,92 @@ +# Automation Scripts + +This directory contains automation scripts for the AutoReadMe project. + +## update-agents.mjs + +Automatically updates `AGENTS.md` with significant commits. + +### How it works + +1. **Triggered** by GitHub Actions on every push to `main` branch +2. **Analyzes** the commit message and changed files +3. **Filters** for significant commits: + - `feat:` / `feature:` - New features + - `fix:` - Bug fixes + - `refactor:` - Code refactoring + - `perf:` - Performance improvements + - `breaking:` - Breaking changes + - Major documentation changes (with `docs:` prefix) + +4. **Extracts** key changes from: + - Commit body (bullet points) + - Files changed (if no body) + - Commit subject line + +5. **Updates** AGENTS.md by: + - Creating or finding the current month section + - Adding formatted entry with commit hash, date, and changes + - Updating the "Last Updated" timestamp + +6. **Commits** changes back to repository automatically + +### Running locally + +```bash +# Test with a specific commit +node .github/scripts/update-agents.mjs + +# Test with latest commit +node .github/scripts/update-agents.mjs HEAD +``` + +### Commit message format + +For best results, use [Conventional Commits](https://www.conventionalcommits.org/) format: + +``` +type: subject line + +- Key change 1 +- Key change 2 +- Key change 3 +``` + +**Examples:** + +``` +feat: add Rust project template support + +- Created src/templates/rust.hbs template +- Updated scanner to detect Cargo.toml +- Added Rust-specific usage examples +``` + +``` +fix: handle missing package.json gracefully + +- Added file existence check in scanner +- Return default project info on error +- Added error logging +``` + +### Skipped commits + +The script skips: +- Non-significant commit types (chore, style, test) +- Commits that don't change significant files +- Self-referential commits (updating AGENTS.md itself) +- Minor documentation fixes + +### Configuration + +Edit the script to adjust: +- `significantTypes` - Which commit types to track +- `isSignificantCommit()` - Filtering logic +- `extractKeyChanges()` - Change extraction logic +- `formatCommitEntry()` - Entry formatting + +--- + +**Maintained by:** AutoReadMe automation system +**License:** MIT diff --git a/.github/scripts/update-agents.mjs b/.github/scripts/update-agents.mjs new file mode 100755 index 0000000..dc12fc2 --- /dev/null +++ b/.github/scripts/update-agents.mjs @@ -0,0 +1,230 @@ +#!/usr/bin/env node + +import { readFileSync, writeFileSync, existsSync } from 'fs'; +import { execSync } from 'child_process'; + +/** + * Parse commit message to determine if it's significant + * Significant commits include: feat, fix, refactor, perf, docs (for major docs) + */ +function isSignificantCommit(message, files) { + const lowerMsg = message.toLowerCase(); + + // Check conventional commit types + const significantTypes = ['feat:', 'feature:', 'fix:', 'refactor:', 'perf:', 'breaking:']; + const isSignificant = significantTypes.some(type => lowerMsg.startsWith(type)); + + // Check if it's a major documentation change (not just typos) + const isMajorDocs = lowerMsg.startsWith('docs:') && ( + lowerMsg.includes('add') || + lowerMsg.includes('create') || + lowerMsg.includes('implement') + ); + + // Check if significant files were changed + const significantFiles = files.some(f => + f.includes('src/') || + f.includes('package.json') || + f.includes('.github/workflows/') + ); + + return (isSignificant || isMajorDocs) && significantFiles; +} + +/** + * Get commit details + */ +function getCommitDetails(commitHash) { + try { + const subject = execSync(`git log -1 --format=%s ${commitHash}`, { encoding: 'utf8' }).trim(); + const body = execSync(`git log -1 --format=%b ${commitHash}`, { encoding: 'utf8' }).trim(); + const author = execSync(`git log -1 --format=%an ${commitHash}`, { encoding: 'utf8' }).trim(); + const date = execSync(`git log -1 --format=%ad --date=short ${commitHash}`, { encoding: 'utf8' }).trim(); + const files = execSync(`git diff-tree --no-commit-id --name-only -r ${commitHash}`, { encoding: 'utf8' }) + .trim() + .split('\n') + .filter(Boolean); + + return { subject, body, author, date, files, hash: commitHash.substring(0, 7) }; + } catch (error) { + console.error('Error getting commit details:', error.message); + return null; + } +} + +/** + * Categorize commit based on message + */ +function categorizeCommit(message) { + const lower = message.toLowerCase(); + + if (lower.startsWith('feat:') || lower.startsWith('feature:')) return 'feature'; + if (lower.startsWith('fix:')) return 'fix'; + if (lower.startsWith('refactor:')) return 'refactor'; + if (lower.startsWith('perf:')) return 'performance'; + if (lower.startsWith('docs:')) return 'documentation'; + if (lower.includes('breaking') || lower.startsWith('breaking:')) return 'breaking'; + + return 'other'; +} + +/** + * Extract key changes from commit body and files + */ +function extractKeyChanges(commit) { + const changes = []; + const { subject, body, files } = commit; + + // Parse body for bullet points or key changes + if (body) { + const lines = body.split('\n').filter(line => { + const trimmed = line.trim(); + return trimmed.startsWith('-') || trimmed.startsWith('*') || trimmed.startsWith('•'); + }); + + lines.forEach(line => { + const cleaned = line.trim().replace(/^[-*•]\s*/, ''); + if (cleaned && !cleaned.toLowerCase().includes('co-authored-by')) { + changes.push(cleaned); + } + }); + } + + // If no bullet points in body, infer from files changed + if (changes.length === 0) { + const srcFiles = files.filter(f => f.startsWith('src/')); + if (srcFiles.length > 0) { + changes.push(`Modified: ${srcFiles.map(f => `\`${f}\``).join(', ')}`); + } + + const workflowFiles = files.filter(f => f.includes('.github/workflows/')); + if (workflowFiles.length > 0) { + changes.push(`Updated GitHub Actions workflow`); + } + + const templateFiles = files.filter(f => f.includes('templates/')); + if (templateFiles.length > 0) { + changes.push(`Modified templates: ${templateFiles.map(f => f.split('/').pop()).join(', ')}`); + } + } + + return changes; +} + +/** + * Format commit entry for AGENTS.md + */ +function formatCommitEntry(commit) { + const category = categorizeCommit(commit.subject); + const changes = extractKeyChanges(commit); + + let entry = `#### ${commit.subject} (${commit.date})\n`; + entry += `**Commit:** \`${commit.hash}\`\n\n`; + + if (category === 'breaking') { + entry += `⚠️ **BREAKING CHANGE**\n\n`; + } + + if (changes.length > 0) { + entry += `**Changes:**\n`; + changes.forEach(change => { + entry += `- ${change}\n`; + }); + } else { + // Fallback to just the subject + entry += `**Changes:**\n`; + entry += `- ${commit.subject.split(':').slice(1).join(':').trim()}\n`; + } + + entry += `\n`; + return entry; +} + +/** + * Get the current month/year section header + */ +function getCurrentSection() { + const now = new Date(); + const month = now.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }); + return `### ${month}`; +} + +/** + * Update AGENTS.md with new commit + */ +function updateAgentsFile(commitHash) { + const agentsPath = 'AGENTS.md'; + + if (!existsSync(agentsPath)) { + console.log('AGENTS.md not found, skipping update'); + return false; + } + + const commit = getCommitDetails(commitHash); + if (!commit) { + console.log('Could not retrieve commit details'); + return false; + } + + // Check if this is a significant commit + if (!isSignificantCommit(commit.subject, commit.files)) { + console.log(`Skipping non-significant commit: ${commit.subject}`); + return false; + } + + // Skip if this is the AGENTS.md update commit itself + if (commit.subject.toLowerCase().includes('update agents.md') || + commit.subject.toLowerCase().includes('update changelog')) { + console.log('Skipping automated AGENTS.md update commit'); + return false; + } + + let content = readFileSync(agentsPath, 'utf8'); + + // Find or create the current month section + const currentSection = getCurrentSection(); + const sectionRegex = new RegExp(`^${currentSection.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'm'); + + const entry = formatCommitEntry(commit); + + if (sectionRegex.test(content)) { + // Section exists, add entry after the section header + content = content.replace( + sectionRegex, + `${currentSection}\n\n${entry}` + ); + } else { + // Create new section under "## Recent Changes" + const recentChangesPos = content.indexOf('## Recent Changes'); + if (recentChangesPos !== -1) { + // Find the end of "## Recent Changes" line + const lineEnd = content.indexOf('\n', recentChangesPos); + // Insert new section + content = + content.substring(0, lineEnd + 1) + + `\n${currentSection}\n\n${entry}` + + content.substring(lineEnd + 1); + } else { + console.error('Could not find "## Recent Changes" section'); + return false; + } + } + + // Update the "Last Updated" timestamp at the bottom + const today = new Date().toISOString().split('T')[0]; + content = content.replace( + /\*\*Last Updated:\*\* \d{4}-\d{2}-\d{2}/, + `**Last Updated:** ${today}` + ); + + writeFileSync(agentsPath, content, 'utf8'); + console.log(`✅ Updated AGENTS.md with commit ${commit.hash}`); + return true; +} + +// Main execution +const commitHash = process.argv[2] || process.env.GITHUB_SHA || 'HEAD'; +console.log(`Processing commit: ${commitHash}`); + +const updated = updateAgentsFile(commitHash); +process.exit(updated ? 0 : 1); diff --git a/.github/workflows/update-agents.yml b/.github/workflows/update-agents.yml new file mode 100644 index 0000000..ba8eb01 --- /dev/null +++ b/.github/workflows/update-agents.yml @@ -0,0 +1,57 @@ +name: Update AGENTS.md + +on: + push: + branches: [main] + paths-ignore: + - 'AGENTS.md' + - '.github/workflows/update-agents.yml' + +jobs: + update-changelog: + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for commit analysis + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Make script executable + run: chmod +x .github/scripts/update-agents.mjs + + - name: Update AGENTS.md + id: update + run: | + if node .github/scripts/update-agents.mjs ${{ github.sha }}; then + echo "updated=true" >> $GITHUB_OUTPUT + else + echo "updated=false" >> $GITHUB_OUTPUT + fi + continue-on-error: true + + - name: Commit changes + if: steps.update.outputs.updated == 'true' + run: | + git config user.name "AutoReadMe Bot" + git config user.email "bot@users.noreply.github.com" + git add AGENTS.md + if git diff --staged --quiet; then + echo "No changes to commit" + else + git commit -m "chore: update AGENTS.md changelog + +Automated update from workflow. + +Co-authored-by: frpboy12 +Generated with [Continue](https://continue.dev) + +Co-Authored-By: Continue " + git push + fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..21d36f4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,134 @@ +# AGENTS.md + +This document tracks significant changes, features, and improvements to the AutoReadMe project, specifically focusing on contributions made through AI agents and automated workflows. + +## Recent Changes + +### October 2025 + +#### Project Initialization (2025-10-20) +**Commit:** `66dba1c` - Add MIT License section to README + +**Major Changes:** +- **Initial project setup** with complete TypeScript-based CLI tool +- **Core functionality implemented:** + - Project scanner (`src/scanner.ts`) that detects Node.js, Python, or generic projects + - README generator (`src/generator.ts`) using Handlebars templates + - CLI interface (`src/index.ts`) powered by Commander.js + +- **Template system created:** + - `default.hbs` - Generic project template + - `node.hbs` - Node.js-specific template with npm instructions + - `python.hbs` - Python-specific template with pip instructions + +- **GitHub Actions workflow added:** + - Automatic README generation on push to main branch + - Auto-commits changes back to repository + - Runs on Ubuntu with Node.js 20 + +- **Project infrastructure:** + - TypeScript configuration with ESM modules + - Build system using tsup for bundling + - Dependencies: commander, fs-extra, handlebars, globby + - MIT License applied + +- **Documentation:** + - Comprehensive README with quick start guide + - Usage examples and CLI options + - Contributing guidelines + - MIT License section clarifying usage rights + +**Key Features Implemented:** +- Auto-detection of project type from `package.json` or `requirements.txt` +- Badge generation (build status, license) +- Customizable output path via `--out` flag +- Template selection via `--template` flag +- Dependency listing in generated READMEs +- Usage examples tailored to project type + +## Architecture Overview + +### Core Components + +1. **Scanner (`src/scanner.ts`)** + - Detects project type by checking for `package.json` or `requirements.txt` + - Extracts metadata: name, description, license, dependencies + - Returns structured `ProjectInfo` object + +2. **Generator (`src/generator.ts`)** + - Loads appropriate Handlebars template + - Compiles template with project data + - Writes formatted README.md to disk + - Generates badges for build and license + +3. **CLI (`src/index.ts`)** + - Command-line interface using Commander.js + - `generate` command with template and output options + - Executes generation workflow + +4. **Templates (`src/templates/*.hbs`)** + - Handlebars-based templating system + - Separate templates for Node.js, Python, and generic projects + - Variables: projectName, description, license, usageExample, dependencies, badges + +### Build & Distribution + +- **TypeScript** source with ESM module format +- **tsup** for fast bundling with minification and source maps +- **bin** entry point: `autoreadme` CLI command +- Can be installed globally via `npm link` or used directly + +### Automation + +- **GitHub Action** workflow runs on every push to main +- Auto-generates and commits README updates +- Ensures documentation stays synchronized with project changes + +## Development Workflow + +### Commands +```bash +npm install # Install dependencies +npm run build # Build CLI tool +npm run start # Run built CLI +npm run test:local # Test generation locally +``` + +### Adding New Templates + +1. Create `src/templates/{language}.hbs` +2. Update scanner to detect the new project type +3. Add template selection logic in generator + +### Extension Points + +- **Scanner:** Add detection logic for more project types (Rust, Go, etc.) +- **Templates:** Create language-specific templates with relevant sections +- **Generator:** Extend badge generation or add AI enhancement stubs +- **CLI:** Add more command options or subcommands + +## Next Steps & Roadmap + +### Planned Enhancements +- AI-powered README polishing (stub exists in CLI options) +- Support for additional languages: Rust, Go, Java, etc. +- Configurable template variables via config file +- More sophisticated dependency analysis +- Section customization options +- Integration with package managers for better metadata extraction + +### Testing +- Add unit tests for scanner, generator, and template rendering +- Integration tests for CLI commands +- Template validation tests + +### Publishing +- Prepare for npm registry publication +- Version management and changelog generation +- Documentation improvements for contributors + +--- + +**Last Updated:** 2025-10-20 +**Maintained by:** frpboy12 +**License:** MIT