Merge branch 'main' into main

This commit is contained in:
Aaron Powell 2025-07-01 10:01:56 +10:00 committed by GitHub
commit 5a0a9415bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 245 additions and 109 deletions

View File

@ -55,9 +55,22 @@ Ready-to-use prompt templates for specific development scenarios and tasks. Thes
### Documentation & Project Management ### Documentation & Project Management
- [Comment Code Generate Tutorial](prompts/comment-code-generate-a-tutorial.prompt.md) - Transform code into educational content - [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 - [Generate Specs as Issues](prompts/gen-specs-as-issues.prompt.md) - Convert requirements into GitHub issues
- [My Issues](prompts/my-issues.prompt.md)
- [My Pull Requests](prompts/my-pull-requests.prompt.md)
> 💡 **Usage**: Use `/prompt-name` in VS Code chat or run `Chat: Run Prompt` command. Prompt files support variables like `${input:name}` for dynamic content. > 💡 **Usage**: Use `/prompt-name` in VS Code chat or run `Chat: Run Prompt` command. Prompt files support variables like `${input:name}` for dynamic content.
## 🎭 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. These `.chatmode.md` files can be loaded by selecting "Chat with Custom Mode" from the Copilot menu.
- [Planning mode instructions](chatmodes/planner.chatmode.md) - Generate an implementation plan for new features or refactoring existing code.
> 💡 **Usage**: Create a `.chatmode.md` file in your workspace or repository, then select "Chat with Custom Mode" from the Copilot Chat menu and select your chat mode file.
## 📚 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

View File

@ -0,0 +1,14 @@
---
description: Generate an implementation plan for new features or refactoring existing code.
tools: ['codebase', 'fetch', 'findTestFiles', 'githubRepo', 'search', 'usages']
---
# Planning mode instructions
You are in planning mode. Your task is to generate an implementation plan for a new feature or for refactoring existing code.
Don't make any code edits, just generate a plan.
The plan consists of a Markdown document that describes the implementation plan, including the following sections:
* Overview: A brief description of the feature or refactoring task.
* Requirements: A list of requirements for the feature or refactoring task.
* Implementation Steps: A detailed list of steps to implement the feature or refactoring task.
* Testing: A list of tests that need to be implemented to verify the feature or refactoring task.

View File

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

View File

@ -0,0 +1,9 @@
---
mode: agent
tools: ['githubRepo', 'github', 'get_issue', 'get_issue_comments', 'get_me', 'list_issues']
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.
Suggest issues that I might want to focus on based on their age, the amount of comments, and their status (open/closed).

View File

@ -0,0 +1,15 @@
---
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"
---
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.
Describe the purpose and details of each pull request.
If a PR is waiting for someone to review, highlight that in the response.
If there were any check failures on the PR, describe them and suggest possible fixes.
If there was no review done by Copilot, offer to request one using #request_copilot_review.

View File

@ -8,7 +8,7 @@ function extractTitle(filePath) {
const content = fs.readFileSync(filePath, "utf8"); const content = fs.readFileSync(filePath, "utf8");
// For prompt files, look for the main heading after frontmatter // For prompt files, look for the main heading after frontmatter
if (filePath.includes(".prompt.md")) { if (filePath.includes(".prompt.md") || filePath.includes(".chatmode.md")) {
const lines = content.split("\n"); const lines = content.split("\n");
let inFrontmatter = false; let inFrontmatter = false;
let frontmatterEnded = false; let frontmatterEnded = false;
@ -29,7 +29,10 @@ function extractTitle(filePath) {
} }
// For prompt files without heading, clean up filename // For prompt files without heading, clean up filename
const basename = path.basename(filePath, ".prompt.md"); const basename = path.basename(
filePath,
filePath.includes(".prompt.md") ? ".prompt.md" : ".chatmode.md"
);
return basename return basename
.replace(/[-_]/g, " ") .replace(/[-_]/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase()); .replace(/\b\w/g, (l) => l.toUpperCase());
@ -129,6 +132,7 @@ function extractDescription(filePath) {
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 readmePath = path.join(__dirname, "README.md"); const readmePath = path.join(__dirname, "README.md");
// Check if README file exists // Check if README file exists
@ -154,6 +158,14 @@ function generateReadme() {
.filter((file) => file.endsWith(".prompt.md")) .filter((file) => file.endsWith(".prompt.md"))
.sort(); .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 - rebuild the whole list // Update instructions section - rebuild the whole list
const instructionsSection = currentReadme.match( const instructionsSection = currentReadme.match(
/## 📋 Custom Instructions\n\nTeam and project-specific instructions.+?(?=\n\n>)/s /## 📋 Custom Instructions\n\nTeam and project-specific instructions.+?(?=\n\n>)/s
@ -204,132 +216,205 @@ function generateReadme() {
(file) => !existingPromptLinks.includes(file) (file) => !existingPromptLinks.includes(file)
); );
if (newPromptFiles.length === 0) { if (newPromptFiles.length > 0) {
console.log("No new prompts to add."); console.log(`Found ${newPromptFiles.length} new prompts to add.`);
return currentReadme; // No changes needed
}
console.log(`Found ${newPromptFiles.length} new prompts to add.`); // Create content for new prompts (in Uncategorised section)
let newPromptsContent = "";
// Create content for new prompts (in Uncategorised section) // Check if we already have an Uncategorised section
let newPromptsContent = ""; const uncategorisedSectionRegex = /### Uncategorised\n/;
const hasUncategorisedSection =
uncategorisedSectionRegex.test(currentReadme);
// Check if we already have an Uncategorised section // If we need to add the section header
const uncategorisedSectionRegex = /### Uncategorised\n/; if (!hasUncategorisedSection) {
const hasUncategorisedSection = uncategorisedSectionRegex.test(currentReadme); newPromptsContent += "### Uncategorised\n";
// If we need to add the section header
if (!hasUncategorisedSection) {
newPromptsContent += "### Uncategorised\n";
}
// Add each new prompt
for (const file of newPromptFiles) {
const filePath = path.join(promptsDir, file);
const title = extractTitle(filePath);
const description = extractDescription(filePath);
const link = `prompts/${file}`;
if (description) {
newPromptsContent += `- [${title}](${link}) - ${description}\n`;
} else {
newPromptsContent += `- [${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;
} }
currentReadme = // Add each new prompt
currentReadme.slice(0, insertPos) + for (const file of newPromptFiles) {
newPromptsContent + const filePath = path.join(promptsDir, file);
currentReadme.slice(insertPos); const title = extractTitle(filePath);
} else { const description = extractDescription(filePath);
// No Uncategorised section exists yet - find where to add it const link = `prompts/${file}`;
// Look for the "Ready-to-use prompt templates" section and the next section after it
const promptSectionRegex = if (description) {
/## 🎯 Reusable Prompts\n\nReady-to-use prompt templates/; newPromptsContent += `- [${title}](${link}) - ${description}\n`;
const promptSectionMatch = currentReadme.match(promptSectionRegex); } else {
newPromptsContent += `- [${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"
if (promptSectionMatch) {
// Find where to insert the new section - after any existing categories
let insertPos; let insertPos;
// First check if there are any existing categories if (sectionEndMatch) {
const existingCategoriesRegex = /### [^\n]+\n/g; insertPos = uncategorisedSectionPos + 16 + sectionEndMatch.index;
let lastCategoryMatch = null; } else {
while ((match = existingCategoriesRegex.exec(currentReadme)) !== null) { // If we can't find the end of the section, just insert at the end of the section header
lastCategoryMatch = match; insertPos = uncategorisedSectionPos + 16;
} }
if (lastCategoryMatch) { currentReadme =
// Find the end of the last category section currentReadme.slice(0, insertPos) +
const afterLastCategory = currentReadme.slice( newPromptsContent +
lastCategoryMatch.index + lastCategoryMatch[0].length currentReadme.slice(insertPos);
); } else {
const nextSectionRegex = /\n\n>/; // No Uncategorised section exists yet - find where to add it
const nextSectionMatch = afterLastCategory.match(nextSectionRegex); // 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 (nextSectionMatch) { if (promptSectionMatch) {
insertPos = // Find where to insert the new section - after any existing categories
lastCategoryMatch.index + let insertPos;
lastCategoryMatch[0].length + // First check if there are any existing categories
nextSectionMatch.index; const existingCategoriesRegex = /### [^\n]+\n/g;
} else { let lastCategoryMatch = null;
// If we can't find the next section, add at the end of the prompt section while ((match = existingCategoriesRegex.exec(currentReadme)) !== null) {
insertPos = currentReadme.indexOf( lastCategoryMatch = match;
"> 💡 **Usage**: Use `/prompt-name`" }
if (lastCategoryMatch) {
// Find the end of the last category section
const afterLastCategory = currentReadme.slice(
lastCategoryMatch.index + lastCategoryMatch[0].length
); );
if (insertPos === -1) { 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 // Fallback position - before Additional Resources
insertPos = currentReadme.indexOf("## 📚 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) { if (insertPos !== -1) {
insertPos = afterIntroMatch.index + afterIntroMatch[0].length; currentReadme =
currentReadme.slice(0, insertPos) +
newPromptsContent +
currentReadme.slice(insertPos);
} else { } else {
// Fallback position - before Additional Resources console.error(
insertPos = currentReadme.indexOf("## 📚 Additional Resources"); "Could not find a suitable place to insert new prompts."
);
} }
}
if (insertPos !== -1) {
currentReadme =
currentReadme.slice(0, insertPos) +
newPromptsContent +
currentReadme.slice(insertPos);
} else { } else {
console.error("Could not find a suitable place to insert new prompts."); console.error(
"Could not find the Reusable Prompts section in the README."
);
} }
} else { }
console.error( } else {
"Could not find the Reusable Prompts section in the README." console.log("No new prompts to add.");
); }
// Update chat modes section
const chatmodesSection = currentReadme.match(
/## 🎭 Custom Chat Modes\n\nCustom chat modes define.+?(?=\n\n>)/s
);
if (chatmodesSection && chatmodeFiles.length > 0) {
let chatmodesListContent = "\n\n";
// Generate list of chat mode links
for (const file of chatmodeFiles) {
const filePath = path.join(chatmodesDir, file);
const title = extractTitle(filePath);
const link = `chatmodes/${file}`;
// Check if there's a description in the frontmatter
const customDescription = extractDescription(filePath);
if (customDescription) {
// Use the description from frontmatter
chatmodesListContent += `- [${title}](${link}) - ${customDescription}\n`;
} else {
// Just add a link without description
chatmodesListContent += `- [${title}](${link})\n`;
}
}
// 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. These `.chatmode.md` files can be loaded by selecting "Chat with Custom Mode" from the Copilot menu.' +
chatmodesListContent;
currentReadme = currentReadme.replace(
chatmodesSection[0],
newChatmodesSection
);
} else if (!chatmodesSection && chatmodeFiles.length > 0) {
// Chat modes section doesn't exist yet but we have chat mode files
const chatmodesListContent = chatmodeFiles
.map((file) => {
const filePath = path.join(chatmodesDir, file);
const title = extractTitle(filePath);
const link = `chatmodes/${file}`;
const customDescription = extractDescription(filePath);
if (customDescription) {
return `- [${title}](${link}) - ${customDescription}`;
} else {
return `- [${title}](${link})`;
}
})
.join("\n");
const newChatmodesSection =
"## 🎭 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. These `.chatmode.md` files can be loaded by selecting "Chat with Custom Mode" from the Copilot menu.\n\n' +
chatmodesListContent +
'\n\n> 💡 **Usage**: Create a `.chatmode.md` file in your workspace or repository, then select "Chat with Custom Mode" from the Copilot Chat menu and select your chat mode file.\n';
// Insert before Additional Resources section
const additionalResourcesPos = currentReadme.indexOf(
"## 📚 Additional Resources"
);
if (additionalResourcesPos !== -1) {
currentReadme =
currentReadme.slice(0, additionalResourcesPos) +
newChatmodesSection +
"\n" +
currentReadme.slice(additionalResourcesPos);
} }
} }