Update development instructions and guidelines (#29)

* Delete outdated development instructions for Next.js + Tailwind and Python; add comprehensive guidelines for PostgreSQL DBA, Angular, ASP.NET REST APIs, Azure Functions with TypeScript, Bicep, Blazor, CMake with vcpkg, C#, .NET MAUI, GenAIScript, Terraform for Azure, localization, and markdown standards.

* Update documentation and prompts for consistency and clarity

- Standardized description formatting in various markdown files to use single quotes.
- Added error handling utility in update-readme.js for safer file operations.
- Improved title extraction logic in update-readme.js to handle frontmatter more robustly.
- Updated chat modes section in README to reflect new emoji and sorted chat mode links.
- Cleaned up various instruction files for better readability and consistency.
- Ensured all markdown files end with a newline for better compatibility with version control.

* Remove standardize-frontmatter.js script

* Add usage instructions for creating and switching chat modes in README.md

* Update README.md generation script to enhance instructions and usage details for custom chat modes

* Update README.md and update-readme.js for improved instruction clarity and consistency

* Refactor README.md links and update readme script for improved clarity and consistency in instructions

* Update README.md and update-readme.js for improved instruction clarity and consistency

* Changing from a patch to regen approach for the readme

* Bit more cleanup for how to show things in the readme

* Adding missing description

* Another missing description

---------

Co-authored-by: Aaron Powell <me@aaron-powell.com>
This commit is contained in:
James Montemagno 2025-07-02 18:18:52 -07:00 committed by GitHub
parent d1256681e7
commit 6fb794bc79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 447 additions and 486 deletions

View File

@ -6,7 +6,7 @@ Enhance your GitHub Copilot experience with community-contributed instructions,
GitHub Copilot provides three main ways to customize AI responses and tailor assistance to your specific workflows, team guidelines, and project requirements:
| **🔧 Custom Instructions** | **📝 Reusable Prompts** | **🎭 Custom Chat Modes** |
| **🔧 Custom Instructions** | **📝 Reusable Prompts** | **🧩 Custom Chat Modes** |
| --- | --- | --- |
| Define common guidelines for tasks like code generation, reviews, and commit messages. Describe *how* tasks should be performed<br><br>**Benefits:**<br>• Automatic inclusion in every chat request<br>• Repository-wide consistency<br>• Multiple implementation options | Create reusable, standalone prompts for specific tasks. Describe *what* should be done with optional task-specific guidelines<br><br>**Benefits:**<br>• Eliminate repetitive prompt writing<br>• Shareable across teams<br>• Support for variables and dependencies | Define chat behavior, available tools, and codebase interaction patterns within specific boundaries for each request<br><br>**Benefits:**<br>• Context-aware assistance<br>• Tool configuration<br>• Role-specific workflows |
@ -21,22 +21,21 @@ We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md)
Team and project-specific instructions to enhance GitHub Copilot's behavior for specific technologies and coding practices:
- [Angular Development Instructions](instructions/angular.md) - Angular-specific coding standards and best practices
- [ASP.NET REST API Development](instructions/aspnet-rest-apis.md) - Guidelines for building REST APIs with ASP.NET
- [Azure Functions Typescript](instructions/azure-functions-typescript.md) - TypeScript patterns for Azure Functions
- [Bicep Code Best Practices](instructions/bicep-code-best-practices.md) - Infrastructure as Code with Bicep
- [Blazor](instructions/blazor.md) - Blazor component and application patterns
- [Cmake Vcpkg](instructions/cmake-vcpkg.md) - C++ project configuration and package management
- [Angular Development Instructions](instructions/angular.instructions.md) - Angular-specific coding standards and best practices
- [ASP.NET REST API Development](instructions/aspnet-rest-apis.instructions.md) - Guidelines for building REST APIs with ASP.NET
- [Azure Functions Typescript](instructions/azure-functions-typescript.instructions.md) - TypeScript patterns for Azure Functions
- [Bicep Code Best Practices](instructions/bicep-code-best-practices.instructions.md) - Infrastructure as Code with Bicep
- [Blazor](instructions/blazor.instructions.md) - Blazor component and application patterns
- [Cmake Vcpkg](instructions/cmake-vcpkg.instructions.md) - C++ project configuration and package management
- [Copilot Process tracking Instructions](instructions/copilot-thought-logging.instructions.md) - See process Copilot is following where you can edit this to reshape the interaction or save when follow up may be needed
- [C# Development](instructions/csharp.md) - Guidelines for building C# applications
- [Dotnet Maui](instructions/dotnet-maui.md) - MAUI component and application patterns
- [Genaiscript](instructions/genaiscript.md) - AI-powered script generation guidelines
- [Generate Modern Terraform Code For Azure](instructions/generate-modern-terraform-code-for-azure.md) - Guidelines for generating modern Terraform code for Azure
- [Guidance for Localization](instructions/localization.md) - Guidelines for localizing markdown documents
- [Markdown](instructions/markdown.md) - Documentation and content creation standards
- [Next.js + Tailwind Development Instructions](instructions/nextjs-tailwind.md) - Next.js + Tailwind development standards and instructions
- [Python Coding Conventions](instructions/python.md) - Python coding conventions and guidelines
- [C# Development](instructions/csharp.instructions.md) - Guidelines for building C# applications
- [.NET MAUI](instructions/dotnet-maui.instructions.md) - .NET MAUI component and application patterns
- [Genaiscript](instructions/genaiscript.instructions.md) - AI-powered script generation guidelines
- [Generate Modern Terraform Code For Azure](instructions/generate-modern-terraform-code-for-azure.instructions.md) - Guidelines for generating modern Terraform code for Azure
- [Guidance for Localization](instructions/localization.instructions.md) - Guidelines for localizing markdown documents
- [Markdown](instructions/markdown.instructions.md) - Documentation and content creation standards
- [Next.js + Tailwind Development Instructions](instructions/nextjs-tailwind.instructions.md) - Next.js + Tailwind development standards and instructions
- [Python Coding Conventions](instructions/python.instructions.md) - Python coding conventions and guidelines
> 💡 **Usage**: Copy these instructions to your `.github/copilot-instructions.md` file or create task-specific `.github/.instructions.md` files in your workspace's `.github/instructions` folder.
@ -44,27 +43,20 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for
Ready-to-use prompt templates for specific development scenarios and tasks, defining prompt text with a specific mode, model, and available set of tools.
### Backend Development
- [ASP.NET Minimal API with OpenAPI](prompts/aspnet-minimal-api-openapi.prompt.md) - Generate API endpoints with proper documentation
- [Entity Framework Core Best Practices](prompts/ef-core.prompt.md) - Database operations and ORM patterns
- [Multi-Stage Dockerfile](prompts/multi-stage-dockerfile.prompt.md) - Optimized container builds for any technology
### Testing & Quality
- [C# Async Programming](prompts/csharp-async.prompt.md) - Asynchronous programming best practices
- [MSTest Best Practices](prompts/csharp-mstest.prompt.md) - MSTest unit testing with data-driven tests
- [NUnit Best Practices](prompts/csharp-nunit.prompt.md) - NUnit testing patterns and assertions
- [XUnit Best Practices](prompts/csharp-xunit.prompt.md) - XUnit testing with modern C# features
- [JavaScript/TypeScript Jest](prompts/javascript-typescript-jest.prompt.md) - Jest testing patterns, mocking, and structure
### Documentation & Project Management
- [Comment Code Generate Tutorial](prompts/comment-code-generate-a-tutorial.prompt.md) - Transform code into educational content
- [Generate Specs as Issues](prompts/gen-specs-as-issues.prompt.md) - Convert requirements into GitHub issues
- [ASP.NET Minimal API with OpenAPI](prompts/aspnet-minimal-api-openapi.prompt.md) - Create ASP.NET Minimal API endpoints with proper OpenAPI documentation
- [Azure Cost Optimize](prompts/az-cost-optimize.prompt.md) - Analyze Azure resources used in the app (IaC files and/or resources in a target rg) and optimize costs - creating GitHub issues for identified optimizations.
- [Comment Code Generate A Tutorial](prompts/comment-code-generate-a-tutorial.prompt.md) - Transform this Python script into a polished, beginner-friendly project by refactoring the code, adding clear instructional comments, and generating a complete markdown tutorial.
- [C# Async Programming Best Practices](prompts/csharp-async.prompt.md) - Get best practices for C# async programming
- [C# Documentation Best Practices](prompts/csharp-docs.prompt.md) - Ensure that C# types are documented with XML comments and follow best practices for documentation.
- [MSTest Best Practices](prompts/csharp-mstest.prompt.md) - Get best practices for MSTest unit testing, including data-driven tests
- [NUnit Best Practices](prompts/csharp-nunit.prompt.md) - Get best practices for NUnit unit testing, including data-driven tests
- [XUnit Best Practices](prompts/csharp-xunit.prompt.md) - Get best practices for XUnit unit testing, including data-driven tests
- [Entity Framework Core Best Practices](prompts/ef-core.prompt.md) - Get best practices for Entity Framework Core
- [Product Manager Assistant: Feature Identification and Specification](prompts/gen-specs-as-issues.prompt.md) - This workflow guides you through a systematic approach to identify missing features, prioritize them, and create detailed specifications for implementation.
- [Javascript Typescript Jest](prompts/javascript-typescript-jest.prompt.md) - Best practices for writing JavaScript/TypeScript tests using Jest, including mocking strategies, test structure, and common patterns.
- [Multi Stage Dockerfile](prompts/multi-stage-dockerfile.prompt.md) - Create optimized multi-stage Dockerfiles for any language or framework
- [My Issues](prompts/my-issues.prompt.md)
- [My Pull Requests](prompts/my-pull-requests.prompt.md)
- [C# Documentation Best Practices](prompts/csharp-docs.prompt.md) - Ensure that C# types are documented with XML comments and follow best practices for documentation.
### FinOps
- [Azure Cost Optimize](prompts/az-cost-optimize.prompt.md) - Analyze Azure resources used in the app (IaC files and/or resources in a target rg) and optimize costs - creating GitHub issues for identified optimizations.
> 💡 **Usage**: Use `/prompt-name` in VS Code chat, run `Chat: Run Prompt` command, or hit the run button while you have a prompt open.
@ -73,12 +65,11 @@ Ready-to-use prompt templates for specific development scenarios and tasks, defi
Custom chat modes define specific behaviors and tools for GitHub Copilot Chat, enabling enhanced context-aware assistance for particular tasks or workflows.
- [4.1 Beast Mode](chatmodes/4.1-Beast.chatmode.md) - A custom prompt to get GPT 4.1 to behave like a top-notch coding agent.
- [Database Administrator Chat Mode](chatmodes/PostgreSQL%20DBA.chatmode.md) - Work with PostgreSQL databases using the PostgreSQL extension.
- [Debug Mode Instructions](chatmodes/debug.chatmode.md) - Debug your application to find and fix a bug
- [Planning mode instructions](chatmodes/planner.chatmode.md) - Generate an implementation plan for new features or refactoring existing code.
- [PostgreSQL Database Administrator](chatmodes/postgresql-dba.chatmode.md) - Work with PostgreSQL databases using the PostgreSQL extension.
- [Refine Requirement or Issue Chat Mode](chatmodes/refine-issue.chatmode.md) - Refine the requirement or issue with Acceptance Criteria, Technical Considerations, Edge Cases, and NFRs
> 💡 **Usage**: Create new chat modes using the command `Chat: Configure Chat Modes...`, then switch your chat mode in the Chat input from _Agent_ or _Ask_ to your own mode.
## 📚 Additional Resources

View File

@ -1,5 +1,5 @@
---
description: Debug your application to find and fix a bug
description: 'Debug your application to find and fix a bug'
tools: ['codebase', 'readFiles', 'editFiles', 'githubRepo', 'runCommands', 'fetch', 'search', 'usages', 'findTestFiles', 'get_errors', 'test_failure', 'run_in_terminal', 'get_terminal_output']
---

View File

@ -1,5 +1,5 @@
---
description: Generate an implementation plan for new features or refactoring existing code.
description: 'Generate an implementation plan for new features or refactoring existing code.'
tools: ['codebase', 'fetch', 'findTestFiles', 'githubRepo', 'search', 'usages']
---
# Planning mode instructions

View File

@ -1,9 +1,11 @@
---
description: 'Work with PostgreSQL databases using the PostgreSQL extension.'
tools: ['codebase', 'editFiles', 'githubRepo', 'runCommands', 'database', 'pgsql_bulkLoadCsv', 'pgsql_connect', 'pgsql_describeCsv', 'pgsql_disconnect', 'pgsql_listDatabases', 'pgsql_listServers', 'pgsql_modifyDatabase', 'pgsql_open_script', 'pgsql_query', 'pgsql_visualizeSchema']
tools: ['codebase', 'editFiles', 'githubRepo', 'extensions', 'runCommands', 'database', 'pgsql_bulkLoadCsv', 'pgsql_connect', 'pgsql_describeCsv', 'pgsql_disconnect', 'pgsql_listDatabases', 'pgsql_listServers', 'pgsql_modifyDatabase', 'pgsql_open_script', 'pgsql_query', 'pgsql_visualizeSchema']
---
# Database Administrator Chat Mode
# PostgreSQL Database Administrator
Before running any tools, use #extensions to ensure that `ms-ossdata.vscode-pgsql` is installed and enabled. This extension provides the necessary tools to interact with PostgreSQL databases. If it is not installed, ask the user to install it before continuing.
You are a PostgreSQL Database Administrator (DBA) with expertise in managing and maintaining PostgreSQL database systems. You can perform tasks such as:
- Creating and managing databases

View File

@ -1,6 +1,6 @@
---
description: |
Angular-specific coding standards and best practices
description: 'Angular-specific coding standards and best practices'
applyTo: '**/*.ts, **/*.html, **/*.scss, **/*.css'
---
# Angular Development Instructions

View File

@ -1,5 +1,6 @@
---
description: Guidelines for building REST APIs with ASP.NET
description: 'Guidelines for building REST APIs with ASP.NET'
applyTo: '**/*.cs, **/*.json'
---
# ASP.NET REST API Development

View File

@ -1,5 +1,6 @@
---
description: TypeScript patterns for Azure Functions
description: 'TypeScript patterns for Azure Functions'
applyTo: '**/*.ts, **/*.js, **/*.json'
---
## Guidance for Code Generation

View File

@ -1,6 +1,6 @@
---
description: Infrastructure as Code with Bicep
applyTo: "**/*.bicep"
description: 'Infrastructure as Code with Bicep'
applyTo: '**/*.bicep'
---
## Naming Conventions

View File

@ -1,6 +1,6 @@
---
description: Blazor component and application patterns
applyTo: "**/*.razor, **/*.razor.cs, **/*.razor.css"
description: 'Blazor component and application patterns'
applyTo: '**/*.razor, **/*.razor.cs, **/*.razor.css'
---
## Blazor Code Style and Structure

View File

@ -1,5 +1,6 @@
---
description: C++ project configuration and package management
description: 'C++ project configuration and package management'
applyTo: '**/*.cmake, **/CMakeLists.txt, **/*.cpp, **/*.h, **/*.hpp'
---
This project uses vcpkg in manifest mode. Please keep this in mind when giving vcpkg suggestions. Do not provide suggestions like vcpkg install library, as they will not work as expected.

View File

@ -1,6 +1,5 @@
---
applyTo: '**'
mode: "agent"
description: 'See process Copilot is following where you can edit this to reshape the interaction or save when follow up may be needed'
---

View File

@ -1,5 +1,6 @@
---
description: Guidelines for building C# applications
description: 'Guidelines for building C# applications'
applyTo: '**/*.cs'
---
# C# Development

View File

@ -1,12 +1,14 @@
---
description: MAUI component and application patterns
appliesTo: "**/*.xaml, **/*.cs"
description: '.NET MAUI component and application patterns'
applyTo: '**/*.xaml, **/*.cs'
---
## MAUI Code Style and Structure
# .NET MAUI
- Write idiomatic and efficient MAUI and C# code.
- Follow .NET and MAUI conventions.
## .NET MAUI Code Style and Structure
- Write idiomatic and efficient .NET MAUI and C# code.
- Follow .NET and .NET MAUI conventions.
- Prefer inline functions for smaller components but separate complex logic into code-behind or service classes.
- Async/await should be used where applicable to ensure non-blocking UI operations.
@ -16,16 +18,16 @@ appliesTo: "**/*.xaml, **/*.cs"
- Use camelCase for private fields and local variables.
- Prefix interface names with "I" (e.g., IUserService).
## MAUI and .NET Specific Guidelines
## .NET MAUI and .NET Specific Guidelines
- Utilize MAUI's built-in features for component lifecycle (e.g. OnAppearing, OnDisappearing).
- Utilize .NET MAUI's built-in features for component lifecycle (e.g. OnAppearing, OnDisappearing).
- Use data binding effectively with {Binding}.
- Structure MAUI components and services following Separation of Concerns.
- Structure .NET MAUI components and services following Separation of Concerns.
- Always use the latest version C#, currently C# 13 features like record types, pattern matching, and global usings.
## Error Handling and Validation
- Implement proper error handling for MAUI pages and API calls.
- Implement proper error handling for .NET MAUI pages and API calls.
- Use logging for error tracking in the backend and consider capturing UI-level errors in MAUI with tools like MAUI Community Toolkit's Logger.
- Implement validation using FluentValidation or DataAnnotations in forms.

View File

@ -1,6 +1,6 @@
---
applyTo: "**/*.genai.*"
description: AI-powered script generation guidelines
description: 'AI-powered script generation guidelines'
applyTo: '**/*.genai.*'
---
## Role

View File

@ -1,6 +1,6 @@
---
description: Guidelines for generating modern Terraform code for Azure
applyTo: "**/*.tf"
description: 'Guidelines for generating modern Terraform code for Azure'
applyTo: '**/*.tf'
---
## 1. Use Latest Terraform and Providers

View File

@ -1,6 +1,6 @@
---
description: Guidelines for localizing markdown documents
applyTo: "**/*.md"
description: 'Guidelines for localizing markdown documents'
applyTo: '**/*.md'
---
# Guidance for Localization

View File

@ -1,6 +1,6 @@
---
description: Documentation and content creation standards
applyTo: "**/*.md"
description: 'Documentation and content creation standards'
applyTo: '**/*.md'
---
## Markdown Content Rules

View File

@ -1,5 +1,6 @@
---
description: Next.js + Tailwind development standards and instructions
description: 'Next.js + Tailwind development standards and instructions'
applyTo: '**/*.tsx, **/*.ts, **/*.jsx, **/*.js, **/*.css'
---
# Next.js + Tailwind Development Instructions

View File

@ -1,5 +1,6 @@
---
description: Python coding conventions and guidelines
description: 'Python coding conventions and guidelines'
applyTo: '**/*.py'
---
# Python Coding Conventions

View File

@ -1,9 +1,11 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems"]
description: "Create ASP.NET Minimal API endpoints with proper OpenAPI documentation"
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems']
description: 'Create ASP.NET Minimal API endpoints with proper OpenAPI documentation'
---
# ASP.NET Minimal API with OpenAPI
Your goal is to help me create well-structured ASP.NET Minimal API endpoints with correct types and comprehensive OpenAPI/Swagger documentation.
## API Organization

View File

@ -1,9 +1,10 @@
---
mode: agent
description: Analyze Azure resources used in the app (IaC files and/or resources in a target rg) and optimize costs - creating GitHub issues for identified optimizations.
mode: 'agent'
description: 'Analyze Azure resources used in the app (IaC files and/or resources in a target rg) and optimize costs - creating GitHub issues for identified optimizations.'
---
## Overview
# Azure Cost Optimize
This workflow analyzes Infrastructure-as-Code (IaC) files and Azure resources to generate cost optimization recommendations. It creates individual GitHub issues for each optimization opportunity plus one EPIC issue to coordinate implementation, enabling efficient tracking and execution of cost savings initiatives.
## Prerequisites

View File

@ -1,3 +1,7 @@
---
description: 'Transform this Python script into a polished, beginner-friendly project by refactoring the code, adding clear instructional comments, and generating a complete markdown tutorial.'
---
Transform this Python script into a polished, beginner-friendly project by refactoring the code, adding clear instructional comments, and generating a complete markdown tutorial.
1. **Refactor the code**

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems"]
description: "Get best practices for C# async programming"
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems']
description: 'Get best practices for C# async programming'
---
# C# Async Programming Best Practices

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems"]
description: "Ensure that C# types are documented with XML comments and follow best practices for documentation."
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems']
description: 'Ensure that C# types are documented with XML comments and follow best practices for documentation.'
---
# C# Documentation Best Practices

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems", "search"]
description: "Get best practices for MSTest unit testing, including data-driven tests"
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems', 'search']
description: 'Get best practices for MSTest unit testing, including data-driven tests'
---
# MSTest Best Practices

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems", "search"]
description: "Get best practices for NUnit unit testing, including data-driven tests"
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems', 'search']
description: 'Get best practices for NUnit unit testing, including data-driven tests'
---
# NUnit Best Practices

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems", "search"]
description: "Get best practices for XUnit unit testing, including data-driven tests"
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems', 'search']
description: 'Get best practices for XUnit unit testing, including data-driven tests'
---
# XUnit Best Practices

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["changes", "codebase", "editFiles", "problems", "runCommands"]
description: "Get best practices for Entity Framework Core"
mode: 'agent'
tools: ['changes', 'codebase', 'editFiles', 'problems', 'runCommands']
description: 'Get best practices for Entity Framework Core'
---
# Entity Framework Core Best Practices

View File

@ -1,3 +1,7 @@
---
description: 'This workflow guides you through a systematic approach to identify missing features, prioritize them, and create detailed specifications for implementation.'
---
# Product Manager Assistant: Feature Identification and Specification
This workflow guides you through a systematic approach to identify missing features, prioritize them, and create detailed specifications for implementation.

View File

@ -1,5 +1,5 @@
---
description: "Best practices for writing JavaScript/TypeScript tests using Jest, including mocking strategies, test structure, and common patterns."
description: 'Best practices for writing JavaScript/TypeScript tests using Jest, including mocking strategies, test structure, and common patterns.'
---
### Test Structure

View File

@ -1,7 +1,7 @@
---
mode: "agent"
tools: ["codebase"]
description: "Create optimized multi-stage Dockerfiles for any language or framework"
mode: 'agent'
tools: ['codebase']
description: 'Create optimized multi-stage Dockerfiles for any language or framework'
---
Your goal is to help me create efficient multi-stage Dockerfiles that follow best practices, resulting in smaller, more secure container images.

View File

@ -1,7 +1,7 @@
---
mode: agent
mode: 'agent'
tools: ['githubRepo', 'github', 'get_issue', 'get_issue_comments', 'get_me', 'list_issues']
description: "List my issues in the current repository"
description: 'List my issues in the current repository'
---
Search the current repo (using #githubRepo for the repo info) and list any issues you find (using #list_issues) that are assigned to me.

View File

@ -1,7 +1,7 @@
---
mode: agent
mode: 'agent'
tools: ['githubRepo', 'github', 'get_me', 'get_pull_request', 'get_pull_request_comments', 'get_pull_request_diff', 'get_pull_request_files', 'get_pull_request_reviews', 'get_pull_request_status', 'list_pull_requests', 'request_copilot_review']
description: "List my pull requests in the current repository"
description: 'List my pull requests in the current repository'
---
Search the current repo (using #githubRepo for the repo info) and list any pull requests you find (using #list_pull_requests) that are assigned to me.

View File

@ -3,191 +3,260 @@
const fs = require("fs");
const path = require("path");
function extractTitle(filePath) {
// Template sections for the README
const TEMPLATES = {
header: `# 🤖 Awesome GitHub Copilot Customizations
Enhance your GitHub Copilot experience with community-contributed instructions, prompts, and configurations. Get consistent AI assistance that follows your team's coding standards and project requirements.
## 🎯 GitHub Copilot Customization Features
GitHub Copilot provides three main ways to customize AI responses and tailor assistance to your specific workflows, team guidelines, and project requirements:
| **🔧 Custom Instructions** | **📝 Reusable Prompts** | **🧩 Custom Chat Modes** |
| --- | --- | --- |
| Define common guidelines for tasks like code generation, reviews, and commit messages. Describe *how* tasks should be performed<br><br>**Benefits:**<br> Automatic inclusion in every chat request<br> Repository-wide consistency<br> Multiple implementation options | Create reusable, standalone prompts for specific tasks. Describe *what* should be done with optional task-specific guidelines<br><br>**Benefits:**<br> Eliminate repetitive prompt writing<br> Shareable across teams<br> Support for variables and dependencies | Define chat behavior, available tools, and codebase interaction patterns within specific boundaries for each request<br><br>**Benefits:**<br> Context-aware assistance<br> Tool configuration<br> Role-specific workflows |
> **💡 Pro Tip:** Custom instructions only affect Copilot Chat (not inline code completions). You can combine all three customization types - use custom instructions for general guidelines, prompt files for specific tasks, and chat modes to control the interaction context.
## 📝 Contributing
We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md) for details on how to submit new instructions and prompts.`,
instructionsSection: `## 📋 Custom Instructions
Team and project-specific instructions to enhance GitHub Copilot's behavior for specific technologies and coding practices:`,
instructionsUsage: `> 💡 **Usage**: Copy these instructions to your \`.github/copilot-instructions.md\` file or create task-specific \`.github/.instructions.md\` files in your workspace's \`.github/instructions\` folder.`,
promptsSection: `## 🎯 Reusable Prompts
Ready-to-use prompt templates for specific development scenarios and tasks, defining prompt text with a specific mode, model, and available set of tools.`,
promptsUsage: `> 💡 **Usage**: Use \`/prompt-name\` in VS Code chat, run \`Chat: Run Prompt\` command, or hit the run button while you have a prompt open.`,
chatmodesSection: `## 🧩 Custom Chat Modes
Custom chat modes define specific behaviors and tools for GitHub Copilot Chat, enabling enhanced context-aware assistance for particular tasks or workflows.`,
chatmodesUsage: `> 💡 **Usage**: Create new chat modes using the command \`Chat: Configure Chat Modes...\`, then switch your chat mode in the Chat input from _Agent_ or _Ask_ to your own mode.`,
footer: `## 📚 Additional Resources
- [VS Code Copilot Customization Documentation](https://code.visualstudio.com/docs/copilot/copilot-customization) - Official Microsoft documentation
- [GitHub Copilot Chat Documentation](https://code.visualstudio.com/docs/copilot/chat/copilot-chat) - Complete chat feature guide
- [Custom Chat Modes](https://code.visualstudio.com/docs/copilot/chat/chat-modes) - Advanced chat configuration
- [VS Code Settings](https://code.visualstudio.com/docs/getstarted/settings) - General VS Code configuration guide
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## 🤝 Code of Conduct
Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
## Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must follow
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.`,
};
// Add error handling utility
function safeFileOperation(operation, filePath, defaultValue = null) {
try {
const content = fs.readFileSync(filePath, "utf8");
const lines = content.split("\n");
return operation();
} catch (error) {
console.error(`Error processing file ${filePath}: ${error.message}`);
return defaultValue;
}
}
// Step 1: Look for title in frontmatter for all file types
let inFrontmatter = false;
let frontmatterEnded = false;
function extractTitle(filePath) {
return safeFileOperation(
() => {
const content = fs.readFileSync(filePath, "utf8");
const lines = content.split("\n");
for (const line of lines) {
if (line.trim() === "---") {
if (!inFrontmatter) {
inFrontmatter = true;
} else if (!frontmatterEnded) {
frontmatterEnded = true;
}
continue;
}
// Step 1: Look for title in frontmatter for all file types
let inFrontmatter = false;
let frontmatterEnded = false;
if (inFrontmatter && !frontmatterEnded) {
// Look for title field in frontmatter
const titleMatch = line.match(/^title:\s*['"]?(.+?)['"]?$/);
if (titleMatch) {
return titleMatch[1].trim();
}
}
}
// Reset for second pass
inFrontmatter = false;
frontmatterEnded = false;
// Step 2: For prompt/chatmode files, look for heading after frontmatter
if (filePath.includes(".prompt.md") || filePath.includes(".chatmode.md")) {
for (const line of lines) {
if (line.trim() === "---") {
if (!inFrontmatter) {
inFrontmatter = true;
} else if (inFrontmatter && !frontmatterEnded) {
} else if (!frontmatterEnded) {
frontmatterEnded = true;
}
continue;
}
if (frontmatterEnded && line.startsWith("# ")) {
if (inFrontmatter && !frontmatterEnded) {
// Look for title field in frontmatter
if (line.includes("title:")) {
// Extract everything after 'title:'
const afterTitle = line
.substring(line.indexOf("title:") + 6)
.trim();
// Remove quotes if present
const cleanTitle = afterTitle.replace(/^['"]|['"]$/g, "");
return cleanTitle;
}
}
}
// Reset for second pass
inFrontmatter = false;
frontmatterEnded = false;
// Step 2: For prompt/chatmode/instructions files, look for heading after frontmatter
if (
filePath.includes(".prompt.md") ||
filePath.includes(".chatmode.md") ||
filePath.includes(".instructions.md")
) {
for (const line of lines) {
if (line.trim() === "---") {
if (!inFrontmatter) {
inFrontmatter = true;
} else if (inFrontmatter && !frontmatterEnded) {
frontmatterEnded = true;
}
continue;
}
if (frontmatterEnded && line.startsWith("# ")) {
return line.substring(2).trim();
}
}
// Step 3: Format filename for prompt/chatmode/instructions files if no heading found
const basename = path.basename(
filePath,
filePath.includes(".prompt.md")
? ".prompt.md"
: filePath.includes(".chatmode.md")
? ".chatmode.md"
: ".instructions.md"
);
return basename
.replace(/[-_]/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase());
}
// Step 4: For instruction files, look for the first heading
for (const line of lines) {
if (line.startsWith("# ")) {
return line.substring(2).trim();
}
}
// Step 3: Format filename for prompt/chatmode files if no heading found
const basename = path.basename(
filePath,
filePath.includes(".prompt.md") ? ".prompt.md" : ".chatmode.md"
);
// Step 5: Fallback to filename
const basename = path.basename(filePath, path.extname(filePath));
return basename
.replace(/[-_]/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase());
}
// Step 4: For instruction files, look for the first heading
for (const line of lines) {
if (line.startsWith("# ")) {
return line.substring(2).trim();
}
}
// Step 5: Fallback to filename
const basename = path.basename(filePath, path.extname(filePath));
return basename
},
filePath,
path
.basename(filePath, path.extname(filePath))
.replace(/[-_]/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase());
} catch (error) {
// Fallback to filename
const basename = path.basename(filePath, path.extname(filePath));
return basename
.replace(/[-_]/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase());
}
.replace(/\b\w/g, (l) => l.toUpperCase())
);
}
function extractDescription(filePath) {
try {
const content = fs.readFileSync(filePath, "utf8");
return safeFileOperation(
() => {
const content = fs.readFileSync(filePath, "utf8");
// Parse frontmatter for description (for both prompts and instructions)
const lines = content.split("\n");
let inFrontmatter = false;
let frontmatterEnded = false;
// Parse frontmatter for description (for both prompts and instructions)
const lines = content.split("\n");
let inFrontmatter = false;
let frontmatterEnded = false;
// For multi-line descriptions
let isMultilineDescription = false;
let multilineDescription = [];
// For multi-line descriptions
let isMultilineDescription = false;
let multilineDescription = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.trim() === "---") {
if (!inFrontmatter) {
inFrontmatter = true;
} else if (inFrontmatter && !frontmatterEnded) {
frontmatterEnded = true;
break;
}
continue;
}
if (inFrontmatter && !frontmatterEnded) {
// Check for multi-line description with pipe syntax (|)
const multilineMatch = line.match(/^description:\s*\|(\s*)$/);
if (multilineMatch) {
isMultilineDescription = true;
// Continue to next line to start collecting the multi-line content
if (line.trim() === "---") {
if (!inFrontmatter) {
inFrontmatter = true;
} else if (inFrontmatter && !frontmatterEnded) {
frontmatterEnded = true;
break;
}
continue;
}
// If we're collecting a multi-line description
if (isMultilineDescription) {
// If the line has no indentation or has another frontmatter key, stop collecting
if (!line.startsWith(" ") || line.match(/^[a-zA-Z0-9_-]+:/)) {
isMultilineDescription = false;
// Join the collected lines and return
return multilineDescription.join(" ").trim();
if (inFrontmatter && !frontmatterEnded) {
// Check for multi-line description with pipe syntax (|)
const multilineMatch = line.match(/^description:\s*\|(\s*)$/);
if (multilineMatch) {
isMultilineDescription = true;
// Continue to next line to start collecting the multi-line content
continue;
}
// Add the line to our multi-line collection (removing the 2-space indentation)
multilineDescription.push(line.substring(2));
} else {
// Look for single-line description field in frontmatter
const descriptionMatch = line.match(
/^description:\s*['"]?(.+?)['"]?$/
);
if (descriptionMatch) {
return descriptionMatch[1];
// If we're collecting a multi-line description
if (isMultilineDescription) {
// If the line has no indentation or has another frontmatter key, stop collecting
if (!line.startsWith(" ") || line.match(/^[a-zA-Z0-9_-]+:/)) {
isMultilineDescription = false;
// Join the collected lines and return
return multilineDescription.join(" ").trim();
}
// Add the line to our multi-line collection (removing the 2-space indentation)
multilineDescription.push(line.substring(2));
} else {
// Look for single-line description field in frontmatter
const descriptionMatch = line.match(
/^description:\s*['"]?(.+?)['"]?$/
);
if (descriptionMatch) {
return descriptionMatch[1];
}
}
}
}
}
// If we've collected multi-line description but the frontmatter ended
if (multilineDescription.length > 0) {
return multilineDescription.join(" ").trim();
}
// If we've collected multi-line description but the frontmatter ended
if (multilineDescription.length > 0) {
return multilineDescription.join(" ").trim();
}
return null;
} catch (error) {
return null;
}
return null;
},
filePath,
null
);
}
function updateInstructionsSection(
currentReadme,
instructionFiles,
instructionsDir
) {
const instructionsSection = currentReadme.match(
/## 📋 Custom Instructions\n\nTeam and project-specific instructions.+?(?=\n\n>)/s
);
/**
* Generate the instructions section with an alphabetical list of all instructions
*/
function generateInstructionsSection(instructionsDir) {
// Get all instruction files
const instructionFiles = fs
.readdirSync(instructionsDir)
.filter((file) => file.endsWith(".md"))
.sort();
if (!instructionsSection) {
return currentReadme;
}
console.log(`Found ${instructionFiles.length} instruction files`);
// Extract existing instruction links from README
const existingInstructionLinks = [];
const instructionLinkRegex = /\[.*?\]\(instructions\/(.+?)\)/g;
let match;
let instructionsContent = "";
while ((match = instructionLinkRegex.exec(currentReadme)) !== null) {
existingInstructionLinks.push(match[1]);
}
// Find new instructions that aren't already in the README
const newInstructionFiles = instructionFiles.filter(
(file) => !existingInstructionLinks.includes(file)
);
if (newInstructionFiles.length === 0) {
console.log("No new instructions to add.");
} else {
console.log(`Found ${newInstructionFiles.length} new instructions to add.`);
}
let instructionsListContent = "\n\n";
// Generate alphabetically sorted list of instruction links
// Generate list items for each instruction file
for (const file of instructionFiles) {
const filePath = path.join(instructionsDir, file);
const title = extractTitle(filePath);
@ -196,210 +265,100 @@ function updateInstructionsSection(
// Check if there's a description in the frontmatter
const customDescription = extractDescription(filePath);
if (customDescription) {
if (customDescription && customDescription !== "null") {
// Use the description from frontmatter
instructionsListContent += `- [${title}](${link}) - ${customDescription}\n`;
instructionsContent += `- [${title}](${link}) - ${customDescription}\n`;
} else {
// Fallback to the default approach - use last word of title for description, removing trailing 's' if present
const topic = title.split(" ").pop().replace(/s$/, "");
instructionsListContent += `- [${title}](${link}) - ${topic} specific coding standards and best practices\n`;
instructionsContent += `- [${title}](${link}) - ${topic} specific coding standards and best practices\n`;
}
}
// Replace the current instructions section with the updated one
const newInstructionsSection =
"## 📋 Custom Instructions\n\nTeam and project-specific instructions to enhance GitHub Copilot's behavior for specific technologies and coding practices:" +
instructionsListContent;
return currentReadme.replace(instructionsSection[0], newInstructionsSection);
return `${TEMPLATES.instructionsSection}\n\n${instructionsContent}\n${TEMPLATES.instructionsUsage}`;
}
function updatePromptsSection(currentReadme, promptFiles, promptsDir) {
// Extract existing prompt links from README
const existingPromptLinks = [];
const promptLinkRegex = /\[.*?\]\(prompts\/(.+?)\)/g;
let match;
/**
* Generate the prompts section with an alphabetical list of all prompts
*/
function generatePromptsSection(promptsDir) {
// Get all prompt files
const promptFiles = fs
.readdirSync(promptsDir)
.filter((file) => file.endsWith(".prompt.md"))
.sort();
while ((match = promptLinkRegex.exec(currentReadme)) !== null) {
existingPromptLinks.push(match[1]);
}
console.log(`Found ${promptFiles.length} prompt files`);
// Find new prompts that aren't already in the README
const newPromptFiles = promptFiles.filter(
(file) => !existingPromptLinks.includes(file)
);
let promptsContent = "";
if (newPromptFiles.length === 0) {
console.log("No new prompts to add.");
return currentReadme;
}
console.log(`Found ${newPromptFiles.length} new prompts to add.`);
// Create content for new prompts (in Uncategorised section)
let newPromptsContent = "";
// Check if we already have an Uncategorised section
const uncategorisedSectionRegex = /### Uncategorised\n/;
const hasUncategorisedSection = uncategorisedSectionRegex.test(currentReadme);
// If we need to add the section header
if (!hasUncategorisedSection) {
newPromptsContent += "### Uncategorised\n";
}
// Add each new prompt
for (const file of newPromptFiles) {
// Generate list items for each prompt file
for (const file of promptFiles) {
const filePath = path.join(promptsDir, file);
const title = extractTitle(filePath);
const description = extractDescription(filePath);
const link = encodeURI(`prompts/${file}`);
if (description) {
newPromptsContent += `- [${title}](${link}) - ${description}\n`;
// Check if there's a description in the frontmatter
const customDescription = extractDescription(filePath);
if (customDescription && customDescription !== "null") {
promptsContent += `- [${title}](${link}) - ${customDescription}\n`;
} else {
newPromptsContent += `- [${title}](${link})\n`;
promptsContent += `- [${title}](${link})\n`;
}
}
// Add a newline if we created a new section
if (!hasUncategorisedSection) {
newPromptsContent += "\n";
}
// Update the README content - insert new content in the right place
if (hasUncategorisedSection) {
// Add to existing Uncategorised section
const uncategorisedSectionPos = currentReadme.match(
uncategorisedSectionRegex
).index;
const sectionEndRegex = /\n\n/;
let sectionEndMatch = sectionEndRegex.exec(
currentReadme.slice(uncategorisedSectionPos + 16)
); // 16 is length of "### Uncategorised\n"
let insertPos;
if (sectionEndMatch) {
insertPos = uncategorisedSectionPos + 16 + sectionEndMatch.index;
} else {
// If we can't find the end of the section, just insert at the end of the section header
insertPos = uncategorisedSectionPos + 16;
}
return (
currentReadme.slice(0, insertPos) +
newPromptsContent +
currentReadme.slice(insertPos)
);
} else {
// No Uncategorised section exists yet - find where to add it
return addNewUncategorisedSection(currentReadme, newPromptsContent);
}
return `${TEMPLATES.promptsSection}\n\n${promptsContent}\n${TEMPLATES.promptsUsage}`;
}
function addNewUncategorisedSection(currentReadme, newPromptsContent) {
// Look for the "Ready-to-use prompt templates" section and the next section after it
const promptSectionRegex =
/## 🎯 Reusable Prompts\n\nReady-to-use prompt templates/;
const promptSectionMatch = currentReadme.match(promptSectionRegex);
if (!promptSectionMatch) {
console.error("Could not find the Reusable Prompts section in the README.");
return currentReadme;
/**
* Generate the chat modes section with an alphabetical list of all chat modes
*/
function generateChatModesSection(chatmodesDir) {
// Check if chatmodes directory exists
if (!fs.existsSync(chatmodesDir)) {
console.log("Chat modes directory does not exist");
return "";
}
// Find where to insert the new section - after any existing categories
let insertPos;
// First check if there are any existing categories
const existingCategoriesRegex = /### [^\n]+\n/g;
let lastCategoryMatch = null;
let match;
// Get all chat mode files
const chatmodeFiles = fs
.readdirSync(chatmodesDir)
.filter((file) => file.endsWith(".chatmode.md"))
.sort();
while ((match = existingCategoriesRegex.exec(currentReadme)) !== null) {
lastCategoryMatch = match;
}
console.log(`Found ${chatmodeFiles.length} chat mode files`);
if (lastCategoryMatch) {
// Find the end of the last category section
const afterLastCategory = currentReadme.slice(
lastCategoryMatch.index + lastCategoryMatch[0].length
);
const nextSectionRegex = /\n\n>/;
const nextSectionMatch = afterLastCategory.match(nextSectionRegex);
if (nextSectionMatch) {
insertPos =
lastCategoryMatch.index +
lastCategoryMatch[0].length +
nextSectionMatch.index;
} else {
// If we can't find the next section, add at the end of the prompt section
insertPos = currentReadme.indexOf("> 💡 **Usage**: Use `/prompt-name`");
if (insertPos === -1) {
// Fallback position - before Additional Resources
insertPos = currentReadme.indexOf("## 📚 Additional Resources");
}
}
} else {
// No categories yet, add right after the intro text
const afterIntroRegex = /prompt\` command\.\n\n/;
const afterIntroMatch = currentReadme.match(afterIntroRegex);
if (afterIntroMatch) {
insertPos = afterIntroMatch.index + afterIntroMatch[0].length;
} else {
// Fallback position - before Additional Resources
insertPos = currentReadme.indexOf("## 📚 Additional Resources");
}
}
if (insertPos !== -1) {
return (
currentReadme.slice(0, insertPos) +
newPromptsContent +
currentReadme.slice(insertPos)
);
} else {
console.error("Could not find a suitable place to insert new prompts.");
return currentReadme;
}
}
function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
// No chat mode files, nothing to do
// If no chat modes, return empty string
if (chatmodeFiles.length === 0) {
return currentReadme;
return "";
}
// Extract existing chat mode links from README
const existingChatModeLinks = [];
const chatModeLinkRegex = /\[.*?\]\(chatmodes\/(.+?)\)/g;
let match;
let chatmodesContent = "";
while ((match = chatModeLinkRegex.exec(currentReadme)) !== null) {
existingChatModeLinks.push(match[1]);
// Generate list items for each chat mode file
for (const file of chatmodeFiles) {
const filePath = path.join(chatmodesDir, file);
const title = extractTitle(filePath);
const link = encodeURI(`chatmodes/${file}`);
// Check if there's a description in the frontmatter
const customDescription = extractDescription(filePath);
if (customDescription && customDescription !== "null") {
chatmodesContent += `- [${title}](${link}) - ${customDescription}\n`;
} else {
chatmodesContent += `- [${title}](${link})\n`;
}
}
// Find new chat modes that aren't already in the README
const newChatModeFiles = chatmodeFiles.filter(
(file) => !existingChatModeLinks.includes(file)
);
if (newChatModeFiles.length === 0) {
console.log("No new chat modes to add.");
} else {
console.log(`Found ${newChatModeFiles.length} new chat modes to add.`);
}
const chatmodesSection = currentReadme.match(
/## 🧩 Custom Chat Modes\n\nCustom chat modes define.+?(?=\n\n>)/s
);
return `${TEMPLATES.chatmodesSection}\n\n${chatmodesContent}\n${TEMPLATES.chatmodesUsage}`;
if (chatmodesSection) {
let chatmodesListContent = "\n\n";
// Generate list of chat mode links
for (const file of chatmodeFiles) {
// Always regenerate the entire list to ensure descriptions are included
for (const file of chatmodeFiles.sort()) {
const filePath = path.join(chatmodesDir, file);
const title = extractTitle(filePath);
const link = encodeURI(`chatmodes/${file}`);
@ -407,7 +366,7 @@ function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
// Check if there's a description in the frontmatter
const customDescription = extractDescription(filePath);
if (customDescription) {
if (customDescription && customDescription !== "null") {
// Use the description from frontmatter
chatmodesListContent += `- [${title}](${link}) - ${customDescription}\n`;
} else {
@ -419,7 +378,8 @@ function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
// Replace the current chat modes section with the updated one
const newChatmodesSection =
"## 🧩 Custom Chat Modes\n\nCustom chat modes define specific behaviors and tools for GitHub Copilot Chat, enabling enhanced context-aware assistance for particular tasks or workflows." +
chatmodesListContent;
chatmodesListContent +
"\n> 💡 **Usage**: Create new chat modes using the command `Chat: Configure Chat Modes...`, then switch your chat mode in the Chat input from _Agent_ or _Ask_ to your own mode.";
return currentReadme.replace(chatmodesSection[0], newChatmodesSection);
} else {
@ -429,6 +389,7 @@ function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
);
const chatmodesListContent = chatmodeFiles
.sort()
.map((file) => {
const filePath = path.join(chatmodesDir, file);
const title = extractTitle(filePath);
@ -444,7 +405,7 @@ function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
.join("\n");
const newChatmodesSection =
"## 🎭 Custom Chat Modes\n\n" +
"## 🧩 Custom Chat Modes\n\n" +
"Custom chat modes define specific behaviors and tools for GitHub Copilot Chat, enabling enhanced context-aware assistance for particular tasks or workflows.\n\n" +
chatmodesListContent +
"\n\n> 💡 **Usage**: Create new chat modes using the command `Chat: Configure Chat Modes...`, then switch your chat mode in the Chat input from _Agent_ or _Ask_ to your own mode.\n";
@ -466,68 +427,57 @@ function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
}
}
/**
* Generate the complete README.md content from scratch
*/
function generateReadme() {
const instructionsDir = path.join(__dirname, "instructions");
const promptsDir = path.join(__dirname, "prompts");
const chatmodesDir = path.join(__dirname, "chatmodes");
const readmePath = path.join(__dirname, "README.md");
// Check if README file exists
if (!fs.existsSync(readmePath)) {
console.error(
"README.md not found! Please create a base README.md file first."
);
process.exit(1);
// Generate each section
const instructionsSection = generateInstructionsSection(instructionsDir);
const promptsSection = generatePromptsSection(promptsDir);
const chatmodesSection = generateChatModesSection(chatmodesDir);
// Build the complete README content with template sections
let readmeContent = [TEMPLATES.header, instructionsSection, promptsSection];
// Only include chat modes section if we have any chat modes
if (chatmodesSection) {
readmeContent.push(chatmodesSection);
}
// Read the current README content
let currentReadme = fs.readFileSync(readmePath, "utf8");
// Add footer
readmeContent.push(TEMPLATES.footer);
// Get all instruction files
const instructionFiles = fs
.readdirSync(instructionsDir)
.filter((file) => file.endsWith(".md"))
.sort();
// Get all prompt files - we'll use this to find new prompts
const promptFiles = fs
.readdirSync(promptsDir)
.filter((file) => file.endsWith(".prompt.md"))
.sort();
// Get all chat mode files - we'll use this to update the chat modes section
const chatmodeFiles = fs.existsSync(chatmodesDir)
? fs
.readdirSync(chatmodesDir)
.filter((file) => file.endsWith(".chatmode.md"))
.sort()
: [];
// Update instructions section
currentReadme = updateInstructionsSection(
currentReadme,
instructionFiles,
instructionsDir
);
// Update prompts section
currentReadme = updatePromptsSection(currentReadme, promptFiles, promptsDir);
// Update chat modes section
currentReadme = updateChatModesSection(
currentReadme,
chatmodeFiles,
chatmodesDir
);
return currentReadme;
return readmeContent.join("\n\n");
}
// Generate and write the README
const updatedReadme = generateReadme();
// Main execution
try {
console.log("Generating README.md from scratch...");
// Only write file if we have content to write
if (updatedReadme) {
fs.writeFileSync(path.join(__dirname, "README.md"), updatedReadme);
console.log("README.md updated successfully!");
const readmePath = path.join(__dirname, "README.md");
const newReadmeContent = generateReadme();
// Check if the README file already exists
if (fs.existsSync(readmePath)) {
const originalContent = fs.readFileSync(readmePath, "utf8");
const hasChanges = originalContent !== newReadmeContent;
if (hasChanges) {
fs.writeFileSync(readmePath, newReadmeContent);
console.log("README.md updated successfully!");
} else {
console.log("README.md is already up to date. No changes needed.");
}
} else {
// Create the README file if it doesn't exist
fs.writeFileSync(readmePath, newReadmeContent);
console.log("README.md created successfully!");
}
} catch (error) {
console.error(`Error generating README.md: ${error.message}`);
process.exit(1);
}