Changing from a patch to regen approach for the readme

This commit is contained in:
Aaron Powell 2025-07-03 11:00:30 +10:00
parent 0ab0f0b90c
commit d88c1ddbd7
2 changed files with 231 additions and 263 deletions

View File

@ -21,54 +21,57 @@ 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: Team and project-specific instructions to enhance GitHub Copilot's behavior for specific technologies and coding practices:
- [Angular Development Instructions](instructions/angular.instructions.md) - Instruction specific coding standards and best practices - [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) - Development 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 specific coding standards and best practices - [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) - Practice specific coding standards and best practices - [Bicep Code Best Practices](instructions/bicep-code-best-practices.instructions.md) - Infrastructure as Code with Bicep
- [Blazor](instructions/blazor.instructions.md) - Blazor specific coding standards and best practices - [Blazor](instructions/blazor.instructions.md) - Blazor component and application patterns
- [Cmake Vcpkg](instructions/cmake-vcpkg.instructions.md) - Vcpkg specific coding standards and best practices - [Cmake Vcpkg](instructions/cmake-vcpkg.instructions.md) - C++ project configuration and package management
- [Copilot Process tracking Instructions](instructions/copilot-thought-logging.instructions.md) - Instruction specific coding standards and best practices - [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.instructions.md) - Development specific coding standards and best practices - [C# Development](instructions/csharp.instructions.md) - Guidelines for building C# applications
- [.NET MAUI](instructions/dotnet-maui.instructions.md) - MAUI specific coding standards and best practices - [.NET MAUI](instructions/dotnet-maui.instructions.md) - .NET MAUI component and application patterns
- [Genaiscript](instructions/genaiscript.instructions.md) - Genaiscript specific coding standards and best practices - [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) - Azure specific coding standards and best practices - [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) - Localization specific coding standards and best practices - [Guidance for Localization](instructions/localization.instructions.md) - Guidelines for localizing markdown documents
- [Markdown](instructions/markdown.instructions.md) - Markdown specific coding standards and best practices - [Markdown](instructions/markdown.instructions.md) - Documentation and content creation standards
- [Next.js + Tailwind Development Instructions](instructions/nextjs-tailwind.instructions.md) - Instruction specific coding standards and best practices - [Next.js + Tailwind Development Instructions](instructions/nextjs-tailwind.instructions.md) - Next.js + Tailwind development standards and instructions
- [Python Coding Conventions](instructions/python.instructions.md) - Convention specific coding standards and best practices - [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. > 💡 **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.
## 🎯 Reusable Prompts ## 🎯 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. Ready-to-use prompt templates for specific development scenarios and tasks, defining prompt text with a specific mode, model, and available set of tools.
- [Aspnet Minimal Api Openapi](prompts/aspnet-minimal-api-openapi.prompt.md) - [Aspnet Minimal Api Openapi](prompts/aspnet-minimal-api-openapi.prompt.md) - Create ASP.NET Minimal API endpoints with proper OpenAPI documentation
- [Az Cost Optimize](prompts/az-cost-optimize.prompt.md) - [Az 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) - [Comment Code Generate A Tutorial](prompts/comment-code-generate-a-tutorial.prompt.md)
- [C# Async Programming Best Practices](prompts/csharp-async.prompt.md) - [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) - [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) - [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) - [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) - [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) - [Entity Framework Core Best Practices](prompts/ef-core.prompt.md) - Get best practices for Entity Framework Core
- [Gen Specs As Issues](prompts/gen-specs-as-issues.prompt.md) - [Gen Specs As Issues](prompts/gen-specs-as-issues.prompt.md)
- [Javascript Typescript Jest](prompts/javascript-typescript-jest.prompt.md) - [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) - [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 Issues](prompts/my-issues.prompt.md)
- [My Pull Requests](prompts/my-pull-requests.prompt.md) - [My Pull Requests](prompts/my-pull-requests.prompt.md)
> 💡 **Usage**: Use `/prompt-name` in VS Code chat, run `Chat: Run Prompt` command, or hit the run button while you have a prompt open. > 💡 **Usage**: Use `/prompt-name` in VS Code chat, run `Chat: Run Prompt` command, or hit the run button while you have a prompt open.
## 🧩 Custom Chat Modes ## 🧩 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. 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) - [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.
- [Debug Mode Instructions](chatmodes/debug.chatmode.md) - [Debug Mode Instructions](chatmodes/debug.chatmode.md) - Debug your application to find and fix a bug
- [Planning mode instructions](chatmodes/planner.chatmode.md) - [Planning mode instructions](chatmodes/planner.chatmode.md) - Generate an implementation plan for new features or refactoring existing code.
- [Database Administrator Chat Mode](chatmodes/postgresql-dba.chatmode.md) - [Database Administrator Chat Mode](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 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. > 💡 **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 ## 📚 Additional Resources
- [VS Code Copilot Customization Documentation](https://code.visualstudio.com/docs/copilot/copilot-customization) - Official Microsoft documentation - [VS Code Copilot Customization Documentation](https://code.visualstudio.com/docs/copilot/copilot-customization) - Official Microsoft documentation
@ -91,4 +94,4 @@ This project may contain trademarks or logos for projects, products, or services
trademarks or logos is subject to and must follow 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). [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. 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. Any use of third-party trademarks or logos are subject to those third-party's policies.

View File

@ -3,6 +3,70 @@
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
// 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 // Add error handling utility
function safeFileOperation(operation, filePath, defaultValue = null) { function safeFileOperation(operation, filePath, defaultValue = null) {
try { try {
@ -35,11 +99,13 @@ function extractTitle(filePath) {
if (inFrontmatter && !frontmatterEnded) { if (inFrontmatter && !frontmatterEnded) {
// Look for title field in frontmatter // Look for title field in frontmatter
if (line.includes('title:')) { if (line.includes("title:")) {
// Extract everything after 'title:' // Extract everything after 'title:'
const afterTitle = line.substring(line.indexOf('title:') + 6).trim(); const afterTitle = line
.substring(line.indexOf("title:") + 6)
.trim();
// Remove quotes if present // Remove quotes if present
const cleanTitle = afterTitle.replace(/^['"]|['"]$/g, ''); const cleanTitle = afterTitle.replace(/^['"]|['"]$/g, "");
return cleanTitle; return cleanTitle;
} }
} }
@ -50,7 +116,11 @@ function extractTitle(filePath) {
frontmatterEnded = false; frontmatterEnded = false;
// Step 2: For prompt/chatmode/instructions files, look for heading after frontmatter // 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")) { if (
filePath.includes(".prompt.md") ||
filePath.includes(".chatmode.md") ||
filePath.includes(".instructions.md")
) {
for (const line of lines) { for (const line of lines) {
if (line.trim() === "---") { if (line.trim() === "---") {
if (!inFrontmatter) { if (!inFrontmatter) {
@ -69,8 +139,11 @@ function extractTitle(filePath) {
// Step 3: Format filename for prompt/chatmode/instructions files if no heading found // Step 3: Format filename for prompt/chatmode/instructions files if no heading found
const basename = path.basename( const basename = path.basename(
filePath, filePath,
filePath.includes(".prompt.md") ? ".prompt.md" : filePath.includes(".prompt.md")
filePath.includes(".chatmode.md") ? ".chatmode.md" : ".instructions.md" ? ".prompt.md"
: filePath.includes(".chatmode.md")
? ".chatmode.md"
: ".instructions.md"
); );
return basename return basename
.replace(/[-_]/g, " ") .replace(/[-_]/g, " ")
@ -91,7 +164,8 @@ function extractTitle(filePath) {
.replace(/\b\w/g, (l) => l.toUpperCase()); .replace(/\b\w/g, (l) => l.toUpperCase());
}, },
filePath, filePath,
path.basename(filePath, path.extname(filePath)) path
.basename(filePath, path.extname(filePath))
.replace(/[-_]/g, " ") .replace(/[-_]/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase()) .replace(/\b\w/g, (l) => l.toUpperCase())
); );
@ -168,44 +242,22 @@ function extractDescription(filePath) {
); );
} }
function updateInstructionsSection( /**
currentReadme, * Generate the instructions section with an alphabetical list of all instructions
instructionFiles, */
instructionsDir function generateInstructionsSection(instructionsDir) {
) { // Get all instruction files
// Look for the instructions section in the README const instructionFiles = fs
const instructionsSectionRegex = /## 📋 Custom Instructions[\s\S]*?(?=\n## |\n\n## |$)/; .readdirSync(instructionsDir)
const instructionsSection = currentReadme.match(instructionsSectionRegex); .filter((file) => file.endsWith(".md"))
.sort();
if (!instructionsSection && instructionFiles.length === 0) { console.log(`Found ${instructionFiles.length} instruction files`);
console.log("No instructions section found in README and no instruction files to add.");
return currentReadme;
}
// Extract existing instruction links from README (for reporting purposes) let instructionsContent = "";
const existingInstructionLinks = [];
const instructionLinkRegex = /\[.*?\]\(instructions\/(.+?)\)/g;
let match;
while ((match = instructionLinkRegex.exec(currentReadme)) !== null) { // Generate list items for each instruction file
existingInstructionLinks.push(match[1]); for (const file of instructionFiles) {
}
// 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";
// Always regenerate the entire list to ensure descriptions are included
for (const file of instructionFiles.sort()) {
const filePath = path.join(instructionsDir, file); const filePath = path.join(instructionsDir, file);
const title = extractTitle(filePath); const title = extractTitle(filePath);
const link = encodeURI(`instructions/${file}`); const link = encodeURI(`instructions/${file}`);
@ -215,157 +267,92 @@ function updateInstructionsSection(
if (customDescription && customDescription !== "null") { if (customDescription && customDescription !== "null") {
// Use the description from frontmatter // Use the description from frontmatter
instructionsListContent += `- [${title}](${link}) - ${customDescription}\n`; instructionsContent += `- [${title}](${link}) - ${customDescription}\n`;
} else { } else {
// Fallback to the default approach - use last word of title for description, removing trailing 's' if present // Fallback to the default approach - use last word of title for description, removing trailing 's' if present
const topic = title.split(" ").pop().replace(/s$/, ""); 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 return `${TEMPLATES.instructionsSection}\n\n${instructionsContent}\n${TEMPLATES.instructionsUsage}`;
const newInstructionsSection =
"## 📋 Custom Instructions\n\nTeam and project-specific instructions to enhance GitHub Copilot's behavior for specific technologies and coding practices:" +
instructionsListContent +
"\n> 💡 **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.";
if (instructionsSection) {
return currentReadme.replace(instructionsSection[0], newInstructionsSection);
} else {
// Instructions section doesn't exist, insert it before Prompts section
const promptsPos = currentReadme.indexOf("## 🎯 Reusable Prompts");
if (promptsPos !== -1) {
return (
currentReadme.slice(0, promptsPos) +
newInstructionsSection +
"\n\n" +
currentReadme.slice(promptsPos)
);
} else {
// Insert before Additional Resources section as fallback
const additionalResourcesPos = currentReadme.indexOf("## 📚 Additional Resources");
if (additionalResourcesPos !== -1) {
return (
currentReadme.slice(0, additionalResourcesPos) +
newInstructionsSection +
"\n\n" +
currentReadme.slice(additionalResourcesPos)
);
}
}
return currentReadme;
}
} }
function updatePromptsSection(currentReadme, promptFiles, promptsDir) { /**
// Look for the prompts section in the README * Generate the prompts section with an alphabetical list of all prompts
const promptsSectionRegex = /## 🎯 Reusable Prompts[\s\S]*?(?=\n## |\n\n## |$)/; */
const promptsSection = currentReadme.match(promptsSectionRegex); function generatePromptsSection(promptsDir) {
// Get all prompt files
const promptFiles = fs
.readdirSync(promptsDir)
.filter((file) => file.endsWith(".prompt.md"))
.sort();
if (!promptsSection && promptFiles.length === 0) { console.log(`Found ${promptFiles.length} prompt files`);
console.log("No prompts section found in README and no prompt files to add.");
return currentReadme;
}
// Extract existing prompt links from README (for reporting purposes) let promptsContent = "";
const existingPromptLinks = [];
const promptLinkRegex = /\[.*?\]\(prompts\/(.+?)\)/g;
let match;
while ((match = promptLinkRegex.exec(currentReadme)) !== null) { // Generate list items for each prompt file
existingPromptLinks.push(match[1]); for (const file of promptFiles) {
}
// Find new prompts that aren't already in the README
const newPromptFiles = promptFiles.filter(
(file) => !existingPromptLinks.includes(file)
);
if (newPromptFiles.length === 0) {
console.log("No new prompts to add.");
} else {
console.log(`Found ${newPromptFiles.length} new prompts to add.`);
}
let promptsListContent = "\n\n";
// Always regenerate the entire list to ensure descriptions are included
for (const file of promptFiles.sort()) {
const filePath = path.join(promptsDir, file); const filePath = path.join(promptsDir, file);
const title = extractTitle(filePath); const title = extractTitle(filePath);
const description = extractDescription(filePath);
const link = encodeURI(`prompts/${file}`); const link = encodeURI(`prompts/${file}`);
if (description && description !== "null") { // Check if there's a description in the frontmatter
promptsListContent += `- [${title}](${link}) - ${description}\n`; const customDescription = extractDescription(filePath);
if (customDescription && customDescription !== "null") {
promptsContent += `- [${title}](${link}) - ${customDescription}\n`;
} else { } else {
promptsListContent += `- [${title}](${link})\n`; promptsContent += `- [${title}](${link})\n`;
} }
} }
// Replace the current prompts section with the updated one return `${TEMPLATES.promptsSection}\n\n${promptsContent}\n${TEMPLATES.promptsUsage}`;
const newPromptsSection =
"## 🎯 Reusable Prompts\n\nReady-to-use prompt templates for specific development scenarios and tasks, defining prompt text with a specific mode, model, and available set of tools." +
promptsListContent +
"\n> 💡 **Usage**: Use `/prompt-name` in VS Code chat, run `Chat: Run Prompt` command, or hit the run button while you have a prompt open.";
if (promptsSection) {
return currentReadme.replace(promptsSection[0], newPromptsSection);
} else {
// Prompts section doesn't exist, insert it before Chat Modes section
const chatModesPos = currentReadme.indexOf("## 🧩 Custom Chat Modes");
if (chatModesPos !== -1) {
return (
currentReadme.slice(0, chatModesPos) +
newPromptsSection +
"\n\n" +
currentReadme.slice(chatModesPos)
);
} else {
// Insert before Additional Resources section as fallback
const additionalResourcesPos = currentReadme.indexOf("## 📚 Additional Resources");
if (additionalResourcesPos !== -1) {
return (
currentReadme.slice(0, additionalResourcesPos) +
newPromptsSection +
"\n\n" +
currentReadme.slice(additionalResourcesPos)
);
}
}
return currentReadme;
}
} }
function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) { /**
// No chat mode files, nothing to do * 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 "";
}
// Get all chat mode files
const chatmodeFiles = fs
.readdirSync(chatmodesDir)
.filter((file) => file.endsWith(".chatmode.md"))
.sort();
console.log(`Found ${chatmodeFiles.length} chat mode files`);
// If no chat modes, return empty string
if (chatmodeFiles.length === 0) { if (chatmodeFiles.length === 0) {
return currentReadme; return "";
} }
// Extract existing chat mode links from README (for reporting purposes) let chatmodesContent = "";
const existingChatModeLinks = [];
const chatModeLinkRegex = /\[.*?\]\(chatmodes\/(.+?)\)/g;
let match;
while ((match = chatModeLinkRegex.exec(currentReadme)) !== null) { // Generate list items for each chat mode file
existingChatModeLinks.push(match[1]); 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 return `${TEMPLATES.chatmodesSection}\n\n${chatmodesContent}\n${TEMPLATES.chatmodesUsage}`;
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.`);
}
// Look for ANY existing chat modes section (with any emoji)
const chatmodesSectionRegex = /## [🧩🎭].*Custom Chat Modes[\s\S]*?(?=\n## |\n\n## |$)/;
const chatmodesSection = currentReadme.match(chatmodesSectionRegex);
if (chatmodesSection) { if (chatmodesSection) {
let chatmodesListContent = "\n\n"; let chatmodesListContent = "\n\n";
@ -440,79 +427,57 @@ function updateChatModesSection(currentReadme, chatmodeFiles, chatmodesDir) {
} }
} }
/**
* Generate the complete README.md content from scratch
*/
function generateReadme() { function generateReadme() {
const instructionsDir = path.join(__dirname, "instructions"); const instructionsDir = path.join(__dirname, "instructions");
const promptsDir = path.join(__dirname, "prompts"); const promptsDir = path.join(__dirname, "prompts");
const chatmodesDir = path.join(__dirname, "chatmodes"); const chatmodesDir = path.join(__dirname, "chatmodes");
// 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);
}
// Add footer
readmeContent.push(TEMPLATES.footer);
return readmeContent.join("\n\n");
}
// Main execution
try {
console.log("Generating README.md from scratch...");
const readmePath = path.join(__dirname, "README.md"); const readmePath = path.join(__dirname, "README.md");
const newReadmeContent = generateReadme();
// Check if README file exists // Check if the README file already exists
if (!fs.existsSync(readmePath)) { if (fs.existsSync(readmePath)) {
console.error( const originalContent = fs.readFileSync(readmePath, "utf8");
"README.md not found! Please create a base README.md file first." const hasChanges = originalContent !== newReadmeContent;
);
process.exit(1);
}
// Read the current README content if (hasChanges) {
let currentReadme = fs.readFileSync(readmePath, "utf8"); fs.writeFileSync(readmePath, newReadmeContent);
console.log("README.md updated successfully!");
// Get all instruction files } else {
const instructionFiles = fs console.log("README.md is already up to date. No changes needed.");
.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;
}
// Generate and write the README
const readmePath = path.join(__dirname, "README.md");
const originalReadme = fs.readFileSync(readmePath, "utf8");
const updatedReadme = generateReadme();
// Only write file if we have content to write
if (updatedReadme) {
// Check if there are changes
const hasChanges = originalReadme !== updatedReadme;
if (hasChanges) {
fs.writeFileSync(readmePath, updatedReadme);
console.log("README.md updated successfully!");
console.log("Changes detected in README.md after running update script.");
} else { } else {
console.log("README.md is already up to date."); // Create the README file if it doesn't exist
console.log("No changes to README.md after running update script."); fs.writeFileSync(readmePath, newReadmeContent);
console.log("README.md created successfully!");
} }
} catch (error) {
console.error(`Error generating README.md: ${error.message}`);
process.exit(1);
} }