├── .devcontainer └── devcontainer.json ├── .github ├── steps │ ├── 1-preparing.md │ ├── 2-running-our-extension.md │ ├── 3-connecting-to-github.md │ ├── 4-customizing-our-extension.md │ ├── 5-merge-our-changes.md │ └── x-review.md └── workflows │ ├── 0-start-exercise.yml │ ├── 1-preparing.yml │ ├── 2-running-our-extension.yml │ ├── 3-connecting-to-github.yml │ ├── 4-customizing-our-extension.yml │ └── 5-merge-our-changes.yml ├── .gitignore ├── .vscode └── launch.json ├── LICENSE ├── README.md └── ghc-extension-js ├── agent-knowledge ├── job-description-ext.md ├── job-description.md ├── school-overview-ext.md ├── school-overview.md ├── staff-roles-ext.md └── staff-roles.md ├── index.js ├── info.html ├── package-lock.json └── package.json /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | { 3 | // A universal image that includes several runtimes and tools 4 | "image": "mcr.microsoft.com/devcontainers/universal:2-linux", 5 | 6 | // The service is hosted on port 3000 7 | "forwardPorts": [3000], 8 | "portsAttributes": { 9 | "3000": { 10 | "label": "copilot-extension-service", 11 | "onAutoForward": "silent", 12 | "requireLocalPort": true 13 | } 14 | }, 15 | 16 | // Add the GitHub Copilot extension for VS Code (for older installations). 17 | "customizations": { 18 | "vscode": { 19 | "extensions": ["GitHub.copilot"] 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/steps/1-preparing.md: -------------------------------------------------------------------------------- 1 | ## Step 1: Preparing to make your extension 2 | 3 | Welcome to **"Your first extension for GitHub Copilot"** exercise! :robot: 4 | 5 | We will be making an extension for GitHub Copilot by creating a web service, connecting to a GitHub App, and customizing it to our needs (the staff of a high school). But before we get started, let's learn a bit more about extensions. 6 | 7 | ### What is a GitHub Copilot Extension? 8 | 9 | A [GitHub Copilot Extension](https://github.com/features/copilot/extensions) is an add-on that provides customized abilities for GitHub Chat and github.com. That means, it can be more dynamic and include consistent context. 10 | 11 | For example: 12 | 13 | - **Querying documentation**: A Copilot Extension can allow Copilot Chat to query a third-party documentation service to find information about a specific topic. 14 | - **AI-assisted coding**: A Copilot Extension can use a third-party AI model to provide code suggestions. 15 | - **Data retrieval**: A Copilot Extension can allow Copilot Chat to query a third-party data service to retrieve information about a specific topic. 16 | - **Action execution**: A Copilot Extension can allow Copilot Chat to execute a specific action, such as posting to a message board or updating a tracking item in an external system. 17 | 18 | In fact, you can even publish your extension on the [GitHub Marketplace](https://github.com/marketplace?type=apps&copilot_app=true) to share it with the world! 19 | 20 | > Ref: For more information, see the [About building extensions](https://docs.github.com/en/copilot/building-copilot-extensions/about-building-copilot-extensions) page. 21 | 22 | ### How do I make an extension? 23 | 24 | Creating an extension is fairly easy. It includes 3 parts, which we will learn in this lesson. 25 | Naturally, the web service must be hosted, but that is covered in another lesson. For this exercise, we will use a [Codespace](https://github.com/features/codespaces). 26 | 27 | 1. **GitHub App** - Enables message handling and communicating with GitHub Copilot. 28 | 1. **Extension Service** - A standard web service for receiving the messages, performing the custom actions, and responding back to GitHub Copilot. 29 | 1. **Extension Content** - Materials provided to your extension to customize it for your application. 30 | 31 | > [!IMPORTANT] 32 | > A [GitHub Copilot Extension](https://github.com/features/copilot/extensions) is _NOT_ the [GitHub Copilot VS Code Extension](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) found in your IDE, but rather an extra capability to enhance it. 33 | 34 | ```mermaid 35 | flowchart LR 36 | 37 | %% User 38 | user@{ shape: circle, label: "User" } 39 | ide@{ shape: div-rect, label: "IDE 40 | (Copilot Chat)" } 41 | 42 | %% Extension 43 | github_app@{ shape: div-rect, label: "GitHub App" } 44 | extension_content@{ shape: docs, label: "Extension Content"} 45 | %% extension_calls@{ shape: docs, label: "Function Calls"} 46 | %% extension_resource@{ shape: cyl, label: "Other 47 | %% Resources" } 48 | extension_service@{ shape: subproc, label: "Extension Service" } 49 | 50 | %% Copilot 51 | copilot_service@{ shape: curv-trap, label: "Copilot 52 | Services" } 53 | 54 | %%% Main Flow 55 | user -- "**@my-ghc-extension**: 56 | How do I...?" --> ide 57 | --> github_app --> extension_service --response--> ide 58 | 59 | %% Extension Flow 60 | extension_service --> copilot_service --> extension_service 61 | extension_content o--o extension_service 62 | %% extension_resource <--> extension_calls --> extension_service --> extension_calls 63 | ``` 64 | 65 | ### Ok, let's get to developing! :mechanical_arm: 66 | 67 | Before we get started on your extension, we have to configure our development environment. 68 | Fortunately, this has been bootstrapped for us with a pre-configured [Codespace](https://github.com/features/codespaces). 69 | 70 | This development environment includes: 71 | 72 | - The Node.js runtime. 73 | - A template GitHub Extension (javascript web app service). 74 | - [VS Code](https://code.visualstudio.com/) launch settings to start your extension in debug mode. 75 | 76 | ### :keyboard: Activity: Getting to know your extension development environment 77 | 78 | 1. Right-click the below button to open the **Create Codespace** page in a new tab. 79 | 80 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/{{full_repo_name}}?quickstart=1) 81 | 82 | - The free tier of Codespaces that comes with all GitHub accounts is fine, assuming you still have minutes available. 83 | - The default Codespace settings are fine. 84 | - This repository will provide the additional settings and files for making your extension. 85 | 86 | 1. Confirm the **Repository** field is your copy of the exercise, not the original, then click the green **Create Codespace** button. 87 | 88 | - ✅ Your copy: `/{{{full_repo_name}}}` 89 | - ❌ Original: `/skills/your-first-extension-for-github-copilot` 90 | 91 | 1. Wait a moment for Visual Studio Code to load. 92 | 93 | 1. Before we continue let's take a moment to familiarize ourselves with the project folder. 94 | 95 | - The left navigation bar is where you can access the file explorer, debugger, and search. 96 | - The lower panel (Ctrl+J) shows the debugger output, allows running terminal commands, and allows configuring the web service ports. 97 | - Our template extension is in the `ghc-extension-js` folder. More on that in the next steps! 98 | - The `index.js` file is the entry point for the extension and hosts the web service for Copilot to interact with. 99 | - The `package-lock.json` and `package.json` files define the extension's dependencies. 100 | 101 | 1. Create a new branch named `my-ghc-extension`. Ensure it is checked out in VS Code and published to GitHub. 102 | 103 | - Note: Creating this branch triggers the next step in your exercise. 104 | -------------------------------------------------------------------------------- /.github/steps/2-running-our-extension.md: -------------------------------------------------------------------------------- 1 | ## Step 2: Running our Extension 2 | 3 | Let's learn a bit more about the web application that will become our GitHub Copilot Extension, more specifically, the needed endpoints for communicating with our [GitHub App](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) (next step). 4 | 5 | There are 2 required and 1 recommended web service endpoints: 6 | 7 | - **[GET] /callback** - A simple HTML message provided to the user after authorization to confirm that the extension has permissions. 8 | - **[POST] /copilot** - A response endpoint to exchange messages with GitHub Copilot. 9 | - **[GET] /** - (Optional) A default response from the root of your web service for viewing in a normal web browser, to provide an overview of the extension. 10 | 11 | > [!NOTE] 12 | > The `/callback` and `/copilot` endpoints can be renamed as desired. They just have match the GitHub App settings. 13 | 14 | ### :keyboard: Activity: Running our extension 15 | 16 | Before we start customizing, let's try running the template extension that was provided. 17 | 18 | 1. In VS Code, expand the the lower panel (Ctrl+J) and select the **Terminal** tab. 19 | 20 | 1. Run the below command to install the required javascript packages. 21 | 22 | ```bash 23 | cd ghc-extension-js 24 | npm install 25 | ``` 26 | 27 | 1. Configure the open ports. 28 | 29 | 1. In the lower panel bar, select the **Ports** tab. 30 | 1. Verify port `3000` is active and the visibility is `public`. 31 | 1. If the port visibility is not `public`, right click on the entry and select **Port Visibility** to update it. 32 | 33 | 1. Verify the included template program works. 34 | 35 | 1. In the left navigation bar, select the debug icon. 36 | 1. Click the green play button to start the debugger. 37 | 1. The program should run and output some text like: `Copilot extension service running at: {URL}` 38 | 1. This is the global URL for your extension running in this codespace. 39 | 40 | 1. Verify our extension service is running. 41 | 42 | 1. In the lower panel bar, return to the **Ports** tab. 43 | 1. Right click on the URL and select **Open in Browser**. 44 | 1. You should see a web page describing your extension! 45 | 46 | 1. Leave the debugger running to keep the service alive, and add an issue comment using the example below. Make sure you tag Professor Octocat to notify her and to update the link! 47 | 48 | ```markdown 49 | Hey @professortocat, please check if my codespace is running correctly. 50 | 51 | https://my-codespace-link-3000.app.github.dev 52 | ``` 53 | 54 | > [!IMPORTANT] 55 | > When you restart a Codespace, the exposed ports are reset. 56 | > This may mean they are removed or changed to private visibility. 57 | -------------------------------------------------------------------------------- /.github/steps/3-connecting-to-github.md: -------------------------------------------------------------------------------- 1 | ## Step 3: Connecting to GitHub 2 | 3 | A critical component for using our extension is creating a [GitHub App](https://docs.github.com/en/apps/overview), which handles presenting our extension to the user and providing authorization to resources. In fact, GitHub Apps can be used for many things such as managing issues, commenting on pull requests, and even talking to other services like Slack. 4 | 5 | For our extension, it will be similar to talking to another service, and displaying it in a general purpose chat on github.com and in Copilot Chat for Visual Studio Code. 6 | 7 | > [!TIP] 8 | > If you would like to learn more about these and other capabilities, check out the [GitHub Apps Overview](https://docs.github.com/en/apps/overview) page. 9 | 10 | ### :keyboard: Activity: Connecting to GitHub 11 | 12 | Let's make a GitHub App, configure it to work with GitHub Copilot as an Agent, and install it on your account. 13 | 14 | 1. Navigate to GitHub.com 15 | 1. In the top right, click your profile picture, then click **Settings**. 16 | 1. In the left sidebar at the bottom, select **Developer settings**. 17 | 1. In the left sidebar at the top, select **GitHub Apps** . 18 | 1. Click the **New GitHub App** button. 19 | 1. In the displayed form, enter the following: 20 | 1. In the **Register new GitHub App** section, enter: 21 | - **GitHub App name**: `my-ghc-extension-{{login}}` 22 | - The app name must be unique across all GitHub. 23 | - Note: The handle in Copilot Chat will be lowercase, like `@my-ghc-extension-{{login_lowercase}}`. 24 | - **Description**: `My first extension for GitHub Copilot` 25 | - **Homepage URL**: Any url that provides an overview and usage instructions for your extension. 26 | - We will use our web service's information page. This is the url displayed on console when you run the extension, plus `/info`. 27 | - Example: `https://conscious-jumper-abcdefg-3000.app.github.dev/info` 28 | 1. In the **Identifying and authorizing users** section, enter: 29 | - **Callback URL**: The url displayed on console when you run the extension, plus `/callback`. 30 | - Example: `https://conscious-jumper-abcdefg-3000.app.github.dev/callback` 31 | - **Expire user authorization tokens**: `[x] Checked` 32 | - **Request user authorization (OAuth) during installation**: `[x] Checked` 33 | - **Enable Device Flow**: `[ ] Unchecked` 34 | 1. In the **Webhook** section enter: 35 | - **Active**: `[ ] Unchecked` 36 | 1. In the **Permissions** section, select the following permissions: 37 | - Repository: `None` 38 | - Organization: `None` 39 | - Account: 40 | - **Copilot Chat**: `read only` 41 | 1. In the **Where can this GitHub App be installed?** section, select: 42 | - `Only on this account` 43 | 1. Click **Create GitHub App**. 44 | 1. On the left sidebar, click **Copilot**. 45 | - If this is your first time creating a Copilot extension, you will be prompted to accept the terms. 46 | 1. In the **App Type** dropdown, select `Agent`. Enter the following details: 47 | - **Preauthorization URL**: Blank 48 | - **Agent Definition > URL**: The url displayed on the console when you run the extension, plus `/copilot`. 49 | - Example: `https://conscious-jumper-abcdefg-3000.app.github.dev/copilot` 50 | - **Inference Description**: `My first extension for GitHub Copilot` 51 | - This will be displayed as a tooltip in the Copilot chat interface. 52 | 1. click **Save**. 53 | 1. On the left sidebar, click **Install App**. 54 | 1. Click **Install** and **Install & Authorize**. 55 | 56 | ### :keyboard: Activity: Testing the connection 57 | 58 | Let's check if our extension service is available to use on github.com and in our IDE, and that they are able to communicate. 59 | 60 | 1. In VS Code, use the debugger to start the extension service if it is not already running. 61 | 1. Open a web browser and navigate to [github.com](https://github.com). 62 | 1. At the top of the page, click the **Copilot Icon**. 63 | 1. Start a general purpose chat. 64 | 1. Type `@my-ghc-extension-{{login_lowercase}} How can you help me?` and press enter. You should get a response. 65 | > **Tip:** Try opening another VS Code window. You can use the extension there with Copilot Chat as well! 66 | 1. After you are done configuring your **GitHub App** and testing the connection, leave the following comment on the issue to let Mona know you are ready for the next step. 67 | 68 | ```markdown 69 | Hey @professortocat, I'm all done configuring my GitHub App. Here's the link. What's next? 70 | 71 | https://github.com/apps/my-ghc-extension-{{login}} 72 | ``` 73 | -------------------------------------------------------------------------------- /.github/steps/4-customizing-our-extension.md: -------------------------------------------------------------------------------- 1 | ## Step 4: Customizing our Extension 2 | 3 | Nice work getting your extension up and running! :tada: 4 | It feels cool to see Copilot responding, right?! :sunglasses: 5 | 6 | Now let's get into the fun parts where we customize it to support the staff of our local high school! :unicorn: 7 | 8 | But, before we do that, let's talk about the nature of the exchanged messages with GitHub Copilot and "context passing". 9 | 10 | ### What is context? 11 | 12 | Simply put, context is the information you provide GitHub Copilot for it to make a better informed response. That could be asking Copilot to assume a persona, providing it some background data, or asking it a particular question. 13 | 14 | For this application, that means JSON objects with a defined role and some text content. In our case, we will attach a few `system` messages that look similar to the below. When the user interacts with GitHub Copilot, you will notice those attached as the `user` role. 15 | 16 | ```json 17 | { 18 | "role": "system", 19 | "content": "You are a software developer creating desktop and web-based programs to support a high school staff." 20 | } 21 | ``` 22 | 23 | ### :keyboard: Activity: Configuring our extension 24 | 25 | Customizing Copilot is pretty simple. It's similar to sharing more information with a coworker. 26 | You simply have to add more context to help them make an informed decision. 27 | 28 | We'll do that here with a few markdown files that can be easily updated without any worry of breaking the extension. 29 | 30 | 1. Open VS Code and expand the `/ghc-extension-js` folder. 31 | 1. Let's give our extension Agent a job description. Everyone likes job clarity, right? 32 | 33 | 1. Open `index.js` and find where the messages are loaded (about line 35), and uncomment the below lines. 34 | This will insert the job description at the beginning of Copilot's context, aka "short term memory". 35 | 36 | ```js 37 | const messages = payload.messages; // After this line, add the below 38 | 39 | // Add the agent job description to copilot's messages 40 | const jobDescription = await fs.readFile( 41 | path.join(__dirname, "agent-knowledge", "job-description.md"), 42 | "utf8" 43 | ); 44 | messages.unshift({ 45 | role: "system", 46 | content: jobDescription, 47 | }); 48 | ``` 49 | 50 | 1. Open the file `/agent-knowledge/job-description.md` and replace the placeholder with the following content. 51 | 52 | ```markdown 53 | You are a software developer supporting the staff of a high school. 54 | Your goal is to provide automation services and tools to help them work faster. 55 | ``` 56 | 57 | > **Tip:** You can add more detail to your description. Check out the `job-description-ext.md` file for ideas. 58 | 59 | 1. Now, let's repeat the above process for 2 more files. 60 | 1. Modify `index.js` to also use `/agent-knowledge/school-overview.md` with the below content for ideas. 61 | 62 | ```markdown 63 | This is an overview of the high school so instructors can more naturally describe their needs. 64 | 65 | - The school name is "Mergington High School" 66 | - The school is a public high school in Mergington, Florida. 67 | - The school moto is "Branch out and grow". 68 | - It serves grades 9 through 12 and typically has 100 to 150 students per grade. 69 | 70 | - The school year starts in August and ends in May. 71 | - There are 3 trimesters per year. 72 | - There is a 4th summer cycle, but it is optional. 73 | ``` 74 | 75 | > **Tip:** You can add more detail to your description. Check out the `school-overview-ext.md` file for ideas. 76 | 77 | 1. Modify `index.js` to also use `/agent-knowledge/staff-roles.md` with the below content. 78 | 79 | ```markdown 80 | Below is a list of common roles and tasks they might want help with. 81 | If a user specifies their role, you can use this information to provide more targeted suggestions or offer ways to help them. 82 | 83 | ## School Administration 84 | 85 | - Budget management and resource allocation 86 | - Staff recruitment, management, and development 87 | - School improvement plans, vision setting, and culture building 88 | - Community relations 89 | 90 | ## Instructional Staff 91 | 92 | - Curriculum planning and lesson design 93 | - Grading and performance tracking 94 | - Course customization and differentiation for students 95 | - Parent communication and student support 96 | - Classroom management and behavior systems 97 | ``` 98 | 99 | > **Tip:** You can add more detail to your description. Check out the `staff-roles-ext.md` file. 100 | 101 | 1. Great work! Now we have a job description and some context for our extension to use. Let's test it out! 102 | 1. If the extension service is not already running, use the debugger to start it. 103 | 1. Like previously, navigate to [github.com](https://github.com) and start a generic chat with Copilot. 104 | 1. Try interacting with Copilot using some of the below prompts. 105 | 106 | > **Prompt** 107 | > 108 | > ```prompt 109 | > @my-ghc-extension-{{login_lowercase}} I heard you can help me with my students. In what ways? 110 | > ``` 111 | 112 | > **Prompt** 113 | > 114 | > ```prompt 115 | > @my-ghc-extension-{{login_lowercase}} Tell me a bit about our school? 116 | > ``` 117 | 118 | > **Prompt** 119 | > 120 | > ```prompt 121 | > @my-ghc-extension-{{login_lowercase}} I'd like to create a system for tracking student progress 122 | > across years and teachers. Let's make a website for it. 123 | > ``` 124 | 125 | > **Prompt** 126 | > 127 | > ```prompt 128 | > @my-ghc-extension-{{login_lowercase}} How can I visualize data exported from our student management system? 129 | > For example a graph of each students' grades over the year. 130 | > ``` 131 | 132 | 1. When you are done experimenting with prompts and changing the files, please commit and push the changes. 133 | - Make sure you are on the `my-ghc-extension` branch. 134 | - Git should show changes for 4 files: 135 | - `index.js` 136 | - `agent-knowledge/job-description.md` 137 | - `agent-knowledge/school-overview.md` 138 | - `agent-knowledge/staff-roles.md` 139 | -------------------------------------------------------------------------------- /.github/steps/5-merge-our-changes.md: -------------------------------------------------------------------------------- 1 | ## Step 5: Merge our changes 2 | 3 | Not much left! Let's create a pull request and merge our changes to `main`. 4 | 5 | ### :keyboard: Create a pull request and merge 6 | 7 | 1. In the web browser, navigate to your repository. 8 | 1. At the top click on the **Pull requests** tab. Notice the banner suggesting to create a pull request. 9 | 1. In the top right, press the green **Compare & pull request** button. 10 | 1. On the **Open a pull request** page, enter the following options: 11 | 12 | - For the **base** branch, select `main`. 13 | - For the **compare** branch, select the `my-ghc-extension` branch. 14 | - For the **add a title** field, enter `Create GitHub Copilot Extension`. 15 | - For the **add a description** field, click the Copilot button to have one generated. 16 | Alternately, you write your own such as: 17 | 18 | ```md 19 | Create a GitHub Copilot Extension to enable school staff to make their customized web and desktop applications. 20 | ``` 21 | 22 | 1. Press the green **Create pull request** button. 23 | 1. Scroll down to review the commit history and ensure your changes are present. 24 | 1. At the bottom, press the green **Merge pull request** button and then the green **Confirm merge** button. 25 | -------------------------------------------------------------------------------- /.github/steps/x-review.md: -------------------------------------------------------------------------------- 1 | ## Review 2 | 3 | _Congratulations, you've completed this exercise and made your first GitHub Copilot Extension!_ 4 | 5 | celebrate 6 | 7 | Here's a recap of your accomplishments: 8 | 9 | - You prepared your development environment to make a GitHub Copilot Extension. 10 | - You created a new GitHub Copilot Extension using a template. 11 | - You connected your extension to GitHub. 12 | - You customized your extension to help a high school staff become developers with natural language. 13 | 14 | ### What's next? 15 | 16 | - Use GitHub Actions to automate [deploying your service to Azure](https://github.com/skills/deploy-to-azure). 17 | - Publish your extension to the [GitHub Marketplace](https://docs.github.com/en/copilot/building-copilot-extensions/about-building-copilot-extensions#about-visibility-of-github-copilot-extensions). 18 | - Check out the other [GitHub Skills exercises](https://skills.github.com). 19 | 20 | Check out these resources to learn more about GitHub Copilot Extensions: 21 | 22 | - View the GitHub docs for this exercise: [Creating a Copilot Extension](https://docs.github.com/en/copilot/building-copilot-extensions/creating-a-copilot-extension) 23 | - Need something simpler? Try creating a [Copilot SkillSet](https://docs.github.com/en/copilot/building-copilot-extensions/building-a-copilot-skillset-for-your-copilot-extension/building-copilot-skillsets). 24 | - Are you a student? Check out the [Student Developer Pack](https://education.github.com/pack). 25 | -------------------------------------------------------------------------------- /.github/workflows/0-start-exercise.yml: -------------------------------------------------------------------------------- 1 | name: Step 0 # Start Exercise 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write 10 | actions: write 11 | issues: write 12 | 13 | env: 14 | EXERCISE_NAME: "Your First Extension for GitHub Copilot" 15 | INTRO_MESSAGE: "Get excited! We're about to learn how to make your favorite AI pair programmer even better by extending it with some customized skills!" 16 | STEP_1_FILE: ".github/steps/1-preparing.md" 17 | 18 | jobs: 19 | disable_workflows: 20 | name: Disable workflows 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | 27 | - name: Disable all workflows 28 | run: | 29 | workflows=$(git ls-files | grep -E '\.yml$|\.yaml$') 30 | for workflow in $workflows; do 31 | workflow_name=$(basename $workflow) 32 | gh workflow disable "$workflow_name" || true 33 | done 34 | env: 35 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | 37 | start_exercise: 38 | if: | 39 | !github.event.repository.is_template 40 | name: Start Exercise 41 | runs-on: ubuntu-latest 42 | 43 | steps: 44 | - name: Checkout 45 | uses: actions/checkout@v4 46 | 47 | - name: Configure Git user 48 | run: | 49 | git config user.name github-actions[bot] 50 | git config user.email github-actions[bot]@users.noreply.github.com 51 | 52 | - name: Deactivate 'Start Excercise' button 53 | run: | 54 | # Remove href from 'Start Exercise' button 55 | target='id="copy-exercise"[^>]*href="[^"]*"' 56 | replacement='id="copy-exercise"' 57 | sed -i "s|$target|$replacement|g" README.md 58 | 59 | # Change color from green to gray 60 | target=Copy_Exercise-008000 61 | replacement=Copy_Exercise-AAA 62 | sed -i "s|$target|$replacement|g" README.md 63 | 64 | - name: Activate 'Start Exercise' button 65 | run: | 66 | # Add link to issue 67 | target='id="start-exercise"' 68 | replacement='id="start-exercise" href="../../issues/1"' 69 | sed -i "s|$target|$replacement|g" README.md 70 | 71 | # Change color from gray to green 72 | target=Start_Exercise-AAA 73 | replacement=Start_Exercise-008000 74 | sed -i "s|$target|$replacement|g" README.md 75 | 76 | - name: Replace relative links in readme 77 | run: | 78 | target=../../ 79 | replacement=https://github.com/${{ github.repository }}/ 80 | sed -i "s|$target|$replacement|g" README.md 81 | 82 | - name: Push README changes 83 | run: | 84 | git add README.md 85 | git commit --message="Start exercise" 86 | git push 87 | env: 88 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 89 | 90 | create_exercise: 91 | if: | 92 | !github.event.repository.is_template 93 | name: Create exercise issue 94 | runs-on: ubuntu-latest 95 | 96 | outputs: 97 | issue-url: ${{ steps.create-issue.outputs.ISSUE_URL }} 98 | 99 | steps: 100 | - name: Checkout 101 | uses: actions/checkout@v4 102 | 103 | - name: Get response templates 104 | uses: actions/checkout@v4 105 | with: 106 | repository: skills/response-templates 107 | path: skills-response-templates 108 | 109 | - name: Configure Git user 110 | run: | 111 | git config user.name github-actions[bot] 112 | git config user.email github-actions[bot]@users.noreply.github.com 113 | 114 | - name: Build welcome message from template 115 | id: build-issue-description 116 | uses: skills/action-text-variables@v1 117 | with: 118 | template-file: skills-response-templates/step-feedback/welcome.md 119 | template-vars: | 120 | title=${{ env.EXERCISE_NAME }} 121 | login=${{ github.actor }} 122 | intro_message=${{ env.INTRO_MESSAGE }} 123 | 124 | - name: Create issue - add welcome message 125 | id: create-issue 126 | run: | 127 | issue_url=$(gh issue create \ 128 | --title "Exercise: $EXERCISE_NAME" \ 129 | --body "$ISSUE_BODY") 130 | echo "ISSUE_URL=$issue_url" >> "$GITHUB_OUTPUT" 131 | env: 132 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 133 | ISSUE_BODY: ${{ steps.build-issue-description.outputs.updated-text }} 134 | 135 | post_next_step_content: 136 | name: Post next step content 137 | runs-on: ubuntu-latest 138 | needs: [create_exercise] 139 | env: 140 | ISSUE_URL: ${{ needs.create_exercise.outputs.issue-url }} 141 | 142 | steps: 143 | - name: Checkout 144 | uses: actions/checkout@v4 145 | 146 | - name: Get response templates 147 | uses: actions/checkout@v4 148 | with: 149 | repository: skills/response-templates 150 | path: skills-response-templates 151 | 152 | - name: Configure Git user 153 | run: | 154 | git config user.name github-actions[bot] 155 | git config user.email github-actions[bot]@users.noreply.github.com 156 | 157 | - name: Build comment - add step content 158 | id: build-comment 159 | uses: skills/action-text-variables@v1 160 | with: 161 | template-file: ${{ env.STEP_1_FILE }} 162 | template-vars: | 163 | login=${{ github.actor }} 164 | full_repo_name=${{ github.repository }} 165 | 166 | - name: Create comment - add step content 167 | run: | 168 | gh issue comment "$ISSUE_URL" \ 169 | --body "$COMMENT_BODY" 170 | env: 171 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 172 | COMMENT_BODY: ${{ steps.build-comment.outputs.updated-text }} 173 | 174 | - name: Create comment - watching for progress 175 | run: | 176 | gh issue comment "$ISSUE_URL" \ 177 | --body-file "skills-response-templates/step-feedback/watching-for-progress.md" 178 | env: 179 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 180 | 181 | - name: Disable current workflow and enable next one 182 | run: | 183 | # gh workflow enable "Step 0" # Already disabled 184 | gh workflow enable "Step 1" 185 | env: 186 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 187 | -------------------------------------------------------------------------------- /.github/workflows/1-preparing.yml: -------------------------------------------------------------------------------- 1 | name: Step 1 # Preparing to make your extension 2 | 3 | on: 4 | push: 5 | branches: 6 | - "!main" 7 | - "my-ghc-extension" 8 | 9 | permissions: 10 | contents: read 11 | actions: write 12 | issues: write 13 | 14 | env: 15 | STEP_2_FILE: ".github/steps/2-running-our-extension.md" 16 | 17 | jobs: 18 | find_exercise: 19 | name: Find exercise by issue title 20 | runs-on: ubuntu-latest 21 | 22 | outputs: 23 | issue-url: ${{ steps.get-issue-url-by-title.outputs.ISSUE_URL }} 24 | 25 | steps: 26 | - id: get-issue-url-by-title 27 | run: | 28 | issue_url=$(gh issue list --repo $REPO --search "in:title Exercise:" --json url,title --jq '.[].url') 29 | echo "ISSUE_URL=$issue_url" >> $GITHUB_OUTPUT 30 | env: 31 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | REPO: ${{ github.repository }} 33 | 34 | check_step_work: 35 | name: Check step work 36 | runs-on: ubuntu-latest 37 | needs: [find_exercise] 38 | env: 39 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 40 | 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v4 44 | 45 | - name: Get response templates 46 | uses: actions/checkout@v4 47 | with: 48 | repository: skills/response-templates 49 | path: skills-response-templates 50 | 51 | - name: Update comment - checking work 52 | run: | 53 | gh issue comment "$ISSUE_URL" \ 54 | --body-file skills-response-templates/step-feedback/checking-work.md \ 55 | --edit-last 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | 59 | # START: Check practical exercise 60 | 61 | # Nothing to verify. Creating the branch is enough for now. 62 | # In a future update, we will check that the codepsace is running and that the port is set properly. 63 | # - Get the list of codespaces 64 | # gh codespace list --json "name" 65 | # - Check if the codespace has port 3000 set to open 66 | # gh codespace ports --codespace symmetrical-winner-w9xjw5wv59pf5vvj --json "sourcePort,visibility" 67 | 68 | # END: Check practical exercise 69 | 70 | - name: Build message - step finished 71 | id: build-message-step-finish 72 | uses: skills/action-text-variables@v1 73 | with: 74 | template-file: skills-response-templates/step-feedback/step-finished-prepare-next-step.md 75 | template-vars: | 76 | next_step_number=2 77 | 78 | - name: Update comment - step finished 79 | run: | 80 | gh issue comment "$ISSUE_URL" \ 81 | --body "$ISSUE_BODY" \ 82 | --edit-last 83 | env: 84 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 85 | ISSUE_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 86 | 87 | post_next_step_content: 88 | name: Post next step content 89 | needs: [find_exercise, check_step_work] 90 | runs-on: ubuntu-latest 91 | env: 92 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 93 | 94 | steps: 95 | - name: Checkout 96 | uses: actions/checkout@v4 97 | 98 | - name: Get response templates 99 | uses: actions/checkout@v4 100 | with: 101 | repository: skills/response-templates 102 | path: skills-response-templates 103 | 104 | - name: Create comment - add step content 105 | run: | 106 | gh issue comment "$ISSUE_URL" \ 107 | --body-file "$STEP_2_FILE" 108 | env: 109 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 110 | 111 | - name: Create comment - watching for progress 112 | run: | 113 | gh issue comment "$ISSUE_URL" \ 114 | --body-file skills-response-templates/step-feedback/watching-for-progress.md 115 | env: 116 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 117 | 118 | - name: Disable current workflow and enable next one 119 | run: | 120 | gh workflow disable "Step 1" 121 | gh workflow enable "Step 2" 122 | env: 123 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 124 | -------------------------------------------------------------------------------- /.github/workflows/2-running-our-extension.yml: -------------------------------------------------------------------------------- 1 | name: Step 2 # Running our extension 2 | 3 | on: 4 | issue_comment: 5 | types: [created, edited] 6 | 7 | permissions: 8 | contents: read 9 | actions: write 10 | issues: write 11 | 12 | env: 13 | # Keywords required in the issue comment to let this workflow run 14 | REQUIRED_ISSUE_COMMENT_KEYWORDS: "@professortocat,https,app.github.dev" 15 | STEP_3_FILE: ".github/steps/3-connecting-to-github.md" 16 | 17 | jobs: 18 | required_issue_comment_keywords: 19 | name: Check issue comment text for required keywords 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Stop early if missing the expected keywords 24 | run: | 25 | required_keywords=(${REQUIRED_ISSUE_COMMENT_KEYWORDS//,/ }) 26 | for keyword in "${required_keywords[@]}"; do 27 | if [[ ! "$COMMENT_BODY" =~ $keyword ]]; then 28 | echo "Unrecognized request. Ending workflow." 29 | exit 0 30 | fi 31 | done 32 | env: 33 | COMMENT_BODY: ${{ github.event.comment.body }} 34 | 35 | find_exercise: 36 | name: Find exercise by issue title 37 | runs-on: ubuntu-latest 38 | 39 | outputs: 40 | issue-url: ${{ steps.get-issue-url.outputs.ISSUE_URL }} 41 | 42 | steps: 43 | - id: get-issue-url 44 | run: | 45 | # Get the issue url from the event or search for it. 46 | if [ -n "${{ github.event.issue }}" ]; then 47 | issue_url="${{ github.event.issue.html_url }}" 48 | else 49 | issue_url=$(gh issue list --repo $REPO --search "in:title Exercise:" --json url,title --jq '.[].url') 50 | fi 51 | 52 | # Save to output 53 | echo "ISSUE_URL=$issue_url" >> $GITHUB_OUTPUT 54 | 55 | env: 56 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | REPO: ${{ github.repository }} 58 | 59 | check_step_work: 60 | name: Check step work 61 | runs-on: ubuntu-latest 62 | needs: [required_issue_comment_keywords, find_exercise] 63 | env: 64 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 65 | 66 | steps: 67 | - name: Checkout 68 | uses: actions/checkout@v4 69 | 70 | - name: Get response templates 71 | uses: actions/checkout@v4 72 | with: 73 | repository: skills/response-templates 74 | path: skills-response-templates 75 | 76 | - name: Update comment - checking work 77 | run: | 78 | gh issue comment "$ISSUE_URL" \ 79 | --body-file skills-response-templates/step-feedback/checking-work.md \ 80 | --edit-last 81 | env: 82 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 83 | 84 | # START: Check practical exercise 85 | 86 | - name: Check codespace is running 87 | run: | 88 | # Get the codespace url from the comment body 89 | url_regex="https://[a-z0-9-]*.app.github.dev" 90 | codespace_url=$(echo $ISSUE_COMMENT_BODY | grep -oP "$url_regex" | head -n 1) 91 | 92 | # Ping the web service for a status code 93 | echo "Checking codespace is running at: $codespace_url" 94 | resp_code=$(curl -s -o /dev/null -w "%{http_code}" $codespace_url) 95 | 96 | # If the codespace is not running, comment on the issue and exit 97 | if [ "$resp_code" -eq 200 ]; then 98 | echo "Codespace confirmed running" 99 | else 100 | echo "Codespace is not running. Response Code: $resp_code" 101 | gh issue comment "$ISSUE_URL" \ 102 | --body "I can't seem to find the service. Please confirm you can access it from a web browser and ask for review again." \ 103 | --edit-last 104 | exit 1 105 | fi 106 | env: 107 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 108 | ISSUE_COMMENT_BODY: ${{ github.event.comment.body }} 109 | 110 | # END: Check practical exercise 111 | 112 | - name: Build message - step finished 113 | id: build-message-step-finish 114 | uses: skills/action-text-variables@v1 115 | with: 116 | template-file: skills-response-templates/step-feedback/step-finished-prepare-next-step.md 117 | template-vars: | 118 | next_step_number=3 119 | 120 | - name: Update comment - step finished 121 | run: | 122 | gh issue comment "$ISSUE_URL" \ 123 | --body "$COMMENT_BODY" \ 124 | --edit-last 125 | env: 126 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 127 | COMMENT_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 128 | 129 | post_next_step_content: 130 | name: Post next step content 131 | needs: [find_exercise, check_step_work] 132 | runs-on: ubuntu-latest 133 | env: 134 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 135 | 136 | steps: 137 | - name: Checkout 138 | uses: actions/checkout@v4 139 | 140 | - name: Get response templates 141 | uses: actions/checkout@v4 142 | with: 143 | repository: skills/response-templates 144 | path: skills-response-templates 145 | 146 | - name: Create lowercase version of login 147 | if: true 148 | run: | 149 | login_lowercase=$(echo "${{ github.actor }}" | tr '[:upper:]' '[:lower:]') 150 | echo "login_lowercase=$login_lowercase" >> $GITHUB_ENV 151 | 152 | - name: Build comment - add step content 153 | id: build-comment 154 | uses: skills/action-text-variables@v1 155 | with: 156 | template-file: ${{ env.STEP_3_FILE }} 157 | template-vars: | 158 | login=${{ github.actor }} 159 | login_lowercase=${{ env.login_lowercase }} 160 | 161 | - name: Create comment - add step content 162 | run: | 163 | gh issue comment "$ISSUE_URL" \ 164 | --body "$COMMENT_BODY" 165 | env: 166 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 167 | COMMENT_BODY: ${{ steps.build-comment.outputs.updated-text }} 168 | 169 | - name: Create comment - watching for progress 170 | run: | 171 | gh issue comment "$ISSUE_URL" \ 172 | --body-file skills-response-templates/step-feedback/watching-for-progress.md 173 | env: 174 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 175 | 176 | - name: Disable current workflow and enable next one 177 | run: | 178 | gh workflow disable "Step 2" 179 | gh workflow enable "Step 3" 180 | env: 181 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 182 | -------------------------------------------------------------------------------- /.github/workflows/3-connecting-to-github.yml: -------------------------------------------------------------------------------- 1 | name: Step 3 # Connecting to GitHub 2 | 3 | on: 4 | issue_comment: 5 | types: [created, edited] 6 | 7 | permissions: 8 | contents: read 9 | actions: write 10 | issues: write 11 | 12 | env: 13 | # Keywords required in the issue comment to allow this workflow to run 14 | REQUIRED_ISSUE_COMMENT_KEYWORDS: "@professortocat,https://github.com/apps" 15 | STEP_4_FILE: ".github/steps/4-customizing-our-extension.md" 16 | 17 | jobs: 18 | required_issue_comment_keywords: 19 | name: Check issue comment text for required keywords 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Stop early if missing the expected keywords 24 | run: | 25 | required_keywords=(${REQUIRED_ISSUE_COMMENT_KEYWORDS//,/ }) 26 | for keyword in "${required_keywords[@]}"; do 27 | if [[ ! "$COMMENT_BODY" =~ $keyword ]]; then 28 | exit 1 29 | fi 30 | done 31 | env: 32 | COMMENT_BODY: ${{ github.event.comment.body }} 33 | 34 | find_exercise: 35 | name: Find exercise by issue title 36 | runs-on: ubuntu-latest 37 | 38 | outputs: 39 | issue-url: ${{ steps.get-issue-url.outputs.ISSUE_URL }} 40 | 41 | steps: 42 | - id: get-issue-url 43 | run: | 44 | # Get the issue url from the event or search for it. 45 | if [ -n "${{ github.event.issue }}" ]; then 46 | issue_url="${{ github.event.issue.html_url }}" 47 | else 48 | issue_url=$(gh issue list --repo $REPO --search "in:title Exercise:" --json url,title --jq '.[].url') 49 | fi 50 | 51 | # Save to output 52 | echo "ISSUE_URL=$issue_url" >> $GITHUB_OUTPUT 53 | env: 54 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | REPO: ${{ github.repository }} 56 | 57 | check_step_work: 58 | name: Check step work 59 | runs-on: ubuntu-latest 60 | needs: [required_issue_comment_keywords, find_exercise] 61 | env: 62 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 63 | 64 | steps: 65 | - name: Checkout 66 | uses: actions/checkout@v4 67 | 68 | - name: Get response templates 69 | uses: actions/checkout@v4 70 | with: 71 | repository: skills/response-templates 72 | path: skills-response-templates 73 | 74 | # START: Check practical exercise 75 | 76 | - name: Check gitub app url is valid 77 | run: | 78 | # Get the GitHub App url from the comment body 79 | url_regex="https://github.com/apps/[^[:space:]]*" 80 | app_url=$(echo $ISSUE_COMMENT_BODY | grep -oP "$url_regex" | head -n 1) 81 | 82 | # Ping the url and get the content 83 | echo "Checking GitHub App exists at: $app_url" 84 | resp_code=$(curl -s -o /dev/null -w "%{http_code}" $app_url) 85 | echo "Response Code: $resp_code" 86 | 87 | # If the GitHub App url is not valid, it wasn't created. Comment on the issue and exit 88 | if [ "$resp_code" -eq 200 ]; then 89 | echo "GitHub App confirmed existing" 90 | else 91 | echo "Codespace is not running. Response Code: $resp_code" 92 | gh issue comment "$ISSUE_URL" \ 93 | --body "I can't seem to find your GitHub App. Please verify the app url by visiting it in a web browser, then try asking to check again." \ 94 | --edit-last 95 | exit 1 96 | fi 97 | env: 98 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 99 | ISSUE_COMMENT_BODY: ${{ github.event.comment.body }} 100 | 101 | # END: Check practical exercise 102 | 103 | - name: Build message - step finished 104 | id: build-message-step-finish 105 | uses: skills/action-text-variables@v1 106 | with: 107 | template-file: skills-response-templates/step-feedback/step-finished-prepare-next-step.md 108 | template-vars: | 109 | next_step_number=4 110 | 111 | - name: Update comment - step finished 112 | run: | 113 | gh issue comment "$ISSUE_URL" \ 114 | --body "$COMMENT_BODY" \ 115 | --edit-last 116 | env: 117 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 118 | COMMENT_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 119 | 120 | post_step_4_content: 121 | name: Post step 4 content 122 | needs: [find_exercise, check_step_work] 123 | runs-on: ubuntu-latest 124 | env: 125 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 126 | 127 | steps: 128 | - name: Checkout 129 | uses: actions/checkout@v4 130 | 131 | - name: Get response templates 132 | uses: actions/checkout@v4 133 | with: 134 | repository: skills/response-templates 135 | path: skills-response-templates 136 | 137 | - name: Create lowercase version of login 138 | if: true 139 | run: | 140 | login_lowercase=$(echo "${{ github.actor }}" | tr '[:upper:]' '[:lower:]') 141 | echo "login_lowercase=$login_lowercase" >> $GITHUB_ENV 142 | 143 | - name: Build comment - add step content 144 | id: build-comment 145 | uses: skills/action-text-variables@v1 146 | with: 147 | template-file: ${{ env.STEP_4_FILE }} 148 | template-vars: | 149 | login_lowercase=${{ env.login_lowercase }} 150 | 151 | - name: Create comment - add step content 152 | run: | 153 | gh issue comment "$ISSUE_URL" \ 154 | --body "$COMMENT_BODY" 155 | env: 156 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 157 | COMMENT_BODY: ${{ steps.build-comment.outputs.updated-text }} 158 | 159 | - name: Create comment - watching for progress 160 | run: | 161 | gh issue comment "$ISSUE_URL" \ 162 | --body-file skills-response-templates/step-feedback/watching-for-progress.md 163 | env: 164 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 165 | 166 | - name: Disable current workflow and enable next one 167 | run: | 168 | gh workflow disable "Step 3" 169 | gh workflow enable "Step 4" 170 | env: 171 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 172 | -------------------------------------------------------------------------------- /.github/workflows/4-customizing-our-extension.yml: -------------------------------------------------------------------------------- 1 | name: Step 4 # Customizing our extension 2 | 3 | on: 4 | push: 5 | branches: 6 | - my-ghc-extension 7 | paths: 8 | - "ghc-extension-js/agent-knowledge/**" 9 | 10 | permissions: 11 | contents: read 12 | actions: write 13 | issues: write 14 | 15 | env: 16 | STEP_5_FILE: ".github/steps/5-merge-our-changes.md" 17 | 18 | jobs: 19 | find_exercise: 20 | name: Find exercise by issue title 21 | runs-on: ubuntu-latest 22 | 23 | outputs: 24 | issue-url: ${{ steps.get-issue-url.outputs.ISSUE_URL }} 25 | 26 | steps: 27 | - id: get-issue-url 28 | run: | 29 | # Get the issue url from the event or search for it. 30 | if [ -n "${{ github.event.issue }}" ]; then 31 | issue_url="${{ github.event.issue.html_url }}" 32 | else 33 | issue_url=$(gh issue list --repo $REPO --search "in:title Exercise:" --json url,title --jq '.[].url') 34 | fi 35 | 36 | # Save to output 37 | echo "ISSUE_URL=$issue_url" >> $GITHUB_OUTPUT 38 | env: 39 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | REPO: ${{ github.repository }} 41 | 42 | check_step_work: 43 | name: Check step work 44 | runs-on: ubuntu-latest 45 | needs: [find_exercise] 46 | env: 47 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 48 | 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v4 52 | 53 | - name: Get response templates 54 | uses: actions/checkout@v4 55 | with: 56 | repository: skills/response-templates 57 | path: skills-response-templates 58 | 59 | # START: Check practical exercise 60 | 61 | - name: Check agent knowledge is updated 62 | id: check-user-work 63 | run: | 64 | # Checks to perform 65 | checks='{ 66 | "job_description": { 67 | "name": "Job Description", 68 | "passed": true, 69 | "message": "" 70 | }, 71 | "school_overview": { 72 | "name": "School Overview", 73 | "passed": true, 74 | "message": "" 75 | }, 76 | "staff_roles": { 77 | "name": "Staff Roles", 78 | "passed": true, 79 | "message": "" 80 | } 81 | }' 82 | 83 | # Check agent job description does not use the template 84 | job_description=$(<"./ghc-extension-js/agent-knowledge/job-description.md") 85 | if [[ $job_description =~ "customize the job description" ]]; then 86 | checks=$(echo $checks | jq '.job_description.passed = false') 87 | checks=$(echo $checks | jq '.job_description.message = "Please customize the agent job description. Do not use the template."') 88 | fi 89 | 90 | # Check school overview does not use the template 91 | school_overview=$(<"./ghc-extension-js/agent-knowledge/school-overview.md") 92 | if [[ $school_overview =~ "customize the school overview" ]]; then 93 | checks=$(echo $checks | jq '.school_overview.passed = false') 94 | checks=$(echo $checks | jq '.school_overview.message = "Please customize the school overview. Do not use the template."') 95 | fi 96 | 97 | # Check staff roles does not use the template 98 | staff_roles=$(<"./ghc-extension-js/agent-knowledge/staff-roles.md") 99 | if [[ $staff_roles =~ "some roles a high school might have" ]]; then 100 | checks=$(echo $checks | jq '.staff_roles.passed = false') 101 | checks=$(echo $checks | jq '.staff_roles.message = "Please customize the staff roles. Do not use the template."') 102 | fi 103 | 104 | # Verify all checks passed 105 | passed=$(echo $checks | jq '. | all(.passed?)') 106 | 107 | # Flatten to an array for returning. Allows iteration during rendering. 108 | results=$(echo $checks | jq 'to_entries | map({name: .key} + .value)') 109 | 110 | # Save pass status to output 111 | echo "passed=$passed" >> $GITHUB_OUTPUT 112 | 113 | # Save results to output 114 | echo 'results<> $GITHUB_OUTPUT 115 | echo $results >> $GITHUB_OUTPUT 116 | echo 'EOF' >> $GITHUB_OUTPUT 117 | 118 | - name: Build message - step results 119 | id: build-message-step-results 120 | uses: skills/action-text-variables@v1 121 | with: 122 | template-file: skills-response-templates/step-feedback/step-results.md 123 | template-vars: '{ 124 | "step_number": 4, 125 | "passed": ${{ steps.check-user-work.outputs.passed }}, 126 | "results_table": ${{ steps.check-user-work.outputs.results }}, 127 | "tips": [ 128 | "You can also use Copilot to call functions! Another lesson though!", 129 | "You might try reading the incoming context to dynamically include agent knowledge files." 130 | ] 131 | }' 132 | 133 | - name: Create comment - step results 134 | run: | 135 | gh issue comment "$ISSUE_URL" \ 136 | --body "$COMMENT_BODY" \ 137 | --edit-last 138 | env: 139 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 140 | COMMENT_BODY: ${{ steps.build-message-step-results.outputs.updated-text }} 141 | 142 | - name: Fail job if not all checks passed 143 | if: steps.check-user-work.outputs.passed == 'false' 144 | run: exit 1 145 | 146 | # END: Check practical exercise 147 | 148 | - name: Build message - step finished 149 | id: build-message-step-finish 150 | uses: skills/action-text-variables@v1 151 | with: 152 | template-file: skills-response-templates/step-feedback/step-finished-prepare-next-step.md 153 | template-vars: | 154 | next_step_number=5 155 | 156 | - name: Update comment - step finished 157 | run: | 158 | gh issue comment "$ISSUE_URL" \ 159 | --body "$COMMENT_BODY" 160 | env: 161 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 162 | COMMENT_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 163 | 164 | post_step_4_content: 165 | name: Post step 4 content 166 | needs: [find_exercise, check_step_work] 167 | runs-on: ubuntu-latest 168 | env: 169 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 170 | 171 | steps: 172 | - name: Checkout 173 | uses: actions/checkout@v4 174 | 175 | - name: Get response templates 176 | uses: actions/checkout@v4 177 | with: 178 | repository: skills/response-templates 179 | path: skills-response-templates 180 | 181 | - name: Create comment - add step content 182 | run: | 183 | gh issue comment "$ISSUE_URL" \ 184 | --body-file "$STEP_5_FILE" 185 | env: 186 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 187 | 188 | - name: Create comment - watching for progress 189 | run: | 190 | gh issue comment "$ISSUE_URL" \ 191 | --body-file skills-response-templates/step-feedback/watching-for-progress.md 192 | env: 193 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 194 | 195 | - name: Disable current workflow and enable next one 196 | run: | 197 | gh workflow disable "Step 4" 198 | gh workflow enable "Step 5" 199 | env: 200 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 201 | -------------------------------------------------------------------------------- /.github/workflows/5-merge-our-changes.yml: -------------------------------------------------------------------------------- 1 | name: Step 5 # Merge your pull request 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | types: 8 | - closed 9 | 10 | permissions: 11 | contents: write 12 | actions: write 13 | issues: write 14 | 15 | env: 16 | REVIEW_FILE: ".github/steps/x-review.md" 17 | 18 | jobs: 19 | find_exercise: 20 | if: | 21 | !github.event.repository.is_template && 22 | github.event.pull_request.merged 23 | name: Find exercise by issue title 24 | runs-on: ubuntu-latest 25 | 26 | outputs: 27 | issue-url: ${{ steps.get-issue-url.outputs.ISSUE_URL }} 28 | 29 | steps: 30 | - id: get-issue-url 31 | run: | 32 | # Get the issue url from the event or search for it. 33 | if [ -n "${{ github.event.issue }}" ]; then 34 | issue_url="${{ github.event.issue.html_url }}" 35 | else 36 | issue_url=$(gh issue list --repo $REPO --search "in:title Exercise:" --json url,title --jq '.[].url') 37 | fi 38 | 39 | # Save to output 40 | echo "ISSUE_URL=$issue_url" >> $GITHUB_OUTPUT 41 | env: 42 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | REPO: ${{ github.repository }} 44 | 45 | check_step_work: 46 | name: Check step work 47 | needs: [find_exercise] 48 | runs-on: ubuntu-latest 49 | env: 50 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 51 | 52 | steps: 53 | - name: Get response templates 54 | uses: actions/checkout@v4 55 | with: 56 | repository: skills/response-templates 57 | path: skills-response-templates 58 | 59 | # START: Check practical exercise 60 | 61 | # Nothing to verify. Merging the pull request is enough. 62 | 63 | # END: Check practical exercise 64 | 65 | - name: Update comment - step finished - final review next 66 | run: | 67 | gh issue comment "$ISSUE_URL" \ 68 | --body-file skills-response-templates/step-feedback/lesson-review.md \ 69 | --edit-last 70 | env: 71 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | 73 | post_review_content: 74 | name: Post review content 75 | needs: [find_exercise, check_step_work] 76 | runs-on: ubuntu-latest 77 | env: 78 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 79 | 80 | steps: 81 | - name: Checkout 82 | uses: actions/checkout@v4 83 | 84 | - name: Create comment - add review content 85 | run: | 86 | gh issue comment "$ISSUE_URL" \ 87 | --body-file "$REVIEW_FILE" 88 | env: 89 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 90 | 91 | finish_course: 92 | name: Finish course 93 | needs: [find_exercise, post_review_content] 94 | runs-on: ubuntu-latest 95 | env: 96 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 97 | 98 | steps: 99 | - name: Checkout 100 | uses: actions/checkout@v4 101 | with: 102 | ref: main 103 | 104 | - name: Get response templates 105 | uses: actions/checkout@v4 106 | with: 107 | repository: skills/response-templates 108 | path: skills-response-templates 109 | 110 | - name: Configure Git user 111 | run: | 112 | git config user.name github-actions[bot] 113 | git config user.email github-actions[bot]@users.noreply.github.com 114 | 115 | - name: Build message - congratulations 116 | id: build-message-congratulations 117 | uses: skills/action-text-variables@v1 118 | with: 119 | template-file: skills-response-templates/readme/congratulations.md 120 | template-vars: | 121 | login=${{ github.actor }} 122 | 123 | - name: Update README - congratulations 124 | run: | 125 | # Add "Congratulations" to the start of the README 126 | orig_readme=$(cat README.md) 127 | new_readme="$MESSAGE $orig_readme" 128 | 129 | # Update file and push 130 | echo "$new_readme" > README.md 131 | git add README.md 132 | git commit --message="Congratulations!🎉" 133 | git push 134 | env: 135 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 136 | MESSAGE: ${{ steps.build-message-congratulations.outputs.updated-text }} 137 | 138 | - name: Build message - exercise finished 139 | id: build-finish-message 140 | uses: skills/action-text-variables@v1 141 | with: 142 | template-file: skills-response-templates/step-feedback/lesson-finished.md 143 | template-vars: | 144 | login=${{ github.actor }} 145 | repo_full_name=${{ github.repository }} 146 | 147 | - name: Create comment - exercise finished 148 | run: | 149 | gh issue comment "$ISSUE_URL" \ 150 | --body "$COMMENT_BODY" 151 | env: 152 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 153 | COMMENT_BODY: ${{ steps.build-finish-message.outputs.updated-text }} 154 | 155 | - name: Close issue 156 | run: gh issue close "$ISSUE_URL" 157 | env: 158 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 159 | 160 | - name: Disable current workflow 161 | run: gh workflow disable "${{github.workflow}}" 162 | env: 163 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 164 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "JS: Launch Copilot Extension Service", 11 | "cwd": "${workspaceFolder}/ghc-extension-js", 12 | "skipFiles": ["/**"], 13 | "runtimeExecutable": "npm", 14 | "runtimeArgs": ["start"] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) GitHub and others 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Your first extension for GitHub Copilot 2 | 3 | 4 | 5 | ![](../../actions/workflows/1-preparing.yml/badge.svg) 6 | ![](../../actions/workflows/2-running-our-extension.yml/badge.svg) 7 | ![](../../actions/workflows/3-connecting-to-github.yml/badge.svg) 8 | ![](../../actions/workflows/4-customizing-our-extension.yml/badge.svg) 9 | ![](../../actions/workflows/5-merge-our-changes.yml/badge.svg) 10 | 11 | _Customize GitHub Copilot to your personal or company needs in less than an hour._ 12 | 13 | ## Welcome 14 | 15 | People love how GitHub Copilot helps them write code faster and with fewer errors. 16 | But what if it already knew some context about your job, team, or company? 17 | In this exercise, we will make a custom extension for GitHub Copilot that can help you with that. 18 | 19 | - **Who is this for**: Intermediate developers familiar with GitHub Copilot, basic GitHub, and basic web development 20 | - **What you'll learn**: We'll introduce GitHub Copilot Extensions and how to customize them. 21 | - **What you'll build**: You'll load an existing template extension and then modify it to support the staff of a high school. 22 | - **Prerequisites**: Skills Exercise: Getting Started with GitHub Copilot 23 | - **How long**: This course takes less than one hour to complete. 24 | 25 | In this exercise, you will: 26 | 27 | 1. Start up a preconfigured development environment for making a GitHub Copilot Extension. 28 | 2. Run the included template extension. 29 | 3. Connect the extension to your GitHub account. 30 | 4. Customize the extension to your needs. 31 | 5. Practice prompting with your new custom Github Copilot Extension. 32 | 33 | ### How to start this exercise 34 | 35 | 1. Right-click **Copy Exercise** and open the link in a new tab. 36 | 37 | 38 | 39 | 40 | 41 | 2. In the new tab, most of the fields will automatically fill in for you. 42 | 43 | - For owner, choose your personal account or an organization to host the repository. 44 | - We recommend creating a public repository, as private repositories will use [Actions minutes](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions). 45 | - Scroll down and click the **Create repository** button at the bottom of the form. 46 | 47 | 3. After your new repository is created, wait about 20 seconds for the course to be prepared. 48 | 49 | - The **Copy Exercise** button will deactivate, changing to gray. 50 | - The **Start Exercise** button will activate, changing to green. 51 | 52 | 4. Click **Start Exercise**. Follow the step-by-step instructions and feedback will be provided as you progress. 53 | 54 | 55 | 56 | 57 | 58 | > [!IMPORTANT] 59 | > The **Start Exercise** button will activate after copying the repository. You will probably need to refresh the page. 60 | 61 | --- 62 | 63 | Get help: [Post in our discussion board](https://github.com/orgs/skills/discussions/categories/your-first-extension-for-github-copilot) • [Review the GitHub status page](https://www.githubstatus.com/) 64 | 65 | © 2025 GitHub • [Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md) • [MIT License](https://gh.io/mit) 66 | -------------------------------------------------------------------------------- /ghc-extension-js/agent-knowledge/job-description-ext.md: -------------------------------------------------------------------------------- 1 | ### Job Description 2 | 3 | - You are a software developer supporting the staff of a high school. 4 | - Your goal is to provide automation services and tools to help them work faster. 5 | 6 | ### User Interaction 7 | 8 | Consider the following when communicating with the staff. 9 | 10 | - The staff is not technical, explain in simple terms as much as possible and avoid software jargon. 11 | - Any software needs to be easy to use. 12 | - The user will probably not explicitly ask to make a software project. Assume that is what they want. 13 | 14 | ## Program architecture 15 | 16 | - Only create web applications and desktop applications. 17 | - Web applications should not need a backend server. Use the browser as the runtime environment. 18 | - Do not create applications that require a database. Use the file system for storage. 19 | - Do not make mobile apps. 20 | - Do not make command line tools. 21 | - Do not create a long single file application. Always use an easy-to-understand directory structure. 22 | - Only use HTML, CSS, Javascript, and Python. No other languages. 23 | 24 | ### Documentation 25 | 26 | - Always update the README file to explain how to use the program. Assume the user will quickly forget so good documentation is important. 27 | - Once the readme gets too long, start organizing it into a docs directory. 28 | 29 | ### Quality considerations 30 | 31 | - If the tasks involves grades, scores, or other numerical data, isolate those functions and make sure they are correct with unit tests. 32 | - Add caching to any calls to web services. Default to 5 minutes. 33 | 34 | ### Security considerations 35 | 36 | - Personal information may be processed so privacy and security are important. 37 | - Do not provide examples that encourage the user hardcode secrets, passwords, or other sensitive information. 38 | - If credentials or other sensitive information is required, add features to the program to prompt for it, store it locally, and logout. 39 | -------------------------------------------------------------------------------- /ghc-extension-js/agent-knowledge/job-description.md: -------------------------------------------------------------------------------- 1 | ### Job Description 2 | 3 | - Replace this text to customize the job description. 4 | -------------------------------------------------------------------------------- /ghc-extension-js/agent-knowledge/school-overview-ext.md: -------------------------------------------------------------------------------- 1 | # School Overview 2 | 3 | This is overview of the high school so instructors can more naturally describe their needs. 4 | 5 | - The school name is "Mergington High School" 6 | - The school is a public high school in Mergington, Florida. 7 | - It is best known for its practical combining of the arts and sciences. 8 | - It serves grades 9 through 12 and typically has 100 to 150 students per grade. 9 | 10 | ### Branding 11 | 12 | - The school mascot is an Octocat and the school colors are lime green and white. 13 | - An Octocat which has a cat face and 8 legs, like an octopus. 14 | - The school moto is "Branch out and grow". 15 | 16 | ### Education Year Cycle 17 | 18 | - Starts in August and ends in May. 19 | - There are 3 trimesters per year. 20 | - There is a 4th summer cycle, but that is optional for students. 21 | 22 | ### History 23 | 24 | The school was founded in 2008 and has with only 4 staff members. 25 | -------------------------------------------------------------------------------- /ghc-extension-js/agent-knowledge/school-overview.md: -------------------------------------------------------------------------------- 1 | # School Overview 2 | 3 | - Replace this text to customize the school overview. 4 | -------------------------------------------------------------------------------- /ghc-extension-js/agent-knowledge/staff-roles-ext.md: -------------------------------------------------------------------------------- 1 | # Staff Descriptions 2 | 3 | Below is a list of common roles and tasks they might need. 4 | If a user specifies their role, you can use this information to provide more targeted suggestions or offer ways to help them. 5 | 6 | ## School Administration 7 | 8 | ### Principal 9 | 10 | - Strategic Planning 11 | - School improvement plans 12 | - Budget management 13 | - Resource allocation 14 | - Staff recruitment and development 15 | - Leadership Responsibilities 16 | - Vision setting and culture building 17 | - Policy implementation 18 | - Community relations 19 | - Crisis management 20 | - Teacher evaluation 21 | 22 | ### Assistant Principal 23 | 24 | - Operations Management 25 | - Daily scheduling 26 | - Discipline management 27 | - Facility supervision 28 | - Event coordination 29 | - Support Functions 30 | - Teacher coaching 31 | - Parent communication 32 | - Student intervention 33 | - Safety protocols 34 | 35 | ## Instructional Staff 36 | 37 | ### Classroom Teacher 38 | 39 | - Instructional Planning 40 | - Curriculum implementation 41 | - Lesson design 42 | - Assessment creation 43 | - Differentiation strategies 44 | - Classroom Management 45 | - Behavior systems 46 | - Learning environment 47 | - Student engagement 48 | - Parent communication 49 | 50 | ### Special Education Teacher 51 | 52 | - Student Support 53 | - IEP development 54 | - Modification planning 55 | - Progress monitoring 56 | - Collaborative teaching 57 | - Documentation 58 | - Legal compliance 59 | - Service records 60 | - Accommodation tracking 61 | - Assessment data 62 | 63 | ### Educational Specialist 64 | 65 | - Subject Expertise 66 | - Content mastery 67 | - Curriculum development 68 | - Best practices research 69 | - Teacher mentoring 70 | - Resource Management 71 | - Materials selection 72 | - Technology integration 73 | - Professional development 74 | - Department coordination 75 | 76 | ## Support Staff 77 | 78 | ### School Counselor 79 | 80 | - Student Services 81 | - Academic guidance 82 | - Social-emotional support 83 | - Career planning 84 | - Crisis intervention 85 | - Program Management 86 | - Testing coordination 87 | - College readiness 88 | - Schedule planning 89 | - Student records 90 | 91 | ### School Psychologist 92 | 93 | - Assessment 94 | - Psychological evaluation 95 | - Learning diagnostics 96 | - Behavioral analysis 97 | - Intervention planning 98 | - Support Services 99 | - Student counseling 100 | - Staff consultation 101 | - Parent education 102 | - Crisis response 103 | 104 | ### Instructional Coach 105 | 106 | - Teacher Support 107 | - Classroom observation 108 | - Feedback provision 109 | - Strategy modeling 110 | - Resource sharing 111 | - Professional Development 112 | - Workshop facilitation 113 | - PLC leadership 114 | - Data analysis 115 | - Best practice research 116 | 117 | ## Specialized Roles 118 | 119 | ### Technology Coordinator 120 | 121 | - System Management 122 | - Infrastructure planning 123 | - Software deployment 124 | - Device management 125 | - Security protocols 126 | - Integration Support 127 | - Teacher training 128 | - Digital resources 129 | - Troubleshooting 130 | - Innovation planning 131 | 132 | ### Media Specialist/Librarian 133 | 134 | - Resource Management 135 | - Collection development 136 | - Digital resources 137 | - Research guidance 138 | - Information literacy 139 | - Program Implementation 140 | - Reading programs 141 | - Technology integration 142 | - Collaboration support 143 | - Student engagement 144 | 145 | ### Parent Coordinator 146 | 147 | - Community Engagement 148 | - Family outreach 149 | - Event planning 150 | - Resource connection 151 | - Communication facilitation 152 | - Support Services 153 | - Translation services 154 | - Parent education 155 | - Volunteer coordination 156 | - Community partnerships 157 | 158 | ## Administrative Support 159 | 160 | ### Registrar 161 | 162 | - Records Management 163 | - Enrollment processing 164 | - Transcript maintenance 165 | - Data verification 166 | - Compliance monitoring 167 | - Administrative Support 168 | - Schedule management 169 | - Report generation 170 | - Records requests 171 | - Database maintenance 172 | 173 | ### Administrative Assistant 174 | 175 | - Office Management 176 | - Daily operations 177 | - Visitor processing 178 | - Supply management 179 | - Calendar coordination 180 | - Communication Support 181 | - Phone system 182 | - Mail distribution 183 | - Message relay 184 | - Document preparation 185 | -------------------------------------------------------------------------------- /ghc-extension-js/agent-knowledge/staff-roles.md: -------------------------------------------------------------------------------- 1 | # Staff Descriptions 2 | 3 | - Replace this text to describe some roles a high school might have. 4 | - Add some tasks those roles might want help solving. 5 | -------------------------------------------------------------------------------- /ghc-extension-js/index.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { Readable } from "node:stream"; 3 | import { fileURLToPath } from "url"; 4 | import { dirname } from "path"; 5 | import path from "path"; 6 | import { promises as fs } from "node:fs"; 7 | 8 | // Get current directory to help with loading files 9 | const __filename = fileURLToPath(import.meta.url); 10 | const __dirname = dirname(__filename); 11 | 12 | // Create a web service that listens for incoming requests 13 | const app = express(); 14 | 15 | // Provide a basic website if the user visits the extension's URL 16 | app.get("/", (req, res) => { 17 | console.log("Endpoint called: /"); 18 | res.sendFile(__dirname + "/info.html"); 19 | }); 20 | app.get("/info", (req, res) => { 21 | console.log("Endpoint called: /info"); 22 | res.sendFile(__dirname + "/info.html"); 23 | }); 24 | 25 | // After installing the app, GitHub will redirect the user to this URL 26 | app.get("/callback", (req, res) => { 27 | console.log("Endpoint called: /callback"); 28 | res.send("Success! You may close this window and return to GitHub."); 29 | }); 30 | 31 | // Receive chat requests, process, and return a response 32 | app.post("/copilot", express.json(), async (req, res) => { 33 | // Load messages array from the request payload 34 | const payload = req.body; 35 | const messages = payload.messages; 36 | 37 | // Add the agent job description to copilot's messages 38 | // const jobDescription = await fs.readFile( 39 | // path.join(__dirname, "agent-knowledge", "job-description.md"), 40 | // "utf8" 41 | // ); 42 | // messages.unshift({ 43 | // role: "system", 44 | // content: jobDescription, 45 | // }); 46 | 47 | // Add the school overview to copilot's messages 48 | // const schoolOverview = await fs.readFile( 49 | // path.join(__dirname, "agent-knowledge", "school-overview.md"), 50 | // "utf8" 51 | // ); 52 | // messages.unshift({ 53 | // role: "system", 54 | // content: schoolOverview, 55 | // }); 56 | 57 | // Add the staff descriptions to copilot's messages 58 | // const staffDescriptions = await fs.readFile( 59 | // path.join(__dirname, "agent-knowledge", "staff-roles.md"), 60 | // "utf8" 61 | // ); 62 | // messages.unshift({ 63 | // role: "system", 64 | // content: staffDescriptions, 65 | // }); 66 | 67 | // Send messages array to copilot and collect the response 68 | const userToken = req.get("X-GitHub-Token"); 69 | const copilotResponse = await fetch("https://api.githubcopilot.com/chat/completions", { 70 | method: "POST", 71 | headers: { 72 | authorization: `Bearer ${userToken}`, 73 | "content-type": "application/json", 74 | }, 75 | body: JSON.stringify({ 76 | messages, 77 | stream: true, 78 | }), 79 | }); 80 | 81 | // Forward the response stream back to the user 82 | Readable.from(copilotResponse.body).pipe(res); 83 | }); 84 | 85 | // Start the extension web service and show the URL where the web service is running. 86 | const port = Number(process.env.PORT || "3000"); 87 | app.listen(port, () => { 88 | const codespaceName = process.env.CODESPACE_NAME; 89 | const url = codespaceName 90 | ? `https://${codespaceName}-${port}.app.github.dev` 91 | : `http://localhost:${port}`; 92 | console.log(`Copilot extension service running at: ${url}`); 93 | }); 94 | -------------------------------------------------------------------------------- /ghc-extension-js/info.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GitHub Copilot for Mergington High School 5 | 55 | 56 | 57 |
58 |

GitHub Copilot for Mergington High School

59 |
60 |
61 | Octodex Professor Octocat 66 |
67 |

Summary

68 |

69 | This Copilot extension is designed to support the staff of 70 | Mergington High School by providing automation services and tools to help staff 71 | work faster, finding more time to support our students. It includes an overview of the 72 | school and guidelines for developing simple software solutions tailored to our needs. 73 |

74 |

75 | The extension is designed to assist a wide range of staff roles including principals, 76 | teachers, counselors, and administrative support. If you are unsure what how to use it, 77 | just ask. It has already has some ideas for supporting each role to get started. 78 |

79 |
80 | 81 |
82 |

How do I use this?

83 |

Here are some example things you can ask (prompts) to help you get started:

84 |
85 |
86 | I'm a principal and spend a lot of time preparing summaries for the board meetings. Can 87 | you help with that? 88 |
89 |
90 | I am unsure how to use this AI tool thing. Can you really help me? Like, what can you do 91 | for me to make my job easier? 92 |
93 |
What job roles can you support? I'm an English teacher.
94 |
95 | Please make me a program that shows a summary of my students' grades over the years. 96 |
97 |
98 |
99 |
100 | 101 | 102 | -------------------------------------------------------------------------------- /ghc-extension-js/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "your-first-extension-for-github-copilot", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "your-first-extension-for-github-copilot", 8 | "dependencies": { 9 | "@octokit/core": "^6.1.2", 10 | "express": "^4.19.2" 11 | } 12 | }, 13 | "node_modules/@octokit/auth-token": { 14 | "version": "5.1.2", 15 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", 16 | "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", 17 | "license": "MIT", 18 | "engines": { 19 | "node": ">= 18" 20 | } 21 | }, 22 | "node_modules/@octokit/core": { 23 | "version": "6.1.4", 24 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz", 25 | "integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==", 26 | "license": "MIT", 27 | "dependencies": { 28 | "@octokit/auth-token": "^5.0.0", 29 | "@octokit/graphql": "^8.1.2", 30 | "@octokit/request": "^9.2.1", 31 | "@octokit/request-error": "^6.1.7", 32 | "@octokit/types": "^13.6.2", 33 | "before-after-hook": "^3.0.2", 34 | "universal-user-agent": "^7.0.0" 35 | }, 36 | "engines": { 37 | "node": ">= 18" 38 | } 39 | }, 40 | "node_modules/@octokit/endpoint": { 41 | "version": "10.1.3", 42 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz", 43 | "integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==", 44 | "license": "MIT", 45 | "dependencies": { 46 | "@octokit/types": "^13.6.2", 47 | "universal-user-agent": "^7.0.2" 48 | }, 49 | "engines": { 50 | "node": ">= 18" 51 | } 52 | }, 53 | "node_modules/@octokit/graphql": { 54 | "version": "8.2.1", 55 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz", 56 | "integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==", 57 | "license": "MIT", 58 | "dependencies": { 59 | "@octokit/request": "^9.2.2", 60 | "@octokit/types": "^13.8.0", 61 | "universal-user-agent": "^7.0.0" 62 | }, 63 | "engines": { 64 | "node": ">= 18" 65 | } 66 | }, 67 | "node_modules/@octokit/openapi-types": { 68 | "version": "23.0.1", 69 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", 70 | "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", 71 | "license": "MIT" 72 | }, 73 | "node_modules/@octokit/request": { 74 | "version": "9.2.2", 75 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz", 76 | "integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==", 77 | "license": "MIT", 78 | "dependencies": { 79 | "@octokit/endpoint": "^10.1.3", 80 | "@octokit/request-error": "^6.1.7", 81 | "@octokit/types": "^13.6.2", 82 | "fast-content-type-parse": "^2.0.0", 83 | "universal-user-agent": "^7.0.2" 84 | }, 85 | "engines": { 86 | "node": ">= 18" 87 | } 88 | }, 89 | "node_modules/@octokit/request-error": { 90 | "version": "6.1.7", 91 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz", 92 | "integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==", 93 | "license": "MIT", 94 | "dependencies": { 95 | "@octokit/types": "^13.6.2" 96 | }, 97 | "engines": { 98 | "node": ">= 18" 99 | } 100 | }, 101 | "node_modules/@octokit/types": { 102 | "version": "13.8.0", 103 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", 104 | "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", 105 | "license": "MIT", 106 | "dependencies": { 107 | "@octokit/openapi-types": "^23.0.1" 108 | } 109 | }, 110 | "node_modules/accepts": { 111 | "version": "1.3.8", 112 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 113 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 114 | "license": "MIT", 115 | "dependencies": { 116 | "mime-types": "~2.1.34", 117 | "negotiator": "0.6.3" 118 | }, 119 | "engines": { 120 | "node": ">= 0.6" 121 | } 122 | }, 123 | "node_modules/array-flatten": { 124 | "version": "1.1.1", 125 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 126 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", 127 | "license": "MIT" 128 | }, 129 | "node_modules/before-after-hook": { 130 | "version": "3.0.2", 131 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", 132 | "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", 133 | "license": "Apache-2.0" 134 | }, 135 | "node_modules/body-parser": { 136 | "version": "1.20.3", 137 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 138 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 139 | "license": "MIT", 140 | "dependencies": { 141 | "bytes": "3.1.2", 142 | "content-type": "~1.0.5", 143 | "debug": "2.6.9", 144 | "depd": "2.0.0", 145 | "destroy": "1.2.0", 146 | "http-errors": "2.0.0", 147 | "iconv-lite": "0.4.24", 148 | "on-finished": "2.4.1", 149 | "qs": "6.13.0", 150 | "raw-body": "2.5.2", 151 | "type-is": "~1.6.18", 152 | "unpipe": "1.0.0" 153 | }, 154 | "engines": { 155 | "node": ">= 0.8", 156 | "npm": "1.2.8000 || >= 1.4.16" 157 | } 158 | }, 159 | "node_modules/bytes": { 160 | "version": "3.1.2", 161 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 162 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 163 | "license": "MIT", 164 | "engines": { 165 | "node": ">= 0.8" 166 | } 167 | }, 168 | "node_modules/call-bind-apply-helpers": { 169 | "version": "1.0.2", 170 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", 171 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", 172 | "license": "MIT", 173 | "dependencies": { 174 | "es-errors": "^1.3.0", 175 | "function-bind": "^1.1.2" 176 | }, 177 | "engines": { 178 | "node": ">= 0.4" 179 | } 180 | }, 181 | "node_modules/call-bound": { 182 | "version": "1.0.3", 183 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", 184 | "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", 185 | "license": "MIT", 186 | "dependencies": { 187 | "call-bind-apply-helpers": "^1.0.1", 188 | "get-intrinsic": "^1.2.6" 189 | }, 190 | "engines": { 191 | "node": ">= 0.4" 192 | }, 193 | "funding": { 194 | "url": "https://github.com/sponsors/ljharb" 195 | } 196 | }, 197 | "node_modules/content-disposition": { 198 | "version": "0.5.4", 199 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 200 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 201 | "license": "MIT", 202 | "dependencies": { 203 | "safe-buffer": "5.2.1" 204 | }, 205 | "engines": { 206 | "node": ">= 0.6" 207 | } 208 | }, 209 | "node_modules/content-type": { 210 | "version": "1.0.5", 211 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 212 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 213 | "license": "MIT", 214 | "engines": { 215 | "node": ">= 0.6" 216 | } 217 | }, 218 | "node_modules/cookie": { 219 | "version": "0.7.1", 220 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", 221 | "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", 222 | "license": "MIT", 223 | "engines": { 224 | "node": ">= 0.6" 225 | } 226 | }, 227 | "node_modules/cookie-signature": { 228 | "version": "1.0.6", 229 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 230 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", 231 | "license": "MIT" 232 | }, 233 | "node_modules/debug": { 234 | "version": "2.6.9", 235 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 236 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 237 | "license": "MIT", 238 | "dependencies": { 239 | "ms": "2.0.0" 240 | } 241 | }, 242 | "node_modules/depd": { 243 | "version": "2.0.0", 244 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 245 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 246 | "license": "MIT", 247 | "engines": { 248 | "node": ">= 0.8" 249 | } 250 | }, 251 | "node_modules/destroy": { 252 | "version": "1.2.0", 253 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 254 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 255 | "license": "MIT", 256 | "engines": { 257 | "node": ">= 0.8", 258 | "npm": "1.2.8000 || >= 1.4.16" 259 | } 260 | }, 261 | "node_modules/dunder-proto": { 262 | "version": "1.0.1", 263 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 264 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 265 | "license": "MIT", 266 | "dependencies": { 267 | "call-bind-apply-helpers": "^1.0.1", 268 | "es-errors": "^1.3.0", 269 | "gopd": "^1.2.0" 270 | }, 271 | "engines": { 272 | "node": ">= 0.4" 273 | } 274 | }, 275 | "node_modules/ee-first": { 276 | "version": "1.1.1", 277 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 278 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 279 | "license": "MIT" 280 | }, 281 | "node_modules/encodeurl": { 282 | "version": "2.0.0", 283 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 284 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 285 | "license": "MIT", 286 | "engines": { 287 | "node": ">= 0.8" 288 | } 289 | }, 290 | "node_modules/es-define-property": { 291 | "version": "1.0.1", 292 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", 293 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", 294 | "license": "MIT", 295 | "engines": { 296 | "node": ">= 0.4" 297 | } 298 | }, 299 | "node_modules/es-errors": { 300 | "version": "1.3.0", 301 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 302 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 303 | "license": "MIT", 304 | "engines": { 305 | "node": ">= 0.4" 306 | } 307 | }, 308 | "node_modules/es-object-atoms": { 309 | "version": "1.1.1", 310 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", 311 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", 312 | "license": "MIT", 313 | "dependencies": { 314 | "es-errors": "^1.3.0" 315 | }, 316 | "engines": { 317 | "node": ">= 0.4" 318 | } 319 | }, 320 | "node_modules/escape-html": { 321 | "version": "1.0.3", 322 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 323 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 324 | "license": "MIT" 325 | }, 326 | "node_modules/etag": { 327 | "version": "1.8.1", 328 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 329 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 330 | "license": "MIT", 331 | "engines": { 332 | "node": ">= 0.6" 333 | } 334 | }, 335 | "node_modules/express": { 336 | "version": "4.21.2", 337 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", 338 | "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", 339 | "license": "MIT", 340 | "dependencies": { 341 | "accepts": "~1.3.8", 342 | "array-flatten": "1.1.1", 343 | "body-parser": "1.20.3", 344 | "content-disposition": "0.5.4", 345 | "content-type": "~1.0.4", 346 | "cookie": "0.7.1", 347 | "cookie-signature": "1.0.6", 348 | "debug": "2.6.9", 349 | "depd": "2.0.0", 350 | "encodeurl": "~2.0.0", 351 | "escape-html": "~1.0.3", 352 | "etag": "~1.8.1", 353 | "finalhandler": "1.3.1", 354 | "fresh": "0.5.2", 355 | "http-errors": "2.0.0", 356 | "merge-descriptors": "1.0.3", 357 | "methods": "~1.1.2", 358 | "on-finished": "2.4.1", 359 | "parseurl": "~1.3.3", 360 | "path-to-regexp": "0.1.12", 361 | "proxy-addr": "~2.0.7", 362 | "qs": "6.13.0", 363 | "range-parser": "~1.2.1", 364 | "safe-buffer": "5.2.1", 365 | "send": "0.19.0", 366 | "serve-static": "1.16.2", 367 | "setprototypeof": "1.2.0", 368 | "statuses": "2.0.1", 369 | "type-is": "~1.6.18", 370 | "utils-merge": "1.0.1", 371 | "vary": "~1.1.2" 372 | }, 373 | "engines": { 374 | "node": ">= 0.10.0" 375 | }, 376 | "funding": { 377 | "type": "opencollective", 378 | "url": "https://opencollective.com/express" 379 | } 380 | }, 381 | "node_modules/fast-content-type-parse": { 382 | "version": "2.0.1", 383 | "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", 384 | "integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==", 385 | "funding": [ 386 | { 387 | "type": "github", 388 | "url": "https://github.com/sponsors/fastify" 389 | }, 390 | { 391 | "type": "opencollective", 392 | "url": "https://opencollective.com/fastify" 393 | } 394 | ], 395 | "license": "MIT" 396 | }, 397 | "node_modules/finalhandler": { 398 | "version": "1.3.1", 399 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 400 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 401 | "license": "MIT", 402 | "dependencies": { 403 | "debug": "2.6.9", 404 | "encodeurl": "~2.0.0", 405 | "escape-html": "~1.0.3", 406 | "on-finished": "2.4.1", 407 | "parseurl": "~1.3.3", 408 | "statuses": "2.0.1", 409 | "unpipe": "~1.0.0" 410 | }, 411 | "engines": { 412 | "node": ">= 0.8" 413 | } 414 | }, 415 | "node_modules/forwarded": { 416 | "version": "0.2.0", 417 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 418 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 419 | "license": "MIT", 420 | "engines": { 421 | "node": ">= 0.6" 422 | } 423 | }, 424 | "node_modules/fresh": { 425 | "version": "0.5.2", 426 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 427 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 428 | "license": "MIT", 429 | "engines": { 430 | "node": ">= 0.6" 431 | } 432 | }, 433 | "node_modules/function-bind": { 434 | "version": "1.1.2", 435 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 436 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 437 | "license": "MIT", 438 | "funding": { 439 | "url": "https://github.com/sponsors/ljharb" 440 | } 441 | }, 442 | "node_modules/get-intrinsic": { 443 | "version": "1.2.7", 444 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", 445 | "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", 446 | "license": "MIT", 447 | "dependencies": { 448 | "call-bind-apply-helpers": "^1.0.1", 449 | "es-define-property": "^1.0.1", 450 | "es-errors": "^1.3.0", 451 | "es-object-atoms": "^1.0.0", 452 | "function-bind": "^1.1.2", 453 | "get-proto": "^1.0.0", 454 | "gopd": "^1.2.0", 455 | "has-symbols": "^1.1.0", 456 | "hasown": "^2.0.2", 457 | "math-intrinsics": "^1.1.0" 458 | }, 459 | "engines": { 460 | "node": ">= 0.4" 461 | }, 462 | "funding": { 463 | "url": "https://github.com/sponsors/ljharb" 464 | } 465 | }, 466 | "node_modules/get-proto": { 467 | "version": "1.0.1", 468 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", 469 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", 470 | "license": "MIT", 471 | "dependencies": { 472 | "dunder-proto": "^1.0.1", 473 | "es-object-atoms": "^1.0.0" 474 | }, 475 | "engines": { 476 | "node": ">= 0.4" 477 | } 478 | }, 479 | "node_modules/gopd": { 480 | "version": "1.2.0", 481 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", 482 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", 483 | "license": "MIT", 484 | "engines": { 485 | "node": ">= 0.4" 486 | }, 487 | "funding": { 488 | "url": "https://github.com/sponsors/ljharb" 489 | } 490 | }, 491 | "node_modules/has-symbols": { 492 | "version": "1.1.0", 493 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", 494 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", 495 | "license": "MIT", 496 | "engines": { 497 | "node": ">= 0.4" 498 | }, 499 | "funding": { 500 | "url": "https://github.com/sponsors/ljharb" 501 | } 502 | }, 503 | "node_modules/hasown": { 504 | "version": "2.0.2", 505 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 506 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 507 | "license": "MIT", 508 | "dependencies": { 509 | "function-bind": "^1.1.2" 510 | }, 511 | "engines": { 512 | "node": ">= 0.4" 513 | } 514 | }, 515 | "node_modules/http-errors": { 516 | "version": "2.0.0", 517 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 518 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 519 | "license": "MIT", 520 | "dependencies": { 521 | "depd": "2.0.0", 522 | "inherits": "2.0.4", 523 | "setprototypeof": "1.2.0", 524 | "statuses": "2.0.1", 525 | "toidentifier": "1.0.1" 526 | }, 527 | "engines": { 528 | "node": ">= 0.8" 529 | } 530 | }, 531 | "node_modules/iconv-lite": { 532 | "version": "0.4.24", 533 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 534 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 535 | "license": "MIT", 536 | "dependencies": { 537 | "safer-buffer": ">= 2.1.2 < 3" 538 | }, 539 | "engines": { 540 | "node": ">=0.10.0" 541 | } 542 | }, 543 | "node_modules/inherits": { 544 | "version": "2.0.4", 545 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 546 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 547 | "license": "ISC" 548 | }, 549 | "node_modules/ipaddr.js": { 550 | "version": "1.9.1", 551 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 552 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 553 | "license": "MIT", 554 | "engines": { 555 | "node": ">= 0.10" 556 | } 557 | }, 558 | "node_modules/math-intrinsics": { 559 | "version": "1.1.0", 560 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", 561 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", 562 | "license": "MIT", 563 | "engines": { 564 | "node": ">= 0.4" 565 | } 566 | }, 567 | "node_modules/media-typer": { 568 | "version": "0.3.0", 569 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 570 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 571 | "license": "MIT", 572 | "engines": { 573 | "node": ">= 0.6" 574 | } 575 | }, 576 | "node_modules/merge-descriptors": { 577 | "version": "1.0.3", 578 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 579 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", 580 | "license": "MIT", 581 | "funding": { 582 | "url": "https://github.com/sponsors/sindresorhus" 583 | } 584 | }, 585 | "node_modules/methods": { 586 | "version": "1.1.2", 587 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 588 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 589 | "license": "MIT", 590 | "engines": { 591 | "node": ">= 0.6" 592 | } 593 | }, 594 | "node_modules/mime": { 595 | "version": "1.6.0", 596 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 597 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 598 | "license": "MIT", 599 | "bin": { 600 | "mime": "cli.js" 601 | }, 602 | "engines": { 603 | "node": ">=4" 604 | } 605 | }, 606 | "node_modules/mime-db": { 607 | "version": "1.52.0", 608 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 609 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 610 | "license": "MIT", 611 | "engines": { 612 | "node": ">= 0.6" 613 | } 614 | }, 615 | "node_modules/mime-types": { 616 | "version": "2.1.35", 617 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 618 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 619 | "license": "MIT", 620 | "dependencies": { 621 | "mime-db": "1.52.0" 622 | }, 623 | "engines": { 624 | "node": ">= 0.6" 625 | } 626 | }, 627 | "node_modules/ms": { 628 | "version": "2.0.0", 629 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 630 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 631 | "license": "MIT" 632 | }, 633 | "node_modules/negotiator": { 634 | "version": "0.6.3", 635 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 636 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 637 | "license": "MIT", 638 | "engines": { 639 | "node": ">= 0.6" 640 | } 641 | }, 642 | "node_modules/object-inspect": { 643 | "version": "1.13.4", 644 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", 645 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", 646 | "license": "MIT", 647 | "engines": { 648 | "node": ">= 0.4" 649 | }, 650 | "funding": { 651 | "url": "https://github.com/sponsors/ljharb" 652 | } 653 | }, 654 | "node_modules/on-finished": { 655 | "version": "2.4.1", 656 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 657 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 658 | "license": "MIT", 659 | "dependencies": { 660 | "ee-first": "1.1.1" 661 | }, 662 | "engines": { 663 | "node": ">= 0.8" 664 | } 665 | }, 666 | "node_modules/parseurl": { 667 | "version": "1.3.3", 668 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 669 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 670 | "license": "MIT", 671 | "engines": { 672 | "node": ">= 0.8" 673 | } 674 | }, 675 | "node_modules/path-to-regexp": { 676 | "version": "0.1.12", 677 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", 678 | "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", 679 | "license": "MIT" 680 | }, 681 | "node_modules/proxy-addr": { 682 | "version": "2.0.7", 683 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 684 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 685 | "license": "MIT", 686 | "dependencies": { 687 | "forwarded": "0.2.0", 688 | "ipaddr.js": "1.9.1" 689 | }, 690 | "engines": { 691 | "node": ">= 0.10" 692 | } 693 | }, 694 | "node_modules/qs": { 695 | "version": "6.13.0", 696 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 697 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 698 | "license": "BSD-3-Clause", 699 | "dependencies": { 700 | "side-channel": "^1.0.6" 701 | }, 702 | "engines": { 703 | "node": ">=0.6" 704 | }, 705 | "funding": { 706 | "url": "https://github.com/sponsors/ljharb" 707 | } 708 | }, 709 | "node_modules/range-parser": { 710 | "version": "1.2.1", 711 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 712 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 713 | "license": "MIT", 714 | "engines": { 715 | "node": ">= 0.6" 716 | } 717 | }, 718 | "node_modules/raw-body": { 719 | "version": "2.5.2", 720 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 721 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 722 | "license": "MIT", 723 | "dependencies": { 724 | "bytes": "3.1.2", 725 | "http-errors": "2.0.0", 726 | "iconv-lite": "0.4.24", 727 | "unpipe": "1.0.0" 728 | }, 729 | "engines": { 730 | "node": ">= 0.8" 731 | } 732 | }, 733 | "node_modules/safe-buffer": { 734 | "version": "5.2.1", 735 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 736 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 737 | "funding": [ 738 | { 739 | "type": "github", 740 | "url": "https://github.com/sponsors/feross" 741 | }, 742 | { 743 | "type": "patreon", 744 | "url": "https://www.patreon.com/feross" 745 | }, 746 | { 747 | "type": "consulting", 748 | "url": "https://feross.org/support" 749 | } 750 | ], 751 | "license": "MIT" 752 | }, 753 | "node_modules/safer-buffer": { 754 | "version": "2.1.2", 755 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 756 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 757 | "license": "MIT" 758 | }, 759 | "node_modules/send": { 760 | "version": "0.19.0", 761 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 762 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 763 | "license": "MIT", 764 | "dependencies": { 765 | "debug": "2.6.9", 766 | "depd": "2.0.0", 767 | "destroy": "1.2.0", 768 | "encodeurl": "~1.0.2", 769 | "escape-html": "~1.0.3", 770 | "etag": "~1.8.1", 771 | "fresh": "0.5.2", 772 | "http-errors": "2.0.0", 773 | "mime": "1.6.0", 774 | "ms": "2.1.3", 775 | "on-finished": "2.4.1", 776 | "range-parser": "~1.2.1", 777 | "statuses": "2.0.1" 778 | }, 779 | "engines": { 780 | "node": ">= 0.8.0" 781 | } 782 | }, 783 | "node_modules/send/node_modules/encodeurl": { 784 | "version": "1.0.2", 785 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 786 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 787 | "license": "MIT", 788 | "engines": { 789 | "node": ">= 0.8" 790 | } 791 | }, 792 | "node_modules/send/node_modules/ms": { 793 | "version": "2.1.3", 794 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 795 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 796 | "license": "MIT" 797 | }, 798 | "node_modules/serve-static": { 799 | "version": "1.16.2", 800 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 801 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 802 | "license": "MIT", 803 | "dependencies": { 804 | "encodeurl": "~2.0.0", 805 | "escape-html": "~1.0.3", 806 | "parseurl": "~1.3.3", 807 | "send": "0.19.0" 808 | }, 809 | "engines": { 810 | "node": ">= 0.8.0" 811 | } 812 | }, 813 | "node_modules/setprototypeof": { 814 | "version": "1.2.0", 815 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 816 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 817 | "license": "ISC" 818 | }, 819 | "node_modules/side-channel": { 820 | "version": "1.1.0", 821 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", 822 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", 823 | "license": "MIT", 824 | "dependencies": { 825 | "es-errors": "^1.3.0", 826 | "object-inspect": "^1.13.3", 827 | "side-channel-list": "^1.0.0", 828 | "side-channel-map": "^1.0.1", 829 | "side-channel-weakmap": "^1.0.2" 830 | }, 831 | "engines": { 832 | "node": ">= 0.4" 833 | }, 834 | "funding": { 835 | "url": "https://github.com/sponsors/ljharb" 836 | } 837 | }, 838 | "node_modules/side-channel-list": { 839 | "version": "1.0.0", 840 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", 841 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", 842 | "license": "MIT", 843 | "dependencies": { 844 | "es-errors": "^1.3.0", 845 | "object-inspect": "^1.13.3" 846 | }, 847 | "engines": { 848 | "node": ">= 0.4" 849 | }, 850 | "funding": { 851 | "url": "https://github.com/sponsors/ljharb" 852 | } 853 | }, 854 | "node_modules/side-channel-map": { 855 | "version": "1.0.1", 856 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", 857 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", 858 | "license": "MIT", 859 | "dependencies": { 860 | "call-bound": "^1.0.2", 861 | "es-errors": "^1.3.0", 862 | "get-intrinsic": "^1.2.5", 863 | "object-inspect": "^1.13.3" 864 | }, 865 | "engines": { 866 | "node": ">= 0.4" 867 | }, 868 | "funding": { 869 | "url": "https://github.com/sponsors/ljharb" 870 | } 871 | }, 872 | "node_modules/side-channel-weakmap": { 873 | "version": "1.0.2", 874 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", 875 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", 876 | "license": "MIT", 877 | "dependencies": { 878 | "call-bound": "^1.0.2", 879 | "es-errors": "^1.3.0", 880 | "get-intrinsic": "^1.2.5", 881 | "object-inspect": "^1.13.3", 882 | "side-channel-map": "^1.0.1" 883 | }, 884 | "engines": { 885 | "node": ">= 0.4" 886 | }, 887 | "funding": { 888 | "url": "https://github.com/sponsors/ljharb" 889 | } 890 | }, 891 | "node_modules/statuses": { 892 | "version": "2.0.1", 893 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 894 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 895 | "license": "MIT", 896 | "engines": { 897 | "node": ">= 0.8" 898 | } 899 | }, 900 | "node_modules/toidentifier": { 901 | "version": "1.0.1", 902 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 903 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 904 | "license": "MIT", 905 | "engines": { 906 | "node": ">=0.6" 907 | } 908 | }, 909 | "node_modules/type-is": { 910 | "version": "1.6.18", 911 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 912 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 913 | "license": "MIT", 914 | "dependencies": { 915 | "media-typer": "0.3.0", 916 | "mime-types": "~2.1.24" 917 | }, 918 | "engines": { 919 | "node": ">= 0.6" 920 | } 921 | }, 922 | "node_modules/universal-user-agent": { 923 | "version": "7.0.2", 924 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", 925 | "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==", 926 | "license": "ISC" 927 | }, 928 | "node_modules/unpipe": { 929 | "version": "1.0.0", 930 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 931 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 932 | "license": "MIT", 933 | "engines": { 934 | "node": ">= 0.8" 935 | } 936 | }, 937 | "node_modules/utils-merge": { 938 | "version": "1.0.1", 939 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 940 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 941 | "license": "MIT", 942 | "engines": { 943 | "node": ">= 0.4.0" 944 | } 945 | }, 946 | "node_modules/vary": { 947 | "version": "1.1.2", 948 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 949 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 950 | "license": "MIT", 951 | "engines": { 952 | "node": ">= 0.8" 953 | } 954 | } 955 | } 956 | } 957 | -------------------------------------------------------------------------------- /ghc-extension-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "your-first-extension-for-github-copilot", 3 | "private": "true", 4 | "description": "A basic example of customizing GitHub Copilot to your needs", 5 | "scripts": { 6 | "start": "node index.js", 7 | "dev": "node --watch index.js" 8 | }, 9 | "type": "module", 10 | "dependencies": { 11 | "@octokit/core": "^6.1.2", 12 | "express": "^4.19.2" 13 | } 14 | } 15 | --------------------------------------------------------------------------------