Repository: grafana/shared-workflows
Pull request #927: feat(dependabot-auto-triage): add dependabot-auto-triage workflow
Author: login: guicaulada
Created: 2025-04-25T20:41:50Z | Merged: 2025-05-08T14:49:04Z

This workflow can be used to automatically dismiss Dependabot security alerts based on manifest path.

This is our version of [Auto-triage rules](https://docs.github.com/en/code-security/dependabot/dependabot-auto-triage-rules/about-dependabot-auto-triage-rules), since those alerts aren't controlled by `dependabot.yml`.

Release-As: 0.1.0


Diff:
diff --git a/actions/dependabot-auto-triage/.bun-version b/actions/dependabot-auto-triage/.bun-version
new file mode 100644
index 000000000..db6fb4a91
--- /dev/null
+++ b/actions/dependabot-auto-triage/.bun-version
@@ -0,0 +1 @@
+1.2.8
diff --git a/actions/dependabot-auto-triage/.gitignore b/actions/dependabot-auto-triage/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/actions/dependabot-auto-triage/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/actions/dependabot-auto-triage/README.md b/actions/dependabot-auto-triage/README.md
new file mode 100644
index 000000000..a9bb47147
--- /dev/null
+++ b/actions/dependabot-auto-triage/README.md
@@ -0,0 +1,115 @@
+# Auto Dismiss Dependabot Alerts
+
+A GitHub composite action to automatically dismiss Dependabot alerts based on manifest paths using glob patterns.
+
+## Usage
+
+This action can be used in a workflow to automatically dismiss Dependabot alerts for specific manifest paths. This is particularly useful for repositories with dependencies that are not directly used in production or for which vulnerabilities may not be relevant.
+
+### Example Workflow
+
+Create a workflow file (e.g., `.github/workflows/auto-dismiss-dependabot-alerts.yml`) with the following content:
+
+<!-- x-release-please-start-version -->
+
+```yaml
+name: Auto Dismiss Dependabot Alerts
+
+on:
+  # Run daily to dismiss new alerts
+  schedule:
+    - cron: "0 0 * * *"
+
+  # Allow manual triggering
+  workflow_dispatch:
+
+jobs:
+  auto-dismiss:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      contents: read
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      # Get GitHub App token with Dependabot alerts permissions
+      - name: Retrieve GitHub App secrets
+        id: get-secrets
+        uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.1.0
+        with:
+          common_secrets: |
+            DEPENDABOT_AUTO_TRIAGE_APP_ID=dependabot-auto-triage:app-id
+            DEPENDABOT_AUTO_TRIAGE_APP_PRIVATE_KEY=dependabot-auto-triage:private-key
+
+      - name: Generate token
+        id: generate-token
+        uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2
+        with:
+          app-id: ${{ env.DEPENDABOT_AUTO_TRIAGE_APP_ID }}
+          private-key: ${{ env.DEPENDABOT_AUTO_TRIAGE_APP_PRIVATE_KEY }}
+
+      # Use the token with the auto-triage action
+      - name: Auto Dismiss Dependabot Alerts
+        uses: grafana/shared-workflows/actions/dependabot-auto-triage@dependabot-auto-triage-v0.1.0
+        with:
+          token: ${{ steps.generate-token.outputs.token }}
+          paths: |
+            terraform/modules/**/*.json
+            docker/vendor/**
+            ksonnet/lib/argo-workflows/charts/**/*.json
+          dismissal-reason: "not_used"
+          dismissal-comment: "These dependencies are not used in production and pose no risk"
+```
+
+<!-- x-release-please-end-version -->
+
+### Inputs
+
+| Name                | Description                                                                                                       | Required | Default                                               |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------- |
+| `token`             | GitHub token with permissions to dismiss alerts                                                                   | Yes      | N/A                                                   |
+| `alert-types`       | Comma-separated list of alert types to dismiss                                                                    | No       | `dependency`                                          |
+| `paths`             | Multi-line list of glob patterns to match manifest paths to dismiss                                               | Yes      | N/A                                                   |
+| `dismissal-comment` | Default comment to add when dismissing alerts                                                                     | No       | `Auto-dismissed based on manifest path configuration` |
+| `dismissal-reason`  | Default reason for dismissal (options: `fix_started`, `inaccurate`, `no_bandwidth`, `not_used`, `tolerable_risk`) | No       | `not_used`                                            |
+
+### How It Works
+
+1. The action fetches all open Dependabot alerts for the repository
+2. For each alert, it checks if the manifest path matches any of the provided glob patterns
+3. If the path matches a pattern, it dismisses the alert with the specified reason and comment
+
+### Glob Pattern Syntax
+
+The action uses [minimatch](https://github.com/isaacs/minimatch) for glob pattern matching. Some common patterns:
+
+- `**/*.json` - Match all JSON files in any directory
+- `terraform/modules/**` - Match all files in terraform/modules and subdirectories
+- `docker/vendor/**/package-lock.json` - Match all package-lock.json files in docker/vendor and subdirectories
+- `ksonnet/lib/*/charts/**` - Match all files in any charts subdirectory under ksonnet/lib/\*/
+
+### Permissions
+
+Due to API limitations, accessing and dismissing Dependabot alerts requires a GitHub App token with specific permissions. The standard `GITHUB_TOKEN` does not have sufficient access to the Dependabot API, even when `security-events: write` permissions are specified.
+
+#### GitHub App Requirements
+
+To use this action, you need:
+
+1. A GitHub App with the following permissions:
+
+   - Repository permissions:
+     - **Dependabot alerts**: Read & Write
+
+2. The GitHub App needs to be installed on your repository or organization
+
+3. The App ID and private key should be stored securely (e.g., in Vault)
+
+The example workflow above demonstrates using the `actions/create-github-app-token` action to generate a token with the required permissions.
+
+If you're experiencing "Resource not accessible by integration" errors, this indicates that the token being used doesn't have the necessary permissions to access the Dependabot API.
+
+## License
+
+This action is licensed under the same license as the parent repository.
diff --git a/actions/dependabot-auto-triage/action.yml b/actions/dependabot-auto-triage/action.yml
new file mode 100644
index 000000000..e559e5f6c
--- /dev/null
+++ b/actions/dependabot-auto-triage/action.yml
@@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
+description: "Auto dismiss Dependabot alerts based on manifest path"
+inputs:
+  token:
+    description: "GitHub token with permissions to dismiss alerts"
+    required: true
+  alert-types:
+    description: 'Comma-separated list of alert types to dismiss (default: "dependency")'
+    required: false
+    default: "dependency"
+  paths:
+    description: "Multi-line list of glob patterns to match manifest paths to dismiss"
+    required: true
+    # Example: |
+    #   terraform/modules/**/*.json
+    #   docker/vendor/**
+  dismissal-comment:
+    description: "Default comment to add when dismissing alerts"
+    required: false
+    default: "Auto-dismissed based on manifest path configuration"
+  dismissal-reason:
+    description: "Default reason for dismissal"
+    required: false
+    default: "not_used"
+    # Options: 'fix_started', 'inaccurate', 'no_bandwidth', 'not_used', 'tolerable_risk'
+
+runs:
+  using: "composite"
+  steps:
+    - name: Install bun package manager
+      uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
+      with:
+        bun-version-file: ${{ github.action_path }}/.bun-version
+
+    - name: Install dependencies
+      shell: bash
+      working-directory: ${{ github.action_path }}
+      run: |
+        bun install --frozen-lockfile --production
+
+    - name: Auto dismiss Dependabot alerts
+      shell: bash
+      working-directory: ${{ github.action_path }}
+      env:
+        GITHUB_TOKEN: ${{ inputs.token }}
+        INPUT_ALERT_TYPES: ${{ inputs.alert-types }}
+        INPUT_PATHS: ${{ inputs.paths }}
+        INPUT_DISMISSAL_COMMENT: ${{ inputs.dismissal-comment }}
+        INPUT_DISMISSAL_REASON: ${{ inputs.dismissal-reason }}
+        NODE_ENV: "production"
+      run: |
+        bun run src/index.ts
diff --git a/actions/dependabot-auto-triage/bun.lock b/actions/dependabot-auto-triage/bun.lock
new file mode 100644
index 000000000..11b9f0476
--- /dev/null
+++ b/actions/dependabot-auto-triage/bun.lock
@@ -0,0 +1,507 @@
+{
+  "lockfileVersion": 1,
+  "workspaces": {
+    "": {
+      "name": "auto-dismiss-dependabot-alerts",
+      "dependencies": {
+        "@octokit/request-error": "^5.0.1",
+        "@octokit/rest": "^19.0.8",
+        "minimatch": "^9.0.3",
+      },
+      "devDependencies": {
+        "@eslint/js": "^9.26.0",
+        "@types/bun": "^1.2.12",
+        "eslint-config-prettier": "^10.1.3",
+        "eslint-plugin-jest": "^28.11.0",
+        "eslint-plugin-prettier": "^5.4.0",
+        "typescript": "^5.8.3",
+        "typescript-eslint": "^8.32.0",
+      },
+    },
+  },
+  "packages": {
+    "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
+
+    "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
+
+    "@eslint/config-array": ["@eslint/config-array@0.20.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ=="],
+
+    "@eslint/config-helpers": ["@eslint/config-helpers@0.2.2", "", {}, "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg=="],
+
+    "@eslint/core": ["@eslint/core@0.13.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw=="],
+
+    "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
+
+    "@eslint/js": ["@eslint/js@9.26.0", "", {}, "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ=="],
+
+    "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
+
+    "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.8", "", { "dependencies": { "@eslint/core": "^0.13.0", "levn": "^0.4.1" } }, "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA=="],
+
+    "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
+
+    "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
+
+    "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
+
+    "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
+
+    "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.11.0", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.3", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ=="],
+
+    "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
+
+    "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
+
+    "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
+
+    "@octokit/auth-token": ["@octokit/auth-token@3.0.4", "", {}, "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ=="],
+
+    "@octokit/core": ["@octokit/core@4.2.4", "", { "dependencies": { "@octokit/auth-token": "^3.0.0", "@octokit/graphql": "^5.0.0", "@octokit/request": "^6.0.0", "@octokit/request-error": "^3.0.0", "@octokit/types": "^9.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ=="],
+
+    "@octokit/endpoint": ["@octokit/endpoint@7.0.6", "", { "dependencies": { "@octokit/types": "^9.0.0", "is-plain-object": "^5.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg=="],
+
+    "@octokit/graphql": ["@octokit/graphql@5.0.6", "", { "dependencies": { "@octokit/request": "^6.0.0", "@octokit/types": "^9.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw=="],
+
+    "@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
+
+    "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@6.1.2", "", { "dependencies": { "@octokit/tsconfig": "^1.0.2", "@octokit/types": "^9.2.3" }, "peerDependencies": { "@octokit/core": ">=4" } }, "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ=="],
+
+    "@octokit/plugin-request-log": ["@octokit/plugin-request-log@1.0.4", "", { "peerDependencies": { "@octokit/core": ">=3" } }, "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA=="],
+
+    "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@7.2.3", "", { "dependencies": { "@octokit/types": "^10.0.0" }, "peerDependencies": { "@octokit/core": ">=3" } }, "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA=="],
+
+    "@octokit/request": ["@octokit/request@6.2.8", "", { "dependencies": { "@octokit/endpoint": "^7.0.0", "@octokit/request-error": "^3.0.0", "@octokit/types": "^9.0.0", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.7", "universal-user-agent": "^6.0.0" } }, "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw=="],
+
+    "@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="],
+
+    "@octokit/rest": ["@octokit/rest@19.0.13", "", { "dependencies": { "@octokit/core": "^4.2.1", "@octokit/plugin-paginate-rest": "^6.1.2", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-rest-endpoint-methods": "^7.1.2" } }, "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA=="],
+
+    "@octokit/tsconfig": ["@octokit/tsconfig@1.0.2", "", {}, "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA=="],
+
+    "@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
+
+    "@pkgr/core": ["@pkgr/core@0.2.4", "", {}, "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw=="],
+
+    "@types/bun": ["@types/bun@1.2.12", "", { "dependencies": { "bun-types": "1.2.12" } }, "sha512-lY/GQTXDGsolT/TiH72p1tuyUORuRrdV7VwOTOjDOt8uTBJQOJc5zz3ufwwDl0VBaoxotSk4LdP0hhjLJ6ypIQ=="],
+
+    "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
+
+    "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
+
+    "@types/node": ["@types/node@22.15.14", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-BL1eyu/XWsFGTtDWOYULQEs4KR0qdtYfCxYAUYRoB7JP7h9ETYLgQTww6kH8Sj2C0pFGgrpM0XKv6/kbIzYJ1g=="],
+
+    "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.32.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/type-utils": "8.32.0", "@typescript-eslint/utils": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ=="],
+
+    "@typescript-eslint/parser": ["@typescript-eslint/parser@8.32.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A=="],
+
+    "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0" } }, "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ=="],
+
+    "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.32.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.32.0", "@typescript-eslint/utils": "8.32.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg=="],
+
+    "@typescript-eslint/types": ["@typescript-eslint/types@8.32.0", "", {}, "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA=="],
+
+    "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ=="],
+
+    "@typescript-eslint/utils": ["@typescript-eslint/utils@8.32.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw=="],
+
+    "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w=="],
+
+    "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
+
+    "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
+
+    "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
+
+    "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
+
+    "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+
+    "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
+
+    "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
+
+    "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
+
+    "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
+
+    "brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+
+    "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
+
+    "bun-types": ["bun-types@1.2.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-tvWMx5vPqbRXgE8WUZI94iS1xAYs8bkqESR9cxBB1Wi+urvfTrF1uzuDgBHFAdO0+d2lmsbG3HmeKMvUyj6pWA=="],
+
+    "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
+
+    "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
+
+    "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
+
+    "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
+
+    "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+
+    "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
+
+    "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
+
+    "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
+
+    "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
+
+    "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
+
+    "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
+
+    "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
+
+    "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
+
+    "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
+
+    "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+    "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
+
+    "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
+
+    "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="],
+
+    "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
+
+    "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
+
+    "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
+
+    "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
+
+    "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
+
+    "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
+
+    "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
+
+    "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
+
+    "eslint": ["eslint@9.26.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.13.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.26.0", "@eslint/plugin-kit": "^0.2.8", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@modelcontextprotocol/sdk": "^1.8.0", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "zod": "^3.24.2" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ=="],
+
+    "eslint-config-prettier": ["eslint-config-prettier@10.1.3", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-vDo4d9yQE+cS2tdIT4J02H/16veRvkHgiLDRpej+WL67oCfbOb97itZXn8wMPJ/GsiEBVjrjs//AVNw2Cp1EcA=="],
+
+    "eslint-plugin-jest": ["eslint-plugin-jest@28.11.0", "", { "dependencies": { "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", "jest": "*" }, "optionalPeers": ["@typescript-eslint/eslint-plugin", "jest"] }, "sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig=="],
+
+    "eslint-plugin-prettier": ["eslint-plugin-prettier@5.4.0", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.0" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA=="],
+
+    "eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="],
+
+    "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
+
+    "espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="],
+
+    "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
+
+    "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
+
+    "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
+
+    "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
+
+    "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
+
+    "eventsource": ["eventsource@3.0.6", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA=="],
+
+    "eventsource-parser": ["eventsource-parser@3.0.1", "", {}, "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA=="],
+
+    "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
+
+    "express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="],
+
+    "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
+
+    "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
+
+    "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
+
+    "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
+
+    "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
+
+    "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
+
+    "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
+
+    "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
+
+    "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
+
+    "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
+
+    "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
+
+    "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
+
+    "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
+
+    "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
+
+    "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
+
+    "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
+
+    "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
+
+    "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
+
+    "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
+
+    "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
+
+    "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
+
+    "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
+
+    "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
+
+    "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
+
+    "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
+
+    "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
+
+    "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
+
+    "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
+
+    "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
+
+    "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
+
+    "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
+
+    "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
+
+    "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
+
+    "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
+
+    "is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="],
+
+    "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
+
+    "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
+
+    "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
+
+    "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
+
+    "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
+
+    "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
+
+    "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
+
+    "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
+
+    "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
+
+    "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
+
+    "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
+
+    "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
+
+    "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
+
+    "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
+
+    "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
+
+    "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+
+    "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
+
+    "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+    "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+    "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
+
+    "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
+
+    "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
+
+    "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
+
+    "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
+
+    "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
+
+    "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
+
+    "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
+
+    "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
+
+    "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
+
+    "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
+
+    "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
+
+    "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
+
+    "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
+
+    "path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
+
+    "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+
+    "pkce-challenge": ["pkce-challenge@5.0.0", "", {}, "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="],
+
+    "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
+
+    "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
+
+    "prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
+
+    "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
+
+    "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
+
+    "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
+
+    "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
+
+    "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
+
+    "raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
+
+    "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
+
+    "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
+
+    "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
+
+    "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
+
+    "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
+
+    "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
+
+    "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
+
+    "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
+
+    "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
+
+    "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
+
+    "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
+
+    "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
+
+    "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
+
+    "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
+
+    "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
+
+    "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
+
+    "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
+
+    "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
+
+    "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+
+    "synckit": ["synckit@0.11.4", "", { "dependencies": { "@pkgr/core": "^0.2.3", "tslib": "^2.8.1" } }, "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ=="],
+
+    "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
+
+    "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
+
+    "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
+
+    "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
+
+    "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+    "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
+
+    "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
+
+    "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
+
+    "typescript-eslint": ["typescript-eslint@8.32.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.32.0", "@typescript-eslint/parser": "8.32.0", "@typescript-eslint/utils": "8.32.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A=="],
+
+    "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
+
+    "universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
+
+    "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
+
+    "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
+
+    "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
+
+    "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
+
+    "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
+
+    "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
+
+    "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
+
+    "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
+
+    "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
+
+    "zod": ["zod@3.24.4", "", {}, "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg=="],
+
+    "zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
+
+    "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
+
+    "@eslint/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
+    "@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
+    "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
+
+    "@octokit/core/@octokit/request-error": ["@octokit/request-error@3.0.3", "", { "dependencies": { "@octokit/types": "^9.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ=="],
+
+    "@octokit/core/@octokit/types": ["@octokit/types@9.3.2", "", { "dependencies": { "@octokit/openapi-types": "^18.0.0" } }, "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA=="],
+
+    "@octokit/endpoint/@octokit/types": ["@octokit/types@9.3.2", "", { "dependencies": { "@octokit/openapi-types": "^18.0.0" } }, "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA=="],
+
+    "@octokit/graphql/@octokit/types": ["@octokit/types@9.3.2", "", { "dependencies": { "@octokit/openapi-types": "^18.0.0" } }, "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@9.3.2", "", { "dependencies": { "@octokit/openapi-types": "^18.0.0" } }, "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@10.0.0", "", { "dependencies": { "@octokit/openapi-types": "^18.0.0" } }, "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg=="],
+
+    "@octokit/request/@octokit/request-error": ["@octokit/request-error@3.0.3", "", { "dependencies": { "@octokit/types": "^9.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ=="],
+
+    "@octokit/request/@octokit/types": ["@octokit/types@9.3.2", "", { "dependencies": { "@octokit/openapi-types": "^18.0.0" } }, "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA=="],
+
+    "eslint/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
+    "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
+
+    "@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
+
+    "@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
+
+    "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@18.1.1", "", {}, "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="],
+
+    "@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@18.1.1", "", {}, "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="],
+
+    "@octokit/graphql/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@18.1.1", "", {}, "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="],
+
+    "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@18.1.1", "", {}, "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="],
+
+    "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@18.1.1", "", {}, "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="],
+
+    "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@18.1.1", "", {}, "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="],
+
+    "eslint/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
+  }
+}
diff --git a/actions/dependabot-auto-triage/eslint.config.mjs b/actions/dependabot-auto-triage/eslint.config.mjs
new file mode 100644
index 000000000..a9ab0bac7
--- /dev/null
+++ b/actions/dependabot-auto-triage/eslint.config.mjs
@@ -0,0 +1,40 @@
+import eslint from "@eslint/js";
+import eslintPluginJest from "eslint-plugin-jest";
+import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
+import js from "@eslint/js";
+import tseslint from "typescript-eslint";
+
+export default tseslint.config(
+  js.configs.recommended,
+  eslint.configs.recommended,
+  ...tseslint.configs.strictTypeChecked,
+  eslintPluginPrettierRecommended,
+  {
+    // Allow unused vars if they start with an underscore
+    rules: {
+      "@typescript-eslint/no-unused-vars": [
+        "error",
+        {
+          varsIgnorePattern: "^_",
+          argsIgnorePattern: "^_",
+        },
+      ],
+    },
+    languageOptions: {
+      parserOptions: {
+        projectService: true,
+      },
+    },
+  },
+  {
+    files: ["**/*.js", "**/*.mjs"],
+    ...tseslint.configs.disableTypeChecked,
+  },
+  {
+    files: ["test/**/*.ts"],
+    ...eslintPluginJest.configs["flat/recommended"],
+  },
+  {
+    ignores: ["coverage/", "dist/", "node_modules/"],
+  },
+);
diff --git a/actions/dependabot-auto-triage/package.json b/actions/dependabot-auto-triage/package.json
new file mode 100644
index 000000000..f407a8d53
--- /dev/null
+++ b/actions/dependabot-auto-triage/package.json
@@ -0,0 +1,30 @@
+{
+  "name": "auto-dismiss-dependabot-alerts",
+  "version": "0.1.0",
+  "description": "GitHub action to auto-dismiss Dependabot alerts based on manifest path patterns",
+  "main": "src/index.ts",
+  "type": "module",
+  "private": true,
+  "scripts": {
+    "typecheck": "tsc --noEmit",
+    "lint": "eslint .",
+    "test": "bun test"
+  },
+  "dependencies": {
+    "@octokit/request-error": "^5.0.1",
+    "@octokit/rest": "^19.0.8",
+    "minimatch": "^9.0.3"
+  },
+  "devDependencies": {
+    "@eslint/js": "^9.26.0",
+    "@types/bun": "^1.2.12",
+    "eslint-config-prettier": "^10.1.3",
+    "eslint-plugin-jest": "^28.11.0",
+    "eslint-plugin-prettier": "^5.4.0",
+    "typescript": "^5.8.3",
+    "typescript-eslint": "^8.32.0"
+  },
+  "engines": {
+    "bun": "^1.0.0"
+  }
+}
diff --git a/actions/dependabot-auto-triage/src/index.test.ts b/actions/dependabot-auto-triage/src/index.test.ts
new file mode 100644
index 000000000..bfabf2c0d
--- /dev/null
+++ b/actions/dependabot-auto-triage/src/index.test.ts
@@ -0,0 +1,544 @@
+import {
+  afterEach,
+  beforeEach,
+  describe,
+  expect,
+  it,
+  mock,
+  spyOn,
+} from "bun:test";
+import {
+  matchesAnyPattern,
+  fetchAllAlerts,
+  run,
+  DependabotAlert,
+} from "./index";
+import { Octokit } from "@octokit/rest";
+import { RequestError } from "@octokit/request-error";
+import * as minimatchModule from "minimatch"; // Import for spying
+
+// Mock Octokit globally for all tests in this file
+const mockOctokit = {
+  request: mock(),
+  paginate: mock(),
+};
+mock.module("@octokit/rest", () => ({
+  Octokit: mock(() => mockOctokit),
+}));
+
+describe("Dependabot Auto Triage Action", () => {
+  let consoleLogSpy: any;
+  let consoleErrorSpy: any;
+  let processExitSpy: any;
+
+  beforeEach(() => {
+    // Reset mocks and environment variables
+    mockOctokit.request.mockClear();
+    mockOctokit.paginate.mockClear();
+    process.env.GITHUB_TOKEN = "test-token";
+    process.env.GITHUB_REPOSITORY = "owner/repo";
+    process.env.INPUT_ALERT_TYPES = "dependency";
+    process.env.INPUT_PATHS = "**/package-lock.json\n**/yarn.lock";
+    process.env.INPUT_DISMISSAL_COMMENT = "Test dismissal comment";
+    process.env.INPUT_DISMISSAL_REASON = "tolerable_risk";
+
+    // Spy on console messages and process.exit
+    consoleLogSpy = spyOn(console, "log").mockImplementation(() => {});
+    consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
+    processExitSpy = spyOn(process, "exit").mockImplementation((() => {}) as (
+      code?: number,
+    ) => never);
+  });
+
+  afterEach(() => {
+    mock.restore(); // Restores all mocks
+    // Clear environment variables
+    delete process.env.GITHUB_TOKEN;
+    delete process.env.GITHUB_REPOSITORY;
+    delete process.env.INPUT_ALERT_TYPES;
+    delete process.env.INPUT_PATHS;
+    delete process.env.INPUT_DISMISSAL_COMMENT;
+    delete process.env.INPUT_DISMISSAL_REASON;
+  });
+
+  describe("matchesAnyPattern", () => {
+    let minimatchSpy: ReturnType<typeof spyOn>;
+
+    beforeEach(() => {
+      minimatchSpy = spyOn(minimatchModule, "minimatch");
+    });
+
+    afterEach(() => {
+      minimatchSpy.mockRestore();
+    });
+
+    it("should return true if manifestPath matches any pattern", () => {
+      const manifestPath = "src/package-lock.json";
+      const patterns = ["**/package-lock.json", "**/gemfile.lock"];
+      expect(matchesAnyPattern(manifestPath, patterns)).toBe(true);
+      expect(minimatchSpy).toHaveBeenCalledTimes(1); // Matches first pattern
+    });
+
+    it("should return false if manifestPath does not match any pattern", () => {
+      const manifestPath = "src/some/other/file.txt";
+      const patterns = ["**/package-lock.json", "**/gemfile.lock"];
+      expect(matchesAnyPattern(manifestPath, patterns)).toBe(false);
+      expect(minimatchSpy).toHaveBeenCalledTimes(2);
+    });
+
+    it("should return false if manifestPath is undefined", () => {
+      const patterns = ["**/package-lock.json"];
+      // matchesAnyPattern returns early
+      expect(matchesAnyPattern(undefined, patterns)).toBe(false);
+      expect(minimatchSpy).not.toHaveBeenCalled();
+    });
+
+    it("should return false if patterns array is empty", () => {
+      const manifestPath = "src/package-lock.json";
+      const patterns: string[] = [];
+      // matchesAnyPattern returns early
+      expect(matchesAnyPattern(manifestPath, patterns)).toBe(false);
+      expect(minimatchSpy).not.toHaveBeenCalled();
+    });
+
+    it("should handle glob patterns correctly", () => {
+      expect(matchesAnyPattern("frontend/package.json", ["frontend/**"])).toBe(
+        true,
+      );
+      expect(matchesAnyPattern("backend/package.json", ["frontend/**"])).toBe(
+        false,
+      );
+      expect(minimatchSpy).toHaveBeenCalledTimes(2);
+    });
+
+    it("should use matchBase option for minimatch", () => {
+      expect(
+        matchesAnyPattern("package-lock.json", ["package-lock.json"]),
+      ).toBe(true);
+      expect(
+        matchesAnyPattern("sub/package-lock.json", ["package-lock.json"]),
+      ).toBe(true);
+      expect(minimatchSpy).toHaveBeenCalledTimes(2);
+    });
+
+    it("should log an error, handle it, and continue matching with other patterns", () => {
+      const manifestPath = "src/package-lock.json";
+      const badPattern = "force-error";
+      const goodPattern = "**/package-lock.json";
+      const patterns = [badPattern, goodPattern];
+
+      expect(matchesAnyPattern(manifestPath, patterns)).toBe(true);
+      expect(minimatchSpy).toHaveBeenCalledTimes(2);
+      expect(minimatchSpy.mock.calls[0][1]).toBe(badPattern);
+      expect(minimatchSpy.mock.calls[1][1]).toBe(goodPattern);
+    });
+  });
+
+  describe("fetchAllAlerts", () => {
+    const mockOwner = "owner";
+    const mockRepo = "repo";
+
+    const createMockAlert = (
+      number: number,
+      severity: string,
+      packageName: string,
+      manifestPath: string,
+    ): DependabotAlert => ({
+      number,
+      dependency: {
+        package: { name: packageName },
+        manifest_path: manifestPath,
+      },
+      security_advisory: { severity },
+      security_vulnerability: { severity }, // Assuming advisory and vulnerability severities are the same for simplicity
+    });
+
+    it("should fetch and filter alerts based on severity", async () => {
+      const mockAlertsResponse: DependabotAlert[] = [
+        createMockAlert(1, "critical", "pkg-a", "path/to/manifest1"),
+        createMockAlert(2, "high", "pkg-b", "path/to/manifest2"),
+        createMockAlert(3, "low", "pkg-c", "path/to/manifest3"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlertsResponse as any);
+
+      const octokitInstance = new Octokit(); // Real instance not used due to global mock
+      const filteredAlerts = await fetchAllAlerts(
+        octokitInstance,
+        mockOwner,
+        mockRepo,
+        ["critical", "high"],
+      );
+
+      expect(mockOctokit.paginate).toHaveBeenCalledWith(
+        "GET /repos/{owner}/{repo}/dependabot/alerts",
+        {
+          owner: mockOwner,
+          repo: mockRepo,
+          state: "open",
+          per_page: 100,
+        },
+      );
+      expect(filteredAlerts).toHaveLength(2);
+      expect(filteredAlerts.find((a) => a.number === 1)).toBeDefined();
+      expect(filteredAlerts.find((a) => a.number === 2)).toBeDefined();
+      expect(filteredAlerts.find((a) => a.number === 3)).toBeUndefined();
+    });
+
+    it("should fetch and filter alerts for 'dependency' type if no severity matches", async () => {
+      const mockAlertsResponse: DependabotAlert[] = [
+        createMockAlert(1, "critical", "pkg-a", "path/to/manifest1"),
+        createMockAlert(2, "high", "pkg-b", "path/to/manifest2"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlertsResponse as any);
+      const octokitInstance = new Octokit();
+      const filteredAlerts = await fetchAllAlerts(
+        octokitInstance,
+        mockOwner,
+        mockRepo,
+        ["dependency"],
+      );
+
+      expect(filteredAlerts).toHaveLength(2);
+    });
+
+    it("should return all alerts if 'dependency' is in alertTypes along with severities", async () => {
+      const mockAlertsResponse: DependabotAlert[] = [
+        createMockAlert(1, "critical", "pkg-a", "path/to/manifest1"),
+        createMockAlert(2, "low", "pkg-b", "path/to/manifest2"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlertsResponse as any);
+      const octokitInstance = new Octokit();
+      const filteredAlerts = await fetchAllAlerts(
+        octokitInstance,
+        mockOwner,
+        mockRepo,
+        ["critical", "dependency"],
+      );
+      // The filter is OR based, so both alerts should be returned because 'dependency' matches all, and critical matches one.
+      // The current implementation will include all if 'dependency' is present.
+      expect(filteredAlerts).toHaveLength(2);
+    });
+
+    it("should return empty array if no alerts match severity and 'dependency' type is not included", async () => {
+      const mockAlertsResponse: DependabotAlert[] = [
+        createMockAlert(1, "critical", "pkg-a", "path/to/manifest1"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlertsResponse as any);
+      const octokitInstance = new Octokit();
+      const filteredAlerts = await fetchAllAlerts(
+        octokitInstance,
+        mockOwner,
+        mockRepo,
+        ["low"],
+      );
+
+      expect(filteredAlerts).toHaveLength(0);
+    });
+
+    it("should handle empty list of alerts from paginate", async () => {
+      mockOctokit.paginate.mockResolvedValue([]);
+      const octokitInstance = new Octokit();
+      const filteredAlerts = await fetchAllAlerts(
+        octokitInstance,
+        mockOwner,
+        mockRepo,
+        ["critical"],
+      );
+      expect(filteredAlerts).toHaveLength(0);
+    });
+  });
+
+  // More tests for fetchAllAlerts and run will be added here
+  describe("run", () => {
+    const createMockAlert = (
+      number: number,
+      severity: string,
+      packageName: string,
+      manifestPath: string,
+    ): DependabotAlert => ({
+      number,
+      dependency: {
+        package: { name: packageName },
+        manifest_path: manifestPath,
+      },
+      security_advisory: { severity },
+      security_vulnerability: { severity },
+    });
+
+    it("should successfully fetch, filter, and dismiss alerts", async () => {
+      const mockAlerts: DependabotAlert[] = [
+        createMockAlert(1, "high", "pkg-a", "src/package-lock.json"),
+        createMockAlert(2, "critical", "pkg-b", "other/yarn.lock"),
+        createMockAlert(3, "low", "pkg-c", "nomatch/package.json"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlerts as any);
+      mockOctokit.request.mockResolvedValue({ status: 200 }); // For dismissal
+
+      // Mock successful repo check
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          return { data: { owner: { login: "test-user" } } };
+        }
+        if (
+          route ===
+          "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"
+        ) {
+          return { status: 200 };
+        }
+        return {};
+      });
+
+      process.env.INPUT_PATHS = "src/package-lock.json\nother/yarn.lock";
+
+      await run();
+
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Fetching dependabot alerts for owner/repo...",
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith("Using path patterns:");
+      expect(consoleLogSpy).toHaveBeenCalledWith("- src/package-lock.json");
+      expect(consoleLogSpy).toHaveBeenCalledWith("- other/yarn.lock");
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        `Found ${mockAlerts.length} open alerts`,
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Alert #1 for pkg-a in src/package-lock.json matches patterns",
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Alert #2 for pkg-b in other/yarn.lock matches patterns",
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Skipping alert #3 for nomatch/package.json (does not match any pattern)",
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith("Dismissing 2 alerts...");
+      expect(mockOctokit.request).toHaveBeenCalledWith(
+        "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+        expect.objectContaining({ alert_number: 1, state: "dismissed" }),
+      );
+      expect(mockOctokit.request).toHaveBeenCalledWith(
+        "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+        expect.objectContaining({ alert_number: 2, state: "dismissed" }),
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Alert #1 dismissed successfully",
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Alert #2 dismissed successfully",
+      );
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "Successfully dismissed 2 alerts.",
+      );
+      expect(processExitSpy).not.toHaveBeenCalled();
+    });
+
+    it("should exit if GITHUB_TOKEN is missing", async () => {
+      delete process.env.GITHUB_TOKEN;
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error:",
+        "Missing required env var GITHUB_TOKEN",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should exit if INPUT_PATHS is missing", async () => {
+      process.env.INPUT_PATHS = "";
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error:",
+        "No path patterns provided. Please specify paths to match.",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should exit if INPUT_DISMISSAL_REASON is invalid", async () => {
+      process.env.INPUT_DISMISSAL_REASON = "wrong_reason";
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error:",
+        "Invalid dismissal reason: wrong_reason. Must be one of fix_started, inaccurate, no_bandwidth, not_used, tolerable_risk",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should handle no alerts found", async () => {
+      mockOctokit.paginate.mockResolvedValue([]);
+      // Mock successful repo check
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          return { data: { owner: { login: "test-user" } } };
+        }
+        return {};
+      });
+
+      await run();
+      expect(consoleLogSpy).toHaveBeenCalledWith("Found 0 open alerts");
+      expect(consoleLogSpy).toHaveBeenCalledWith("No alerts found to process.");
+      expect(processExitSpy).not.toHaveBeenCalled();
+    });
+
+    it("should handle no alerts matching path patterns", async () => {
+      const mockAlerts: DependabotAlert[] = [
+        createMockAlert(1, "high", "pkg-a", "nomatch/package.json"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlerts as any);
+      // Mock successful repo check
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          return { data: { owner: { login: "test-user" } } };
+        }
+        return {};
+      });
+
+      process.env.INPUT_PATHS = "src/package-lock.json";
+      await run();
+      expect(consoleLogSpy).toHaveBeenCalledWith(
+        "No alerts matched the provided path patterns.",
+      );
+      expect(processExitSpy).not.toHaveBeenCalled();
+    });
+
+    it("should handle error during token authentication check", async () => {
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          throw new Error("Auth failed");
+        }
+        return {};
+      });
+
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error authenticating with GitHub. Please check your token.",
+      );
+      expect(consoleErrorSpy).toHaveBeenCalledWith("Error:", "Auth failed");
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should handle 404 error when fetching alerts (repo not found or alerts disabled)", async () => {
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          return { data: { owner: { login: "test-user" } } };
+        }
+        return {};
+      });
+      mockOctokit.paginate.mockRejectedValue(
+        new RequestError("Not Found", 404, {
+          request: { headers: {}, url: "http://dummy.url/api" } as any,
+          response: { headers: {}, status: 404, url: "", data: {} },
+        }),
+      );
+
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error: Repository owner/repo not found or Dependabot alerts are not enabled.",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should handle 403 error when fetching alerts (permission issue)", async () => {
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          return { data: { owner: { login: "test-user" } } };
+        }
+        return {};
+      });
+      mockOctokit.paginate.mockRejectedValue(
+        new RequestError("Forbidden", 403, {
+          request: { headers: {}, url: "http://dummy.url/api" } as any,
+          response: { headers: {}, status: 403, url: "", data: {} },
+        }),
+      );
+
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        expect.stringContaining("ERROR: Cannot access Dependabot alerts."),
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should handle general API error when fetching alerts", async () => {
+      mockOctokit.request.mockImplementation(async (route: string) => {
+        if (route === "GET /repos/{owner}/{repo}") {
+          return { data: { owner: { login: "test-user" } } };
+        }
+        return {};
+      });
+      mockOctokit.paginate.mockRejectedValue(
+        new RequestError("Server Error", 500, {
+          request: { headers: {}, url: "http://dummy.url/api" } as any,
+          response: { headers: {}, status: 500, url: "", data: {} },
+        }),
+      );
+
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "API Error 500: Server Error",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should handle 403 error when dismissing alerts", async () => {
+      const mockAlerts: DependabotAlert[] = [
+        createMockAlert(1, "high", "pkg-a", "src/package-lock.json"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlerts as any);
+      mockOctokit.request.mockImplementation(
+        async (route: string, options: any) => {
+          if (route === "GET /repos/{owner}/{repo}") {
+            return { data: { owner: { login: "test-user" } } };
+          }
+          if (
+            route ===
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"
+          ) {
+            throw new RequestError("Forbidden for dismiss", 403, {
+              request: { headers: {}, url: "http://dummy.url/api" } as any,
+              response: { headers: {}, status: 403, url: "", data: {} },
+            });
+          }
+          return {};
+        },
+      );
+
+      process.env.INPUT_PATHS = "src/package-lock.json";
+      await run();
+
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error: Permission denied when trying to dismiss alerts.",
+      );
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Make sure the GITHUB_TOKEN has 'security-events: write' permission.",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+
+    it("should handle non-RequestError when dismissing alerts", async () => {
+      const mockAlerts: DependabotAlert[] = [
+        createMockAlert(1, "high", "pkg-a", "src/package-lock.json"),
+      ];
+      mockOctokit.paginate.mockResolvedValue(mockAlerts as any);
+      mockOctokit.request.mockImplementation(
+        async (route: string, options: any) => {
+          if (route === "GET /repos/{owner}/{repo}") {
+            return { data: { owner: { login: "test-user" } } };
+          }
+          if (
+            route ===
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"
+          ) {
+            throw new Error("Some other dismiss error");
+          }
+          return {};
+        },
+      );
+
+      process.env.INPUT_PATHS = "src/package-lock.json";
+      await run();
+      expect(consoleErrorSpy).toHaveBeenCalledWith(
+        "Error dismissing alerts:",
+        "Some other dismiss error",
+      );
+      expect(processExitSpy).toHaveBeenCalledWith(1);
+    });
+  });
+});
diff --git a/actions/dependabot-auto-triage/src/index.ts b/actions/dependabot-auto-triage/src/index.ts
new file mode 100644
index 000000000..6f4dc28a5
--- /dev/null
+++ b/actions/dependabot-auto-triage/src/index.ts
@@ -0,0 +1,276 @@
+import { Octokit } from "@octokit/rest";
+import { minimatch } from "minimatch";
+import { RequestError } from "@octokit/request-error";
+
+// Define a simplified type for DependabotAlert with used properties
+export interface DependabotAlert {
+  number: number;
+  dependency?: {
+    package?: {
+      name?: string;
+    };
+    manifest_path?: string;
+  };
+  security_advisory?: {
+    severity?: string;
+  };
+  security_vulnerability?: {
+    severity?: string;
+  };
+}
+
+export async function run() {
+  try {
+    const token = process.env.GITHUB_TOKEN;
+    const alertTypes = (process.env.INPUT_ALERT_TYPES || "dependency")
+      .split(",")
+      .map((t) => t.trim());
+    // Parse path patterns from multi-line format, filtering out empty lines
+    const pathPatterns = (process.env.INPUT_PATHS || "")
+      .split("\n")
+      .map((p) => p.trim())
+      .filter((p) => p !== "");
+
+    const dismissalComment = process.env.INPUT_DISMISSAL_COMMENT;
+    const dismissalReason = process.env.INPUT_DISMISSAL_REASON;
+
+    const allowedDismissalReasons = [
+      "fix_started",
+      "inaccurate",
+      "no_bandwidth",
+      "not_used",
+      "tolerable_risk",
+    ];
+
+    if (dismissalReason && !allowedDismissalReasons.includes(dismissalReason)) {
+      throw new Error(
+        `Invalid dismissal reason: ${dismissalReason}. Must be one of ${allowedDismissalReasons.join(", ")}`,
+      );
+    }
+
+    if (!token) {
+      throw new Error("Missing required env var GITHUB_TOKEN");
+    }
+
+    if (pathPatterns.length === 0) {
+      throw new Error(
+        "No path patterns provided. Please specify paths to match.",
+      );
+    }
+
+    const octokit = new Octokit({ auth: token });
+    const [owner, repo] = (process.env.GITHUB_REPOSITORY || "/").split("/");
+
+    if (!owner || !repo) {
+      throw new Error(
+        "Could not determine repository owner and name from GITHUB_REPOSITORY",
+      );
+    }
+
+    // Check token permissions first
+    console.log("Checking GitHub token permissions...");
+    try {
+      const { data: tokenData } = await octokit.request(
+        "GET /repos/{owner}/{repo}",
+        {
+          owner,
+          repo,
+        },
+      );
+      console.log(
+        `Successfully authenticated with GitHub as ${tokenData.owner?.login || "unknown user"}`,
+      );
+    } catch (error) {
+      console.error(
+        "Error authenticating with GitHub. Please check your token.",
+      );
+      throw error;
+    }
+
+    console.log(`Fetching dependabot alerts for ${owner}/${repo}...`);
+    console.log(`Using path patterns:`);
+    pathPatterns.forEach((pattern) => console.log(`- ${pattern}`));
+
+    try {
+      // Get all open alerts using the correct endpoint
+      const alerts = await fetchAllAlerts(octokit, owner, repo, alertTypes);
+      console.log(`Found ${alerts.length} open alerts`);
+
+      if (alerts.length === 0) {
+        console.log("No alerts found to process.");
+        return;
+      }
+
+      // Process matching alerts
+      const alertsToProcess: number[] = [];
+      for (const alert of alerts) {
+        const manifestPath = alert.dependency?.manifest_path;
+        if (manifestPath && matchesAnyPattern(manifestPath, pathPatterns)) {
+          console.log(
+            `Alert #${alert.number} for ${alert.dependency?.package?.name ?? "unknown package"} in ${manifestPath} matches patterns`,
+          );
+          alertsToProcess.push(alert.number);
+        } else {
+          console.log(
+            `Skipping alert #${alert.number} for ${manifestPath || "unknown path"} (does not match any pattern)`,
+          );
+        }
+      }
+
+      if (alertsToProcess.length === 0) {
+        console.log("No alerts matched the provided path patterns.");
+        return;
+      }
+
+      console.log(`Dismissing ${alertsToProcess.length} alerts...`);
+
+      // Use the correct endpoint to dismiss multiple alerts at once
+      try {
+        for (const alertNumber of alertsToProcess) {
+          await octokit.request(
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+            {
+              owner,
+              repo,
+              alert_number: alertNumber,
+              state: "dismissed",
+              dismissed_reason: dismissalReason as
+                | "fix_started"
+                | "inaccurate"
+                | "no_bandwidth"
+                | "not_used"
+                | "tolerable_risk"
+                | undefined,
+              dismissed_comment: dismissalComment,
+            },
+          );
+          console.log(`Alert #${alertNumber} dismissed successfully`);
+        }
+        console.log(`Successfully dismissed ${alertsToProcess.length} alerts.`);
+      } catch (error) {
+        if (error instanceof RequestError) {
+          if (error.status === 403) {
+            console.error(
+              `Error: Permission denied when trying to dismiss alerts.`,
+            );
+            console.error(
+              `Make sure the GITHUB_TOKEN has 'security-events: write' permission.`,
+            );
+            process.exit(1);
+          } else {
+            console.error(`API Error ${error.status}: ${error.message}`);
+            process.exit(1);
+          }
+        } else {
+          console.error(
+            "Error dismissing alerts:",
+            error instanceof Error ? error.message : String(error),
+          );
+          process.exit(1);
+        }
+      }
+    } catch (error) {
+      if (error instanceof RequestError) {
+        if (error.status === 404) {
+          console.error(
+            `Error: Repository ${owner}/${repo} not found or Dependabot alerts are not enabled.`,
+          );
+          console.error(
+            "Make sure Dependabot alerts are enabled in the repository's Security settings.",
+          );
+          process.exit(1);
+        } else if (
+          error.status === 403 ||
+          error.message.includes("Resource not accessible by integration")
+        ) {
+          console.error(`
+ERROR: Cannot access Dependabot alerts.
+
+This error may occur for several reasons:
+1. Dependabot alerts might not be enabled for this repository
+   - Enable them at: https://github.com/${owner}/${repo}/settings/security_analysis
+   
+2. The token being used might not have sufficient permissions
+   - For GITHUB_TOKEN: Make sure the workflow has 'security-events: write' permission
+   - For fine-grained tokens: Make sure the 'Dependabot alerts: write' permission is enabled
+
+3. Organization policies might be restricting access to security features
+   - Check with your organization administrator
+
+If you're sure the token has the right permissions, try accessing the alerts manually at:
+https://github.com/${owner}/${repo}/security/dependabot
+          `);
+          process.exit(1);
+        } else {
+          console.error(`API Error ${error.status}: ${error.message}`);
+          process.exit(1);
+        }
+      } else {
+        console.error(
+          "Error:",
+          error instanceof Error ? error.message : String(error),
+        );
+        process.exit(1);
+      }
+    }
+  } catch (error) {
+    console.error(
+      "Error:",
+      error instanceof Error ? error.message : String(error),
+    );
+    process.exit(1);
+  }
+}
+
+export async function fetchAllAlerts(
+  octokit: Octokit,
+  owner: string,
+  repo: string,
+  alertTypes: string[],
+): Promise<DependabotAlert[]> {
+  const allAlerts: DependabotAlert[] = await octokit.paginate(
+    "GET /repos/{owner}/{repo}/dependabot/alerts",
+    {
+      owner,
+      repo,
+      state: "open",
+      per_page: 100,
+    },
+  );
+
+  // Filter alerts based on severity or 'dependency' type
+  const filteredAlerts = allAlerts.filter(
+    (alert) =>
+      alertTypes.includes(alert.security_advisory?.severity as string) ||
+      alertTypes.includes(alert.security_vulnerability?.severity as string) ||
+      alertTypes.includes("dependency"),
+  );
+
+  return filteredAlerts;
+}
+
+export function matchesAnyPattern(
+  manifestPath: string | undefined,
+  patterns: string[],
+): boolean {
+  if (!manifestPath) return false;
+
+  return patterns.some((pattern) => {
+    try {
+      return minimatch(manifestPath, pattern, {
+        matchBase: true,
+        strict: true,
+      } as any);
+    } catch (error) {
+      console.error(
+        `Error matching pattern ${pattern}:`,
+        error instanceof Error ? error.message : String(error),
+      );
+      return false;
+    }
+  });
+}
+
+if (import.meta.main) {
+  run();
+}
diff --git a/actions/dependabot-auto-triage/tsconfig.json b/actions/dependabot-auto-triage/tsconfig.json
new file mode 100644
index 000000000..4e2f0d81a
--- /dev/null
+++ b/actions/dependabot-auto-triage/tsconfig.json
@@ -0,0 +1,22 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "compilerOptions": {
+    "types": ["bun-types"],
+    "allowJs": true,
+    "checkJs": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "module": "es2022",
+    "moduleResolution": "Bundler",
+    "newLine": "lf",
+    "noImplicitAny": true,
+    "outDir": "./dist",
+    "resolveJsonModule": true,
+    "skipLibCheck": true,
+    "sourceMap": true,
+    "strict": true,
+    "strictNullChecks": true,
+    "target": "es2022"
+  },
+  "include": ["**/*.ts"]
+}
diff --git a/release-please-config.json b/release-please-config.json
index 4a7b66140..dfd9b96b5 100644
--- a/release-please-config.json
+++ b/release-please-config.json
@@ -133,6 +133,10 @@
     "actions/validate-policy-bot-config": {
       "package-name": "validate-policy-bot-config",
       "extra-files": ["README.md"]
+    },
+    "actions/dependabot-auto-triage": {
+      "package-name": "dependabot-auto-triage",
+      "extra-files": ["README.md"]
     }
   },
   "release-type": "simple",


