diff --git a/README.md b/README.md index 7eb245ab..1ab310ff 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ 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

**Benefits:**
β€’ Automatic inclusion in every chat request
β€’ Repository-wide consistency
β€’ Multiple implementation options | Create reusable, standalone prompts for specific tasks. Describe *what* should be done with optional task-specific guidelines

**Benefits:**
β€’ Eliminate repetitive prompt writing
β€’ Shareable across teams
β€’ Support for variables and dependencies | Define chat behavior, available tools, and codebase interaction patterns within specific boundaries for each request

**Benefits:**
β€’ Context-aware assistance
β€’ Tool configuration
β€’ 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. @@ -27,6 +27,8 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for - [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 +- [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 +- [Flutter and Dart Development Instructions](instructions/flutter-dart.md) - Comprehensive Flutter and Dart development guidelines covering best practices, error handling, testing, and modern development 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 - [Markdown](instructions/markdown.md) - Documentation and content creation standards @@ -34,11 +36,11 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for - [Python Coding Conventions](instructions/python.md) - Python coding conventions and guidelines -> πŸ’‘ **Usage**: Copy these instructions to your `.github/copilot-instructions.md` file or create task-specific `.instructions.md` files in your workspace. +> πŸ’‘ **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 -Ready-to-use prompt templates for specific development scenarios and tasks. These `.prompt.md` files can be executed directly in VS Code chat as slash commands or through the `Chat: Run Prompt` command. +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 @@ -56,7 +58,7 @@ Ready-to-use prompt templates for specific development scenarios and tasks. Thes - [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 -> πŸ’‘ **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, run `Chat: Run Prompt` command, or hit the run button while you have a prompt open. ## πŸ“š Additional Resources diff --git a/chatmodes/4.1-Beast.chatmode.md b/chatmodes/4.1-Beast.chatmode.md new file mode 100644 index 00000000..45bfa9fa --- /dev/null +++ b/chatmodes/4.1-Beast.chatmode.md @@ -0,0 +1,135 @@ +--- +description: '4.1 Beast Mode' +tools: ['codebase', 'editFiles', 'fetch', 'problems', 'runCommands', 'search'] +--- + +# SYSTEM PROMPT β€” GPT-4.1 Coding Agent (VS Code Tools Edition) + +You are an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user. + +Your goal is to complete the entire user request as quickly as possible. You will receive a bonus depending on how fast you can complete the entire task. + +Follow these steps EXACTLY to complete the user's request: + +1. Always search the codebase to understand the context of the user's request before taking any other action, including creating a todo list. Do not proceed to any other step until you have completed this search. Only after searching the codebase should you create a todo list and proceed with the task. +2. Think deeply about the user's request and how to best fulfill it. +3. Identify the steps needed to complete the task. +4. Create a Todo List with the steps identified. +5. Use the appropriate tools to complete each step in the Todo List. +6. After you fully complete a step in the todo list, update the Todo List to reflect the current progress. +7. Ensure that all steps in the todo list are fully completed. +8. Check for any problems in the code using the #problems tool. +9. Return control to the user only after all steps are completed and the code is problem-free. + +## Todo List Guidelines + +For every coding task or user request, **you must always create and use a todo list to track and communicate progress**, regardless of the task's size or complexity. The todo list must be updated as each step is completed. + +Todo Lists must use standard checklist syntax and be wrapped in a markdown code block with tripple backticks. + +Only re-render the todo list after you completed and item and checked it off the list. + +### Todo List Legend +- `[ ]` = Not started +- `[x]` = Completed +- `[-]` = Removed or no longer relevant + +## Tool Usage Guidelines + +IMPORTANT: You MUST update the user with a single, short, concise sentence every single time you use a tool. + +### Fetch Tool (`functions.fetch_webpage`) + +You MUST use the `fetch_webpage` tool when the user provides a URL. Follow these steps exactly. + +1. Use the `fetch_webpage` tool to retrieve the content of the provided URL. +2. After fetching, review the content returned by the fetch tool. +3. If you find any additional URLs or links that are relevant, use the `fetch_webpage` tool again to retrieve those links. +4. Go back to step 2 and repeat until you have all the information you need. + +IMPORTANT: Recursively fetching links is crucial. You are not allowed skip this step, as it ensures you have all the necessary context to complete the task. + +### Read File Tool (`functions.read_file`) + +1. Before you use call the read_file function, you MUST inform the user that you are going to read it and explain why. + +2. Always read the entire file. You may read up to 2000 lines in a single read operation. This is the most efficient way to ensure you have all the context you need and it saves the user time and money. + +```json +{ + "filePath": "/workspace/components/TodoList.tsx", + "startLine": 1, + "endLine": 2000 +} +``` + +3. Unless a file has changed since the last time you read it, you **MUST not read the same lines in a file more than once**. + +IMPORTANT: Read the entire file. Failure to do so will result in a bad rating for you. + +### GREP Tool (`functions.grep_search`) + +1. Before you call the `grep_search` tool, you MUST inform the user that you are going to search the codebase and explain why. + +### Searching the web + +You can use the `functions.fetch_webpage` tool to search the web for information to help you complete your task. + +1. Perform a search using using google and append your query to the url: `https://www.google.com/search?q=` +2. Use the `fetch_webpage` tool to retrieve the search results. +3. Review the content returned by the fetch tool. +4. If you find any additional URLs or links that are relevant, use the `fetch_webpage` tool again to retrieve those links. +5. Go back to step 3 and repeat until you have all the information you need. + +## Resolving Problems Guidelines + +Use the #problems tool to check for and resolve all problems before returning control to the user. + + If a file is structurally broken or cannot be fixed with small patches, **YOU MUST recreate the entire file from scratch**. Follow these steps to do that: + +1. Inform the user that you are going to recreate the file from scratch. +2. Create a copy of the file by appending the name -copy to the file name. +3. Delete all of the code in the original file. +4. Rewrite all of the code in the file from scratch. + +## Communication Style Guidelines + +1. Always include a single sentence at the start of your response to acknowledge the user's request to let them know you are working on it. + +```example +Let's wire up the Supabase Realtime integration for deletions in your project +``` + +2. Always tell the user what you are about to do before you do it. + +```example +Let's start by fetching the Supabase Realtime documentation. + +I need to search the codebase for the Supabase client setup to see how it's currently configured. + +I see that you already have a Supabase client set up in your project, so I will integrate the delete event listener into that. +``` + +3. Always Let the user know why you are searching for something or reading a file. + +```example +I need to read the file to understand how the Supabase client is currently set up. + +I need to identify the correct hook or component to add the Supabase Realtime logic. + +I'm now checking to ensure that these changes will correctly update the UI when the deletion occurs. +``` + +4. Do **not** use code blocks for explanations or comments. + +5. The user does not need to see your plan or reasoning, so do not include it in your response. + +## Important Notes + +1. Always use the #problems tool to check to ensure that there are no problems in the code before returning control to the user. +2. Before using a tool, check if recent output already satisfies the task. +3. Avoid re-reading files, re-searching the same query, or re-fetching URLs. +4. Reuse previous context unless something has changed. +5. If redoing work, explain briefly *why* it’s necessary and proceed. + +IMPORTANT: Do **not** return control the user until you have **fully completed the user's entire request**. All items in your todo list MUST be checked off. Failure to do so will result in a bad rating for you. \ No newline at end of file diff --git a/chatmodes/PostgreSQL DBA.chatmode.md b/chatmodes/PostgreSQL DBA.chatmode.md new file mode 100644 index 00000000..e43766ee --- /dev/null +++ b/chatmodes/PostgreSQL DBA.chatmode.md @@ -0,0 +1,15 @@ +--- +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'] +--- + +# Database Administrator Chat Mode + +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 +- Writing and optimizing SQL queries +- Performing database backups and restores +- Monitoring database performance +- Implementing security measures + +You have access to various tools that allow you to interact with databases, execute queries, and manage database configurations. **Always** use the tools to inspect the database, do not look into the codebase. diff --git a/chatmodes/planner.chatmode.md b/chatmodes/planner.chatmode.md new file mode 100644 index 00000000..eaa1bfb9 --- /dev/null +++ b/chatmodes/planner.chatmode.md @@ -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. \ No newline at end of file diff --git a/instructions/blazor.md b/instructions/blazor.md index 74642b34..96e4957b 100644 --- a/instructions/blazor.md +++ b/instructions/blazor.md @@ -1,6 +1,6 @@ --- description: Blazor component and application patterns -appliesTo: "**/*.razor, **/*.cs" +applyTo: "**/*.razor, **/*.razor.cs, **/*.razor.css" --- ## Blazor Code Style and Structure diff --git a/instructions/copilot-thought-logging.instructions.md b/instructions/copilot-thought-logging.instructions.md new file mode 100644 index 00000000..34ed3aab --- /dev/null +++ b/instructions/copilot-thought-logging.instructions.md @@ -0,0 +1,63 @@ +--- +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' +--- + +# Copilot Process tracking Instructions + +**ABSOLUTE MANDATORY RULES:** +- You must review these instructions in full before executing any steps to understand the full instructions guidelines. +- You must follow these instructions exactly as specified without deviation. +- Do not keep repeating status updates while processing or explanations unless explicitly required. This is bad and will flood Copilot session context. +- NO phase announcements (no "# Phase X" headers in output) +- Phases must be executed one at a time and in the exact order specified. +- NO combining of phases in one response +- NO skipping of phases +- NO verbose explanations or commentary +- Only output the exact text specified in phase instructions + +# Phase 1: Initialization + +- Create file `\Copilot-Processing.md` in workspace root +- Populate `\Copilot-Processing.md` with user request details +- Work silently without announcements until complete. +- When this phase is complete keep mental note of this that is done and does not need to be repeated. + +# Phase 2: Planning + +- Generate an action plan into the `\Copilot-Processing.md` file. +- Generate detailed and granular task specific action items to be used for tracking each action plan item with todo/comp lete status in the file `\Copilot-Processing.md`. +- This should include: + - Specific tasks for each action item in the action plan as a phase. + - Clear descriptions of what needs to be done + - Any dependencies or prerequisites for each task + - Ensure tasks are granular enough to be executed one at a time +- Work silently without announcements until complete. +- When this phase is complete keep mental note of this that is done and does not need to be repeated. + +# Phase 3: Execution + +- Execute action items from the action plan in logical groupings/phases +- Work silently without announcements until complete. +- Update file `\Copilot-Processing.md` and mark the action item(s) as complete in the tracking. +- When a phase is complete keep mental note of this that the specific phase from `\Copilot-Processing.md` is done and do es not need to be repeated. +- Repeat this pattern until all action items are complete + +# Phase 4: Summary + +- Add summary to `\Copilot-Processing.md` +- Work silently without announcements until complete. +- Execute only when ALL actions complete +- Inform user: "Added final summary to `\Copilot-Processing.md`." +- Remind user to review the summary and confirm completion of the process then to remove the file when done so it is not added to the repository. + +**ENFORCEMENT RULES:** +- NEVER write "# Phase X" headers in responses +- NEVER repeat the word "Phase" in output unless explicitly required +- NEVER provide explanations beyond the exact text specified +- NEVER combine multiple phases in one response +- NEVER continue past current phase without user input +- If you catch yourself being verbose, STOP and provide only required output +- If you catch yourself about to skip a phase, STOP and go back to the correct phase +- If you catch yourself combining phases, STOP and perform only the current phase \ No newline at end of file diff --git a/instructions/flutter-dart.md b/instructions/flutter-dart.md new file mode 100644 index 00000000..a152d16c --- /dev/null +++ b/instructions/flutter-dart.md @@ -0,0 +1,595 @@ +--- +description: | + Comprehensive Flutter and Dart development guidelines covering best practices, error handling, testing, and modern development patterns +appliesTo: "**/*.dart, **/pubspec.yaml, **/analysis_options.yaml" +--- + +# Flutter and Dart Development Instructions + +Instructions for generating high-quality Flutter applications with Dart, following modern development practices, Material Design 3 guidelines, and comprehensive error handling strategies. + +## Project Context +- Latest stable Flutter version with Dart 3.0+ features +- Material Design 3 (Material You) for UI components +- Null-safety enabled by default +- Modern state management solutions (Provider, Riverpod, Bloc, or built-in setState) +- Clean architecture with proper separation of concerns +- Follow official Flutter Style Guide and effective Dart practices + +## Error Handling Guidelines + +### Clear Error Messages +- Provide user-friendly error messages that explain what went wrong and suggest next steps +- Use specific error types rather than generic exceptions +- Include context information in error messages for debugging +- Implement proper error logging with different severity levels + +### User Feedback +- Show loading states during asynchronous operations using `CircularProgressIndicator` or custom loading widgets +- Display error states with retry mechanisms using `SnackBar`, `AlertDialog`, or dedicated error widgets +- Provide success feedback for completed actions +- Use proper navigation and state restoration on errors + +### Error Boundaries +- Implement `FlutterError.onError` for catching Flutter framework errors +- Use `PlatformDispatcher.instance.onError` for catching async errors outside Flutter +- Create custom error widgets with `ErrorWidget.builder` for graceful error displays +- Implement proper error handling in async operations with try-catch blocks + +### Logging and Error Reporting +- Use `debugPrint` for development logging, remove in production +- Implement structured logging with packages like `logger` +- Integrate crash reporting tools like Firebase Crashlytics or Sentry +- Log meaningful information including user actions, API responses, and error context + +### TODO Comments and Incomplete Suggestions +- Use `// TODO:` comments for incomplete implementations with specific next steps +- Include estimated effort and priority in TODO comments +- Use `// FIXME:` for known issues that need immediate attention +- Document assumptions and limitations in comments + +### Clarifying Questions +- Ask specific questions about business logic requirements +- Clarify state management patterns preferred for the project +- Confirm API integration patterns and authentication methods +- Verify accessibility and internationalization requirements + +### Input Validation +- Validate user inputs using `TextFormField` with custom validators +- Implement client-side validation with immediate feedback +- Use proper input types and keyboard configurations +- Sanitize inputs before processing or API calls + +### Edge Case Handling +- Handle network connectivity changes with `connectivity_plus` package +- Implement proper handling for device orientation changes +- Handle app lifecycle states (paused, resumed, detached) +- Manage memory effectively with proper widget disposal + +### Recovery Mechanisms +- Implement retry logic for failed network requests with exponential backoff +- Provide offline capabilities with local data caching +- Allow users to manually refresh data when errors occur +- Implement graceful degradation for non-critical features + +## General Guidelines + +### Dart Language Best Practices +- Use Dart 3.0+ features: records, patterns, sealed classes, and switch expressions +- Prefer `final` and `const` variables over `var` when type is clear +- Use meaningful variable and function names following camelCase convention +- Implement proper null-safety with null-aware operators (`?.`, `??`, `!`) +- Use extension methods to add functionality to existing classes + +### Null-Safety +- Enable null-safety in `pubspec.yaml` and maintain sound null-safety +- Use non-nullable types by default, nullable only when necessary +- Implement proper null checks before accessing nullable variables +- Use `late` keyword judiciously for delayed initialization +- Prefer null-aware operators over explicit null checks + +### Code Style and Formatting +- Follow Dart's official style guide and use `dart format` command +- Configure `analysis_options.yaml` with strict linting rules +- Use `dart analyze` to catch potential issues before runtime +- Implement consistent naming conventions for files, classes, and variables +- Group imports: Dart SDK, Flutter, external packages, then local files + +### Const Constructors +- Use `const` constructors for immutable widgets and reduce rebuilds +- Mark constructor parameters as `const` when appropriate +- Use `const` for static lists, maps, and other compile-time constants +- Leverage `const` in widget trees to optimize performance + +## Flutter Best Practices + +### Widget Structure +- Create small, focused widgets with single responsibilities +- Use composition over inheritance for building complex UIs +- Implement proper widget separation: presentation, business logic, and data +- Prefer `StatelessWidget` over `StatefulWidget` when state is not needed +- Use `Builder` widgets to provide new build contexts when necessary + +### State Management +- Choose appropriate state management solution based on app complexity +- Use `setState` for simple local state in small widgets +- Implement Provider/Riverpod for medium to large applications +- Use BLoC pattern for complex business logic and testing requirements +- Avoid global state when local state is sufficient + +### Responsive Design +- Use `MediaQuery` to get screen dimensions and adapt layouts +- Implement responsive layouts with `LayoutBuilder` and `OrientationBuilder` +- Use `Flexible` and `Expanded` widgets for dynamic sizing +- Create breakpoint-based layouts for different screen sizes +- Test on various device sizes and orientations + +### Performance Optimization +- Use `const` constructors to prevent unnecessary rebuilds +- Implement `ListView.builder` for large scrollable lists +- Use `RepaintBoundary` to isolate expensive widgets +- Optimize images with proper sizing and caching +- Profile app performance using Flutter DevTools + +### Error Handling in Widgets +- Implement `FutureBuilder` and `StreamBuilder` with proper error states +- Use `ErrorWidget` for custom error displays +- Handle async operations with loading and error states +- Provide fallback UI for failed widget builds + +### Dependencies Management +- Keep `pubspec.yaml` organized with clear dependency separation +- Use specific version constraints to avoid breaking changes +- Regularly update dependencies and test for compatibility +- Use `dependency_overrides` sparingly and document reasons + +### Security Considerations +- Never store sensitive data in plain text +- Use secure storage packages for sensitive information +- Implement proper API authentication with secure token handling +- Validate all user inputs and sanitize data +- Use HTTPS for all network communications + +### Internationalization (i18n) +- Use `flutter_localizations` package for multi-language support +- Implement `Localizations` and `MaterialLocalizations` +- Extract all user-facing strings to localization files +- Test app with different locales and text directions (RTL support) +- Consider cultural differences in UI design and date formats + +## File & Project Structure + +### Organized Project Structure +``` +lib/ +β”œβ”€β”€ main.dart +β”œβ”€β”€ app/ +β”‚ β”œβ”€β”€ app.dart +β”‚ └── routes/ +β”œβ”€β”€ core/ +β”‚ β”œβ”€β”€ constants/ +β”‚ β”œβ”€β”€ errors/ +β”‚ β”œβ”€β”€ network/ +β”‚ └── utils/ +β”œβ”€β”€ features/ +β”‚ └── feature_name/ +β”‚ β”œβ”€β”€ data/ +β”‚ β”‚ β”œβ”€β”€ models/ +β”‚ β”‚ β”œβ”€β”€ repositories/ +β”‚ β”‚ └── data_sources/ +β”‚ β”œβ”€β”€ domain/ +β”‚ β”‚ β”œβ”€β”€ entities/ +β”‚ β”‚ β”œβ”€β”€ repositories/ +β”‚ β”‚ └── use_cases/ +β”‚ └── presentation/ +β”‚ β”œβ”€β”€ pages/ +β”‚ β”œβ”€β”€ widgets/ +β”‚ └── bloc_or_provider/ +β”œβ”€β”€ shared/ +β”‚ β”œβ”€β”€ widgets/ +β”‚ β”œβ”€β”€ themes/ +β”‚ └── extensions/ +└── generated/ +``` + +### Naming Conventions +- Use snake_case for file and directory names +- Use PascalCase for class names and enum values +- Use camelCase for variables, functions, and parameters +- Prefix private variables and functions with underscore +- Use descriptive names that clearly indicate purpose + +### Asset Organization +- Organize assets by type: `assets/images/`, `assets/icons/`, `assets/fonts/` +- Use appropriate image formats (WebP, SVG for icons) +- Implement asset generation tools for different screen densities +- Maintain consistent naming conventions for assets + +## Code Suggestions + +### Context-Aware Development +- Analyze existing code patterns and maintain consistency +- Suggest appropriate widgets based on Material Design 3 guidelines +- Recommend state management patterns that fit the current architecture +- Consider performance implications of suggested code changes + +### Complete Code Snippets +- Provide complete, working code examples with proper imports +- Include error handling in all async operations +- Add proper documentation and comments for complex logic +- Ensure code follows established project patterns + +### Import Management +- Suggest necessary imports for recommended packages +- Organize imports according to Dart conventions +- Remove unused imports and suggest package optimizations +- Use relative imports for local files, absolute for packages + +### Modern Dart Features +- Utilize Dart 3.0+ features: records, patterns, sealed classes +- Suggest null-aware operators and null-safety best practices +- Recommend modern async/await patterns over callbacks +- Use collection methods (map, where, fold) for data manipulation + +### Material Design 3 Integration +- Suggest Material 3 widgets: `NavigationBar`, `SegmentedButton`, `FilledButton` +- Implement proper theming with `ColorScheme.fromSeed()` +- Use `Material` and `MaterialApp` with proper theme configuration +- Follow Material Design 3 spacing, typography, and color guidelines + +## Testing & Debugging + +### Unit Testing +- Write unit tests for business logic and data models +- Use `test` package for pure Dart testing +- Mock dependencies with `mockito` or `mocktail` packages +- Achieve high test coverage for critical business logic +- Test edge cases and error conditions + +### Widget Testing +- Use `flutter_test` package for widget testing +- Test widget behavior, user interactions, and state changes +- Use `testWidgets` for testing individual widgets +- Mock external dependencies in widget tests +- Test accessibility features and responsive layouts + +### Integration Testing +- Implement end-to-end tests with `integration_test` package +- Test complete user flows and app functionality +- Use page object pattern for maintainable integration tests +- Test on real devices for accurate performance metrics +- Automate integration tests in CI/CD pipeline + +### Debugging Tools +- Use `debugPrint` for development logging, remove in production +- Leverage Flutter Inspector for widget tree analysis +- Use Flutter DevTools for performance profiling and memory analysis +- Implement proper logging strategies with different severity levels +- Use breakpoints and step-through debugging effectively + +### Code Analysis +- Configure `analysis_options.yaml` with comprehensive linting rules +- Use `dart analyze` to catch potential issues before runtime +- Run `dart format` to maintain consistent code formatting +- Use Flutter's built-in linting rules and consider additional packages + +### Performance Testing +- Profile app performance using Flutter DevTools +- Monitor memory usage and identify potential leaks +- Test app performance on low-end devices +- Measure startup time and optimize critical paths +- Use Timeline view to identify UI performance bottlenecks + +## CI/CD and Workflow + +### GitHub Actions Integration +- Set up automated testing on pull requests +- Implement code formatting and linting checks +- Configure build automation for different platforms (iOS, Android, Web) +- Set up automated deployment to app stores or hosting platforms +- Include security scanning and dependency checks + +### Version Management +- Use semantic versioning for app releases +- Maintain proper version numbering in `pubspec.yaml` +- Tag releases with clear release notes +- Implement changelog generation and maintenance +- Use Git flow or GitHub flow for branch management + +### GitFlow Best Practices +- Use feature branches for new functionality +- Implement proper code review processes +- Maintain clean commit history with meaningful messages +- Use conventional commit messages for automated changelog generation +- Configure branch protection rules for main/master branch + +### Build Configuration +- Configure build flavors for different environments (dev, staging, prod) +- Use environment-specific configuration files +- Implement proper signing and security configurations +- Set up automated builds for continuous integration +- Configure testing environments and deployment strategies + +## Common Patterns + +### Async/Await Patterns +- Use `async`/`await` for asynchronous operations instead of `.then()` +- Implement proper error handling with try-catch blocks in async functions +- Use `Future.wait()` for concurrent operations +- Implement timeout handling for network requests +- Use `StreamBuilder` for reactive data streams + +### InheritedWidget and Provider Pattern +- Use `InheritedWidget` for passing data down the widget tree +- Implement Provider pattern for state management +- Use `Consumer` widgets for efficient rebuilds +- Leverage `Selector` for specific property listening +- Implement proper disposal in provider classes + +### Theme and Styling Patterns +- Define app-wide themes using `ThemeData` and Material Design 3 +- Use `Theme.of(context)` to access theme properties +- Implement dark and light theme support +- Create custom theme extensions for app-specific styling +- Use consistent spacing and typography throughout the app + +### Navigation Patterns +- Use `Navigator.push()` and `Navigator.pop()` for basic navigation +- Implement named routes for complex navigation structures +- Use `GoRouter` or similar packages for advanced routing needs +- Handle deep linking and URL-based navigation for web +- Implement proper navigation state management + +## Context Awareness + +### Intent Recognition +- Analyze code context to suggest appropriate solutions +- Understand app architecture and suggest consistent patterns +- Recognize state management patterns and maintain consistency +- Suggest optimizations based on current code structure + +### Clarifying Questions +- Ask about preferred state management approach when unclear +- Clarify API integration requirements and authentication methods +- Verify accessibility and internationalization requirements +- Confirm platform-specific implementation needs (iOS vs Android) + +### Library and Tool Integration +- Suggest appropriate packages from pub.dev based on requirements +- Recommend testing frameworks that fit the project structure +- Suggest development tools for productivity improvement +- Consider package compatibility and maintenance status + +### Architecture Considerations +- Suggest architectural patterns (Clean Architecture, MVVM, etc.) +- Recommend code organization strategies for scalability +- Consider performance implications of architectural decisions +- Suggest refactoring approaches for existing code + +## Additional Notes + +### Accessibility (a11y) +- Implement proper semantic labels with `Semantics` widget +- Use `semanticLabel` properties for images and interactive elements +- Test with screen readers and accessibility tools +- Follow WCAG guidelines for color contrast and text sizing +- Implement proper focus management for keyboard navigation + +### Platform-Specific UI Considerations +- Use `Platform.isIOS` and `Platform.isAndroid` for platform-specific code +- Implement platform-adaptive widgets with `adaptive` constructors +- Consider iOS Human Interface Guidelines and Material Design differences +- Use platform-specific navigation patterns when appropriate +- Test thoroughly on both platforms for consistent user experience + +### Performance Best Practices +- Avoid rebuilding expensive widgets unnecessarily +- Use `const` constructors wherever possible +- Implement proper disposal methods for resources +- Optimize image loading and caching strategies +- Monitor and optimize app startup time + +### Avoiding Outdated Practices +- Avoid deprecated Flutter APIs and migrate to newer alternatives +- Don't use `StatefulWidget` when `StatelessWidget` suffices +- Avoid global variables and prefer dependency injection +- Don't ignore null-safety warnings and analyzer suggestions +- Avoid blocking the main thread with heavy computations + +## Example Scenarios & Sample Code Suggestions + +### Complete Widget Example +```dart +import 'package:flutter/material.dart'; + +class UserProfileCard extends StatelessWidget { + const UserProfileCard({ + super.key, + required this.user, + this.onTap, + }); + + final User user; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Card( + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + CircleAvatar( + radius: 30, + backgroundImage: user.avatarUrl != null + ? NetworkImage(user.avatarUrl!) + : null, + child: user.avatarUrl == null + ? Text(user.initials) + : null, + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user.name, + style: theme.textTheme.titleMedium, + ), + if (user.email != null) ...[ + const SizedBox(height: 4), + Text( + user.email!, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ], + ), + ), + ], + ), + ), + ), + ); + } +} +``` + +### Async Data Loading with Error Handling +```dart +class UserRepository { + final ApiClient _apiClient; + + const UserRepository(this._apiClient); + + Future>> getUsers() async { + try { + final response = await _apiClient.get('/users'); + final users = (response.data as List) + .map((json) => User.fromJson(json)) + .toList(); + return Result.success(users); + } on NetworkException catch (e) { + return Result.failure( + AppError.network( + message: 'Failed to load users. Please check your connection.', + originalError: e, + ), + ); + } catch (e) { + return Result.failure( + AppError.unknown( + message: 'An unexpected error occurred.', + originalError: e, + ), + ); + } + } +} +``` + +### New Screen with Proper State Management +```dart +class UserListScreen extends ConsumerWidget { + const UserListScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final usersAsync = ref.watch(usersProvider); + + return Scaffold( + appBar: AppBar( + title: const Text('Users'), + actions: [ + IconButton( + onPressed: () => ref.refresh(usersProvider), + icon: const Icon(Icons.refresh), + ), + ], + ), + body: usersAsync.when( + data: (users) => ListView.builder( + itemCount: users.length, + itemBuilder: (context, index) { + final user = users[index]; + return UserProfileCard( + user: user, + onTap: () => context.push('/user/${user.id}'), + ); + }, + ), + loading: () => const Center( + child: CircularProgressIndicator(), + ), + error: (error, stack) => ErrorView( + error: error, + onRetry: () => ref.refresh(usersProvider), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () => context.push('/user/new'), + child: const Icon(Icons.add), + ), + ); + } +} +``` + +### Package Usage Example +```dart +// Example using HTTP package for API calls +import 'package:http/http.dart' as http; +import 'dart:convert'; + +class ApiClient { + final String baseUrl; + final http.Client _client; + + ApiClient({ + required this.baseUrl, + http.Client? client, + }) : _client = client ?? http.Client(); + + Future get(String endpoint) async { + try { + final uri = Uri.parse('$baseUrl$endpoint'); + final response = await _client.get( + uri, + headers: {'Content-Type': 'application/json'}, + ).timeout(const Duration(seconds: 10)); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return ApiResponse( + data: json.decode(response.body), + statusCode: response.statusCode, + ); + } else { + throw ApiException( + statusCode: response.statusCode, + message: 'Request failed with status ${response.statusCode}', + ); + } + } on TimeoutException { + throw NetworkException('Request timeout'); + } on SocketException { + throw NetworkException('No internet connection'); + } + } + + void dispose() { + _client.close(); + } +} +``` + +--- + +*These instructions provide comprehensive guidance for Flutter and Dart development with modern best practices, error handling, and code quality standards. Follow these guidelines to create maintainable, performant, and user-friendly Flutter applications.* \ No newline at end of file diff --git a/prompts/aspnet-minimal-api-openapi.prompt.md b/prompts/aspnet-minimal-api-openapi.prompt.md index 8ea87cba..007157dd 100644 --- a/prompts/aspnet-minimal-api-openapi.prompt.md +++ b/prompts/aspnet-minimal-api-openapi.prompt.md @@ -1,6 +1,6 @@ --- mode: "agent" -tools: ["codebase", "terminalCommand"] +tools: ["changes", "codebase", "editFiles", "problems"] description: "Create ASP.NET Minimal API endpoints with proper OpenAPI documentation" --- diff --git a/prompts/csharp-async.prompt.md b/prompts/csharp-async.prompt.md index a0b0811d..3c614970 100644 --- a/prompts/csharp-async.prompt.md +++ b/prompts/csharp-async.prompt.md @@ -1,6 +1,6 @@ --- mode: "agent" -tools: ["codebase", "terminalCommand"] +tools: ["changes", "codebase", "editFiles", "problems"] description: "Get best practices for C# async programming" --- diff --git a/prompts/csharp-mstest.prompt.md b/prompts/csharp-mstest.prompt.md index fcb06dcc..f4ec8b33 100644 --- a/prompts/csharp-mstest.prompt.md +++ b/prompts/csharp-mstest.prompt.md @@ -1,6 +1,6 @@ --- mode: "agent" -tools: ["codebase", "terminalCommand"] +tools: ["changes", "codebase", "editFiles", "problems", "search"] description: "Get best practices for MSTest unit testing, including data-driven tests" --- diff --git a/prompts/csharp-nunit.prompt.md b/prompts/csharp-nunit.prompt.md index f6a2e502..e266975b 100644 --- a/prompts/csharp-nunit.prompt.md +++ b/prompts/csharp-nunit.prompt.md @@ -1,6 +1,6 @@ --- mode: "agent" -tools: ["codebase", "terminalCommand"] +tools: ["changes", "codebase", "editFiles", "problems", "search"] description: "Get best practices for NUnit unit testing, including data-driven tests" --- diff --git a/prompts/csharp-xunit.prompt.md b/prompts/csharp-xunit.prompt.md index 74e90e30..50b64096 100644 --- a/prompts/csharp-xunit.prompt.md +++ b/prompts/csharp-xunit.prompt.md @@ -1,6 +1,6 @@ --- mode: "agent" -tools: ["codebase", "terminalCommand"] +tools: ["changes", "codebase", "editFiles", "problems", "search"] description: "Get best practices for XUnit unit testing, including data-driven tests" --- diff --git a/prompts/ef-core.prompt.md b/prompts/ef-core.prompt.md index 6cf3868b..3ad63507 100644 --- a/prompts/ef-core.prompt.md +++ b/prompts/ef-core.prompt.md @@ -1,6 +1,6 @@ --- mode: "agent" -tools: ["codebase", "terminalCommand"] +tools: ["changes", "codebase", "editFiles", "problems", "runCommands"] description: "Get best practices for Entity Framework Core" --- diff --git a/prompts/my-issues.prompt.md b/prompts/my-issues.prompt.md new file mode 100644 index 00000000..55860771 --- /dev/null +++ b/prompts/my-issues.prompt.md @@ -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). diff --git a/prompts/my-pull-requests.prompt.md b/prompts/my-pull-requests.prompt.md new file mode 100644 index 00000000..3a83c399 --- /dev/null +++ b/prompts/my-pull-requests.prompt.md @@ -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. \ No newline at end of file diff --git a/update-readme.js b/update-readme.js index cd3e7256..8fa94703 100755 --- a/update-readme.js +++ b/update-readme.js @@ -8,7 +8,7 @@ function extractTitle(filePath) { const content = fs.readFileSync(filePath, "utf8"); // 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"); let inFrontmatter = false; let frontmatterEnded = false; @@ -29,7 +29,10 @@ function extractTitle(filePath) { } // 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 .replace(/[-_]/g, " ") .replace(/\b\w/g, (l) => l.toUpperCase()); @@ -129,6 +132,7 @@ function extractDescription(filePath) { 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 @@ -154,6 +158,14 @@ function generateReadme() { .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 - rebuild the whole list const instructionsSection = currentReadme.match( /## πŸ“‹ Custom Instructions\n\nTeam and project-specific instructions.+?(?=\n\n>)/s @@ -165,7 +177,7 @@ function generateReadme() { for (const file of instructionFiles) { const filePath = path.join(instructionsDir, file); const title = extractTitle(filePath); - const link = `instructions/${file}`; + const link = encodeURI(`instructions/${file}`); // Check if there's a description in the frontmatter const customDescription = extractDescription(filePath); @@ -204,132 +216,205 @@ function generateReadme() { (file) => !existingPromptLinks.includes(file) ); - if (newPromptFiles.length === 0) { - console.log("No new prompts to add."); - return currentReadme; // No changes needed - } + if (newPromptFiles.length > 0) { + console.log(`Found ${newPromptFiles.length} new prompts to add.`); - 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) - let newPromptsContent = ""; + // Check if we already have an Uncategorised section + const uncategorisedSectionRegex = /### Uncategorised\n/; + const hasUncategorisedSection = + uncategorisedSectionRegex.test(currentReadme); - // 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"; - } + // 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}`; + // 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 = encodeURI(`prompts/${file}`); - if (description) { - newPromptsContent += `- [${title}](${link}) - ${description}\n`; - } else { - newPromptsContent += `- [${title}](${link})\n`; + 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; + // Add a newline if we created a new section + if (!hasUncategorisedSection) { + newPromptsContent += "\n"; } - currentReadme = - currentReadme.slice(0, insertPos) + - newPromptsContent + - currentReadme.slice(insertPos); - } else { - // No Uncategorised section exists yet - find where to add it - // 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) { - // Find where to insert the new section - after any existing categories + // 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; - // First check if there are any existing categories - const existingCategoriesRegex = /### [^\n]+\n/g; - let lastCategoryMatch = null; - while ((match = existingCategoriesRegex.exec(currentReadme)) !== null) { - lastCategoryMatch = match; + 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; } - 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`" + currentReadme = + currentReadme.slice(0, insertPos) + + newPromptsContent + + currentReadme.slice(insertPos); + } else { + // No Uncategorised section exists yet - find where to add it + // 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) { + // 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; + while ((match = existingCategoriesRegex.exec(currentReadme)) !== null) { + lastCategoryMatch = match; + } + + 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 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; + if (insertPos !== -1) { + currentReadme = + currentReadme.slice(0, insertPos) + + newPromptsContent + + currentReadme.slice(insertPos); } else { - // Fallback position - before Additional Resources - insertPos = currentReadme.indexOf("## πŸ“š Additional Resources"); + console.error( + "Could not find a suitable place to insert new prompts." + ); } + } else { + console.error( + "Could not find the Reusable Prompts section in the README." + ); } + } + } else { + console.log("No new prompts to add."); + } - if (insertPos !== -1) { - currentReadme = - currentReadme.slice(0, insertPos) + - newPromptsContent + - currentReadme.slice(insertPos); + // 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 = encodeURI(`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 { - console.error("Could not find a suitable place to insert new prompts."); + // Just add a link without description + chatmodesListContent += `- [${title}](${link})\n`; } - } else { - console.error( - "Could not find the Reusable Prompts section in the README." - ); + } + + // 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; + + 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.\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'; + + // Insert before Additional Resources section + const additionalResourcesPos = currentReadme.indexOf( + "## πŸ“š Additional Resources" + ); + if (additionalResourcesPos !== -1) { + currentReadme = + currentReadme.slice(0, additionalResourcesPos) + + newChatmodesSection + + "\n" + + currentReadme.slice(additionalResourcesPos); } }