Reviews:
user: login: zerok
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T13:55:32Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T14:59:28Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T14:59:34Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T14:59:45Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T14:59:57Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T15:00:27Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T15:00:34Z
user: login: guicaulada
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T15:00:40Z
user: login: zerok
body: 🚀 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T09:13:27Z

Review comments:
diff_hunk: @@ -0,0 +1,111 @@
+# Auto Dismiss Dependabot Alerts
+
+A GitHub composite action to automatically dismiss Dependabot alerts based on manifest paths using glob patterns.
+
+## Usage
+
+This action can be used in a workflow to automatically dismiss Dependabot alerts for specific manifest paths. This is particularly useful for repositories with dependencies that are not directly used in production or for which vulnerabilities may not be relevant.
+
+### Example Workflow
+
+Create a workflow file (e.g., `.github/workflows/auto-dismiss-dependabot-alerts.yml`) with the following content:
+
+```yaml
+name: Auto Dismiss Dependabot Alerts
+
+on:
+  # Run daily to dismiss new alerts
+  schedule:
+    - cron: "0 0 * * *"
+
+  # Allow manual triggering
+  workflow_dispatch:
+
+jobs:
+  auto-dismiss:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      contents: read
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      # Get GitHub App token with Dependabot alerts permissions
+      - name: Retrieve GitHub App secrets
+        id: get-secrets
+        uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.1.0
+        with:
+          common_secrets: |
+            DEPENDABOT_AUTO_TRIAGE_APP_ID=dependabot-auto-triage:app-id
+            DEPENDABOT_AUTO_TRIAGE_APP_PRIVATE_KEY=dependabot-auto-triage:private-key
+
+      - name: Generate token
+        id: generate-token
+        uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2
+        with:
+          app-id: ${{ env.DEPENDABOT_AUTO_TRIAGE_APP_ID }}
+          private-key: ${{ env.DEPENDABOT_AUTO_TRIAGE_APP_PRIVATE_KEY }}
+
+      # Use the token with the auto-triage action
+      - name: Auto Dismiss Dependabot Alerts
+        uses: ./.github/actions/auto-triage
path: actions/dependabot-auto-triage/README.md
user: login: zerok
body: Please update the uses-value before merging 🙂 
created_at: 2025-05-07T13:37:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
+description: "Auto dismiss Dependabot alerts based on manifest path"
+inputs:
+  token:
+    description: "GitHub token with permissions to dismiss alerts"
+    required: true
+  alert-types:
+    description: 'Comma-separated list of alert types to dismiss (default: "dependency")'
+    required: false
+    default: "dependency"
+  paths:
+    description: "Multi-line list of glob patterns to match manifest paths to dismiss"
+    required: true
+    # Example: |
+    #   terraform/modules/**/*.json
+    #   docker/vendor/**
+  dismissal-comment:
+    description: "Default comment to add when dismissing alerts"
+    required: false
+    default: "Auto-dismissed based on manifest path configuration"
+  dismissal-reason:
+    description: "Default reason for dismissal"
+    required: false
+    default: "not_used"
+    # Options: 'fix_started', 'inaccurate', 'no_bandwidth', 'not_used', 'tolerable_risk'
+
+runs:
+  using: "composite"
+  steps:
+    - name: Install bun package manager
+      uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
+      with:
+        bun-version-file: ${{ github.action_path }}/.bun-version
+
+    - name: Install dependencies
+      shell: bash
+      working-directory: ${{ github.action_path }}
+      run: |
+        bun install --frozen-lockfile --production
path: actions/dependabot-auto-triage/action.yml
user: login: zerok
body: The lockfile is currently not checked in but should be IMO.
created_at: 2025-05-07T13:39:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,260 @@
+import { Octokit } from "@octokit/rest";
+import { minimatch } from "minimatch";
+import { RequestError } from "@octokit/request-error";
+
+async function run() {
+  try {
+    const token = process.env.GITHUB_TOKEN;
+    const alertTypes = (process.env.INPUT_ALERT_TYPES || "dependency")
+      .split(",")
+      .map((t) => t.trim());
+    // Parse path patterns from multi-line format, filtering out empty lines
+    const pathPatterns = (process.env.INPUT_PATHS || "")
+      .split("\n")
+      .map((p) => p.trim())
+      .filter((p) => p !== "");
+
+    const dismissalComment = process.env.INPUT_DISMISSAL_COMMENT;
+    const dismissalReason = process.env.INPUT_DISMISSAL_REASON;
+
+    if (!token) {
+      throw new Error("Missing required env var GITHUB_TOKEN");
+    }
+
+    if (pathPatterns.length === 0) {
+      throw new Error(
+        "No path patterns provided. Please specify paths to match.",
+      );
+    }
+
+    const octokit = new Octokit({ auth: token });
+    const [owner, repo] = (process.env.GITHUB_REPOSITORY || "/").split("/");
+
+    if (!owner || !repo) {
+      throw new Error(
+        "Could not determine repository owner and name from GITHUB_REPOSITORY",
+      );
+    }
+
+    // Check token permissions first
+    console.log("Checking GitHub token permissions...");
+    try {
+      const { data: tokenData } = await octokit.request(
+        "GET /repos/{owner}/{repo}",
+        {
+          owner,
+          repo,
+        },
+      );
+      console.log(
+        `Successfully authenticated with GitHub as ${tokenData.owner?.login || "unknown user"}`,
+      );
+    } catch (error) {
+      console.error(
+        "Error authenticating with GitHub. Please check your token.",
+      );
+      throw error;
+    }
+
+    console.log(`Fetching dependabot alerts for ${owner}/${repo}...`);
+    console.log(`Using path patterns:`);
+    pathPatterns.forEach((pattern) => console.log(`- ${pattern}`));
+
+    try {
+      // Get all open alerts using the correct endpoint
+      const alerts = await fetchAllAlerts(octokit, owner, repo, alertTypes);
+      console.log(`Found ${alerts.length} open alerts`);
+
+      if (alerts.length === 0) {
+        console.log("No alerts found to process.");
+        return;
+      }
+
+      // Process matching alerts
+      const alertsToProcess = [];
+      for (const alert of alerts) {
+        const manifestPath = alert.dependency?.manifest_path;
+        if (manifestPath && matchesAnyPattern(manifestPath, pathPatterns)) {
+          console.log(
+            `Alert #${alert.number} for ${alert.dependency.package.name} in ${manifestPath} matches patterns`,
+          );
+          alertsToProcess.push(alert.number);
+        } else {
+          console.log(
+            `Skipping alert #${alert.number} for ${manifestPath || "unknown path"} (does not match any pattern)`,
+          );
+        }
+      }
+
+      if (alertsToProcess.length === 0) {
+        console.log("No alerts matched the provided path patterns.");
+        return;
+      }
+
+      console.log(`Dismissing ${alertsToProcess.length} alerts...`);
+
+      // Use the correct endpoint to dismiss multiple alerts at once
+      try {
+        for (const alertNumber of alertsToProcess) {
+          await octokit.request(
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+            {
+              owner,
+              repo,
+              alert_number: alertNumber,
+              state: "dismissed",
+              dismissed_reason: dismissalReason as
+                | "fix_started"
+                | "inaccurate"
+                | "no_bandwidth"
+                | "not_used"
+                | "tolerable_risk"
+                | undefined,
+              dismissed_comment: dismissalComment,
+            },
+          );
+          console.log(`Alert #${alertNumber} dismissed successfully`);
+        }
+        console.log(`Successfully dismissed ${alertsToProcess.length} alerts.`);
+      } catch (error) {
+        if (error instanceof RequestError) {
+          if (error.status === 403) {
+            console.error(
+              `Error: Permission denied when trying to dismiss alerts.`,
+            );
+            console.error(
+              `Make sure the GITHUB_TOKEN has 'security-events: write' permission.`,
+            );
+            process.exit(1);
+          } else {
+            console.error(`API Error ${error.status}: ${error.message}`);
+            process.exit(1);
+          }
+        } else {
+          console.error(
+            "Error dismissing alerts:",
+            error instanceof Error ? error.message : String(error),
+          );
+          process.exit(1);
+        }
+      }
+    } catch (error) {
+      if (error instanceof RequestError) {
+        if (error.status === 404) {
+          console.error(
+            `Error: Repository ${owner}/${repo} not found or Dependabot alerts are not enabled.`,
+          );
+          console.error(
+            "Make sure Dependabot alerts are enabled in the repository's Security settings.",
+          );
+          process.exit(1);
+        } else if (
+          error.status === 403 ||
+          error.message.includes("Resource not accessible by integration")
+        ) {
+          console.error(`
+ERROR: Cannot access Dependabot alerts.
+
+This error may occur for several reasons:
+1. Dependabot alerts might not be enabled for this repository
+   - Enable them at: https://github.com/${owner}/${repo}/settings/security_analysis
+   
+2. The token being used might not have sufficient permissions
+   - For GITHUB_TOKEN: Make sure the workflow has 'security-events: write' permission
+   - For fine-grained tokens: Make sure the 'Dependabot alerts: write' permission is enabled
+
+3. Organization policies might be restricting access to security features
+   - Check with your organization administrator
+
+If you're sure the token has the right permissions, try accessing the alerts manually at:
+https://github.com/${owner}/${repo}/security/dependabot
+          `);
+          process.exit(1);
+        } else {
+          console.error(`API Error ${error.status}: ${error.message}`);
+          process.exit(1);
+        }
+      } else {
+        console.error(
+          "Error:",
+          error instanceof Error ? error.message : String(error),
+        );
+        process.exit(1);
+      }
+    }
+  } catch (error) {
+    console.error(
+      "Error:",
+      error instanceof Error ? error.message : String(error),
+    );
+    process.exit(1);
+  }
+}
+
+async function fetchAllAlerts(
+  octokit: Octokit,
+  owner: string,
+  repo: string,
+  alertTypes: string[],
+) {
+  const alerts = [];
+  let page = 1;
+  let hasMorePages = true;
+
+  try {
+    while (hasMorePages) {
+      // Using the dependabot alerts endpoint directly
+      const response = await octokit.request(
path: actions/dependabot-auto-triage/src/index.ts
user: login: zerok
body: octokit has a `paginate` function that should doe all the paging for you 🙂 
created_at: 2025-05-07T13:46:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,260 @@
+import { Octokit } from "@octokit/rest";
+import { minimatch } from "minimatch";
+import { RequestError } from "@octokit/request-error";
+
+async function run() {
+  try {
+    const token = process.env.GITHUB_TOKEN;
+    const alertTypes = (process.env.INPUT_ALERT_TYPES || "dependency")
+      .split(",")
+      .map((t) => t.trim());
+    // Parse path patterns from multi-line format, filtering out empty lines
+    const pathPatterns = (process.env.INPUT_PATHS || "")
+      .split("\n")
+      .map((p) => p.trim())
+      .filter((p) => p !== "");
+
+    const dismissalComment = process.env.INPUT_DISMISSAL_COMMENT;
+    const dismissalReason = process.env.INPUT_DISMISSAL_REASON;
+
+    if (!token) {
+      throw new Error("Missing required env var GITHUB_TOKEN");
+    }
+
+    if (pathPatterns.length === 0) {
+      throw new Error(
+        "No path patterns provided. Please specify paths to match.",
+      );
+    }
+
+    const octokit = new Octokit({ auth: token });
+    const [owner, repo] = (process.env.GITHUB_REPOSITORY || "/").split("/");
+
+    if (!owner || !repo) {
+      throw new Error(
+        "Could not determine repository owner and name from GITHUB_REPOSITORY",
+      );
+    }
+
+    // Check token permissions first
+    console.log("Checking GitHub token permissions...");
+    try {
+      const { data: tokenData } = await octokit.request(
+        "GET /repos/{owner}/{repo}",
+        {
+          owner,
+          repo,
+        },
+      );
+      console.log(
+        `Successfully authenticated with GitHub as ${tokenData.owner?.login || "unknown user"}`,
+      );
+    } catch (error) {
+      console.error(
+        "Error authenticating with GitHub. Please check your token.",
+      );
+      throw error;
+    }
+
+    console.log(`Fetching dependabot alerts for ${owner}/${repo}...`);
+    console.log(`Using path patterns:`);
+    pathPatterns.forEach((pattern) => console.log(`- ${pattern}`));
+
+    try {
+      // Get all open alerts using the correct endpoint
+      const alerts = await fetchAllAlerts(octokit, owner, repo, alertTypes);
+      console.log(`Found ${alerts.length} open alerts`);
+
+      if (alerts.length === 0) {
+        console.log("No alerts found to process.");
+        return;
+      }
+
+      // Process matching alerts
+      const alertsToProcess = [];
+      for (const alert of alerts) {
+        const manifestPath = alert.dependency?.manifest_path;
+        if (manifestPath && matchesAnyPattern(manifestPath, pathPatterns)) {
+          console.log(
+            `Alert #${alert.number} for ${alert.dependency.package.name} in ${manifestPath} matches patterns`,
+          );
+          alertsToProcess.push(alert.number);
+        } else {
+          console.log(
+            `Skipping alert #${alert.number} for ${manifestPath || "unknown path"} (does not match any pattern)`,
+          );
+        }
+      }
+
+      if (alertsToProcess.length === 0) {
+        console.log("No alerts matched the provided path patterns.");
+        return;
+      }
+
+      console.log(`Dismissing ${alertsToProcess.length} alerts...`);
+
+      // Use the correct endpoint to dismiss multiple alerts at once
+      try {
+        for (const alertNumber of alertsToProcess) {
+          await octokit.request(
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+            {
+              owner,
+              repo,
+              alert_number: alertNumber,
+              state: "dismissed",
+              dismissed_reason: dismissalReason as
+                | "fix_started"
+                | "inaccurate"
+                | "no_bandwidth"
+                | "not_used"
+                | "tolerable_risk"
+                | undefined,
+              dismissed_comment: dismissalComment,
+            },
+          );
+          console.log(`Alert #${alertNumber} dismissed successfully`);
+        }
+        console.log(`Successfully dismissed ${alertsToProcess.length} alerts.`);
+      } catch (error) {
+        if (error instanceof RequestError) {
+          if (error.status === 403) {
+            console.error(
+              `Error: Permission denied when trying to dismiss alerts.`,
+            );
+            console.error(
+              `Make sure the GITHUB_TOKEN has 'security-events: write' permission.`,
+            );
+            process.exit(1);
+          } else {
+            console.error(`API Error ${error.status}: ${error.message}`);
+            process.exit(1);
+          }
+        } else {
+          console.error(
+            "Error dismissing alerts:",
+            error instanceof Error ? error.message : String(error),
+          );
+          process.exit(1);
+        }
+      }
+    } catch (error) {
+      if (error instanceof RequestError) {
+        if (error.status === 404) {
+          console.error(
+            `Error: Repository ${owner}/${repo} not found or Dependabot alerts are not enabled.`,
+          );
+          console.error(
+            "Make sure Dependabot alerts are enabled in the repository's Security settings.",
+          );
+          process.exit(1);
+        } else if (
+          error.status === 403 ||
+          error.message.includes("Resource not accessible by integration")
+        ) {
+          console.error(`
+ERROR: Cannot access Dependabot alerts.
+
+This error may occur for several reasons:
+1. Dependabot alerts might not be enabled for this repository
+   - Enable them at: https://github.com/${owner}/${repo}/settings/security_analysis
+   
+2. The token being used might not have sufficient permissions
+   - For GITHUB_TOKEN: Make sure the workflow has 'security-events: write' permission
+   - For fine-grained tokens: Make sure the 'Dependabot alerts: write' permission is enabled
+
+3. Organization policies might be restricting access to security features
+   - Check with your organization administrator
+
+If you're sure the token has the right permissions, try accessing the alerts manually at:
+https://github.com/${owner}/${repo}/security/dependabot
+          `);
+          process.exit(1);
+        } else {
+          console.error(`API Error ${error.status}: ${error.message}`);
+          process.exit(1);
+        }
+      } else {
+        console.error(
+          "Error:",
+          error instanceof Error ? error.message : String(error),
+        );
+        process.exit(1);
+      }
+    }
+  } catch (error) {
+    console.error(
+      "Error:",
+      error instanceof Error ? error.message : String(error),
+    );
+    process.exit(1);
+  }
+}
+
+async function fetchAllAlerts(
+  octokit: Octokit,
+  owner: string,
+  repo: string,
+  alertTypes: string[],
+) {
+  const alerts = [];
+  let page = 1;
+  let hasMorePages = true;
+
+  try {
+    while (hasMorePages) {
+      // Using the dependabot alerts endpoint directly
+      const response = await octokit.request(
+        "GET /repos/{owner}/{repo}/dependabot/alerts",
+        {
+          owner,
+          repo,
+          state: "open",
+          per_page: 100,
+          page,
+        },
+      );
+
+      if (response.data.length === 0) {
+        hasMorePages = false;
+      } else {
+        const filteredAlerts = response.data.filter(
+          (alert) =>
+            alertTypes.includes(alert.security_advisory?.severity as string) ||
+            alertTypes.includes(
+              alert.security_vulnerability?.severity as string,
+            ) ||
+            alertTypes.includes("dependency"),
+        );
+        alerts.push(...filteredAlerts);
+        page++;
+      }
+    }
+
+    return alerts;
+  } catch (error) {
+    // Re-throw to be handled by the main function
+    throw error;
+  }
+}
+
+function matchesAnyPattern(
+  manifestPath: string | undefined,
+  patterns: string[],
+): boolean {
+  if (!manifestPath) return false;
+
+  return patterns.some((pattern) => {
+    try {
+      return minimatch(manifestPath, pattern, { matchBase: true });
+    } catch (error) {
+      console.error(
+        `Error matching pattern ${pattern}:`,
+        error instanceof Error ? error.message : String(error),
+      );
+      return false;
+    }
+  });
+}
+
+run();
path: actions/dependabot-auto-triage/src/index.ts
user: login: zerok
body: ```suggestion
if (import.meta.main) {
  run();
}
```

So that you can also run unittests against that file without executing the `run` function by accident 🙂 
created_at: 2025-05-07T13:49:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
+description: "Auto dismiss Dependabot alerts based on manifest path"
+inputs:
+  token:
+    description: "GitHub token with permissions to dismiss alerts"
+    required: true
+  alert-types:
+    description: 'Comma-separated list of alert types to dismiss (default: "dependency")'
+    required: false
+    default: "dependency"
+  paths:
+    description: "Multi-line list of glob patterns to match manifest paths to dismiss"
+    required: true
+    # Example: |
+    #   terraform/modules/**/*.json
+    #   docker/vendor/**
+  dismissal-comment:
+    description: "Default comment to add when dismissing alerts"
+    required: false
+    default: "Auto-dismissed based on manifest path configuration"
+  dismissal-reason:
+    description: "Default reason for dismissal"
+    required: false
+    default: "not_used"
+    # Options: 'fix_started', 'inaccurate', 'no_bandwidth', 'not_used', 'tolerable_risk'
path: actions/dependabot-auto-triage/action.yml
user: login: zerok
body: Would it make sense to add the validation for this into the index.ts file?
created_at: 2025-05-07T13:50:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
path: actions/dependabot-auto-triage/action.yml
user: login: zerok
body: Please also add this action to the `release-please-config.json` file
created_at: 2025-05-07T13:51:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,111 @@
+# Auto Dismiss Dependabot Alerts
+
+A GitHub composite action to automatically dismiss Dependabot alerts based on manifest paths using glob patterns.
+
+## Usage
+
+This action can be used in a workflow to automatically dismiss Dependabot alerts for specific manifest paths. This is particularly useful for repositories with dependencies that are not directly used in production or for which vulnerabilities may not be relevant.
+
+### Example Workflow
+
+Create a workflow file (e.g., `.github/workflows/auto-dismiss-dependabot-alerts.yml`) with the following content:
+
+```yaml
+name: Auto Dismiss Dependabot Alerts
+
+on:
+  # Run daily to dismiss new alerts
+  schedule:
+    - cron: "0 0 * * *"
+
+  # Allow manual triggering
+  workflow_dispatch:
+
+jobs:
+  auto-dismiss:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      contents: read
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
path: actions/dependabot-auto-triage/README.md
user: login: zerok
body: Please pin that action
created_at: 2025-05-07T13:52:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,111 @@
+# Auto Dismiss Dependabot Alerts
+
+A GitHub composite action to automatically dismiss Dependabot alerts based on manifest paths using glob patterns.
+
+## Usage
+
+This action can be used in a workflow to automatically dismiss Dependabot alerts for specific manifest paths. This is particularly useful for repositories with dependencies that are not directly used in production or for which vulnerabilities may not be relevant.
+
+### Example Workflow
+
+Create a workflow file (e.g., `.github/workflows/auto-dismiss-dependabot-alerts.yml`) with the following content:
+
+```yaml
+name: Auto Dismiss Dependabot Alerts
+
+on:
+  # Run daily to dismiss new alerts
+  schedule:
+    - cron: "0 0 * * *"
+
+  # Allow manual triggering
+  workflow_dispatch:
+
+jobs:
+  auto-dismiss:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      contents: read
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      # Get GitHub App token with Dependabot alerts permissions
+      - name: Retrieve GitHub App secrets
+        id: get-secrets
+        uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.1.0
+        with:
+          common_secrets: |
+            DEPENDABOT_AUTO_TRIAGE_APP_ID=dependabot-auto-triage:app-id
+            DEPENDABOT_AUTO_TRIAGE_APP_PRIVATE_KEY=dependabot-auto-triage:private-key
+
+      - name: Generate token
+        id: generate-token
+        uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2
+        with:
+          app-id: ${{ env.DEPENDABOT_AUTO_TRIAGE_APP_ID }}
+          private-key: ${{ env.DEPENDABOT_AUTO_TRIAGE_APP_PRIVATE_KEY }}
+
+      # Use the token with the auto-triage action
+      - name: Auto Dismiss Dependabot Alerts
+        uses: ./.github/actions/auto-triage
path: actions/dependabot-auto-triage/README.md
user: login: guicaulada
body: Done!
created_at: 2025-05-07T14:59:27Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
+description: "Auto dismiss Dependabot alerts based on manifest path"
+inputs:
+  token:
+    description: "GitHub token with permissions to dismiss alerts"
+    required: true
+  alert-types:
+    description: 'Comma-separated list of alert types to dismiss (default: "dependency")'
+    required: false
+    default: "dependency"
+  paths:
+    description: "Multi-line list of glob patterns to match manifest paths to dismiss"
+    required: true
+    # Example: |
+    #   terraform/modules/**/*.json
+    #   docker/vendor/**
+  dismissal-comment:
+    description: "Default comment to add when dismissing alerts"
+    required: false
+    default: "Auto-dismissed based on manifest path configuration"
+  dismissal-reason:
+    description: "Default reason for dismissal"
+    required: false
+    default: "not_used"
+    # Options: 'fix_started', 'inaccurate', 'no_bandwidth', 'not_used', 'tolerable_risk'
+
+runs:
+  using: "composite"
+  steps:
+    - name: Install bun package manager
+      uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
+      with:
+        bun-version-file: ${{ github.action_path }}/.bun-version
+
+    - name: Install dependencies
+      shell: bash
+      working-directory: ${{ github.action_path }}
+      run: |
+        bun install --frozen-lockfile --production
path: actions/dependabot-auto-triage/action.yml
user: login: guicaulada
body: Done!
created_at: 2025-05-07T14:59:34Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,260 @@
+import { Octokit } from "@octokit/rest";
+import { minimatch } from "minimatch";
+import { RequestError } from "@octokit/request-error";
+
+async function run() {
+  try {
+    const token = process.env.GITHUB_TOKEN;
+    const alertTypes = (process.env.INPUT_ALERT_TYPES || "dependency")
+      .split(",")
+      .map((t) => t.trim());
+    // Parse path patterns from multi-line format, filtering out empty lines
+    const pathPatterns = (process.env.INPUT_PATHS || "")
+      .split("\n")
+      .map((p) => p.trim())
+      .filter((p) => p !== "");
+
+    const dismissalComment = process.env.INPUT_DISMISSAL_COMMENT;
+    const dismissalReason = process.env.INPUT_DISMISSAL_REASON;
+
+    if (!token) {
+      throw new Error("Missing required env var GITHUB_TOKEN");
+    }
+
+    if (pathPatterns.length === 0) {
+      throw new Error(
+        "No path patterns provided. Please specify paths to match.",
+      );
+    }
+
+    const octokit = new Octokit({ auth: token });
+    const [owner, repo] = (process.env.GITHUB_REPOSITORY || "/").split("/");
+
+    if (!owner || !repo) {
+      throw new Error(
+        "Could not determine repository owner and name from GITHUB_REPOSITORY",
+      );
+    }
+
+    // Check token permissions first
+    console.log("Checking GitHub token permissions...");
+    try {
+      const { data: tokenData } = await octokit.request(
+        "GET /repos/{owner}/{repo}",
+        {
+          owner,
+          repo,
+        },
+      );
+      console.log(
+        `Successfully authenticated with GitHub as ${tokenData.owner?.login || "unknown user"}`,
+      );
+    } catch (error) {
+      console.error(
+        "Error authenticating with GitHub. Please check your token.",
+      );
+      throw error;
+    }
+
+    console.log(`Fetching dependabot alerts for ${owner}/${repo}...`);
+    console.log(`Using path patterns:`);
+    pathPatterns.forEach((pattern) => console.log(`- ${pattern}`));
+
+    try {
+      // Get all open alerts using the correct endpoint
+      const alerts = await fetchAllAlerts(octokit, owner, repo, alertTypes);
+      console.log(`Found ${alerts.length} open alerts`);
+
+      if (alerts.length === 0) {
+        console.log("No alerts found to process.");
+        return;
+      }
+
+      // Process matching alerts
+      const alertsToProcess = [];
+      for (const alert of alerts) {
+        const manifestPath = alert.dependency?.manifest_path;
+        if (manifestPath && matchesAnyPattern(manifestPath, pathPatterns)) {
+          console.log(
+            `Alert #${alert.number} for ${alert.dependency.package.name} in ${manifestPath} matches patterns`,
+          );
+          alertsToProcess.push(alert.number);
+        } else {
+          console.log(
+            `Skipping alert #${alert.number} for ${manifestPath || "unknown path"} (does not match any pattern)`,
+          );
+        }
+      }
+
+      if (alertsToProcess.length === 0) {
+        console.log("No alerts matched the provided path patterns.");
+        return;
+      }
+
+      console.log(`Dismissing ${alertsToProcess.length} alerts...`);
+
+      // Use the correct endpoint to dismiss multiple alerts at once
+      try {
+        for (const alertNumber of alertsToProcess) {
+          await octokit.request(
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+            {
+              owner,
+              repo,
+              alert_number: alertNumber,
+              state: "dismissed",
+              dismissed_reason: dismissalReason as
+                | "fix_started"
+                | "inaccurate"
+                | "no_bandwidth"
+                | "not_used"
+                | "tolerable_risk"
+                | undefined,
+              dismissed_comment: dismissalComment,
+            },
+          );
+          console.log(`Alert #${alertNumber} dismissed successfully`);
+        }
+        console.log(`Successfully dismissed ${alertsToProcess.length} alerts.`);
+      } catch (error) {
+        if (error instanceof RequestError) {
+          if (error.status === 403) {
+            console.error(
+              `Error: Permission denied when trying to dismiss alerts.`,
+            );
+            console.error(
+              `Make sure the GITHUB_TOKEN has 'security-events: write' permission.`,
+            );
+            process.exit(1);
+          } else {
+            console.error(`API Error ${error.status}: ${error.message}`);
+            process.exit(1);
+          }
+        } else {
+          console.error(
+            "Error dismissing alerts:",
+            error instanceof Error ? error.message : String(error),
+          );
+          process.exit(1);
+        }
+      }
+    } catch (error) {
+      if (error instanceof RequestError) {
+        if (error.status === 404) {
+          console.error(
+            `Error: Repository ${owner}/${repo} not found or Dependabot alerts are not enabled.`,
+          );
+          console.error(
+            "Make sure Dependabot alerts are enabled in the repository's Security settings.",
+          );
+          process.exit(1);
+        } else if (
+          error.status === 403 ||
+          error.message.includes("Resource not accessible by integration")
+        ) {
+          console.error(`
+ERROR: Cannot access Dependabot alerts.
+
+This error may occur for several reasons:
+1. Dependabot alerts might not be enabled for this repository
+   - Enable them at: https://github.com/${owner}/${repo}/settings/security_analysis
+   
+2. The token being used might not have sufficient permissions
+   - For GITHUB_TOKEN: Make sure the workflow has 'security-events: write' permission
+   - For fine-grained tokens: Make sure the 'Dependabot alerts: write' permission is enabled
+
+3. Organization policies might be restricting access to security features
+   - Check with your organization administrator
+
+If you're sure the token has the right permissions, try accessing the alerts manually at:
+https://github.com/${owner}/${repo}/security/dependabot
+          `);
+          process.exit(1);
+        } else {
+          console.error(`API Error ${error.status}: ${error.message}`);
+          process.exit(1);
+        }
+      } else {
+        console.error(
+          "Error:",
+          error instanceof Error ? error.message : String(error),
+        );
+        process.exit(1);
+      }
+    }
+  } catch (error) {
+    console.error(
+      "Error:",
+      error instanceof Error ? error.message : String(error),
+    );
+    process.exit(1);
+  }
+}
+
+async function fetchAllAlerts(
+  octokit: Octokit,
+  owner: string,
+  repo: string,
+  alertTypes: string[],
+) {
+  const alerts = [];
+  let page = 1;
+  let hasMorePages = true;
+
+  try {
+    while (hasMorePages) {
+      // Using the dependabot alerts endpoint directly
+      const response = await octokit.request(
path: actions/dependabot-auto-triage/src/index.ts
user: login: guicaulada
body: Done!
created_at: 2025-05-07T14:59:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,260 @@
+import { Octokit } from "@octokit/rest";
+import { minimatch } from "minimatch";
+import { RequestError } from "@octokit/request-error";
+
+async function run() {
+  try {
+    const token = process.env.GITHUB_TOKEN;
+    const alertTypes = (process.env.INPUT_ALERT_TYPES || "dependency")
+      .split(",")
+      .map((t) => t.trim());
+    // Parse path patterns from multi-line format, filtering out empty lines
+    const pathPatterns = (process.env.INPUT_PATHS || "")
+      .split("\n")
+      .map((p) => p.trim())
+      .filter((p) => p !== "");
+
+    const dismissalComment = process.env.INPUT_DISMISSAL_COMMENT;
+    const dismissalReason = process.env.INPUT_DISMISSAL_REASON;
+
+    if (!token) {
+      throw new Error("Missing required env var GITHUB_TOKEN");
+    }
+
+    if (pathPatterns.length === 0) {
+      throw new Error(
+        "No path patterns provided. Please specify paths to match.",
+      );
+    }
+
+    const octokit = new Octokit({ auth: token });
+    const [owner, repo] = (process.env.GITHUB_REPOSITORY || "/").split("/");
+
+    if (!owner || !repo) {
+      throw new Error(
+        "Could not determine repository owner and name from GITHUB_REPOSITORY",
+      );
+    }
+
+    // Check token permissions first
+    console.log("Checking GitHub token permissions...");
+    try {
+      const { data: tokenData } = await octokit.request(
+        "GET /repos/{owner}/{repo}",
+        {
+          owner,
+          repo,
+        },
+      );
+      console.log(
+        `Successfully authenticated with GitHub as ${tokenData.owner?.login || "unknown user"}`,
+      );
+    } catch (error) {
+      console.error(
+        "Error authenticating with GitHub. Please check your token.",
+      );
+      throw error;
+    }
+
+    console.log(`Fetching dependabot alerts for ${owner}/${repo}...`);
+    console.log(`Using path patterns:`);
+    pathPatterns.forEach((pattern) => console.log(`- ${pattern}`));
+
+    try {
+      // Get all open alerts using the correct endpoint
+      const alerts = await fetchAllAlerts(octokit, owner, repo, alertTypes);
+      console.log(`Found ${alerts.length} open alerts`);
+
+      if (alerts.length === 0) {
+        console.log("No alerts found to process.");
+        return;
+      }
+
+      // Process matching alerts
+      const alertsToProcess = [];
+      for (const alert of alerts) {
+        const manifestPath = alert.dependency?.manifest_path;
+        if (manifestPath && matchesAnyPattern(manifestPath, pathPatterns)) {
+          console.log(
+            `Alert #${alert.number} for ${alert.dependency.package.name} in ${manifestPath} matches patterns`,
+          );
+          alertsToProcess.push(alert.number);
+        } else {
+          console.log(
+            `Skipping alert #${alert.number} for ${manifestPath || "unknown path"} (does not match any pattern)`,
+          );
+        }
+      }
+
+      if (alertsToProcess.length === 0) {
+        console.log("No alerts matched the provided path patterns.");
+        return;
+      }
+
+      console.log(`Dismissing ${alertsToProcess.length} alerts...`);
+
+      // Use the correct endpoint to dismiss multiple alerts at once
+      try {
+        for (const alertNumber of alertsToProcess) {
+          await octokit.request(
+            "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}",
+            {
+              owner,
+              repo,
+              alert_number: alertNumber,
+              state: "dismissed",
+              dismissed_reason: dismissalReason as
+                | "fix_started"
+                | "inaccurate"
+                | "no_bandwidth"
+                | "not_used"
+                | "tolerable_risk"
+                | undefined,
+              dismissed_comment: dismissalComment,
+            },
+          );
+          console.log(`Alert #${alertNumber} dismissed successfully`);
+        }
+        console.log(`Successfully dismissed ${alertsToProcess.length} alerts.`);
+      } catch (error) {
+        if (error instanceof RequestError) {
+          if (error.status === 403) {
+            console.error(
+              `Error: Permission denied when trying to dismiss alerts.`,
+            );
+            console.error(
+              `Make sure the GITHUB_TOKEN has 'security-events: write' permission.`,
+            );
+            process.exit(1);
+          } else {
+            console.error(`API Error ${error.status}: ${error.message}`);
+            process.exit(1);
+          }
+        } else {
+          console.error(
+            "Error dismissing alerts:",
+            error instanceof Error ? error.message : String(error),
+          );
+          process.exit(1);
+        }
+      }
+    } catch (error) {
+      if (error instanceof RequestError) {
+        if (error.status === 404) {
+          console.error(
+            `Error: Repository ${owner}/${repo} not found or Dependabot alerts are not enabled.`,
+          );
+          console.error(
+            "Make sure Dependabot alerts are enabled in the repository's Security settings.",
+          );
+          process.exit(1);
+        } else if (
+          error.status === 403 ||
+          error.message.includes("Resource not accessible by integration")
+        ) {
+          console.error(`
+ERROR: Cannot access Dependabot alerts.
+
+This error may occur for several reasons:
+1. Dependabot alerts might not be enabled for this repository
+   - Enable them at: https://github.com/${owner}/${repo}/settings/security_analysis
+   
+2. The token being used might not have sufficient permissions
+   - For GITHUB_TOKEN: Make sure the workflow has 'security-events: write' permission
+   - For fine-grained tokens: Make sure the 'Dependabot alerts: write' permission is enabled
+
+3. Organization policies might be restricting access to security features
+   - Check with your organization administrator
+
+If you're sure the token has the right permissions, try accessing the alerts manually at:
+https://github.com/${owner}/${repo}/security/dependabot
+          `);
+          process.exit(1);
+        } else {
+          console.error(`API Error ${error.status}: ${error.message}`);
+          process.exit(1);
+        }
+      } else {
+        console.error(
+          "Error:",
+          error instanceof Error ? error.message : String(error),
+        );
+        process.exit(1);
+      }
+    }
+  } catch (error) {
+    console.error(
+      "Error:",
+      error instanceof Error ? error.message : String(error),
+    );
+    process.exit(1);
+  }
+}
+
+async function fetchAllAlerts(
+  octokit: Octokit,
+  owner: string,
+  repo: string,
+  alertTypes: string[],
+) {
+  const alerts = [];
+  let page = 1;
+  let hasMorePages = true;
+
+  try {
+    while (hasMorePages) {
+      // Using the dependabot alerts endpoint directly
+      const response = await octokit.request(
+        "GET /repos/{owner}/{repo}/dependabot/alerts",
+        {
+          owner,
+          repo,
+          state: "open",
+          per_page: 100,
+          page,
+        },
+      );
+
+      if (response.data.length === 0) {
+        hasMorePages = false;
+      } else {
+        const filteredAlerts = response.data.filter(
+          (alert) =>
+            alertTypes.includes(alert.security_advisory?.severity as string) ||
+            alertTypes.includes(
+              alert.security_vulnerability?.severity as string,
+            ) ||
+            alertTypes.includes("dependency"),
+        );
+        alerts.push(...filteredAlerts);
+        page++;
+      }
+    }
+
+    return alerts;
+  } catch (error) {
+    // Re-throw to be handled by the main function
+    throw error;
+  }
+}
+
+function matchesAnyPattern(
+  manifestPath: string | undefined,
+  patterns: string[],
+): boolean {
+  if (!manifestPath) return false;
+
+  return patterns.some((pattern) => {
+    try {
+      return minimatch(manifestPath, pattern, { matchBase: true });
+    } catch (error) {
+      console.error(
+        `Error matching pattern ${pattern}:`,
+        error instanceof Error ? error.message : String(error),
+      );
+      return false;
+    }
+  });
+}
+
+run();
path: actions/dependabot-auto-triage/src/index.ts
user: login: guicaulada
body: Done!
created_at: 2025-05-07T14:59:57Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
+description: "Auto dismiss Dependabot alerts based on manifest path"
+inputs:
+  token:
+    description: "GitHub token with permissions to dismiss alerts"
+    required: true
+  alert-types:
+    description: 'Comma-separated list of alert types to dismiss (default: "dependency")'
+    required: false
+    default: "dependency"
+  paths:
+    description: "Multi-line list of glob patterns to match manifest paths to dismiss"
+    required: true
+    # Example: |
+    #   terraform/modules/**/*.json
+    #   docker/vendor/**
+  dismissal-comment:
+    description: "Default comment to add when dismissing alerts"
+    required: false
+    default: "Auto-dismissed based on manifest path configuration"
+  dismissal-reason:
+    description: "Default reason for dismissal"
+    required: false
+    default: "not_used"
+    # Options: 'fix_started', 'inaccurate', 'no_bandwidth', 'not_used', 'tolerable_risk'
path: actions/dependabot-auto-triage/action.yml
user: login: guicaulada
body: Done!
created_at: 2025-05-07T15:00:27Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+# Auto Dismiss Dependabot Alerts
+
+A GitHub composite action to automatically dismiss Dependabot alerts based on manifest paths using glob patterns.
+
+## Usage
+
+This action can be used in a workflow to automatically dismiss Dependabot alerts for specific manifest paths. This is particularly useful for repositories with dependencies that are not directly used in production or for which vulnerabilities may not be relevant.
+
+### Example Workflow
+
+Create a workflow file (e.g., `.github/workflows/auto-dismiss-dependabot-alerts.yml`) with the following content:
+
+```yaml
+name: Auto Dismiss Dependabot Alerts
+
+on:
+  # Run daily to dismiss new alerts
+  schedule:
+    - cron: "0 0 * * *"
+
+  # Allow manual triggering
+  workflow_dispatch:
+
+jobs:
+  auto-dismiss:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      contents: read
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
path: actions/dependabot-auto-triage/README.md
user: login: guicaulada
body: Done!
created_at: 2025-05-07T15:00:34Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+name: "Auto Dismiss Dependabot Alerts"
path: actions/dependabot-auto-triage/action.yml
user: login: guicaulada
body: Done!
created_at: 2025-05-07T15:00:40Z
author_association: MEMBER

PR comments:
user: login: zerok
created_at: 2025-05-07T13:55:21Z
body: I've added the `Release-As: 0.1.0` line so that release-please will not create a 1.0.0 version yet 🙂 

Also please rebase so that you will get the catalog-info tooling 🙂 
author_association: CONTRIBUTOR
user: login: guicaulada
created_at: 2025-05-07T15:08:00Z
body: @zerok Thank you! This was the best PR review ever.
author_association: MEMBER
user: login: zerok
created_at: 2025-05-07T15:33:21Z
body: Thank you! Want to give it another review-round tomorrow if that's fine for you 🙂 
author_association: CONTRIBUTOR