From cb5e0ec753dcb08ecb1f2d54ed82e3ab53b788bd Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Wed, 11 Feb 2026 17:50:46 -0800 Subject: [PATCH 01/17] Add ospo-readiness skill: open source readiness scanner Adds a new skill that scans any GitHub repository for open source readiness across 8 checks: LICENSE, CONTRIBUTING.md, dependency license compatibility, README quality, SECURITY.md, CODE_OF_CONDUCT.md, CI/CD workflows, and issue/PR templates. Produces a scored readiness report with a letter grade (A-F) and actionable recommendations for OSPO review and compliance. --- skills/ospo-readiness/SKILL.md | 313 +++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 skills/ospo-readiness/SKILL.md diff --git a/skills/ospo-readiness/SKILL.md b/skills/ospo-readiness/SKILL.md new file mode 100644 index 000000000..98a960047 --- /dev/null +++ b/skills/ospo-readiness/SKILL.md @@ -0,0 +1,313 @@ +--- +name: ospo-readiness +description: Scan any GitHub repository for open source readiness. Evaluates LICENSE, CONTRIBUTING.md, dependency license compatibility, README quality, SECURITY.md, CODE_OF_CONDUCT.md, CI/CD workflows, and issue/PR templates. Produces a scored readiness report with a letter grade (A–F) and actionable recommendations. Use when evaluating a repo for open source compliance, OSPO review, or community health. Invoke by providing a GitHub owner/repo (e.g. "scan expressjs/express for open source readiness"). +--- + +# Open Source Readiness Scanner + +Evaluate any GitHub repository for open source readiness. Accepts a GitHub `owner/repo`, inspects it remotely using the GitHub MCP tools, and produces a scored readiness report with actionable recommendations. + +## Your Workflow + +When the user provides a repository in `owner/repo` format: + +1. **Parse the input** — Extract the `owner` and `repo` from the user's message. +2. **Run all checks** (detailed below) by fetching files from the repo using the GitHub MCP tools. +3. **Score each check** using the scoring model. +4. **Output the readiness report** in the format specified below. +5. **If the user asks**, create a GitHub Issue on the repo with the report. + +Always run ALL checks before producing the report. Do not stop early. + +--- + +## Check 1: LICENSE File (Weight: High — 3 pts) + +Use `get_file_contents` to look for a license file at these paths (try in order, stop at first match): +- `LICENSE` +- `LICENSE.md` +- `LICENSE.txt` +- `COPYING` + +### Scoring +- **✅ Pass (3 pts):** File exists AND contains a recognized OSI-approved license. Identify it by matching against these SPDX identifiers: `MIT`, `Apache-2.0`, `BSD-2-Clause`, `BSD-3-Clause`, `ISC`, `MPL-2.0`, `LGPL-2.1`, `LGPL-3.0`, `GPL-2.0`, `GPL-3.0`, `AGPL-3.0`, `Unlicense`, `0BSD`, `Artistic-2.0`, `Zlib`, `BSL-1.0`, `PostgreSQL`, `EUPL-1.2`. Look for the license name or SPDX identifier in the file text. +- **⚠️ Partial (1.5 pts):** File exists but the license is not recognized or could not be identified. +- **❌ Fail (0 pts):** No license file found. + +### Recommendation on Fail +> Add a LICENSE file to the repository root. Use https://choosealicense.com to select an appropriate OSI-approved license. + +--- + +## Check 2: CONTRIBUTING.md (Weight: High — 3 pts) + +Use `get_file_contents` to look for: +- `CONTRIBUTING.md` +- `.github/CONTRIBUTING.md` +- `docs/CONTRIBUTING.md` + +Then analyze the content for these key sections (case-insensitive header matching): +- **How to contribute** (look for: "how to", "getting started", "contribute", "contributing") +- **Pull request process** (look for: "pull request", "PR", "submit", "review") +- **Code of Conduct reference** (look for: "code of conduct", "CoC", "behavior") + +### Scoring +- **✅ Pass (3 pts):** File exists AND contains all 3 key sections. +- **⚠️ Partial (1.5 pts):** File exists but is missing 1 or more key sections. +- **❌ Fail (0 pts):** No CONTRIBUTING.md found. + +### Recommendation on Fail +> Add a CONTRIBUTING.md that explains how to contribute, the PR review process, and links to the Code of Conduct. See https://mozillascience.github.io/working-open-workshop/contributing/ for a template. + +--- + +## Check 3: Dependency License Compatibility (Weight: High — 3 pts) + +### Step 1: Detect manifest files +Use `get_file_contents` on the repo root `/` to list files. Look for any of these manifest files: +- `package.json` (Node.js/npm) +- `requirements.txt` or `setup.py` or `pyproject.toml` (Python) +- `go.mod` (Go) +- `Gemfile` (Ruby) +- `pom.xml` or `build.gradle` (Java) +- `Cargo.toml` (Rust) +- `composer.json` (PHP) +- `*.csproj` or `packages.config` (C#/.NET) + +### Step 2: Parse dependencies +Fetch the manifest file contents and extract dependency names. For `package.json`, look at `dependencies` and `devDependencies`. For other formats, extract package names from the relevant fields. + +### Step 3: Check dependency licenses +For each dependency (sample up to 15 to stay efficient): +- For npm packages: use `web_fetch` on `https://registry.npmjs.org/{package}/latest` and check the `license` field. +- For other ecosystems: use `get_file_contents` to check the dependency's GitHub repo LICENSE file if the repo URL is available in the manifest, or use `web_search` to find the license. + +### Step 4: Evaluate compatibility +Flag any dependencies with: +- **Copyleft licenses** (GPL, AGPL) in a project using a permissive license (MIT, Apache, BSD) — this is a compatibility issue. +- **No license / unknown license** — this is a risk. +- **Non-OSI-approved licenses** — flag for review. + +### Scoring +- **✅ Pass (3 pts):** Manifest found, all sampled dependencies have compatible OSI-approved licenses. +- **⚠️ Partial (1.5 pts):** Manifest found, but some dependencies have unknown or potentially incompatible licenses. +- **❌ Fail (0 pts):** No manifest file found, OR multiple dependencies have incompatible or missing licenses. + +### Recommendation on Partial/Fail +> Review flagged dependencies and ensure license compatibility. Consider using a tool like `license-checker` (npm), `pip-licenses` (Python), or `go-licenses` (Go) for a full audit. + +--- + +## Check 4: README.md Quality (Weight: Medium — 2 pts) + +Use `get_file_contents` for `README.md` (or `readme.md`, `Readme.md`). + +Check for these sections (case-insensitive header matching): +- **Project description** (first paragraph or section with "about", "description", "overview", "what is") +- **Installation instructions** (look for: "install", "getting started", "setup", "quick start") +- **Usage examples** (look for: "usage", "example", "how to use", "demo") +- **License mention** (look for: "license" section or badge) + +### Scoring +- **✅ Pass (2 pts):** README exists AND has all 4 sections. +- **⚠️ Partial (1 pt):** README exists but missing 1-2 sections. +- **❌ Fail (0 pts):** No README, or missing 3+ sections. + +### Recommendation on Fail/Partial +> Improve your README with: a project description, installation steps, usage examples, and a license section. See https://www.makeareadme.com for best practices. + +--- + +## Check 5: SECURITY.md (Weight: Medium — 2 pts) + +Use `get_file_contents` to look for: +- `SECURITY.md` +- `.github/SECURITY.md` +- `docs/SECURITY.md` + +### Scoring +- **✅ Pass (2 pts):** Security policy file exists and includes how to report vulnerabilities (look for: "report", "vulnerability", "security", "disclosure", "email", "contact"). +- **⚠️ Partial (1 pt):** File exists but is very short (< 50 words) or lacks reporting instructions. +- **❌ Fail (0 pts):** No security policy found. + +### Recommendation on Fail +> Add a SECURITY.md explaining how to report security vulnerabilities privately. See https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository. + +--- + +## Check 6: CODE_OF_CONDUCT.md (Weight: Medium — 2 pts) + +Use `get_file_contents` to look for: +- `CODE_OF_CONDUCT.md` +- `.github/CODE_OF_CONDUCT.md` + +### Scoring +- **✅ Pass (2 pts):** Code of Conduct file exists. +- **⚠️ Partial (1 pt):** CONTRIBUTING.md references a Code of Conduct, but no standalone CoC file exists. +- **❌ Fail (0 pts):** No Code of Conduct found anywhere. + +### Recommendation on Fail +> Add a CODE_OF_CONDUCT.md. The Contributor Covenant (https://www.contributor-covenant.org) is the most widely adopted standard. + +--- + +## Check 7: CI/CD Workflows (Weight: Low — 1 pt) + +Use `get_file_contents` on `.github/workflows/` to list directory contents. + +### Scoring +- **✅ Pass (1 pt):** At least one `.yml` or `.yaml` workflow file exists. +- **❌ Fail (0 pts):** No workflows directory or no workflow files. + +### Recommendation on Fail +> Add a GitHub Actions workflow for CI (build + test). See https://docs.github.com/en/actions/quickstart. + +--- + +## Check 8: Issue/PR Templates (Weight: Low — 1 pt) + +Use `get_file_contents` to check for any of: +- `.github/ISSUE_TEMPLATE/` (directory with templates) +- `.github/ISSUE_TEMPLATE.md` +- `.github/pull_request_template.md` +- `.github/PULL_REQUEST_TEMPLATE/` + +### Scoring +- **✅ Pass (1 pt):** At least one issue template AND one PR template exist. +- **⚠️ Partial (0.5 pts):** Only one of issue or PR template exists. +- **❌ Fail (0 pts):** No templates found. + +### Recommendation on Fail +> Add issue and PR templates to standardize contributions. See https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests. + +--- + +## Org-Level Community Health Files + +Many organizations host CONTRIBUTING.md, CODE_OF_CONDUCT.md, and SECURITY.md in a `.github` repository at the org level (e.g., `expressjs/.github`). If a file is not found in the repo itself: + +1. Check if the README references it via a link (e.g., `[Code of Conduct]: https://github.com/{org}/.github/blob/HEAD/CODE_OF_CONDUCT.md`). +2. If so, try fetching it from `{org}/.github` using `get_file_contents`. +3. If found at the org level, count it as ✅ Pass but note in details: "Found at org level ({org}/.github)". +4. If not found anywhere, score as ❌ Fail. + +--- + +## Scoring Model + +| Weight | Points | +|--------|--------| +| High | 3 pts | +| Medium | 2 pts | +| Low | 1 pt | + +**Maximum total: 18 points** + +Calculate percentage: `(earned / 18) × 100` + +| Grade | Percentage | +|-------|-----------| +| A | 90–100% | +| B | 75–89% | +| C | 60–74% | +| D | 40–59% | +| F | 0–39% | + +--- + +## Output Format + +Always produce the report in this exact format: + +``` +# 📋 Open Source Readiness Report + +**Repository:** {owner}/{repo} +**Scanned:** {current date} +**Grade:** {letter grade} ({percentage}% — {earned}/{max} pts) + +--- + +## Checklist + +| # | Check | Status | Score | Details | +|---|-------|--------|-------|---------| +| 1 | LICENSE | {✅/⚠️/❌} | {score}/3 | {license type or issue found} | +| 2 | CONTRIBUTING.md | {✅/⚠️/❌} | {score}/3 | {sections found/missing} | +| 3 | Dependency Licenses | {✅/⚠️/❌} | {score}/3 | {summary of findings} | +| 4 | README Quality | {✅/⚠️/❌} | {score}/2 | {sections found/missing} | +| 5 | SECURITY.md | {✅/⚠️/❌} | {score}/2 | {exists/missing} | +| 6 | CODE_OF_CONDUCT.md | {✅/⚠️/❌} | {score}/2 | {exists/missing} | +| 7 | CI/CD Workflows | {✅/⚠️/❌} | {score}/1 | {count of workflows found} | +| 8 | Issue/PR Templates | {✅/⚠️/❌} | {score}/1 | {which templates found} | + +--- + +## 🔍 Detailed Findings + +### 1. LICENSE — {status} +{Detailed explanation of what was found} + +### 2. CONTRIBUTING.md — {status} +{Detailed explanation} + +### 3. Dependency Licenses — {status} +{Table of sampled dependencies and their licenses, flagging any issues} + +### 4. README Quality — {status} +{Sections found and missing} + +### 5. SECURITY.md — {status} +{What was found} + +### 6. CODE_OF_CONDUCT.md — {status} +{What was found} + +### 7. CI/CD Workflows — {status} +{Workflow files found} + +### 8. Issue/PR Templates — {status} +{Templates found} + +--- + +## 📌 Recommendations + +{Numbered list of actionable recommendations, ordered by priority (High → Medium → Low weight items first). Only include recommendations for checks that did not fully pass.} + +--- + +## 🏆 Summary + +{2-3 sentence summary of the repo's open source readiness, highlighting strengths and the most important areas for improvement.} +``` + +--- + +## Creating a GitHub Issue (Optional) + +If the user explicitly asks to create a GitHub Issue with the findings, create an issue on the target repo with: +- **Title:** `Open Source Readiness Report — Grade: {letter grade}` +- **Body:** The full report from above +- **Labels:** If possible, add the label `ospo` or `open-source-readiness` (create the label if needed, or skip labeling if you can't) + +Only do this if the user asks. Never create issues automatically. + +--- + +## Error Handling + +- If `get_file_contents` returns a 404 or permission error for the repo itself, inform the user that the repository may not exist or may be private/inaccessible. +- If a specific file is not found, that's expected — score it as ❌ and move on. +- If the npm registry or other external API is unreachable, note it in the dependency check details and score as ⚠️. +- Always complete all 8 checks even if some fail — never stop early. + +--- + +## Important Rules + +1. **Always use the GitHub MCP tools** — never try to clone, download, or shell out to access the repo. +2. **Be thorough but efficient** — for dependency scanning, sample up to 15 dependencies to avoid excessive API calls. +3. **Be precise in scoring** — follow the scoring rubric exactly. Do not inflate or deflate scores. +4. **Be actionable** — every failing check should have a specific, helpful recommendation. +5. **Stay in scope** — only evaluate what's defined in the 8 checks. Don't add extra opinions unless asked. From d89a8198393df1ae3005c1b75d9031014db7d00a Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Wed, 11 Feb 2026 20:18:46 -0800 Subject: [PATCH 02/17] Add MCP server for dependency license scanning - TypeScript MCP server with 3 tools: - scan_dependencies: clones repo, npm install, license-checker - check_license_compatibility: flags copyleft/unknown/non-OSI - generate_sbom: CycloneDX 1.5 SBOM generation - .mcp.json for auto-start via Copilot CLI - Updated SKILL.md Check 3 to use MCP tools with API fallback - Added optional SBOM generation section --- skills/ospo-readiness/.mcp.json | 9 + skills/ospo-readiness/SKILL.md | 71 +- .../mcp-server/package-lock.json | 1719 +++++++++++++++++ skills/ospo-readiness/mcp-server/package.json | 27 + skills/ospo-readiness/mcp-server/src/index.ts | 280 +++ .../ospo-readiness/mcp-server/tsconfig.json | 14 + 6 files changed, 2090 insertions(+), 30 deletions(-) create mode 100644 skills/ospo-readiness/.mcp.json create mode 100644 skills/ospo-readiness/mcp-server/package-lock.json create mode 100644 skills/ospo-readiness/mcp-server/package.json create mode 100644 skills/ospo-readiness/mcp-server/src/index.ts create mode 100644 skills/ospo-readiness/mcp-server/tsconfig.json diff --git a/skills/ospo-readiness/.mcp.json b/skills/ospo-readiness/.mcp.json new file mode 100644 index 000000000..dbe61e8d5 --- /dev/null +++ b/skills/ospo-readiness/.mcp.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "ospo-readiness": { + "command": "bash", + "args": ["-c", "cd mcp-server && npm install --ignore-scripts 2>/dev/null && npx tsc 2>/dev/null && node dist/index.js"], + "tools": ["*"] + } + } +} diff --git a/skills/ospo-readiness/SKILL.md b/skills/ospo-readiness/SKILL.md index 98a960047..3871c380f 100644 --- a/skills/ospo-readiness/SKILL.md +++ b/skills/ospo-readiness/SKILL.md @@ -63,38 +63,39 @@ Then analyze the content for these key sections (case-insensitive header matchin ## Check 3: Dependency License Compatibility (Weight: High — 3 pts) -### Step 1: Detect manifest files -Use `get_file_contents` on the repo root `/` to list files. Look for any of these manifest files: -- `package.json` (Node.js/npm) -- `requirements.txt` or `setup.py` or `pyproject.toml` (Python) -- `go.mod` (Go) -- `Gemfile` (Ruby) -- `pom.xml` or `build.gradle` (Java) -- `Cargo.toml` (Rust) -- `composer.json` (PHP) -- `*.csproj` or `packages.config` (C#/.NET) - -### Step 2: Parse dependencies -Fetch the manifest file contents and extract dependency names. For `package.json`, look at `dependencies` and `devDependencies`. For other formats, extract package names from the relevant fields. - -### Step 3: Check dependency licenses -For each dependency (sample up to 15 to stay efficient): -- For npm packages: use `web_fetch` on `https://registry.npmjs.org/{package}/latest` and check the `license` field. -- For other ecosystems: use `get_file_contents` to check the dependency's GitHub repo LICENSE file if the repo URL is available in the manifest, or use `web_search` to find the license. - -### Step 4: Evaluate compatibility -Flag any dependencies with: -- **Copyleft licenses** (GPL, AGPL) in a project using a permissive license (MIT, Apache, BSD) — this is a compatibility issue. -- **No license / unknown license** — this is a risk. -- **Non-OSI-approved licenses** — flag for review. +This check uses the **ospo-readiness MCP server** for accurate analysis of all transitive dependencies (not just direct ones). + +### Step 1: Scan dependencies +Call the `scan_dependencies` MCP tool with the repo's `owner` and `repo`: +``` +scan_dependencies({ owner: "expressjs", repo: "express" }) +``` +This clones the repo, runs `npm install`, and returns structured license data for ALL production dependencies (including transitive). + +### Step 2: Check compatibility +Take the project's license (from Check 1) and the dependency list from Step 1, then call: +``` +check_license_compatibility({ projectLicense: "MIT", dependencies: [...] }) +``` +This returns `compatible`, `incompatible`, and `unknown` arrays with reasons for each flag. + +### Step 3: Report findings +Include in the report: +- Total number of dependencies scanned +- License distribution summary (e.g., "60 MIT, 4 ISC, 1 BSD-3-Clause") +- Any incompatible dependencies with the reason +- Any unknown/unlicensed dependencies + +### Fallback +If the MCP server is unavailable (e.g., not installed), fall back to the manual approach: use `get_file_contents` to read `package.json`, extract dependency names, and check licenses via `web_fetch` on `https://registry.npmjs.org/{package}/latest`. Sample up to 15 dependencies. ### Scoring -- **✅ Pass (3 pts):** Manifest found, all sampled dependencies have compatible OSI-approved licenses. -- **⚠️ Partial (1.5 pts):** Manifest found, but some dependencies have unknown or potentially incompatible licenses. -- **❌ Fail (0 pts):** No manifest file found, OR multiple dependencies have incompatible or missing licenses. +- **✅ Pass (3 pts):** All dependencies have compatible OSI-approved licenses (0 incompatible, 0 unknown). +- **⚠️ Partial (1.5 pts):** Some dependencies have unknown licenses, but none are incompatible. +- **❌ Fail (0 pts):** No manifest file found, OR one or more dependencies have incompatible licenses. ### Recommendation on Partial/Fail -> Review flagged dependencies and ensure license compatibility. Consider using a tool like `license-checker` (npm), `pip-licenses` (Python), or `go-licenses` (Go) for a full audit. +> Review flagged dependencies and ensure license compatibility. Run `npx license-checker --production --json` locally for a full audit. --- @@ -284,6 +285,16 @@ Always produce the report in this exact format: --- +## Generating an SBOM (Optional) + +If the user asks for an SBOM (Software Bill of Materials), call the `generate_sbom` MCP tool: +``` +generate_sbom({ owner: "expressjs", repo: "express" }) +``` +This returns a CycloneDX 1.5 SBOM in JSON format with all production dependencies, their versions, licenses, and repository URLs. Present it to the user or save it as a file. + +--- + ## Creating a GitHub Issue (Optional) If the user explicitly asks to create a GitHub Issue with the findings, create an issue on the target repo with: @@ -306,8 +317,8 @@ Only do this if the user asks. Never create issues automatically. ## Important Rules -1. **Always use the GitHub MCP tools** — never try to clone, download, or shell out to access the repo. -2. **Be thorough but efficient** — for dependency scanning, sample up to 15 dependencies to avoid excessive API calls. +1. **Always use the GitHub MCP tools** for file/repo inspection — never try to clone or shell out directly. +2. **Use the ospo-readiness MCP tools** (`scan_dependencies`, `check_license_compatibility`, `generate_sbom`) for dependency analysis when available. 3. **Be precise in scoring** — follow the scoring rubric exactly. Do not inflate or deflate scores. 4. **Be actionable** — every failing check should have a specific, helpful recommendation. 5. **Stay in scope** — only evaluate what's defined in the 8 checks. Don't add extra opinions unless asked. diff --git a/skills/ospo-readiness/mcp-server/package-lock.json b/skills/ospo-readiness/mcp-server/package-lock.json new file mode 100644 index 000000000..d73290cfc --- /dev/null +++ b/skills/ospo-readiness/mcp-server/package-lock.json @@ -0,0 +1,1719 @@ +{ + "name": "ospo-readiness-mcp", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ospo-readiness-mcp", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "license-checker": "^25.0.1", + "tmp-promise": "^3.0.3" + }, + "bin": { + "ospo-readiness-mcp": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^25.2.3", + "typescript": "^5.9.3" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.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" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", + "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/license-checker": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", + "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", + "license": "BSD-3-Clause", + "dependencies": { + "chalk": "^2.4.1", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "read-installed": "~4.0.3", + "semver": "^5.5.0", + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-satisfies": "^4.0.0", + "treeify": "^1.1.0" + }, + "bin": { + "license-checker": "bin/license-checker" + } + }, + "node_modules/license-checker/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "license": "ISC", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "license": "ISC" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/read-installed": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", + "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "license": "MIT", + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "license": "CC0-1.0" + }, + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", + "license": "(MIT AND CC-BY-3.0)" + }, + "node_modules/spdx-satisfies": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", + "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", + "license": "MIT", + "dependencies": { + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + } + } +} diff --git a/skills/ospo-readiness/mcp-server/package.json b/skills/ospo-readiness/mcp-server/package.json new file mode 100644 index 000000000..dfa1c18eb --- /dev/null +++ b/skills/ospo-readiness/mcp-server/package.json @@ -0,0 +1,27 @@ +{ + "name": "ospo-readiness-mcp", + "version": "1.0.0", + "description": "MCP server for OSPO open source readiness dependency scanning", + "main": "dist/index.js", + "bin": "dist/index.js", + "scripts": { + "build": "tsc", + "start": "node dist/index.js" + }, + "keywords": [ + "ospo", + "license", + "mcp", + "open-source" + ], + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "license-checker": "^25.0.1", + "tmp-promise": "^3.0.3" + }, + "devDependencies": { + "@types/node": "^25.2.3", + "typescript": "^5.9.3" + } +} diff --git a/skills/ospo-readiness/mcp-server/src/index.ts b/skills/ospo-readiness/mcp-server/src/index.ts new file mode 100644 index 000000000..4c2091d45 --- /dev/null +++ b/skills/ospo-readiness/mcp-server/src/index.ts @@ -0,0 +1,280 @@ +#!/usr/bin/env node + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { z } from "zod"; +import { execSync } from "child_process"; +import * as path from "path"; +import * as fs from "fs"; +import { dir as tmpDir } from "tmp-promise"; + +// License compatibility data +const COPYLEFT_LICENSES = new Set([ + "GPL-2.0", "GPL-2.0-only", "GPL-2.0-or-later", "GPL-2.0+", + "GPL-3.0", "GPL-3.0-only", "GPL-3.0-or-later", "GPL-3.0+", + "AGPL-3.0", "AGPL-3.0-only", "AGPL-3.0-or-later", + "LGPL-2.1", "LGPL-2.1-only", "LGPL-2.1-or-later", + "LGPL-3.0", "LGPL-3.0-only", "LGPL-3.0-or-later", + "MPL-2.0", "EUPL-1.2", "CECILL-2.1", +]); + +const PERMISSIVE_LICENSES = new Set([ + "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", + "Unlicense", "0BSD", "Artistic-2.0", "Zlib", "BSL-1.0", + "CC0-1.0", "WTFPL", "PostgreSQL", +]); + +const OSI_APPROVED = new Set([...COPYLEFT_LICENSES, ...PERMISSIVE_LICENSES]); + +function normalizeLicense(license: string): string { + const l = license.trim(); + // Handle common variations + const map: Record = { + "MIT": "MIT", + "ISC": "ISC", + "Apache 2.0": "Apache-2.0", + "Apache-2.0": "Apache-2.0", + "Apache License 2.0": "Apache-2.0", + "BSD-2-Clause": "BSD-2-Clause", + "BSD-3-Clause": "BSD-3-Clause", + "BSD": "BSD-3-Clause", + "GPL-2.0": "GPL-2.0", + "GPL-3.0": "GPL-3.0", + "LGPL-2.1": "LGPL-2.1", + "LGPL-3.0": "LGPL-3.0", + "MPL-2.0": "MPL-2.0", + "Unlicense": "Unlicense", + "UNLICENSED": "UNLICENSED", + "CC0-1.0": "CC0-1.0", + "0BSD": "0BSD", + "Python-2.0": "Python-2.0", + "BlueOak-1.0.0": "BlueOak-1.0.0", + }; + return map[l] || l; +} + +interface DepInfo { + name: string; + version: string; + license: string; + repository: string; +} + +interface LicenseCheckerResult { + [key: string]: { + licenses: string; + repository?: string; + licenseFile?: string; + }; +} + +async function cloneAndInstall(owner: string, repo: string, ref?: string): Promise<{ tmpPath: string; cleanup: () => Promise }> { + const { path: tmpPath, cleanup } = await tmpDir({ unsafeCleanup: true }); + const cloneUrl = `https://github.com/${owner}/${repo}.git`; + const cloneArgs = ref ? `--branch ${ref} --depth 1` : "--depth 1"; + + try { + execSync(`git clone ${cloneArgs} ${cloneUrl} ${tmpPath}/repo`, { + stdio: "pipe", + timeout: 60000, + }); + execSync("npm install --ignore-scripts --no-audit --no-fund", { + cwd: path.join(tmpPath, "repo"), + stdio: "pipe", + timeout: 120000, + }); + } catch (err: any) { + await cleanup(); + throw new Error(`Failed to clone/install: ${err.message}`); + } + + return { tmpPath: path.join(tmpPath, "repo"), cleanup }; +} + +async function runLicenseChecker(repoPath: string): Promise { + return new Promise((resolve, reject) => { + const checker = require("license-checker"); + checker.init({ start: repoPath, json: true, production: true }, (err: Error, packages: LicenseCheckerResult) => { + if (err) return reject(err); + + const deps: DepInfo[] = []; + for (const [key, val] of Object.entries(packages)) { + const atIndex = key.lastIndexOf("@"); + if (atIndex <= 0) continue; + const name = key.substring(0, atIndex); + const version = key.substring(atIndex + 1); + deps.push({ + name, + version, + license: normalizeLicense(val.licenses || "UNKNOWN"), + repository: val.repository || "", + }); + } + resolve(deps); + }); + }); +} + +// Create server +const server = new McpServer({ + name: "ospo-readiness-mcp", + version: "1.0.0", +}); + +// Tool 1: scan_dependencies +server.tool( + "scan_dependencies", + "Clone a GitHub repo, install npm dependencies, and return license information for all production dependencies", + { + owner: z.string().describe("GitHub repository owner"), + repo: z.string().describe("GitHub repository name"), + ref: z.string().optional().describe("Git ref (branch/tag) to check out"), + }, + async ({ owner, repo, ref }) => { + let cleanup: (() => Promise) | undefined; + try { + const result = await cloneAndInstall(owner, repo, ref); + cleanup = result.cleanup; + + const deps = await runLicenseChecker(result.tmpPath); + + // Build summary + const byLicense: Record = {}; + for (const dep of deps) { + byLicense[dep.license] = (byLicense[dep.license] || 0) + 1; + } + + const response = { + owner, + repo, + total: deps.length, + dependencies: deps, + summary: { byLicense }, + }; + + return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; + } catch (err: any) { + return { content: [{ type: "text" as const, text: `Error scanning dependencies: ${err.message}` }], isError: true }; + } finally { + if (cleanup) await cleanup(); + } + } +); + +// Tool 2: check_license_compatibility +server.tool( + "check_license_compatibility", + "Check if dependency licenses are compatible with the project's license", + { + projectLicense: z.string().describe("The project's SPDX license identifier (e.g. MIT, Apache-2.0)"), + dependencies: z.array(z.object({ + name: z.string(), + license: z.string(), + })).describe("Array of dependencies with their license identifiers"), + }, + async ({ projectLicense, dependencies }) => { + const normalized = normalizeLicense(projectLicense); + const isProjectPermissive = PERMISSIVE_LICENSES.has(normalized); + + const compatible: Array<{ name: string; license: string }> = []; + const incompatible: Array<{ name: string; license: string; reason: string }> = []; + const unknown: Array<{ name: string; license: string }> = []; + + for (const dep of dependencies) { + const depLicense = normalizeLicense(dep.license); + + if (depLicense === "UNKNOWN" || depLicense === "UNLICENSED" || depLicense === "") { + unknown.push({ name: dep.name, license: dep.license }); + } else if (isProjectPermissive && COPYLEFT_LICENSES.has(depLicense)) { + incompatible.push({ + name: dep.name, + license: depLicense, + reason: `Copyleft license ${depLicense} is incompatible with permissive project license ${normalized}`, + }); + } else if (!OSI_APPROVED.has(depLicense)) { + unknown.push({ name: dep.name, license: depLicense }); + } else { + compatible.push({ name: dep.name, license: depLicense }); + } + } + + const response = { + projectLicense: normalized, + totalChecked: dependencies.length, + compatible, + incompatible, + unknown, + summary: { + compatible: compatible.length, + incompatible: incompatible.length, + unknown: unknown.length, + }, + }; + + return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; + } +); + +// Tool 3: generate_sbom +server.tool( + "generate_sbom", + "Clone a GitHub repo and generate a CycloneDX SBOM (Software Bill of Materials) from its npm dependencies", + { + owner: z.string().describe("GitHub repository owner"), + repo: z.string().describe("GitHub repository name"), + ref: z.string().optional().describe("Git ref (branch/tag) to check out"), + }, + async ({ owner, repo, ref }) => { + let cleanup: (() => Promise) | undefined; + try { + const result = await cloneAndInstall(owner, repo, ref); + cleanup = result.cleanup; + + const deps = await runLicenseChecker(result.tmpPath); + + // Read project package.json for metadata + const pkgJsonPath = path.join(result.tmpPath, "package.json"); + const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")); + + // Build CycloneDX-like SBOM + const sbom = { + bomFormat: "CycloneDX", + specVersion: "1.5", + version: 1, + metadata: { + timestamp: new Date().toISOString(), + component: { + type: "application", + name: pkgJson.name || `${owner}/${repo}`, + version: pkgJson.version || "0.0.0", + licenses: pkgJson.license ? [{ license: { id: normalizeLicense(pkgJson.license) } }] : [], + }, + tools: [{ name: "ospo-readiness-mcp", version: "1.0.0" }], + }, + components: deps.map((dep) => ({ + type: "library", + name: dep.name, + version: dep.version, + licenses: [{ license: { id: dep.license } }], + externalReferences: dep.repository + ? [{ type: "vcs", url: dep.repository }] + : [], + })), + }; + + return { content: [{ type: "text" as const, text: JSON.stringify(sbom, null, 2) }] }; + } catch (err: any) { + return { content: [{ type: "text" as const, text: `Error generating SBOM: ${err.message}` }], isError: true }; + } finally { + if (cleanup) await cleanup(); + } + } +); + +// Start server +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); +} + +main().catch(console.error); diff --git a/skills/ospo-readiness/mcp-server/tsconfig.json b/skills/ospo-readiness/mcp-server/tsconfig.json new file mode 100644 index 000000000..8d4e7cc6a --- /dev/null +++ b/skills/ospo-readiness/mcp-server/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true + }, + "include": ["src/**/*"] +} From 7add2c47303718969ff8829c45c380720cf0dabb Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Wed, 11 Feb 2026 20:22:58 -0800 Subject: [PATCH 03/17] Revert "Add MCP server for dependency license scanning" This reverts commit d89a8198393df1ae3005c1b75d9031014db7d00a. --- skills/ospo-readiness/.mcp.json | 9 - skills/ospo-readiness/SKILL.md | 71 +- .../mcp-server/package-lock.json | 1719 ----------------- skills/ospo-readiness/mcp-server/package.json | 27 - skills/ospo-readiness/mcp-server/src/index.ts | 280 --- .../ospo-readiness/mcp-server/tsconfig.json | 14 - 6 files changed, 30 insertions(+), 2090 deletions(-) delete mode 100644 skills/ospo-readiness/.mcp.json delete mode 100644 skills/ospo-readiness/mcp-server/package-lock.json delete mode 100644 skills/ospo-readiness/mcp-server/package.json delete mode 100644 skills/ospo-readiness/mcp-server/src/index.ts delete mode 100644 skills/ospo-readiness/mcp-server/tsconfig.json diff --git a/skills/ospo-readiness/.mcp.json b/skills/ospo-readiness/.mcp.json deleted file mode 100644 index dbe61e8d5..000000000 --- a/skills/ospo-readiness/.mcp.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "mcpServers": { - "ospo-readiness": { - "command": "bash", - "args": ["-c", "cd mcp-server && npm install --ignore-scripts 2>/dev/null && npx tsc 2>/dev/null && node dist/index.js"], - "tools": ["*"] - } - } -} diff --git a/skills/ospo-readiness/SKILL.md b/skills/ospo-readiness/SKILL.md index 3871c380f..98a960047 100644 --- a/skills/ospo-readiness/SKILL.md +++ b/skills/ospo-readiness/SKILL.md @@ -63,39 +63,38 @@ Then analyze the content for these key sections (case-insensitive header matchin ## Check 3: Dependency License Compatibility (Weight: High — 3 pts) -This check uses the **ospo-readiness MCP server** for accurate analysis of all transitive dependencies (not just direct ones). - -### Step 1: Scan dependencies -Call the `scan_dependencies` MCP tool with the repo's `owner` and `repo`: -``` -scan_dependencies({ owner: "expressjs", repo: "express" }) -``` -This clones the repo, runs `npm install`, and returns structured license data for ALL production dependencies (including transitive). - -### Step 2: Check compatibility -Take the project's license (from Check 1) and the dependency list from Step 1, then call: -``` -check_license_compatibility({ projectLicense: "MIT", dependencies: [...] }) -``` -This returns `compatible`, `incompatible`, and `unknown` arrays with reasons for each flag. - -### Step 3: Report findings -Include in the report: -- Total number of dependencies scanned -- License distribution summary (e.g., "60 MIT, 4 ISC, 1 BSD-3-Clause") -- Any incompatible dependencies with the reason -- Any unknown/unlicensed dependencies - -### Fallback -If the MCP server is unavailable (e.g., not installed), fall back to the manual approach: use `get_file_contents` to read `package.json`, extract dependency names, and check licenses via `web_fetch` on `https://registry.npmjs.org/{package}/latest`. Sample up to 15 dependencies. +### Step 1: Detect manifest files +Use `get_file_contents` on the repo root `/` to list files. Look for any of these manifest files: +- `package.json` (Node.js/npm) +- `requirements.txt` or `setup.py` or `pyproject.toml` (Python) +- `go.mod` (Go) +- `Gemfile` (Ruby) +- `pom.xml` or `build.gradle` (Java) +- `Cargo.toml` (Rust) +- `composer.json` (PHP) +- `*.csproj` or `packages.config` (C#/.NET) + +### Step 2: Parse dependencies +Fetch the manifest file contents and extract dependency names. For `package.json`, look at `dependencies` and `devDependencies`. For other formats, extract package names from the relevant fields. + +### Step 3: Check dependency licenses +For each dependency (sample up to 15 to stay efficient): +- For npm packages: use `web_fetch` on `https://registry.npmjs.org/{package}/latest` and check the `license` field. +- For other ecosystems: use `get_file_contents` to check the dependency's GitHub repo LICENSE file if the repo URL is available in the manifest, or use `web_search` to find the license. + +### Step 4: Evaluate compatibility +Flag any dependencies with: +- **Copyleft licenses** (GPL, AGPL) in a project using a permissive license (MIT, Apache, BSD) — this is a compatibility issue. +- **No license / unknown license** — this is a risk. +- **Non-OSI-approved licenses** — flag for review. ### Scoring -- **✅ Pass (3 pts):** All dependencies have compatible OSI-approved licenses (0 incompatible, 0 unknown). -- **⚠️ Partial (1.5 pts):** Some dependencies have unknown licenses, but none are incompatible. -- **❌ Fail (0 pts):** No manifest file found, OR one or more dependencies have incompatible licenses. +- **✅ Pass (3 pts):** Manifest found, all sampled dependencies have compatible OSI-approved licenses. +- **⚠️ Partial (1.5 pts):** Manifest found, but some dependencies have unknown or potentially incompatible licenses. +- **❌ Fail (0 pts):** No manifest file found, OR multiple dependencies have incompatible or missing licenses. ### Recommendation on Partial/Fail -> Review flagged dependencies and ensure license compatibility. Run `npx license-checker --production --json` locally for a full audit. +> Review flagged dependencies and ensure license compatibility. Consider using a tool like `license-checker` (npm), `pip-licenses` (Python), or `go-licenses` (Go) for a full audit. --- @@ -285,16 +284,6 @@ Always produce the report in this exact format: --- -## Generating an SBOM (Optional) - -If the user asks for an SBOM (Software Bill of Materials), call the `generate_sbom` MCP tool: -``` -generate_sbom({ owner: "expressjs", repo: "express" }) -``` -This returns a CycloneDX 1.5 SBOM in JSON format with all production dependencies, their versions, licenses, and repository URLs. Present it to the user or save it as a file. - ---- - ## Creating a GitHub Issue (Optional) If the user explicitly asks to create a GitHub Issue with the findings, create an issue on the target repo with: @@ -317,8 +306,8 @@ Only do this if the user asks. Never create issues automatically. ## Important Rules -1. **Always use the GitHub MCP tools** for file/repo inspection — never try to clone or shell out directly. -2. **Use the ospo-readiness MCP tools** (`scan_dependencies`, `check_license_compatibility`, `generate_sbom`) for dependency analysis when available. +1. **Always use the GitHub MCP tools** — never try to clone, download, or shell out to access the repo. +2. **Be thorough but efficient** — for dependency scanning, sample up to 15 dependencies to avoid excessive API calls. 3. **Be precise in scoring** — follow the scoring rubric exactly. Do not inflate or deflate scores. 4. **Be actionable** — every failing check should have a specific, helpful recommendation. 5. **Stay in scope** — only evaluate what's defined in the 8 checks. Don't add extra opinions unless asked. diff --git a/skills/ospo-readiness/mcp-server/package-lock.json b/skills/ospo-readiness/mcp-server/package-lock.json deleted file mode 100644 index d73290cfc..000000000 --- a/skills/ospo-readiness/mcp-server/package-lock.json +++ /dev/null @@ -1,1719 +0,0 @@ -{ - "name": "ospo-readiness-mcp", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "ospo-readiness-mcp", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "license-checker": "^25.0.1", - "tmp-promise": "^3.0.3" - }, - "bin": { - "ospo-readiness-mcp": "dist/index.js" - }, - "devDependencies": { - "@types/node": "^25.2.3", - "typescript": "^5.9.3" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@types/node": { - "version": "25.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", - "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC" - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.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" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", - "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", - "license": "MIT", - "dependencies": { - "ip-address": "10.0.1" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", - "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "license": "ISC" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "license": "BSD-3-Clause", - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" - }, - "bin": { - "license-checker": "bin/license-checker" - } - }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "license": "ISC", - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "license": "ISC" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "license": "ISC", - "engines": { - "node": "*" - } - }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "license": "MIT", - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "license": "CC0-1.0" - }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "license": "(MIT AND CC-BY-3.0)" - }, - "node_modules/spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "license": "MIT", - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "license": "MIT", - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "license": "MIT" - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - } - } -} diff --git a/skills/ospo-readiness/mcp-server/package.json b/skills/ospo-readiness/mcp-server/package.json deleted file mode 100644 index dfa1c18eb..000000000 --- a/skills/ospo-readiness/mcp-server/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "ospo-readiness-mcp", - "version": "1.0.0", - "description": "MCP server for OSPO open source readiness dependency scanning", - "main": "dist/index.js", - "bin": "dist/index.js", - "scripts": { - "build": "tsc", - "start": "node dist/index.js" - }, - "keywords": [ - "ospo", - "license", - "mcp", - "open-source" - ], - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "license-checker": "^25.0.1", - "tmp-promise": "^3.0.3" - }, - "devDependencies": { - "@types/node": "^25.2.3", - "typescript": "^5.9.3" - } -} diff --git a/skills/ospo-readiness/mcp-server/src/index.ts b/skills/ospo-readiness/mcp-server/src/index.ts deleted file mode 100644 index 4c2091d45..000000000 --- a/skills/ospo-readiness/mcp-server/src/index.ts +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env node - -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { z } from "zod"; -import { execSync } from "child_process"; -import * as path from "path"; -import * as fs from "fs"; -import { dir as tmpDir } from "tmp-promise"; - -// License compatibility data -const COPYLEFT_LICENSES = new Set([ - "GPL-2.0", "GPL-2.0-only", "GPL-2.0-or-later", "GPL-2.0+", - "GPL-3.0", "GPL-3.0-only", "GPL-3.0-or-later", "GPL-3.0+", - "AGPL-3.0", "AGPL-3.0-only", "AGPL-3.0-or-later", - "LGPL-2.1", "LGPL-2.1-only", "LGPL-2.1-or-later", - "LGPL-3.0", "LGPL-3.0-only", "LGPL-3.0-or-later", - "MPL-2.0", "EUPL-1.2", "CECILL-2.1", -]); - -const PERMISSIVE_LICENSES = new Set([ - "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", - "Unlicense", "0BSD", "Artistic-2.0", "Zlib", "BSL-1.0", - "CC0-1.0", "WTFPL", "PostgreSQL", -]); - -const OSI_APPROVED = new Set([...COPYLEFT_LICENSES, ...PERMISSIVE_LICENSES]); - -function normalizeLicense(license: string): string { - const l = license.trim(); - // Handle common variations - const map: Record = { - "MIT": "MIT", - "ISC": "ISC", - "Apache 2.0": "Apache-2.0", - "Apache-2.0": "Apache-2.0", - "Apache License 2.0": "Apache-2.0", - "BSD-2-Clause": "BSD-2-Clause", - "BSD-3-Clause": "BSD-3-Clause", - "BSD": "BSD-3-Clause", - "GPL-2.0": "GPL-2.0", - "GPL-3.0": "GPL-3.0", - "LGPL-2.1": "LGPL-2.1", - "LGPL-3.0": "LGPL-3.0", - "MPL-2.0": "MPL-2.0", - "Unlicense": "Unlicense", - "UNLICENSED": "UNLICENSED", - "CC0-1.0": "CC0-1.0", - "0BSD": "0BSD", - "Python-2.0": "Python-2.0", - "BlueOak-1.0.0": "BlueOak-1.0.0", - }; - return map[l] || l; -} - -interface DepInfo { - name: string; - version: string; - license: string; - repository: string; -} - -interface LicenseCheckerResult { - [key: string]: { - licenses: string; - repository?: string; - licenseFile?: string; - }; -} - -async function cloneAndInstall(owner: string, repo: string, ref?: string): Promise<{ tmpPath: string; cleanup: () => Promise }> { - const { path: tmpPath, cleanup } = await tmpDir({ unsafeCleanup: true }); - const cloneUrl = `https://github.com/${owner}/${repo}.git`; - const cloneArgs = ref ? `--branch ${ref} --depth 1` : "--depth 1"; - - try { - execSync(`git clone ${cloneArgs} ${cloneUrl} ${tmpPath}/repo`, { - stdio: "pipe", - timeout: 60000, - }); - execSync("npm install --ignore-scripts --no-audit --no-fund", { - cwd: path.join(tmpPath, "repo"), - stdio: "pipe", - timeout: 120000, - }); - } catch (err: any) { - await cleanup(); - throw new Error(`Failed to clone/install: ${err.message}`); - } - - return { tmpPath: path.join(tmpPath, "repo"), cleanup }; -} - -async function runLicenseChecker(repoPath: string): Promise { - return new Promise((resolve, reject) => { - const checker = require("license-checker"); - checker.init({ start: repoPath, json: true, production: true }, (err: Error, packages: LicenseCheckerResult) => { - if (err) return reject(err); - - const deps: DepInfo[] = []; - for (const [key, val] of Object.entries(packages)) { - const atIndex = key.lastIndexOf("@"); - if (atIndex <= 0) continue; - const name = key.substring(0, atIndex); - const version = key.substring(atIndex + 1); - deps.push({ - name, - version, - license: normalizeLicense(val.licenses || "UNKNOWN"), - repository: val.repository || "", - }); - } - resolve(deps); - }); - }); -} - -// Create server -const server = new McpServer({ - name: "ospo-readiness-mcp", - version: "1.0.0", -}); - -// Tool 1: scan_dependencies -server.tool( - "scan_dependencies", - "Clone a GitHub repo, install npm dependencies, and return license information for all production dependencies", - { - owner: z.string().describe("GitHub repository owner"), - repo: z.string().describe("GitHub repository name"), - ref: z.string().optional().describe("Git ref (branch/tag) to check out"), - }, - async ({ owner, repo, ref }) => { - let cleanup: (() => Promise) | undefined; - try { - const result = await cloneAndInstall(owner, repo, ref); - cleanup = result.cleanup; - - const deps = await runLicenseChecker(result.tmpPath); - - // Build summary - const byLicense: Record = {}; - for (const dep of deps) { - byLicense[dep.license] = (byLicense[dep.license] || 0) + 1; - } - - const response = { - owner, - repo, - total: deps.length, - dependencies: deps, - summary: { byLicense }, - }; - - return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; - } catch (err: any) { - return { content: [{ type: "text" as const, text: `Error scanning dependencies: ${err.message}` }], isError: true }; - } finally { - if (cleanup) await cleanup(); - } - } -); - -// Tool 2: check_license_compatibility -server.tool( - "check_license_compatibility", - "Check if dependency licenses are compatible with the project's license", - { - projectLicense: z.string().describe("The project's SPDX license identifier (e.g. MIT, Apache-2.0)"), - dependencies: z.array(z.object({ - name: z.string(), - license: z.string(), - })).describe("Array of dependencies with their license identifiers"), - }, - async ({ projectLicense, dependencies }) => { - const normalized = normalizeLicense(projectLicense); - const isProjectPermissive = PERMISSIVE_LICENSES.has(normalized); - - const compatible: Array<{ name: string; license: string }> = []; - const incompatible: Array<{ name: string; license: string; reason: string }> = []; - const unknown: Array<{ name: string; license: string }> = []; - - for (const dep of dependencies) { - const depLicense = normalizeLicense(dep.license); - - if (depLicense === "UNKNOWN" || depLicense === "UNLICENSED" || depLicense === "") { - unknown.push({ name: dep.name, license: dep.license }); - } else if (isProjectPermissive && COPYLEFT_LICENSES.has(depLicense)) { - incompatible.push({ - name: dep.name, - license: depLicense, - reason: `Copyleft license ${depLicense} is incompatible with permissive project license ${normalized}`, - }); - } else if (!OSI_APPROVED.has(depLicense)) { - unknown.push({ name: dep.name, license: depLicense }); - } else { - compatible.push({ name: dep.name, license: depLicense }); - } - } - - const response = { - projectLicense: normalized, - totalChecked: dependencies.length, - compatible, - incompatible, - unknown, - summary: { - compatible: compatible.length, - incompatible: incompatible.length, - unknown: unknown.length, - }, - }; - - return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; - } -); - -// Tool 3: generate_sbom -server.tool( - "generate_sbom", - "Clone a GitHub repo and generate a CycloneDX SBOM (Software Bill of Materials) from its npm dependencies", - { - owner: z.string().describe("GitHub repository owner"), - repo: z.string().describe("GitHub repository name"), - ref: z.string().optional().describe("Git ref (branch/tag) to check out"), - }, - async ({ owner, repo, ref }) => { - let cleanup: (() => Promise) | undefined; - try { - const result = await cloneAndInstall(owner, repo, ref); - cleanup = result.cleanup; - - const deps = await runLicenseChecker(result.tmpPath); - - // Read project package.json for metadata - const pkgJsonPath = path.join(result.tmpPath, "package.json"); - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")); - - // Build CycloneDX-like SBOM - const sbom = { - bomFormat: "CycloneDX", - specVersion: "1.5", - version: 1, - metadata: { - timestamp: new Date().toISOString(), - component: { - type: "application", - name: pkgJson.name || `${owner}/${repo}`, - version: pkgJson.version || "0.0.0", - licenses: pkgJson.license ? [{ license: { id: normalizeLicense(pkgJson.license) } }] : [], - }, - tools: [{ name: "ospo-readiness-mcp", version: "1.0.0" }], - }, - components: deps.map((dep) => ({ - type: "library", - name: dep.name, - version: dep.version, - licenses: [{ license: { id: dep.license } }], - externalReferences: dep.repository - ? [{ type: "vcs", url: dep.repository }] - : [], - })), - }; - - return { content: [{ type: "text" as const, text: JSON.stringify(sbom, null, 2) }] }; - } catch (err: any) { - return { content: [{ type: "text" as const, text: `Error generating SBOM: ${err.message}` }], isError: true }; - } finally { - if (cleanup) await cleanup(); - } - } -); - -// Start server -async function main() { - const transport = new StdioServerTransport(); - await server.connect(transport); -} - -main().catch(console.error); diff --git a/skills/ospo-readiness/mcp-server/tsconfig.json b/skills/ospo-readiness/mcp-server/tsconfig.json deleted file mode 100644 index 8d4e7cc6a..000000000 --- a/skills/ospo-readiness/mcp-server/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16", - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "declaration": true - }, - "include": ["src/**/*"] -} From 48d7d16fa2ffae0fc681e161904218397eb69177 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Wed, 11 Feb 2026 20:23:59 -0800 Subject: [PATCH 04/17] Add ospo-dependency-scanner skill: MCP-powered npm license scanning Separate skill with a TypeScript MCP server that provides: - scan_dependencies: clones repo, npm install, license-checker for all transitive deps - check_license_compatibility: flags copyleft/unknown/non-OSI conflicts - generate_sbom: CycloneDX 1.5 SBOM generation Works alongside the ospo-readiness skill (unchanged). --- skills/ospo-dependency-scanner/.mcp.json | 9 + skills/ospo-dependency-scanner/SKILL.md | 122 ++ .../mcp-server/package-lock.json | 1719 +++++++++++++++++ .../mcp-server/package.json | 27 + .../mcp-server/src/index.ts | 280 +++ .../mcp-server/tsconfig.json | 14 + 6 files changed, 2171 insertions(+) create mode 100644 skills/ospo-dependency-scanner/.mcp.json create mode 100644 skills/ospo-dependency-scanner/SKILL.md create mode 100644 skills/ospo-dependency-scanner/mcp-server/package-lock.json create mode 100644 skills/ospo-dependency-scanner/mcp-server/package.json create mode 100644 skills/ospo-dependency-scanner/mcp-server/src/index.ts create mode 100644 skills/ospo-dependency-scanner/mcp-server/tsconfig.json diff --git a/skills/ospo-dependency-scanner/.mcp.json b/skills/ospo-dependency-scanner/.mcp.json new file mode 100644 index 000000000..9200ebfde --- /dev/null +++ b/skills/ospo-dependency-scanner/.mcp.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "ospo-dependency-scanner": { + "command": "bash", + "args": ["-c", "cd mcp-server && npm install --ignore-scripts 2>/dev/null && npx tsc 2>/dev/null && node dist/index.js"], + "tools": ["*"] + } + } +} diff --git a/skills/ospo-dependency-scanner/SKILL.md b/skills/ospo-dependency-scanner/SKILL.md new file mode 100644 index 000000000..6e71b3f9f --- /dev/null +++ b/skills/ospo-dependency-scanner/SKILL.md @@ -0,0 +1,122 @@ +--- +name: ospo-dependency-scanner +description: Scan npm dependencies for license compliance. Clones a GitHub repo, installs dependencies, and analyzes all transitive dependency licenses using license-checker. Checks compatibility with the project license, flags copyleft-in-permissive conflicts, and generates CycloneDX SBOMs. Use when the user wants to audit dependency licenses, check license compatibility, or generate an SBOM for a Node.js project. +--- + +# OSPO Dependency Scanner + +Scan any GitHub repository's npm dependencies for license compliance. This skill uses an MCP server that clones the repo locally, runs `npm install`, and analyzes all production dependencies (including transitive) using `license-checker`. + +## Available MCP Tools + +### `scan_dependencies` +Clone a GitHub repo, install npm dependencies, and return license information for all production dependencies. + +**Input:** +- `owner` (string) — GitHub repository owner +- `repo` (string) — GitHub repository name +- `ref` (string, optional) — Git ref (branch/tag) to check out + +**Output:** JSON with: +- `total` — number of dependencies found +- `dependencies` — array of `{ name, version, license, repository }` for every production dependency +- `summary.byLicense` — count of dependencies grouped by license type + +**Example:** +``` +scan_dependencies({ owner: "expressjs", repo: "express" }) +→ { total: 65, dependencies: [...], summary: { byLicense: { MIT: 60, ISC: 4, "BSD-3-Clause": 1 } } } +``` + +### `check_license_compatibility` +Check if dependency licenses are compatible with the project's license. + +**Input:** +- `projectLicense` (string) — The project's SPDX license identifier (e.g. `MIT`, `Apache-2.0`) +- `dependencies` (array) — Array of `{ name, license }` objects (use output from `scan_dependencies`) + +**Output:** JSON with: +- `compatible` — dependencies with compatible licenses +- `incompatible` — dependencies with incompatible licenses + reason (e.g., copyleft in permissive project) +- `unknown` — dependencies with unknown or unrecognized licenses +- `summary` — counts of each category + +**Example:** +``` +check_license_compatibility({ + projectLicense: "MIT", + dependencies: [ + { name: "accepts", license: "MIT" }, + { name: "some-gpl-pkg", license: "GPL-3.0" } + ] +}) +→ { compatible: [{ name: "accepts", license: "MIT" }], + incompatible: [{ name: "some-gpl-pkg", license: "GPL-3.0", reason: "Copyleft license GPL-3.0 is incompatible with permissive project license MIT" }], + unknown: [] } +``` + +### `generate_sbom` +Clone a GitHub repo and generate a CycloneDX 1.5 SBOM (Software Bill of Materials) from its npm dependencies. + +**Input:** +- `owner` (string) — GitHub repository owner +- `repo` (string) — GitHub repository name +- `ref` (string, optional) — Git ref (branch/tag) to check out + +**Output:** CycloneDX 1.5 JSON document with: +- `metadata` — project name, version, license, scan timestamp +- `components` — every production dependency with name, version, license, and VCS URL + +## Typical Workflow + +When a user asks to scan dependencies or check license compliance: + +1. **Call `scan_dependencies`** with the repo's owner and name +2. **Determine the project license** from the scan results (the project itself is included in the output) or ask the user +3. **Call `check_license_compatibility`** with the project license and the dependency list +4. **Present results** in a clear format: + - Total dependencies scanned + - License distribution (e.g., "60 MIT, 4 ISC, 1 BSD-3-Clause") + - ⚠️ Any incompatible dependencies with reasons + - ❓ Any unknown/unlicensed dependencies + - ✅ Overall compatibility verdict + +If the user asks for an SBOM, call `generate_sbom` and present or save the CycloneDX JSON. + +## Supported Ecosystems + +Currently supports **Node.js/npm** only. The MCP server: +- Clones the repo to a temp directory +- Runs `npm install --ignore-scripts --production` +- Uses `license-checker` to analyze `node_modules` +- Cleans up the temp directory after scanning + +Future: Python (pip-licenses), Go (go-licenses), Rust (cargo-license). + +## Error Handling + +- If the repo doesn't exist or is private, the tool returns an error message — inform the user. +- If `npm install` fails (e.g., no `package.json`), the tool returns an error — note that this skill only works for npm projects. +- Network issues during clone will timeout after 60 seconds. + +## Example Output Format + +``` +## 📦 Dependency License Scan: expressjs/express + +**Total dependencies:** 65 (production, including transitive) + +### License Distribution +| License | Count | +|---------|-------| +| MIT | 60 | +| ISC | 4 | +| BSD-3-Clause | 1 | + +### Compatibility with MIT License +- ✅ **65 compatible** — all dependencies use permissive licenses +- ⚠️ **0 incompatible** +- ❓ **0 unknown** + +**Verdict:** ✅ All dependency licenses are compatible with MIT. +``` diff --git a/skills/ospo-dependency-scanner/mcp-server/package-lock.json b/skills/ospo-dependency-scanner/mcp-server/package-lock.json new file mode 100644 index 000000000..d73290cfc --- /dev/null +++ b/skills/ospo-dependency-scanner/mcp-server/package-lock.json @@ -0,0 +1,1719 @@ +{ + "name": "ospo-readiness-mcp", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ospo-readiness-mcp", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "license-checker": "^25.0.1", + "tmp-promise": "^3.0.3" + }, + "bin": { + "ospo-readiness-mcp": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^25.2.3", + "typescript": "^5.9.3" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.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" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", + "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/license-checker": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", + "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", + "license": "BSD-3-Clause", + "dependencies": { + "chalk": "^2.4.1", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "read-installed": "~4.0.3", + "semver": "^5.5.0", + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-satisfies": "^4.0.0", + "treeify": "^1.1.0" + }, + "bin": { + "license-checker": "bin/license-checker" + } + }, + "node_modules/license-checker/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "license": "ISC", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "license": "ISC" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/read-installed": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", + "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "license": "MIT", + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "license": "CC0-1.0" + }, + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", + "license": "(MIT AND CC-BY-3.0)" + }, + "node_modules/spdx-satisfies": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", + "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", + "license": "MIT", + "dependencies": { + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + } + } +} diff --git a/skills/ospo-dependency-scanner/mcp-server/package.json b/skills/ospo-dependency-scanner/mcp-server/package.json new file mode 100644 index 000000000..dfa1c18eb --- /dev/null +++ b/skills/ospo-dependency-scanner/mcp-server/package.json @@ -0,0 +1,27 @@ +{ + "name": "ospo-readiness-mcp", + "version": "1.0.0", + "description": "MCP server for OSPO open source readiness dependency scanning", + "main": "dist/index.js", + "bin": "dist/index.js", + "scripts": { + "build": "tsc", + "start": "node dist/index.js" + }, + "keywords": [ + "ospo", + "license", + "mcp", + "open-source" + ], + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "license-checker": "^25.0.1", + "tmp-promise": "^3.0.3" + }, + "devDependencies": { + "@types/node": "^25.2.3", + "typescript": "^5.9.3" + } +} diff --git a/skills/ospo-dependency-scanner/mcp-server/src/index.ts b/skills/ospo-dependency-scanner/mcp-server/src/index.ts new file mode 100644 index 000000000..4c2091d45 --- /dev/null +++ b/skills/ospo-dependency-scanner/mcp-server/src/index.ts @@ -0,0 +1,280 @@ +#!/usr/bin/env node + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { z } from "zod"; +import { execSync } from "child_process"; +import * as path from "path"; +import * as fs from "fs"; +import { dir as tmpDir } from "tmp-promise"; + +// License compatibility data +const COPYLEFT_LICENSES = new Set([ + "GPL-2.0", "GPL-2.0-only", "GPL-2.0-or-later", "GPL-2.0+", + "GPL-3.0", "GPL-3.0-only", "GPL-3.0-or-later", "GPL-3.0+", + "AGPL-3.0", "AGPL-3.0-only", "AGPL-3.0-or-later", + "LGPL-2.1", "LGPL-2.1-only", "LGPL-2.1-or-later", + "LGPL-3.0", "LGPL-3.0-only", "LGPL-3.0-or-later", + "MPL-2.0", "EUPL-1.2", "CECILL-2.1", +]); + +const PERMISSIVE_LICENSES = new Set([ + "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", + "Unlicense", "0BSD", "Artistic-2.0", "Zlib", "BSL-1.0", + "CC0-1.0", "WTFPL", "PostgreSQL", +]); + +const OSI_APPROVED = new Set([...COPYLEFT_LICENSES, ...PERMISSIVE_LICENSES]); + +function normalizeLicense(license: string): string { + const l = license.trim(); + // Handle common variations + const map: Record = { + "MIT": "MIT", + "ISC": "ISC", + "Apache 2.0": "Apache-2.0", + "Apache-2.0": "Apache-2.0", + "Apache License 2.0": "Apache-2.0", + "BSD-2-Clause": "BSD-2-Clause", + "BSD-3-Clause": "BSD-3-Clause", + "BSD": "BSD-3-Clause", + "GPL-2.0": "GPL-2.0", + "GPL-3.0": "GPL-3.0", + "LGPL-2.1": "LGPL-2.1", + "LGPL-3.0": "LGPL-3.0", + "MPL-2.0": "MPL-2.0", + "Unlicense": "Unlicense", + "UNLICENSED": "UNLICENSED", + "CC0-1.0": "CC0-1.0", + "0BSD": "0BSD", + "Python-2.0": "Python-2.0", + "BlueOak-1.0.0": "BlueOak-1.0.0", + }; + return map[l] || l; +} + +interface DepInfo { + name: string; + version: string; + license: string; + repository: string; +} + +interface LicenseCheckerResult { + [key: string]: { + licenses: string; + repository?: string; + licenseFile?: string; + }; +} + +async function cloneAndInstall(owner: string, repo: string, ref?: string): Promise<{ tmpPath: string; cleanup: () => Promise }> { + const { path: tmpPath, cleanup } = await tmpDir({ unsafeCleanup: true }); + const cloneUrl = `https://github.com/${owner}/${repo}.git`; + const cloneArgs = ref ? `--branch ${ref} --depth 1` : "--depth 1"; + + try { + execSync(`git clone ${cloneArgs} ${cloneUrl} ${tmpPath}/repo`, { + stdio: "pipe", + timeout: 60000, + }); + execSync("npm install --ignore-scripts --no-audit --no-fund", { + cwd: path.join(tmpPath, "repo"), + stdio: "pipe", + timeout: 120000, + }); + } catch (err: any) { + await cleanup(); + throw new Error(`Failed to clone/install: ${err.message}`); + } + + return { tmpPath: path.join(tmpPath, "repo"), cleanup }; +} + +async function runLicenseChecker(repoPath: string): Promise { + return new Promise((resolve, reject) => { + const checker = require("license-checker"); + checker.init({ start: repoPath, json: true, production: true }, (err: Error, packages: LicenseCheckerResult) => { + if (err) return reject(err); + + const deps: DepInfo[] = []; + for (const [key, val] of Object.entries(packages)) { + const atIndex = key.lastIndexOf("@"); + if (atIndex <= 0) continue; + const name = key.substring(0, atIndex); + const version = key.substring(atIndex + 1); + deps.push({ + name, + version, + license: normalizeLicense(val.licenses || "UNKNOWN"), + repository: val.repository || "", + }); + } + resolve(deps); + }); + }); +} + +// Create server +const server = new McpServer({ + name: "ospo-readiness-mcp", + version: "1.0.0", +}); + +// Tool 1: scan_dependencies +server.tool( + "scan_dependencies", + "Clone a GitHub repo, install npm dependencies, and return license information for all production dependencies", + { + owner: z.string().describe("GitHub repository owner"), + repo: z.string().describe("GitHub repository name"), + ref: z.string().optional().describe("Git ref (branch/tag) to check out"), + }, + async ({ owner, repo, ref }) => { + let cleanup: (() => Promise) | undefined; + try { + const result = await cloneAndInstall(owner, repo, ref); + cleanup = result.cleanup; + + const deps = await runLicenseChecker(result.tmpPath); + + // Build summary + const byLicense: Record = {}; + for (const dep of deps) { + byLicense[dep.license] = (byLicense[dep.license] || 0) + 1; + } + + const response = { + owner, + repo, + total: deps.length, + dependencies: deps, + summary: { byLicense }, + }; + + return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; + } catch (err: any) { + return { content: [{ type: "text" as const, text: `Error scanning dependencies: ${err.message}` }], isError: true }; + } finally { + if (cleanup) await cleanup(); + } + } +); + +// Tool 2: check_license_compatibility +server.tool( + "check_license_compatibility", + "Check if dependency licenses are compatible with the project's license", + { + projectLicense: z.string().describe("The project's SPDX license identifier (e.g. MIT, Apache-2.0)"), + dependencies: z.array(z.object({ + name: z.string(), + license: z.string(), + })).describe("Array of dependencies with their license identifiers"), + }, + async ({ projectLicense, dependencies }) => { + const normalized = normalizeLicense(projectLicense); + const isProjectPermissive = PERMISSIVE_LICENSES.has(normalized); + + const compatible: Array<{ name: string; license: string }> = []; + const incompatible: Array<{ name: string; license: string; reason: string }> = []; + const unknown: Array<{ name: string; license: string }> = []; + + for (const dep of dependencies) { + const depLicense = normalizeLicense(dep.license); + + if (depLicense === "UNKNOWN" || depLicense === "UNLICENSED" || depLicense === "") { + unknown.push({ name: dep.name, license: dep.license }); + } else if (isProjectPermissive && COPYLEFT_LICENSES.has(depLicense)) { + incompatible.push({ + name: dep.name, + license: depLicense, + reason: `Copyleft license ${depLicense} is incompatible with permissive project license ${normalized}`, + }); + } else if (!OSI_APPROVED.has(depLicense)) { + unknown.push({ name: dep.name, license: depLicense }); + } else { + compatible.push({ name: dep.name, license: depLicense }); + } + } + + const response = { + projectLicense: normalized, + totalChecked: dependencies.length, + compatible, + incompatible, + unknown, + summary: { + compatible: compatible.length, + incompatible: incompatible.length, + unknown: unknown.length, + }, + }; + + return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; + } +); + +// Tool 3: generate_sbom +server.tool( + "generate_sbom", + "Clone a GitHub repo and generate a CycloneDX SBOM (Software Bill of Materials) from its npm dependencies", + { + owner: z.string().describe("GitHub repository owner"), + repo: z.string().describe("GitHub repository name"), + ref: z.string().optional().describe("Git ref (branch/tag) to check out"), + }, + async ({ owner, repo, ref }) => { + let cleanup: (() => Promise) | undefined; + try { + const result = await cloneAndInstall(owner, repo, ref); + cleanup = result.cleanup; + + const deps = await runLicenseChecker(result.tmpPath); + + // Read project package.json for metadata + const pkgJsonPath = path.join(result.tmpPath, "package.json"); + const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")); + + // Build CycloneDX-like SBOM + const sbom = { + bomFormat: "CycloneDX", + specVersion: "1.5", + version: 1, + metadata: { + timestamp: new Date().toISOString(), + component: { + type: "application", + name: pkgJson.name || `${owner}/${repo}`, + version: pkgJson.version || "0.0.0", + licenses: pkgJson.license ? [{ license: { id: normalizeLicense(pkgJson.license) } }] : [], + }, + tools: [{ name: "ospo-readiness-mcp", version: "1.0.0" }], + }, + components: deps.map((dep) => ({ + type: "library", + name: dep.name, + version: dep.version, + licenses: [{ license: { id: dep.license } }], + externalReferences: dep.repository + ? [{ type: "vcs", url: dep.repository }] + : [], + })), + }; + + return { content: [{ type: "text" as const, text: JSON.stringify(sbom, null, 2) }] }; + } catch (err: any) { + return { content: [{ type: "text" as const, text: `Error generating SBOM: ${err.message}` }], isError: true }; + } finally { + if (cleanup) await cleanup(); + } + } +); + +// Start server +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); +} + +main().catch(console.error); diff --git a/skills/ospo-dependency-scanner/mcp-server/tsconfig.json b/skills/ospo-dependency-scanner/mcp-server/tsconfig.json new file mode 100644 index 000000000..8d4e7cc6a --- /dev/null +++ b/skills/ospo-dependency-scanner/mcp-server/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true + }, + "include": ["src/**/*"] +} From 76314269f2fc67d7274a75bcac6acaafe492a352 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Wed, 11 Feb 2026 20:45:41 -0800 Subject: [PATCH 05/17] feat(ospo-dependency-scanner): add Python ecosystem support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Detect Python projects (requirements.txt, pyproject.toml, setup.py, Pipfile) - Use python3 venv + pip-licenses for dependency license scanning - Add license normalizer mappings for common Python license strings (e.g. 'Mozilla Public License 2.0 (MPL 2.0)' → 'MPL-2.0') - Add Python-2.0, HPND to permissive license set - Update SKILL.md to document both npm and Python support --- docs/README.skills.md | 2 + skills/ospo-dependency-scanner/SKILL.md | 28 ++- .../mcp-server/src/index.ts | 171 +++++++++++++++--- 3 files changed, 170 insertions(+), 31 deletions(-) diff --git a/docs/README.skills.md b/docs/README.skills.md index e55085b72..9a5613e45 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -48,6 +48,8 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | [microsoft-skill-creator](../skills/microsoft-skill-creator/SKILL.md) | Create agent skills for Microsoft technologies using Learn MCP tools. Use when users want to create a skill that teaches agents about any Microsoft technology, library, framework, or service (Azure, .NET, M365, VS Code, Bicep, etc.). Investigates topics deeply, then generates a hybrid skill storing essential knowledge locally while enabling dynamic deeper investigation. | `references/skill-templates.md` | | [nano-banana-pro-openrouter](../skills/nano-banana-pro-openrouter/SKILL.md) | Generate or edit images via OpenRouter with the Gemini 3 Pro Image model. Use for prompt-only image generation, image edits, and multi-image compositing; supports 1K/2K/4K output. | `assets/SYSTEM_TEMPLATE`
`scripts/generate_image.py` | | [nuget-manager](../skills/nuget-manager/SKILL.md) | Manage NuGet packages in .NET projects/solutions. Use this skill when adding, removing, or updating NuGet package versions. It enforces using `dotnet` CLI for package management and provides strict procedures for direct file edits only when updating versions. | None | +| [ospo-dependency-scanner](../skills/ospo-dependency-scanner/SKILL.md) | Scan npm dependencies for license compliance. Clones a GitHub repo, installs dependencies, and analyzes all transitive dependency licenses using license-checker. Checks compatibility with the project license, flags copyleft-in-permissive conflicts, and generates CycloneDX SBOMs. Use when the user wants to audit dependency licenses, check license compatibility, or generate an SBOM for a Node.js project. | `.mcp.json`
`mcp-server/package-lock.json`
`mcp-server/package.json`
`mcp-server/src/index.ts`
`mcp-server/tsconfig.json` | +| [ospo-readiness](../skills/ospo-readiness/SKILL.md) | Scan any GitHub repository for open source readiness. Evaluates LICENSE, CONTRIBUTING.md, dependency license compatibility, README quality, SECURITY.md, CODE_OF_CONDUCT.md, CI/CD workflows, and issue/PR templates. Produces a scored readiness report with a letter grade (A–F) and actionable recommendations. Use when evaluating a repo for open source compliance, OSPO review, or community health. Invoke by providing a GitHub owner/repo (e.g. "scan expressjs/express for open source readiness"). | None | | [penpot-uiux-design](../skills/penpot-uiux-design/SKILL.md) | Comprehensive guide for creating professional UI/UX designs in Penpot using MCP tools. Use this skill when: (1) Creating new UI/UX designs for web, mobile, or desktop applications, (2) Building design systems with components and tokens, (3) Designing dashboards, forms, navigation, or landing pages, (4) Applying accessibility standards and best practices, (5) Following platform guidelines (iOS, Android, Material Design), (6) Reviewing or improving existing Penpot designs for usability. Triggers: "design a UI", "create interface", "build layout", "design dashboard", "create form", "design landing page", "make it accessible", "design system", "component library". | `references/accessibility.md`
`references/component-patterns.md`
`references/platform-guidelines.md`
`references/setup-troubleshooting.md` | | [plantuml-ascii](../skills/plantuml-ascii/SKILL.md) | Generate ASCII art diagrams using PlantUML text mode. Use when user asks to create ASCII diagrams, text-based diagrams, terminal-friendly diagrams, or mentions plantuml ascii, text diagram, ascii art diagram. Supports: Converting PlantUML diagrams to ASCII art, Creating sequence diagrams, class diagrams, flowcharts in ASCII format, Generating Unicode-enhanced ASCII art with -utxt flag | None | | [powerbi-modeling](../skills/powerbi-modeling/SKILL.md) | Power BI semantic modeling assistant for building optimized data models. Use when working with Power BI semantic models, creating measures, designing star schemas, configuring relationships, implementing RLS, or optimizing model performance. Triggers on queries about DAX calculations, table relationships, dimension/fact table design, naming conventions, model documentation, cardinality, cross-filter direction, calculation groups, and data model best practices. Always connects to the active model first using power-bi-modeling MCP tools to understand the data structure before providing guidance. | `references/MEASURES-DAX.md`
`references/PERFORMANCE.md`
`references/RELATIONSHIPS.md`
`references/RLS.md`
`references/STAR-SCHEMA.md` | diff --git a/skills/ospo-dependency-scanner/SKILL.md b/skills/ospo-dependency-scanner/SKILL.md index 6e71b3f9f..5109673b0 100644 --- a/skills/ospo-dependency-scanner/SKILL.md +++ b/skills/ospo-dependency-scanner/SKILL.md @@ -1,16 +1,16 @@ --- name: ospo-dependency-scanner -description: Scan npm dependencies for license compliance. Clones a GitHub repo, installs dependencies, and analyzes all transitive dependency licenses using license-checker. Checks compatibility with the project license, flags copyleft-in-permissive conflicts, and generates CycloneDX SBOMs. Use when the user wants to audit dependency licenses, check license compatibility, or generate an SBOM for a Node.js project. +description: Scan npm and Python dependencies for license compliance. Clones a GitHub repo, installs dependencies, and analyzes all transitive dependency licenses. Checks compatibility with the project license, flags copyleft-in-permissive conflicts, and generates CycloneDX SBOMs. Use when the user wants to audit dependency licenses, check license compatibility, or generate an SBOM for a Node.js or Python project. --- # OSPO Dependency Scanner -Scan any GitHub repository's npm dependencies for license compliance. This skill uses an MCP server that clones the repo locally, runs `npm install`, and analyzes all production dependencies (including transitive) using `license-checker`. +Scan any GitHub repository's npm or Python dependencies for license compliance. This skill uses an MCP server that clones the repo locally, installs dependencies, and analyzes all production dependencies (including transitive) using `license-checker` (npm) or `pip-licenses` (Python). ## Available MCP Tools ### `scan_dependencies` -Clone a GitHub repo, install npm dependencies, and return license information for all production dependencies. +Clone a GitHub repo, install dependencies, and return license information for all production dependencies. Supports npm (Node.js) and Python (pip) ecosystems. **Input:** - `owner` (string) — GitHub repository owner @@ -56,7 +56,7 @@ check_license_compatibility({ ``` ### `generate_sbom` -Clone a GitHub repo and generate a CycloneDX 1.5 SBOM (Software Bill of Materials) from its npm dependencies. +Clone a GitHub repo and generate a CycloneDX 1.5 SBOM (Software Bill of Materials) from its dependencies. Supports npm and Python. **Input:** - `owner` (string) — GitHub repository owner @@ -85,18 +85,28 @@ If the user asks for an SBOM, call `generate_sbom` and present or save the Cyclo ## Supported Ecosystems -Currently supports **Node.js/npm** only. The MCP server: -- Clones the repo to a temp directory +Supports **Node.js/npm** and **Python** ecosystems: + +### npm (Node.js) +- Detects `package.json` - Runs `npm install --ignore-scripts --production` - Uses `license-checker` to analyze `node_modules` -- Cleans up the temp directory after scanning -Future: Python (pip-licenses), Go (go-licenses), Rust (cargo-license). +### Python +- Detects `requirements.txt`, `pyproject.toml`, `setup.py`, or `Pipfile` +- Creates a virtual environment, installs dependencies via `pip` +- Uses `pip-licenses` to extract license metadata +- Requires `python3` and `pip` on the host machine + +Both ecosystems clean up temp directories after scanning. + +Future: Go (go-licenses), Rust (cargo-license). ## Error Handling - If the repo doesn't exist or is private, the tool returns an error message — inform the user. -- If `npm install` fails (e.g., no `package.json`), the tool returns an error — note that this skill only works for npm projects. +- If `npm install` fails (e.g., no `package.json`) or Python deps fail to install, the tool returns an error — note which ecosystems are supported. +- If no supported manifest is found, the tool lists which files it looks for. - Network issues during clone will timeout after 60 seconds. ## Example Output Format diff --git a/skills/ospo-dependency-scanner/mcp-server/src/index.ts b/skills/ospo-dependency-scanner/mcp-server/src/index.ts index 4c2091d45..f75aa0d8c 100644 --- a/skills/ospo-dependency-scanner/mcp-server/src/index.ts +++ b/skills/ospo-dependency-scanner/mcp-server/src/index.ts @@ -21,7 +21,7 @@ const COPYLEFT_LICENSES = new Set([ const PERMISSIVE_LICENSES = new Set([ "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", "Unlicense", "0BSD", "Artistic-2.0", "Zlib", "BSL-1.0", - "CC0-1.0", "WTFPL", "PostgreSQL", + "CC0-1.0", "WTFPL", "PostgreSQL", "Python-2.0", "HPND", ]); const OSI_APPROVED = new Set([...COPYLEFT_LICENSES, ...PERMISSIVE_LICENSES]); @@ -49,6 +49,21 @@ function normalizeLicense(license: string): string { "0BSD": "0BSD", "Python-2.0": "Python-2.0", "BlueOak-1.0.0": "BlueOak-1.0.0", + // Python ecosystem variations + "Mozilla Public License 2.0 (MPL 2.0)": "MPL-2.0", + "Apache Software License": "Apache-2.0", + "Apache License, Version 2.0": "Apache-2.0", + "BSD License": "BSD-3-Clause", + "MIT License": "MIT", + "ISC License": "ISC", + "GNU General Public License v3 (GPLv3)": "GPL-3.0", + "GNU General Public License v2 (GPLv2)": "GPL-2.0", + "GNU Lesser General Public License v3 (LGPLv3)": "LGPL-3.0", + "GNU Lesser General Public License v2 or later (LGPLv2+)": "LGPL-2.1-or-later", + "GNU Affero General Public License v3": "AGPL-3.0", + "GNU Affero General Public License v3 or later (AGPLv3+)": "AGPL-3.0-or-later", + "Python Software Foundation License": "Python-2.0", + "Historical Permission Notice and Disclaimer (HPND)": "HPND", }; return map[l] || l; } @@ -68,7 +83,7 @@ interface LicenseCheckerResult { }; } -async function cloneAndInstall(owner: string, repo: string, ref?: string): Promise<{ tmpPath: string; cleanup: () => Promise }> { +async function cloneRepo(owner: string, repo: string, ref?: string): Promise<{ repoPath: string; cleanup: () => Promise }> { const { path: tmpPath, cleanup } = await tmpDir({ unsafeCleanup: true }); const cloneUrl = `https://github.com/${owner}/${repo}.git`; const cloneArgs = ref ? `--branch ${ref} --depth 1` : "--depth 1"; @@ -78,17 +93,94 @@ async function cloneAndInstall(owner: string, repo: string, ref?: string): Promi stdio: "pipe", timeout: 60000, }); - execSync("npm install --ignore-scripts --no-audit --no-fund", { - cwd: path.join(tmpPath, "repo"), - stdio: "pipe", - timeout: 120000, - }); } catch (err: any) { await cleanup(); - throw new Error(`Failed to clone/install: ${err.message}`); + throw new Error(`Failed to clone: ${err.message}`); + } + + return { repoPath: path.join(tmpPath, "repo"), cleanup }; +} + +type Ecosystem = "npm" | "python" | "unknown"; + +function detectEcosystem(repoPath: string): Ecosystem { + if (fs.existsSync(path.join(repoPath, "package.json"))) return "npm"; + if ( + fs.existsSync(path.join(repoPath, "requirements.txt")) || + fs.existsSync(path.join(repoPath, "pyproject.toml")) || + fs.existsSync(path.join(repoPath, "setup.py")) || + fs.existsSync(path.join(repoPath, "Pipfile")) + ) return "python"; + return "unknown"; +} + +function hasPython(): boolean { + try { + execSync("python3 --version", { stdio: "pipe" }); + return true; + } catch { + return false; + } +} + +async function installAndScanNpm(repoPath: string): Promise { + execSync("npm install --ignore-scripts --no-audit --no-fund", { + cwd: repoPath, + stdio: "pipe", + timeout: 120000, + }); + return runLicenseChecker(repoPath); +} + +async function installAndScanPython(repoPath: string): Promise { + if (!hasPython()) { + throw new Error("Python/pip not found. Install python3 and pip to enable Python dependency scanning."); + } + + const venvPath = path.join(repoPath, ".ospo-venv"); + + // Create venv and install deps + execSync(`python3 -m venv ${venvPath}`, { cwd: repoPath, stdio: "pipe", timeout: 30000 }); + const pip = path.join(venvPath, "bin", "pip"); + + // Determine install source + if (fs.existsSync(path.join(repoPath, "requirements.txt"))) { + execSync(`${pip} install -r requirements.txt --quiet --no-warn-script-location 2>/dev/null || true`, { + cwd: repoPath, stdio: "pipe", timeout: 180000, + }); + } else if (fs.existsSync(path.join(repoPath, "pyproject.toml"))) { + execSync(`${pip} install . --quiet --no-warn-script-location 2>/dev/null || true`, { + cwd: repoPath, stdio: "pipe", timeout: 180000, + }); + } else if (fs.existsSync(path.join(repoPath, "setup.py"))) { + execSync(`${pip} install . --quiet --no-warn-script-location 2>/dev/null || true`, { + cwd: repoPath, stdio: "pipe", timeout: 180000, + }); + } else if (fs.existsSync(path.join(repoPath, "Pipfile"))) { + execSync(`${pip} install pipenv --quiet --no-warn-script-location && ${venvPath}/bin/pipenv install --skip-lock 2>/dev/null || true`, { + cwd: repoPath, stdio: "pipe", timeout: 180000, + }); } - return { tmpPath: path.join(tmpPath, "repo"), cleanup }; + // Install pip-licenses and run it + execSync(`${pip} install pip-licenses --quiet --no-warn-script-location`, { + cwd: repoPath, stdio: "pipe", timeout: 60000, + }); + + const output = execSync(`${venvPath}/bin/pip-licenses --format=json --with-urls`, { + cwd: repoPath, stdio: "pipe", timeout: 30000, + }).toString(); + + const pipLicenses: Array<{ Name: string; Version: string; License: string; URL: string }> = JSON.parse(output); + + return pipLicenses + .filter((p) => p.Name !== "pip" && p.Name !== "setuptools" && p.Name !== "pip-licenses" && p.Name !== "wheel") + .map((p) => ({ + name: p.Name, + version: p.Version, + license: normalizeLicense(p.License || "UNKNOWN"), + repository: p.URL || "", + })); } async function runLicenseChecker(repoPath: string): Promise { @@ -124,7 +216,7 @@ const server = new McpServer({ // Tool 1: scan_dependencies server.tool( "scan_dependencies", - "Clone a GitHub repo, install npm dependencies, and return license information for all production dependencies", + "Clone a GitHub repo, install dependencies, and return license information for all production dependencies. Supports npm (Node.js) and Python (pip) ecosystems.", { owner: z.string().describe("GitHub repository owner"), repo: z.string().describe("GitHub repository name"), @@ -133,10 +225,25 @@ server.tool( async ({ owner, repo, ref }) => { let cleanup: (() => Promise) | undefined; try { - const result = await cloneAndInstall(owner, repo, ref); + const result = await cloneRepo(owner, repo, ref); cleanup = result.cleanup; - const deps = await runLicenseChecker(result.tmpPath); + const ecosystem = detectEcosystem(result.repoPath); + let deps: DepInfo[]; + + if (ecosystem === "npm") { + deps = await installAndScanNpm(result.repoPath); + } else if (ecosystem === "python") { + deps = await installAndScanPython(result.repoPath); + } else { + return { + content: [{ type: "text" as const, text: JSON.stringify({ + error: "No supported manifest found. Supported: package.json (npm), requirements.txt / pyproject.toml / setup.py / Pipfile (Python)", + owner, repo, + }, null, 2) }], + isError: true, + }; + } // Build summary const byLicense: Record = {}; @@ -147,6 +254,7 @@ server.tool( const response = { owner, repo, + ecosystem, total: deps.length, dependencies: deps, summary: { byLicense }, @@ -218,7 +326,7 @@ server.tool( // Tool 3: generate_sbom server.tool( "generate_sbom", - "Clone a GitHub repo and generate a CycloneDX SBOM (Software Bill of Materials) from its npm dependencies", + "Clone a GitHub repo and generate a CycloneDX SBOM (Software Bill of Materials) from its dependencies. Supports npm and Python.", { owner: z.string().describe("GitHub repository owner"), repo: z.string().describe("GitHub repository name"), @@ -227,16 +335,35 @@ server.tool( async ({ owner, repo, ref }) => { let cleanup: (() => Promise) | undefined; try { - const result = await cloneAndInstall(owner, repo, ref); + const result = await cloneRepo(owner, repo, ref); cleanup = result.cleanup; - const deps = await runLicenseChecker(result.tmpPath); + const ecosystem = detectEcosystem(result.repoPath); + let deps: DepInfo[]; - // Read project package.json for metadata - const pkgJsonPath = path.join(result.tmpPath, "package.json"); - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")); + if (ecosystem === "npm") { + deps = await installAndScanNpm(result.repoPath); + } else if (ecosystem === "python") { + deps = await installAndScanPython(result.repoPath); + } else { + return { + content: [{ type: "text" as const, text: "No supported manifest found (npm or Python)." }], + isError: true, + }; + } + + // Read project metadata + let projectName = `${owner}/${repo}`; + let projectVersion = "0.0.0"; + let projectLicense = ""; + + if (ecosystem === "npm" && fs.existsSync(path.join(result.repoPath, "package.json"))) { + const pkgJson = JSON.parse(fs.readFileSync(path.join(result.repoPath, "package.json"), "utf-8")); + projectName = pkgJson.name || projectName; + projectVersion = pkgJson.version || projectVersion; + projectLicense = pkgJson.license || ""; + } - // Build CycloneDX-like SBOM const sbom = { bomFormat: "CycloneDX", specVersion: "1.5", @@ -245,9 +372,9 @@ server.tool( timestamp: new Date().toISOString(), component: { type: "application", - name: pkgJson.name || `${owner}/${repo}`, - version: pkgJson.version || "0.0.0", - licenses: pkgJson.license ? [{ license: { id: normalizeLicense(pkgJson.license) } }] : [], + name: projectName, + version: projectVersion, + licenses: projectLicense ? [{ license: { id: normalizeLicense(projectLicense) } }] : [], }, tools: [{ name: "ospo-readiness-mcp", version: "1.0.0" }], }, From 53ac90e00398ac40920a9eb848789a8458c324a6 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Wed, 11 Feb 2026 20:46:40 -0800 Subject: [PATCH 06/17] Remove ospo-dependency-scanner skill from awesome-copilot The MCP-powered dependency scanner is a separate standalone project, not part of this community skills submission. Only the text-based ospo-readiness skill belongs here. --- docs/README.skills.md | 1 - skills/ospo-dependency-scanner/.mcp.json | 9 - skills/ospo-dependency-scanner/SKILL.md | 132 -- .../mcp-server/package-lock.json | 1719 ----------------- .../mcp-server/package.json | 27 - .../mcp-server/src/index.ts | 407 ---- .../mcp-server/tsconfig.json | 14 - 7 files changed, 2309 deletions(-) delete mode 100644 skills/ospo-dependency-scanner/.mcp.json delete mode 100644 skills/ospo-dependency-scanner/SKILL.md delete mode 100644 skills/ospo-dependency-scanner/mcp-server/package-lock.json delete mode 100644 skills/ospo-dependency-scanner/mcp-server/package.json delete mode 100644 skills/ospo-dependency-scanner/mcp-server/src/index.ts delete mode 100644 skills/ospo-dependency-scanner/mcp-server/tsconfig.json diff --git a/docs/README.skills.md b/docs/README.skills.md index 9a5613e45..94fc7a24d 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -48,7 +48,6 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | [microsoft-skill-creator](../skills/microsoft-skill-creator/SKILL.md) | Create agent skills for Microsoft technologies using Learn MCP tools. Use when users want to create a skill that teaches agents about any Microsoft technology, library, framework, or service (Azure, .NET, M365, VS Code, Bicep, etc.). Investigates topics deeply, then generates a hybrid skill storing essential knowledge locally while enabling dynamic deeper investigation. | `references/skill-templates.md` | | [nano-banana-pro-openrouter](../skills/nano-banana-pro-openrouter/SKILL.md) | Generate or edit images via OpenRouter with the Gemini 3 Pro Image model. Use for prompt-only image generation, image edits, and multi-image compositing; supports 1K/2K/4K output. | `assets/SYSTEM_TEMPLATE`
`scripts/generate_image.py` | | [nuget-manager](../skills/nuget-manager/SKILL.md) | Manage NuGet packages in .NET projects/solutions. Use this skill when adding, removing, or updating NuGet package versions. It enforces using `dotnet` CLI for package management and provides strict procedures for direct file edits only when updating versions. | None | -| [ospo-dependency-scanner](../skills/ospo-dependency-scanner/SKILL.md) | Scan npm dependencies for license compliance. Clones a GitHub repo, installs dependencies, and analyzes all transitive dependency licenses using license-checker. Checks compatibility with the project license, flags copyleft-in-permissive conflicts, and generates CycloneDX SBOMs. Use when the user wants to audit dependency licenses, check license compatibility, or generate an SBOM for a Node.js project. | `.mcp.json`
`mcp-server/package-lock.json`
`mcp-server/package.json`
`mcp-server/src/index.ts`
`mcp-server/tsconfig.json` | | [ospo-readiness](../skills/ospo-readiness/SKILL.md) | Scan any GitHub repository for open source readiness. Evaluates LICENSE, CONTRIBUTING.md, dependency license compatibility, README quality, SECURITY.md, CODE_OF_CONDUCT.md, CI/CD workflows, and issue/PR templates. Produces a scored readiness report with a letter grade (A–F) and actionable recommendations. Use when evaluating a repo for open source compliance, OSPO review, or community health. Invoke by providing a GitHub owner/repo (e.g. "scan expressjs/express for open source readiness"). | None | | [penpot-uiux-design](../skills/penpot-uiux-design/SKILL.md) | Comprehensive guide for creating professional UI/UX designs in Penpot using MCP tools. Use this skill when: (1) Creating new UI/UX designs for web, mobile, or desktop applications, (2) Building design systems with components and tokens, (3) Designing dashboards, forms, navigation, or landing pages, (4) Applying accessibility standards and best practices, (5) Following platform guidelines (iOS, Android, Material Design), (6) Reviewing or improving existing Penpot designs for usability. Triggers: "design a UI", "create interface", "build layout", "design dashboard", "create form", "design landing page", "make it accessible", "design system", "component library". | `references/accessibility.md`
`references/component-patterns.md`
`references/platform-guidelines.md`
`references/setup-troubleshooting.md` | | [plantuml-ascii](../skills/plantuml-ascii/SKILL.md) | Generate ASCII art diagrams using PlantUML text mode. Use when user asks to create ASCII diagrams, text-based diagrams, terminal-friendly diagrams, or mentions plantuml ascii, text diagram, ascii art diagram. Supports: Converting PlantUML diagrams to ASCII art, Creating sequence diagrams, class diagrams, flowcharts in ASCII format, Generating Unicode-enhanced ASCII art with -utxt flag | None | diff --git a/skills/ospo-dependency-scanner/.mcp.json b/skills/ospo-dependency-scanner/.mcp.json deleted file mode 100644 index 9200ebfde..000000000 --- a/skills/ospo-dependency-scanner/.mcp.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "mcpServers": { - "ospo-dependency-scanner": { - "command": "bash", - "args": ["-c", "cd mcp-server && npm install --ignore-scripts 2>/dev/null && npx tsc 2>/dev/null && node dist/index.js"], - "tools": ["*"] - } - } -} diff --git a/skills/ospo-dependency-scanner/SKILL.md b/skills/ospo-dependency-scanner/SKILL.md deleted file mode 100644 index 5109673b0..000000000 --- a/skills/ospo-dependency-scanner/SKILL.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -name: ospo-dependency-scanner -description: Scan npm and Python dependencies for license compliance. Clones a GitHub repo, installs dependencies, and analyzes all transitive dependency licenses. Checks compatibility with the project license, flags copyleft-in-permissive conflicts, and generates CycloneDX SBOMs. Use when the user wants to audit dependency licenses, check license compatibility, or generate an SBOM for a Node.js or Python project. ---- - -# OSPO Dependency Scanner - -Scan any GitHub repository's npm or Python dependencies for license compliance. This skill uses an MCP server that clones the repo locally, installs dependencies, and analyzes all production dependencies (including transitive) using `license-checker` (npm) or `pip-licenses` (Python). - -## Available MCP Tools - -### `scan_dependencies` -Clone a GitHub repo, install dependencies, and return license information for all production dependencies. Supports npm (Node.js) and Python (pip) ecosystems. - -**Input:** -- `owner` (string) — GitHub repository owner -- `repo` (string) — GitHub repository name -- `ref` (string, optional) — Git ref (branch/tag) to check out - -**Output:** JSON with: -- `total` — number of dependencies found -- `dependencies` — array of `{ name, version, license, repository }` for every production dependency -- `summary.byLicense` — count of dependencies grouped by license type - -**Example:** -``` -scan_dependencies({ owner: "expressjs", repo: "express" }) -→ { total: 65, dependencies: [...], summary: { byLicense: { MIT: 60, ISC: 4, "BSD-3-Clause": 1 } } } -``` - -### `check_license_compatibility` -Check if dependency licenses are compatible with the project's license. - -**Input:** -- `projectLicense` (string) — The project's SPDX license identifier (e.g. `MIT`, `Apache-2.0`) -- `dependencies` (array) — Array of `{ name, license }` objects (use output from `scan_dependencies`) - -**Output:** JSON with: -- `compatible` — dependencies with compatible licenses -- `incompatible` — dependencies with incompatible licenses + reason (e.g., copyleft in permissive project) -- `unknown` — dependencies with unknown or unrecognized licenses -- `summary` — counts of each category - -**Example:** -``` -check_license_compatibility({ - projectLicense: "MIT", - dependencies: [ - { name: "accepts", license: "MIT" }, - { name: "some-gpl-pkg", license: "GPL-3.0" } - ] -}) -→ { compatible: [{ name: "accepts", license: "MIT" }], - incompatible: [{ name: "some-gpl-pkg", license: "GPL-3.0", reason: "Copyleft license GPL-3.0 is incompatible with permissive project license MIT" }], - unknown: [] } -``` - -### `generate_sbom` -Clone a GitHub repo and generate a CycloneDX 1.5 SBOM (Software Bill of Materials) from its dependencies. Supports npm and Python. - -**Input:** -- `owner` (string) — GitHub repository owner -- `repo` (string) — GitHub repository name -- `ref` (string, optional) — Git ref (branch/tag) to check out - -**Output:** CycloneDX 1.5 JSON document with: -- `metadata` — project name, version, license, scan timestamp -- `components` — every production dependency with name, version, license, and VCS URL - -## Typical Workflow - -When a user asks to scan dependencies or check license compliance: - -1. **Call `scan_dependencies`** with the repo's owner and name -2. **Determine the project license** from the scan results (the project itself is included in the output) or ask the user -3. **Call `check_license_compatibility`** with the project license and the dependency list -4. **Present results** in a clear format: - - Total dependencies scanned - - License distribution (e.g., "60 MIT, 4 ISC, 1 BSD-3-Clause") - - ⚠️ Any incompatible dependencies with reasons - - ❓ Any unknown/unlicensed dependencies - - ✅ Overall compatibility verdict - -If the user asks for an SBOM, call `generate_sbom` and present or save the CycloneDX JSON. - -## Supported Ecosystems - -Supports **Node.js/npm** and **Python** ecosystems: - -### npm (Node.js) -- Detects `package.json` -- Runs `npm install --ignore-scripts --production` -- Uses `license-checker` to analyze `node_modules` - -### Python -- Detects `requirements.txt`, `pyproject.toml`, `setup.py`, or `Pipfile` -- Creates a virtual environment, installs dependencies via `pip` -- Uses `pip-licenses` to extract license metadata -- Requires `python3` and `pip` on the host machine - -Both ecosystems clean up temp directories after scanning. - -Future: Go (go-licenses), Rust (cargo-license). - -## Error Handling - -- If the repo doesn't exist or is private, the tool returns an error message — inform the user. -- If `npm install` fails (e.g., no `package.json`) or Python deps fail to install, the tool returns an error — note which ecosystems are supported. -- If no supported manifest is found, the tool lists which files it looks for. -- Network issues during clone will timeout after 60 seconds. - -## Example Output Format - -``` -## 📦 Dependency License Scan: expressjs/express - -**Total dependencies:** 65 (production, including transitive) - -### License Distribution -| License | Count | -|---------|-------| -| MIT | 60 | -| ISC | 4 | -| BSD-3-Clause | 1 | - -### Compatibility with MIT License -- ✅ **65 compatible** — all dependencies use permissive licenses -- ⚠️ **0 incompatible** -- ❓ **0 unknown** - -**Verdict:** ✅ All dependency licenses are compatible with MIT. -``` diff --git a/skills/ospo-dependency-scanner/mcp-server/package-lock.json b/skills/ospo-dependency-scanner/mcp-server/package-lock.json deleted file mode 100644 index d73290cfc..000000000 --- a/skills/ospo-dependency-scanner/mcp-server/package-lock.json +++ /dev/null @@ -1,1719 +0,0 @@ -{ - "name": "ospo-readiness-mcp", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "ospo-readiness-mcp", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "license-checker": "^25.0.1", - "tmp-promise": "^3.0.3" - }, - "bin": { - "ospo-readiness-mcp": "dist/index.js" - }, - "devDependencies": { - "@types/node": "^25.2.3", - "typescript": "^5.9.3" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@types/node": { - "version": "25.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", - "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC" - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.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" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", - "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", - "license": "MIT", - "dependencies": { - "ip-address": "10.0.1" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", - "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "license": "ISC" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "license": "BSD-3-Clause", - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" - }, - "bin": { - "license-checker": "bin/license-checker" - } - }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "license": "ISC", - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "license": "ISC" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "license": "ISC", - "engines": { - "node": "*" - } - }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "license": "MIT", - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "license": "CC0-1.0" - }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "license": "(MIT AND CC-BY-3.0)" - }, - "node_modules/spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "license": "MIT", - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "license": "MIT", - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "license": "MIT" - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - } - } -} diff --git a/skills/ospo-dependency-scanner/mcp-server/package.json b/skills/ospo-dependency-scanner/mcp-server/package.json deleted file mode 100644 index dfa1c18eb..000000000 --- a/skills/ospo-dependency-scanner/mcp-server/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "ospo-readiness-mcp", - "version": "1.0.0", - "description": "MCP server for OSPO open source readiness dependency scanning", - "main": "dist/index.js", - "bin": "dist/index.js", - "scripts": { - "build": "tsc", - "start": "node dist/index.js" - }, - "keywords": [ - "ospo", - "license", - "mcp", - "open-source" - ], - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "license-checker": "^25.0.1", - "tmp-promise": "^3.0.3" - }, - "devDependencies": { - "@types/node": "^25.2.3", - "typescript": "^5.9.3" - } -} diff --git a/skills/ospo-dependency-scanner/mcp-server/src/index.ts b/skills/ospo-dependency-scanner/mcp-server/src/index.ts deleted file mode 100644 index f75aa0d8c..000000000 --- a/skills/ospo-dependency-scanner/mcp-server/src/index.ts +++ /dev/null @@ -1,407 +0,0 @@ -#!/usr/bin/env node - -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { z } from "zod"; -import { execSync } from "child_process"; -import * as path from "path"; -import * as fs from "fs"; -import { dir as tmpDir } from "tmp-promise"; - -// License compatibility data -const COPYLEFT_LICENSES = new Set([ - "GPL-2.0", "GPL-2.0-only", "GPL-2.0-or-later", "GPL-2.0+", - "GPL-3.0", "GPL-3.0-only", "GPL-3.0-or-later", "GPL-3.0+", - "AGPL-3.0", "AGPL-3.0-only", "AGPL-3.0-or-later", - "LGPL-2.1", "LGPL-2.1-only", "LGPL-2.1-or-later", - "LGPL-3.0", "LGPL-3.0-only", "LGPL-3.0-or-later", - "MPL-2.0", "EUPL-1.2", "CECILL-2.1", -]); - -const PERMISSIVE_LICENSES = new Set([ - "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", - "Unlicense", "0BSD", "Artistic-2.0", "Zlib", "BSL-1.0", - "CC0-1.0", "WTFPL", "PostgreSQL", "Python-2.0", "HPND", -]); - -const OSI_APPROVED = new Set([...COPYLEFT_LICENSES, ...PERMISSIVE_LICENSES]); - -function normalizeLicense(license: string): string { - const l = license.trim(); - // Handle common variations - const map: Record = { - "MIT": "MIT", - "ISC": "ISC", - "Apache 2.0": "Apache-2.0", - "Apache-2.0": "Apache-2.0", - "Apache License 2.0": "Apache-2.0", - "BSD-2-Clause": "BSD-2-Clause", - "BSD-3-Clause": "BSD-3-Clause", - "BSD": "BSD-3-Clause", - "GPL-2.0": "GPL-2.0", - "GPL-3.0": "GPL-3.0", - "LGPL-2.1": "LGPL-2.1", - "LGPL-3.0": "LGPL-3.0", - "MPL-2.0": "MPL-2.0", - "Unlicense": "Unlicense", - "UNLICENSED": "UNLICENSED", - "CC0-1.0": "CC0-1.0", - "0BSD": "0BSD", - "Python-2.0": "Python-2.0", - "BlueOak-1.0.0": "BlueOak-1.0.0", - // Python ecosystem variations - "Mozilla Public License 2.0 (MPL 2.0)": "MPL-2.0", - "Apache Software License": "Apache-2.0", - "Apache License, Version 2.0": "Apache-2.0", - "BSD License": "BSD-3-Clause", - "MIT License": "MIT", - "ISC License": "ISC", - "GNU General Public License v3 (GPLv3)": "GPL-3.0", - "GNU General Public License v2 (GPLv2)": "GPL-2.0", - "GNU Lesser General Public License v3 (LGPLv3)": "LGPL-3.0", - "GNU Lesser General Public License v2 or later (LGPLv2+)": "LGPL-2.1-or-later", - "GNU Affero General Public License v3": "AGPL-3.0", - "GNU Affero General Public License v3 or later (AGPLv3+)": "AGPL-3.0-or-later", - "Python Software Foundation License": "Python-2.0", - "Historical Permission Notice and Disclaimer (HPND)": "HPND", - }; - return map[l] || l; -} - -interface DepInfo { - name: string; - version: string; - license: string; - repository: string; -} - -interface LicenseCheckerResult { - [key: string]: { - licenses: string; - repository?: string; - licenseFile?: string; - }; -} - -async function cloneRepo(owner: string, repo: string, ref?: string): Promise<{ repoPath: string; cleanup: () => Promise }> { - const { path: tmpPath, cleanup } = await tmpDir({ unsafeCleanup: true }); - const cloneUrl = `https://github.com/${owner}/${repo}.git`; - const cloneArgs = ref ? `--branch ${ref} --depth 1` : "--depth 1"; - - try { - execSync(`git clone ${cloneArgs} ${cloneUrl} ${tmpPath}/repo`, { - stdio: "pipe", - timeout: 60000, - }); - } catch (err: any) { - await cleanup(); - throw new Error(`Failed to clone: ${err.message}`); - } - - return { repoPath: path.join(tmpPath, "repo"), cleanup }; -} - -type Ecosystem = "npm" | "python" | "unknown"; - -function detectEcosystem(repoPath: string): Ecosystem { - if (fs.existsSync(path.join(repoPath, "package.json"))) return "npm"; - if ( - fs.existsSync(path.join(repoPath, "requirements.txt")) || - fs.existsSync(path.join(repoPath, "pyproject.toml")) || - fs.existsSync(path.join(repoPath, "setup.py")) || - fs.existsSync(path.join(repoPath, "Pipfile")) - ) return "python"; - return "unknown"; -} - -function hasPython(): boolean { - try { - execSync("python3 --version", { stdio: "pipe" }); - return true; - } catch { - return false; - } -} - -async function installAndScanNpm(repoPath: string): Promise { - execSync("npm install --ignore-scripts --no-audit --no-fund", { - cwd: repoPath, - stdio: "pipe", - timeout: 120000, - }); - return runLicenseChecker(repoPath); -} - -async function installAndScanPython(repoPath: string): Promise { - if (!hasPython()) { - throw new Error("Python/pip not found. Install python3 and pip to enable Python dependency scanning."); - } - - const venvPath = path.join(repoPath, ".ospo-venv"); - - // Create venv and install deps - execSync(`python3 -m venv ${venvPath}`, { cwd: repoPath, stdio: "pipe", timeout: 30000 }); - const pip = path.join(venvPath, "bin", "pip"); - - // Determine install source - if (fs.existsSync(path.join(repoPath, "requirements.txt"))) { - execSync(`${pip} install -r requirements.txt --quiet --no-warn-script-location 2>/dev/null || true`, { - cwd: repoPath, stdio: "pipe", timeout: 180000, - }); - } else if (fs.existsSync(path.join(repoPath, "pyproject.toml"))) { - execSync(`${pip} install . --quiet --no-warn-script-location 2>/dev/null || true`, { - cwd: repoPath, stdio: "pipe", timeout: 180000, - }); - } else if (fs.existsSync(path.join(repoPath, "setup.py"))) { - execSync(`${pip} install . --quiet --no-warn-script-location 2>/dev/null || true`, { - cwd: repoPath, stdio: "pipe", timeout: 180000, - }); - } else if (fs.existsSync(path.join(repoPath, "Pipfile"))) { - execSync(`${pip} install pipenv --quiet --no-warn-script-location && ${venvPath}/bin/pipenv install --skip-lock 2>/dev/null || true`, { - cwd: repoPath, stdio: "pipe", timeout: 180000, - }); - } - - // Install pip-licenses and run it - execSync(`${pip} install pip-licenses --quiet --no-warn-script-location`, { - cwd: repoPath, stdio: "pipe", timeout: 60000, - }); - - const output = execSync(`${venvPath}/bin/pip-licenses --format=json --with-urls`, { - cwd: repoPath, stdio: "pipe", timeout: 30000, - }).toString(); - - const pipLicenses: Array<{ Name: string; Version: string; License: string; URL: string }> = JSON.parse(output); - - return pipLicenses - .filter((p) => p.Name !== "pip" && p.Name !== "setuptools" && p.Name !== "pip-licenses" && p.Name !== "wheel") - .map((p) => ({ - name: p.Name, - version: p.Version, - license: normalizeLicense(p.License || "UNKNOWN"), - repository: p.URL || "", - })); -} - -async function runLicenseChecker(repoPath: string): Promise { - return new Promise((resolve, reject) => { - const checker = require("license-checker"); - checker.init({ start: repoPath, json: true, production: true }, (err: Error, packages: LicenseCheckerResult) => { - if (err) return reject(err); - - const deps: DepInfo[] = []; - for (const [key, val] of Object.entries(packages)) { - const atIndex = key.lastIndexOf("@"); - if (atIndex <= 0) continue; - const name = key.substring(0, atIndex); - const version = key.substring(atIndex + 1); - deps.push({ - name, - version, - license: normalizeLicense(val.licenses || "UNKNOWN"), - repository: val.repository || "", - }); - } - resolve(deps); - }); - }); -} - -// Create server -const server = new McpServer({ - name: "ospo-readiness-mcp", - version: "1.0.0", -}); - -// Tool 1: scan_dependencies -server.tool( - "scan_dependencies", - "Clone a GitHub repo, install dependencies, and return license information for all production dependencies. Supports npm (Node.js) and Python (pip) ecosystems.", - { - owner: z.string().describe("GitHub repository owner"), - repo: z.string().describe("GitHub repository name"), - ref: z.string().optional().describe("Git ref (branch/tag) to check out"), - }, - async ({ owner, repo, ref }) => { - let cleanup: (() => Promise) | undefined; - try { - const result = await cloneRepo(owner, repo, ref); - cleanup = result.cleanup; - - const ecosystem = detectEcosystem(result.repoPath); - let deps: DepInfo[]; - - if (ecosystem === "npm") { - deps = await installAndScanNpm(result.repoPath); - } else if (ecosystem === "python") { - deps = await installAndScanPython(result.repoPath); - } else { - return { - content: [{ type: "text" as const, text: JSON.stringify({ - error: "No supported manifest found. Supported: package.json (npm), requirements.txt / pyproject.toml / setup.py / Pipfile (Python)", - owner, repo, - }, null, 2) }], - isError: true, - }; - } - - // Build summary - const byLicense: Record = {}; - for (const dep of deps) { - byLicense[dep.license] = (byLicense[dep.license] || 0) + 1; - } - - const response = { - owner, - repo, - ecosystem, - total: deps.length, - dependencies: deps, - summary: { byLicense }, - }; - - return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; - } catch (err: any) { - return { content: [{ type: "text" as const, text: `Error scanning dependencies: ${err.message}` }], isError: true }; - } finally { - if (cleanup) await cleanup(); - } - } -); - -// Tool 2: check_license_compatibility -server.tool( - "check_license_compatibility", - "Check if dependency licenses are compatible with the project's license", - { - projectLicense: z.string().describe("The project's SPDX license identifier (e.g. MIT, Apache-2.0)"), - dependencies: z.array(z.object({ - name: z.string(), - license: z.string(), - })).describe("Array of dependencies with their license identifiers"), - }, - async ({ projectLicense, dependencies }) => { - const normalized = normalizeLicense(projectLicense); - const isProjectPermissive = PERMISSIVE_LICENSES.has(normalized); - - const compatible: Array<{ name: string; license: string }> = []; - const incompatible: Array<{ name: string; license: string; reason: string }> = []; - const unknown: Array<{ name: string; license: string }> = []; - - for (const dep of dependencies) { - const depLicense = normalizeLicense(dep.license); - - if (depLicense === "UNKNOWN" || depLicense === "UNLICENSED" || depLicense === "") { - unknown.push({ name: dep.name, license: dep.license }); - } else if (isProjectPermissive && COPYLEFT_LICENSES.has(depLicense)) { - incompatible.push({ - name: dep.name, - license: depLicense, - reason: `Copyleft license ${depLicense} is incompatible with permissive project license ${normalized}`, - }); - } else if (!OSI_APPROVED.has(depLicense)) { - unknown.push({ name: dep.name, license: depLicense }); - } else { - compatible.push({ name: dep.name, license: depLicense }); - } - } - - const response = { - projectLicense: normalized, - totalChecked: dependencies.length, - compatible, - incompatible, - unknown, - summary: { - compatible: compatible.length, - incompatible: incompatible.length, - unknown: unknown.length, - }, - }; - - return { content: [{ type: "text" as const, text: JSON.stringify(response, null, 2) }] }; - } -); - -// Tool 3: generate_sbom -server.tool( - "generate_sbom", - "Clone a GitHub repo and generate a CycloneDX SBOM (Software Bill of Materials) from its dependencies. Supports npm and Python.", - { - owner: z.string().describe("GitHub repository owner"), - repo: z.string().describe("GitHub repository name"), - ref: z.string().optional().describe("Git ref (branch/tag) to check out"), - }, - async ({ owner, repo, ref }) => { - let cleanup: (() => Promise) | undefined; - try { - const result = await cloneRepo(owner, repo, ref); - cleanup = result.cleanup; - - const ecosystem = detectEcosystem(result.repoPath); - let deps: DepInfo[]; - - if (ecosystem === "npm") { - deps = await installAndScanNpm(result.repoPath); - } else if (ecosystem === "python") { - deps = await installAndScanPython(result.repoPath); - } else { - return { - content: [{ type: "text" as const, text: "No supported manifest found (npm or Python)." }], - isError: true, - }; - } - - // Read project metadata - let projectName = `${owner}/${repo}`; - let projectVersion = "0.0.0"; - let projectLicense = ""; - - if (ecosystem === "npm" && fs.existsSync(path.join(result.repoPath, "package.json"))) { - const pkgJson = JSON.parse(fs.readFileSync(path.join(result.repoPath, "package.json"), "utf-8")); - projectName = pkgJson.name || projectName; - projectVersion = pkgJson.version || projectVersion; - projectLicense = pkgJson.license || ""; - } - - const sbom = { - bomFormat: "CycloneDX", - specVersion: "1.5", - version: 1, - metadata: { - timestamp: new Date().toISOString(), - component: { - type: "application", - name: projectName, - version: projectVersion, - licenses: projectLicense ? [{ license: { id: normalizeLicense(projectLicense) } }] : [], - }, - tools: [{ name: "ospo-readiness-mcp", version: "1.0.0" }], - }, - components: deps.map((dep) => ({ - type: "library", - name: dep.name, - version: dep.version, - licenses: [{ license: { id: dep.license } }], - externalReferences: dep.repository - ? [{ type: "vcs", url: dep.repository }] - : [], - })), - }; - - return { content: [{ type: "text" as const, text: JSON.stringify(sbom, null, 2) }] }; - } catch (err: any) { - return { content: [{ type: "text" as const, text: `Error generating SBOM: ${err.message}` }], isError: true }; - } finally { - if (cleanup) await cleanup(); - } - } -); - -// Start server -async function main() { - const transport = new StdioServerTransport(); - await server.connect(transport); -} - -main().catch(console.error); diff --git a/skills/ospo-dependency-scanner/mcp-server/tsconfig.json b/skills/ospo-dependency-scanner/mcp-server/tsconfig.json deleted file mode 100644 index 8d4e7cc6a..000000000 --- a/skills/ospo-dependency-scanner/mcp-server/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16", - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "declaration": true - }, - "include": ["src/**/*"] -} From d2155e4a60357dfde92c91d91fde31ff1d5ec7b0 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 15:23:01 -0800 Subject: [PATCH 07/17] feat: add agentic-workflows section with 6 OSPO workflows Introduces a new top-level agentic-workflows/ directory for GitHub Agentic Workflow (.md) files that compile with gh aw. Starts with 6 curated OSPO workflows: - org-health: weekly org health report with stale items, merge times, leaderboards - contributors-report: new/returning contributor metrics - release-compliance-checker: OSS release readiness audit - stale-repos: detect inactive repositories - dora-metrics: DORA engineering metrics (deploy freq, lead time, CFR, MTTR) - team-permissions-audit: flag direct (non-team) collaborator access Includes a top-level README introducing agentic workflows and an OSPO category README with quick-start guide. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- agentic-workflows/README.md | 108 +++++++ agentic-workflows/ospo/README.md | 49 +++ agentic-workflows/ospo/contributors-report.md | 138 +++++++++ agentic-workflows/ospo/dora-metrics.md | 173 +++++++++++ agentic-workflows/ospo/org-health.md | 289 ++++++++++++++++++ .../ospo/release-compliance-checker.md | 171 +++++++++++ agentic-workflows/ospo/stale-repos.md | 117 +++++++ .../ospo/team-permissions-audit.md | 138 +++++++++ 8 files changed, 1183 insertions(+) create mode 100644 agentic-workflows/README.md create mode 100644 agentic-workflows/ospo/README.md create mode 100644 agentic-workflows/ospo/contributors-report.md create mode 100644 agentic-workflows/ospo/dora-metrics.md create mode 100644 agentic-workflows/ospo/org-health.md create mode 100644 agentic-workflows/ospo/release-compliance-checker.md create mode 100644 agentic-workflows/ospo/stale-repos.md create mode 100644 agentic-workflows/ospo/team-permissions-audit.md diff --git a/agentic-workflows/README.md b/agentic-workflows/README.md new file mode 100644 index 000000000..a0f0a1d88 --- /dev/null +++ b/agentic-workflows/README.md @@ -0,0 +1,108 @@ +# GitHub Agentic Workflows + +> AI-powered automation for GitHub — write workflows in natural language, not YAML. + +## What Are Agentic Workflows? + +GitHub Agentic Workflows are a new way to build CI/CD automation. Instead of writing complex YAML with shell scripts, you describe what you want in **Markdown** and an AI agent (GitHub Copilot) interprets and executes your instructions using GitHub APIs. + +Each workflow is a `.md` file with two parts: + +1. **YAML frontmatter** — triggers, permissions, tools, and guardrails +2. **Markdown body** — natural language instructions the AI follows + +```markdown +--- +on: + schedule: + - cron: "0 10 1 * *" # When to run + workflow_dispatch: # Allow manual trigger + +permissions: + contents: read + issues: write + +engine: copilot # AI engine + +tools: + github: + toolsets: [repos, issues] # Which GitHub APIs are available + bash: true # Shell access for date math, etc. + +safe-outputs: + create-issue: + max: 1 # Guardrail: create at most 1 issue per run + title-prefix: "[Report] " + +timeout-minutes: 30 +--- + +## Step 1: Gather Data + +List all public, non-archived repositories in the organization. +For each repo, count open issues and pull requests. + +## Step 2: Generate Report + +Create a markdown table summarizing repo activity. +Create a GitHub issue with the report. +``` + +## How It Differs from Traditional GitHub Actions + +| | Traditional Actions | Agentic Workflows | +|---|---|---| +| **Format** | YAML + shell scripts | Markdown + natural language | +| **Logic** | You write every step explicitly | AI interprets your intent | +| **API calls** | Manual REST/GraphQL calls | AI handles API calls, pagination, error handling | +| **Customization** | Edit YAML/scripts | Edit plain English instructions | +| **Guardrails** | None built-in | `safe-outputs` limits write operations per run | + +## Prerequisites + +- **GitHub CLI** (`gh`) — [install guide](https://cli.github.com/) +- **Agentic Workflows extension** — `gh extension install githubnext/gh-aw` +- **GitHub Copilot** access on your repository + +## Quick Start + +1. **Copy** a workflow `.md` file into your repo's `.github/workflows/` directory +2. **Customize** the instructions (edit the Markdown — it's plain English) +3. **Compile** to generate the Actions lock file: + ```bash + gh aw compile workflow-name + ``` +4. **Commit both files** — the `.md` source and the generated `.lock.yml` +5. **Push** — the workflow runs on the triggers you defined + +## Safe-Outputs: Built-in Guardrails + +Every agentic workflow declares `safe-outputs` in its frontmatter. These are hard limits on what the AI can do per run: + +```yaml +safe-outputs: + create-issue: + max: 1 # Create at most 1 issue + title-prefix: "[Report] " # Must start with this prefix + create-pull-request: + max: 3 + add-comment: + max: 5 + add-labels: + max: 10 +``` + +If the AI attempts to exceed these limits, the operation is blocked. This prevents runaway automation. + +## Available Workflow Categories + +| Category | Description | +|---|---| +| **[OSPO](ospo/)** | Open Source Program Office — org health, contributor metrics, compliance, repo hygiene | + +> More categories coming soon: DevRel, Security, InnerSource, DevOps + +## Learn More + +- [GitHub Agentic Workflows Documentation](https://githubnext.github.io/gh-aw/) +- [GitHub Next — Agentic Workflows](https://githubnext.com/projects/agentic-workflows) diff --git a/agentic-workflows/ospo/README.md b/agentic-workflows/ospo/README.md new file mode 100644 index 000000000..b0fc026f2 --- /dev/null +++ b/agentic-workflows/ospo/README.md @@ -0,0 +1,49 @@ +# OSPO Agentic Workflows + +> AI-powered automation for Open Source Program Offices — org health, contributor metrics, compliance, and more. + +## Overview + +These workflows automate common OSPO tasks using [GitHub Agentic Workflows](../README.md). Copy any workflow into your repo's `.github/workflows/` directory, customize the organization name, compile with `gh aw compile`, and you're running. + +## Workflows + +| Workflow | Schedule | What It Does | +|----------|----------|-------------| +| [**org-health**](org-health.md) | Weekly (Monday) | Comprehensive org health report — stale issues/PRs, merge time analysis, contributor leaderboards, health alerts | +| [**contributors-report**](contributors-report.md) | Monthly (1st) | New vs. returning contributor metrics, commit counts, optional Sponsors info | +| [**release-compliance-checker**](release-compliance-checker.md) | On issue open | Audits a repo for OSS release readiness — required files, security config, license compliance, risk assessment | +| [**stale-repos**](stale-repos.md) | Monthly (1st) | Finds repositories with no activity in X days (default: 365) | +| [**dora-metrics**](dora-metrics.md) | Monthly (1st) | DORA engineering metrics — deploy frequency, lead time, change failure rate, MTTR | +| [**team-permissions-audit**](team-permissions-audit.md) | Monthly (1st) | Flags direct (non-team) collaborator access for better security | + +## Quick Start + +```bash +# 1. Copy a workflow to your repo +cp agentic-workflows/ospo/org-health.md your-repo/.github/workflows/ + +# 2. Edit the workflow — change the organization name and any defaults +# (it's just Markdown — edit the plain English instructions) + +# 3. Compile to generate the Actions lock file +cd your-repo +gh aw compile org-health + +# 4. Commit both files +git add .github/workflows/org-health.md .github/workflows/org-health.lock.yml +git commit -m "feat: add org health agentic workflow" +git push +``` + +## Customization Tips + +- **Change the org**: Most workflows default to `"github"` — update this to your organization name +- **Adjust schedules**: Edit the `cron` expression in the YAML frontmatter +- **Tune thresholds**: Stale days, activity methods, exempt repos — all configurable via `workflow_dispatch` inputs +- **Add/remove checks**: Edit the Markdown instructions to add custom checks or remove ones you don't need + +## See Also + +- [ospo-readiness skill](../../skills/ospo-readiness/) — Interactive repo scanner (graded A–F) for use in Copilot chat +- [GitHub Agentic Workflows docs](https://githubnext.github.io/gh-aw/) diff --git a/agentic-workflows/ospo/contributors-report.md b/agentic-workflows/ospo/contributors-report.md new file mode 100644 index 000000000..42047d1cd --- /dev/null +++ b/agentic-workflows/ospo/contributors-report.md @@ -0,0 +1,138 @@ +--- +name: Contributors Report +on: + schedule: + - cron: "3 2 1 * *" + workflow_dispatch: + inputs: + organization: + description: "GitHub organization to analyze (e.g. github)" + required: false + type: string + repositories: + description: "Comma-separated list of repos to analyze (e.g. owner/repo1,owner/repo2)" + required: false + type: string + start_date: + description: "Start date for the report period (YYYY-MM-DD)" + required: false + type: string + end_date: + description: "End date for the report period (YYYY-MM-DD)" + required: false + type: string + sponsor_info: + description: "Include GitHub Sponsors information for contributors" + required: false + type: boolean + default: false + +permissions: + contents: read + issues: read + pull-requests: read + +engine: copilot + +tools: + github: + toolsets: + - repos + - issues + - pull_requests + - orgs + - users + bash: true + +safe-outputs: + create-issue: + max: 1 + title-prefix: "[Contributors Report] " + +timeout-minutes: 60 +--- + +# Contributors Report + +Generate a contributors report for the specified organization or repositories. + +## Step 1: Validate Configuration + +Check the workflow inputs. Either `organization` or `repositories` must be provided. + +- If **both** are empty and this is a **scheduled run**, default to analyzing all public repositories in the organization that owns the current repository. Determine the org from the `GITHUB_REPOSITORY` environment variable (the part before the `/`). +- If **both** are empty and this is a **manual dispatch**, fail with a clear error message: "You must provide either an organization or a comma-separated list of repositories." +- If **both** are provided, prefer `repositories` and ignore `organization`. + +## Step 2: Determine Date Range + +- If `start_date` and `end_date` are provided, use them. +- Otherwise, default to the **previous calendar month**. For example, if today is 2025-03-15, the range is 2025-02-01 to 2025-02-28. +- Use bash to compute the dates if needed. Store them as `START_DATE` and `END_DATE`. + +## Step 3: Enumerate Repositories + +- If `repositories` input was provided, split the comma-separated string into a list. Each entry should be in `owner/repo` format. +- If `organization` input was provided (or defaulted from Step 1), list all **public, non-archived, non-fork** repositories in the organization using the GitHub API. Collect their `owner/repo` identifiers. + +## Step 4: Collect Contributors from Commit History + +For each repository in scope: + +1. Use the GitHub API to list commits between `START_DATE` and `END_DATE` (use the `since` and `until` parameters on the commits endpoint). +2. For each commit, extract the **author login** (from `author.login` on the commit object). +3. **Exclude bot accounts**: skip any contributor whose username contains `[bot]` or whose `type` field is `"Bot"`. +4. Track per-contributor: + - Total number of commits across all repos. + - The set of repos they contributed to. + +Use bash to aggregate and deduplicate the contributor data across all repositories. + +## Step 5: Determine New vs Returning Contributors + +For each contributor found in Step 4, check whether they have **any commits before `START_DATE`** in any of the in-scope repositories. + +- If a contributor has **no commits before `START_DATE`**, mark them as a **New Contributor**. +- Otherwise, mark them as a **Returning Contributor**. + +## Step 6: Collect Sponsor Information (Optional) + +If the `sponsor_info` input is `true`: + +1. For each contributor, check whether they have a GitHub Sponsors profile by querying the user's profile via the GitHub API. +2. If the user has sponsorship enabled, record their sponsor URL as `https://github.com/sponsors/`. +3. If not, leave the sponsor field empty. + +## Step 7: Generate Markdown Report + +Build a markdown report with the following structure: + +### Summary Table + +| Metric | Value | +|---|---| +| Total Contributors | count | +| Total Contributions (Commits) | count | +| New Contributors | count | +| Returning Contributors | count | +| % New Contributors | percentage | + +### Contributors Detail Table + +Sort contributors by commit count descending. + +| # | Username | Contribution Count | New Contributor | Sponsor URL | Commits | +|---|---|---|---|---|---| +| 1 | @username | 42 | Yes | [Sponsor](url) | [View](commits-url) | + +- The **Username** column should link to the contributor's GitHub profile. +- The **Sponsor URL** column should show "N/A" if `sponsor_info` is false or the user has no Sponsors page. +- The **Commits** column should link to a filtered commits view. + +## Step 8: Create Issue with Report + +Create an issue in the **current repository** with: + +- **Title:** `[Contributors Report] — START_DATE to END_DATE` +- **Body:** The full markdown report from Step 7. +- **Labels:** Add the label `contributors-report` if it exists; do not fail if it does not. diff --git a/agentic-workflows/ospo/dora-metrics.md b/agentic-workflows/ospo/dora-metrics.md new file mode 100644 index 000000000..ca37662be --- /dev/null +++ b/agentic-workflows/ospo/dora-metrics.md @@ -0,0 +1,173 @@ +--- +name: DORA Metrics Report +on: + schedule: + - cron: "3 2 1 * *" + workflow_dispatch: + inputs: + organization: + description: "GitHub organization to analyze" + required: true + type: string + default: "github" + repositories: + description: "Comma-separated list of repos to analyze (leave empty for org-wide)" + required: false + type: string + default: "" + time_period: + description: "Time period to analyze" + required: false + type: choice + options: + - 30d + - 90d + - 6m + - 1y + default: 90d + incident_label: + description: "Issue label that identifies production incidents" + required: false + type: string + default: "incident" + dry_run: + description: "If true, log findings without creating an issue" + required: false + type: boolean + default: false + +permissions: + contents: read + issues: read + pull-requests: read + +engine: copilot +tools: + github: + toolsets: + - repos + - issues + - pull_requests + bash: true + +safe-outputs: + create-issue: + max: 1 + title-prefix: "[DORA Metrics] " + labels: + - dora-metrics + +timeout-minutes: 45 +--- + +You are an assistant that calculates DORA metrics for a GitHub organization. + +## Inputs + +| Input | Default | +|---|---| +| `organization` | `github` | +| `repositories` | _(all repos)_ | +| `time_period` | `90d` | +| `incident_label` | `incident` | +| `dry_run` | `false` | + +Use the workflow dispatch inputs if provided; otherwise fall back to the defaults above. + +## Instructions + +### 1. Determine scope and time window + +Parse `time_period` into a calendar duration: `30d` = 30 days, `90d` = 90 days, `6m` = 180 days, `1y` = 365 days. Compute the **start date** by subtracting that duration from today. + +If `repositories` is non-empty, split it by comma and analyze only those repos. Otherwise, list **all non-archived** repositories in the `organization` and analyze each one. + +### 2. Deployment Frequency + +For each repository, use the Releases API to list all releases published on or after the start date. Count the total releases per repo within the time window. + +Classify each repo: + +| Level | Criteria | +|---|---| +| Elite | On-demand / multiple deploys per day (avg ≥ 1 release per day) | +| High | Between once per week and once per month | +| Medium | Between once per month and once every 6 months | +| Low | Fewer than once every 6 months | + +### 3. Lead Time for Changes + +For each repository, list pull requests merged on or after the start date. For each merged PR, find the earliest commit in that PR and compute the elapsed time from that commit's author date to the PR merge date. + +Compute the **median lead time** across all merged PRs for that repo. + +| Level | Criteria | +|---|---| +| Elite | Median < 1 day (24 hours) | +| High | Median between 1 day and 1 week | +| Medium | Median between 1 week and 1 month | +| Low | Median > 1 month | + +### 4. Change Failure Rate + +For each repository, examine every release published within the time window. For each release, check whether an issue with the `incident_label` label was opened in that repository within **3 days** after the release's published date. If so, count that release as a failure. + +Compute: **Change Failure Rate = (failure releases / total releases) × 100%**. + +| Level | Criteria | +|---|---| +| Elite | 0–5% | +| High | 5–10% | +| Medium | 10–15% | +| Low | > 15% | + +### 5. Time to Restore Service (MTTR) + +For each repository, list all **closed** issues with the `incident_label` label that were opened on or after the start date. For each, compute the duration from when the issue was opened to when it was closed. + +Compute the **median time to restore** across all incident issues for that repo. + +| Level | Criteria | +|---|---| +| Elite | Median < 1 hour | +| High | Median < 1 day (24 hours) | +| Medium | Median < 1 week | +| Low | Median > 1 week | + +### 6. Generate report + +Build a **Markdown report** with: + +**Summary header:** +> **DORA Metrics Report — \** +> Organization: **\** | Period: **\** | Repos analyzed: **N** + +**Per-repository breakdown table:** + +| Repository | Deploy Freq | Lead Time | Change Failure Rate | MTTR | Overall | +|---|---|---|---|---|---| +| [owner/repo](url) | 12 releases (High) | 2.3 days (High) | 4.2% (Elite) | 3.1h (High) | High | + +The **Overall** level for each repo is the lowest (worst) level among its four metrics (excluding N/A values). + +**Org-wide summary:** + +| Metric | Org-Wide Value | Level | +|---|---|---| +| Deployment Frequency | X releases / period | High | +| Lead Time for Changes | X days | Medium | +| Change Failure Rate | X% | Elite | +| Time to Restore Service | X hours | High | +| **Overall** | | **Medium** | + +### 7. Create or update issue + +If `dry_run` is true, log the full report to the workflow output and stop. + +Otherwise, search for an existing **open** issue with the label `dora-metrics` and a title starting with `[DORA Metrics]`. + +- If found, **update its body** with the new report. +- If not found, **create a new issue** with: + - Title: `[DORA Metrics] Organization Performance Report — ` + - Label: `dora-metrics` + - Body: the full report. diff --git a/agentic-workflows/ospo/org-health.md b/agentic-workflows/ospo/org-health.md new file mode 100644 index 000000000..09acd38fe --- /dev/null +++ b/agentic-workflows/ospo/org-health.md @@ -0,0 +1,289 @@ +--- +name: Weekly Organization Health Report +description: > + Comprehensive weekly health report for a GitHub organization. + Surfaces stale issues/PRs, merge time analysis, contributor leaderboards, + and actionable items needing human attention. + +on: + schedule: + - cron: "0 10 * * 1" + workflow_dispatch: + inputs: + organization: + description: "GitHub organization to report on" + type: string + required: true + +permissions: + contents: read + issues: read + pull-requests: read + actions: read + +engine: copilot + +tools: + github: + toolsets: + - repos + - issues + - pull_requests + - orgs + bash: true + +safe-outputs: + create-issue: + max: 1 + title-prefix: "[Org Health] " + +timeout-minutes: 60 + +network: + allowed: + - defaults + - python +--- + +You are an expert GitHub organization analyst. Your job is to produce a +comprehensive weekly health report for the **`github`** organization +(or the organization provided via workflow input). + +## Primary Goal + +**Surface issues and PRs that need human attention**, celebrate wins, and +provide actionable metrics so maintainers can prioritize their time. + +--- + +## Step 1 — Determine the Organization + +``` +ORG = inputs.organization OR "github" +PERIOD_DAYS = 30 +SINCE = date 30 days ago (ISO 8601) +STALE_ISSUE_DAYS = 60 +STALE_PR_DAYS = 30 +``` + +## Step 2 — Gather Organization-Wide Aggregates (Search API) + +Use GitHub search APIs for fast org-wide counts. These are efficient and +avoid per-repo iteration for basic aggregates. + +Collect the following using search queries: + +| Metric | Search Query | +|--------|-------------| +| Total open issues | `org: is:issue is:open` | +| Total open PRs | `org: is:pr is:open` | +| Issues opened (last 30d) | `org: is:issue created:>={SINCE}` | +| Issues closed (last 30d) | `org: is:issue is:closed closed:>={SINCE}` | +| PRs opened (last 30d) | `org: is:pr created:>={SINCE}` | +| PRs merged (last 30d) | `org: is:pr is:merged merged:>={SINCE}` | +| PRs closed unmerged (last 30d) | `org: is:pr is:closed is:unmerged closed:>={SINCE}` | +| Stale issues (60+ days) | `org: is:issue is:open updated:<={60_DAYS_AGO}` | +| Stale PRs (30+ days) | `org: is:pr is:open updated:<={30_DAYS_AGO}` | + +**Performance tip:** Add 1–2 second delays between search API calls to +stay well within rate limits. + +## Step 3 — Stale Issues & PRs (Heat Scores) + +For stale issues and stale PRs found above, retrieve the top results and +sort them by **heat score** (comment count). The heat score helps +maintainers prioritize: a stale issue with many comments signals community +interest that is going unaddressed. + +- **Stale issues**: Retrieve up to 50, sort by `comments` descending, + keep top 10. For each, record: repo, number, title, days since last + update, comment count (heat score), author, labels. +- **Stale PRs**: Same approach — retrieve up to 50, sort by `comments` + descending, keep top 10. + +## Step 4 — PR Merge Time Analysis + +From the PRs merged in the last 30 days (Step 2), retrieve a sample of +recently merged PRs (up to 100). For each, calculate: + +``` +merge_time = merged_at - created_at (in hours) +``` + +Then compute percentiles: +- **p50** (median merge time) +- **p75** +- **p95** + +Use bash with Python for percentile calculations: + +```bash +python3 -c " +import json, sys +times = json.loads(sys.stdin.read()) +times.sort() +n = len(times) +if n == 0: + print('No data') +else: + p50 = times[int(n * 0.50)] + p75 = times[int(n * 0.75)] + p95 = times[int(n * 0.95)] if n >= 20 else times[-1] + print(f'p50={p50:.1f}h, p75={p75:.1f}h, p95={p95:.1f}h') +" +``` + +## Step 5 — First Response Time + +For issues and PRs opened in the last 30 days, sample up to 50 of each. +For each item, find the first comment (excluding the author). Calculate: + +``` +first_response_time = first_comment.created_at - item.created_at (in hours) +``` + +Report median first response time for issues and PRs separately. + +## Step 6 — Repository Activity & Contributor Leaderboard + +### Top 10 Active Repos +List all non-archived repos in the org. For each, count pushes / commits / +issues+PRs opened in the last 30 days. Sort by total activity, keep top 10. + +### Contributor Leaderboard +From the top 10 active repos, aggregate commit authors over the last 30 +days. Rank by commit count, keep top 10. Award: +- 🥇 for #1 +- 🥈 for #2 +- 🥉 for #3 + +### Inactive Repos +Repos with 0 pushes, 0 issues, 0 PRs in the last 30 days. List them +(name + last push date) so the org can decide whether to archive. + +## Step 7 — Health Alerts & Trends + +Compute velocity indicators and assign status: + +| Indicator | 🟢 Green | 🟡 Yellow | 🔴 Red | +|-----------|----------|-----------|--------| +| Issue close rate | closed ≥ opened | closed ≥ 70% opened | closed < 70% opened | +| PR merge rate | merged ≥ opened | merged ≥ 60% opened | merged < 60% opened | +| Median merge time | < 24h | 24–72h | > 72h | +| Median first response | < 24h | 24–72h | > 72h | +| Stale issue count | < 10 | 10–50 | > 50 | +| Stale PR count | < 5 | 5–20 | > 20 | + +## Step 8 — Wins & Shoutouts + +Celebrate positive signals: +- PRs merged with fast turnaround (< 4 hours) +- Issues closed quickly (< 24 hours from open to close) +- Top contributors (from leaderboard) +- Repos with zero stale items + +## Step 9 — Compose the Report + +Create a single issue in the org's `.github` repository (or the most +appropriate central repo) with the title: + +``` +[Org Health] Weekly Report — +``` + +Use this structure for the issue body: + +```markdown +# 🏥 Org Health Report: +**Period**: Last 30 days | **Generated**: + +--- + +## 🚨 Health Alerts & Trends + +| Indicator | Status | Value | +|-----------|--------|-------| +| Issue close rate | 🟢/🟡/🔴 | X closed / Y opened (Z%) | +| PR merge rate | 🟢/🟡/🔴 | X merged / Y opened (Z%) | +| Median merge time | 🟢/🟡/🔴 | Xh | +| Median first response | 🟢/🟡/🔴 | Xh | +| Stale issues | 🟢/🟡/🔴 | N | +| Stale PRs | 🟢/🟡/🔴 | N | + +--- + +## 🏆 Wins & Shoutouts + +- 🎉 **Fast merges**: List PRs merged in < 4h +- ⚡ **Quick closes**: Issues resolved in < 24h +- 🌟 **Top contributors**: @user1, @user2, @user3 + +--- + +## 📋 Action Items + +### Stale Issues Needing Review (Top 10 by Heat Score) +| # | Repo | Issue | Days Stale | 🔥 Heat | Labels | +|---|------|-------|------------|---------|--------| +| 1 | repo | #N title | Xd | Y comments | label1, label2 | + +### Stale PRs Needing Review (Top 10 by Heat Score) +| # | Repo | PR | Days Stale | 🔥 Heat | Author | +|---|------|----|------------|---------|--------| +| 1 | repo | #N title | Xd | Y comments | @user | + +--- + +## ⏱️ PR Merge Time Analysis + +| Percentile | Time | +|------------|------| +| p50 (median) | Xh | +| p75 | Xh | +| p95 | Xh | + +--- + +## ⚡ First Response Time + +| Category | Median First Response | +|----------|---------------------| +| Issues | Xh | +| Pull Requests | Xh | + +--- + +## 📊 Top 10 Active Repositories + +| # | Repository | Issues | PRs | Commits | Total Activity | +|---|------------|--------|-----|---------|---------------| +| 1 | repo-name | N | N | N | N | + +--- + +## 👥 Contributor Leaderboard + +| Rank | Contributor | Commits | Top Repo | +|------|-------------|---------|----------| +| 🥇 | @user1 | N | repo | +| 🥈 | @user2 | N | repo | +| 🥉 | @user3 | N | repo | + +--- + +## 😴 Inactive Repositories (0 activity in 30 days) + +| Repository | Last Push | Description | +|------------|-----------|-------------| +| repo-name | YYYY-MM-DD | Short description | +``` + +## Important Notes + +- **Update `github`** to your organization name before use. +- If any API call fails, note it in the report and continue with available + data. Do not let a single failure block the entire report. +- Keep the issue body under 65,000 characters (GitHub issue body limit). +- All times should be reported in hours. Convert to days only if > 72 hours. +- Use the `safe-outputs` constraint: only create 1 issue, with title + prefixed `[Org Health] `. diff --git a/agentic-workflows/ospo/release-compliance-checker.md b/agentic-workflows/ospo/release-compliance-checker.md new file mode 100644 index 000000000..167442fb8 --- /dev/null +++ b/agentic-workflows/ospo/release-compliance-checker.md @@ -0,0 +1,171 @@ +--- +name: OSS Release Compliance Checker +description: > + Analyzes a target repository against open source release requirements and + posts a detailed compliance report as an issue comment. Checks for required + files, security settings, license compliance, and generates a risk assessment. + +on: + issues: + types: [opened, labeled] + workflow_dispatch: + +permissions: + contents: read + issues: read + pull-requests: read + actions: read + +engine: copilot + +tools: + github: + toolsets: + - repos + - issues + bash: true + +safe-outputs: + add-comment: + max: 1 + +timeout-minutes: 20 +--- + +You are an open source release compliance checker. Your job is to analyze a +repository that has been proposed for open source release and post a thorough, +constructive compliance report as a comment on the triggering issue. + +## 1. Trigger Guard + +First, determine whether this workflow should proceed: + +- If the event is `workflow_dispatch`, proceed. +- If the event is `issues` with type `opened`, proceed. +- If the event is `issues` with type `labeled`, only proceed if the label that + was just added is **`ospo-release-check`**. +- Otherwise, stop and do nothing. + +## 2. Extract Target Repository + +Read the body of the triggering issue. Look for the repository that is being +proposed for release. It may appear as: + +- A full GitHub URL such as `https://github.com/org/repo-name` +- An `owner/repo` shorthand such as `org/repo-name` + +Extract the **owner** and **repo name**. If you cannot find a repository +reference, post a comment asking the issue author to include one and stop. + +## 3. File Compliance Check + +For the target repository, check whether each of the following files exists at +the repository root (or in `.github/` where conventional). For each file that +exists, also assess whether it has meaningful content. + +| File | What to look for | +|------|-----------------| +| `LICENSE` | Must be present. Contents must match the license declared in the repo metadata. | +| `README.md` | Must be present and substantial (>100 lines recommended). Should contain sections for usage, install, and contributing. | +| `CODEOWNERS` | Must list at least one maintainer or team. | +| `CONTRIBUTING.md` | Must describe how to contribute (issues, PRs, CLA/DCO, code style). | +| `SUPPORT.md` | Must explain how users can get help. | +| `CODE_OF_CONDUCT.md` | Must adopt a recognized code of conduct. | +| `SECURITY.md` | Must describe the security vulnerability disclosure process. | + +## 4. Security Configuration Check + +Using the GitHub API, check the following security settings on the target +repository: + +- **Secret scanning** — Is secret scanning enabled? +- **Dependabot** — Are Dependabot alerts and/or security updates enabled? +- **Code scanning (CodeQL)** — Are any code scanning analyses present? +- **Branch protection** — Is the default branch protected? Are required reviews, + status checks, or signed commits configured? + +Handle `404` or `403` responses gracefully — they typically mean the feature is +not enabled or you lack permission to check it. + +## 5. License & Legal Analysis + +- Compare the contents of the `LICENSE` file against the license declared in + the repository metadata (`license.spdx_id` from the repo API response). + Flag any mismatch. +- Look for dependency manifests (`package.json`, `requirements.txt`, `go.mod`, + `Cargo.toml`, `pom.xml`, `Gemfile`, `*.csproj`, etc.) in the repository. +- For each manifest found, attempt to identify declared dependency licenses. + Specifically flag any **GPL**, **AGPL**, **LGPL**, or other strong-copyleft + licenses that would require legal review before an open source release. + +## 6. Risk Assessment + +Based on your findings, assign a risk level (**Low**, **Medium**, or **High**) +to each of the following categories: + +| Category | Low 🟢 | Medium 🟡 | High 🔴 | +|----------|--------|-----------|---------| +| **Business Risk** | No secrets, no proprietary code patterns | Some internal references found | Secrets detected, proprietary code | +| **Legal Risk** | Permissive license, no copyleft deps | Minor license inconsistencies | GPL/AGPL deps, license mismatch | +| **Open Source Risk** | All files present, active maintainers | Some files missing or thin | No README, no CODEOWNERS | + +## 7. Generate Compliance Report + +Post **one** comment on the triggering issue with this structure: + +```markdown +## 🔍 OSS Release Compliance Report + +**Repository:** `owner/repo` +**Checked at:** +**Overall status:** PASS ✅ | NEEDS WORK ⚠️ | BLOCKED 🚫 + +--- + +### 📄 File Compliance + +| File | Status | Notes | +|------|--------|-------| +| LICENSE | ✅ / ❌ | ... | +| README.md | ✅ / ❌ | ... | +| ... | ... | ... | + +### 🔒 Security Configuration + +| Setting | Status | Notes | +|---------|--------|-------| +| Secret scanning | ✅ / ❌ | ... | +| ... | ... | ... | + +### ⚖️ License Analysis + +- **Declared license:** ... +- **LICENSE file match:** ✅ / ❌ +- **Copyleft flags:** ... + +### 📊 Risk Assessment + +| Category | Level | Details | +|----------|-------|---------| +| Business Risk | 🟢/🟡/🔴 | ... | +| Legal Risk | 🟢/🟡/🔴 | ... | +| Open Source Risk | 🟢/🟡/🔴 | ... | + +### 📋 Recommendations + +**🚫 Must Fix (blocking release)** +- ... + +**⚠️ Should Address (strongly recommended)** +- ... + +**💡 Nice to Have (polish)** +- ... +``` + +### Tone Guidelines + +- Be **constructive**. The goal is to help teams succeed, not to gatekeep. +- When something is missing, explain *why* it matters and link to relevant + guidance when possible. +- Celebrate what the team has already done well. diff --git a/agentic-workflows/ospo/stale-repos.md b/agentic-workflows/ospo/stale-repos.md new file mode 100644 index 000000000..588d6b030 --- /dev/null +++ b/agentic-workflows/ospo/stale-repos.md @@ -0,0 +1,117 @@ +--- +name: Stale Repository Report +on: + schedule: + - cron: "3 2 1 * *" + workflow_dispatch: + inputs: + organization: + description: "GitHub organization to scan" + required: true + type: string + default: "github" + inactive_days: + description: "Number of days of inactivity before a repo is considered stale" + required: false + type: number + default: 365 + exempt_repos: + description: "Comma-separated list of repos to exempt from the report" + required: false + type: string + default: "" + exempt_topics: + description: "Comma-separated list of topics — repos with any of these topics are exempt" + required: false + type: string + default: "" + activity_method: + description: "Method to determine last activity" + required: false + type: choice + options: + - pushed + - default_branch_updated + default: pushed + +permissions: + contents: read + issues: read + +engine: copilot +tools: + github: + toolsets: + - repos + - issues + bash: true + +safe-outputs: + create-issue: + max: 1 + title-prefix: "[Stale Repos] " + labels: + - stale-repos + +timeout-minutes: 30 +--- + +You are an assistant that audits GitHub repositories for staleness. + +## Inputs + +| Input | Default | +|---|---| +| `organization` | `github` | +| `inactive_days` | `365` | +| `exempt_repos` | _(none)_ | +| `exempt_topics` | _(none)_ | +| `activity_method` | `pushed` | + +Use the workflow dispatch inputs if provided; otherwise fall back to the defaults above. + +## Instructions + +### 1. Enumerate repositories + +List **all** repositories in the `organization`. Exclude any repo that is: + +- **Archived** — skip it entirely. +- **Listed in `exempt_repos`** — compare repo names (case-insensitive) against the comma-separated list. +- **Tagged with an exempt topic** — if the repo has any topic that appears in the comma-separated `exempt_topics` list, skip it. + +### 2. Determine last activity date + +For each remaining repo, determine the **last activity date** based on `activity_method`: + +- **`pushed`** — use the repository's `pushed_at` timestamp (this is the default and most efficient method). +- **`default_branch_updated`** — fetch the most recent commit on the repo's default branch and use that commit's `committer.date`. + +### 3. Identify stale repos + +Calculate the number of days between the last activity date and **today**. If the number of days exceeds `inactive_days`, mark the repo as **stale**. + +### 4. Generate report + +Build a **Markdown report** with a summary and a table: + +> **Stale Repository Report — \** +> Found **N** repositories with no activity in the last **inactive_days** days. + +| Repository | Days Inactive | Last Push Date | Visibility | +|---|---|---|---| +| [owner/repo](https://github.com/owner/repo) | 420 | 2024-01-15 | public | + +Sort the table by **Days Inactive** descending (most stale first). + +If there are **no stale repos**, still create the issue but note that all repositories are active. + +### 5. Create or update issue + +Search for an existing **open** issue in the `organization/.github` repo (or the repo this workflow runs in) with the label `stale-repos` and a title starting with `[Stale Repos]`. + +- If an **existing open issue** is found, **update its body** with the new report. +- If **no open issue** exists, **create a new issue** with: + - Title: `[Stale Repos] Inactive Repository Report — ` + - Label: `stale-repos` + - Body: the full Markdown report from step 4. diff --git a/agentic-workflows/ospo/team-permissions-audit.md b/agentic-workflows/ospo/team-permissions-audit.md new file mode 100644 index 000000000..9b36b5532 --- /dev/null +++ b/agentic-workflows/ospo/team-permissions-audit.md @@ -0,0 +1,138 @@ +--- +name: Team Permissions Audit +description: > + Scans organization repositories for direct (non-team) collaborator access + and reports findings. Helps enforce team-based permission management for + better security and maintainability. + +on: + schedule: + - cron: "3 2 1 * *" + workflow_dispatch: + inputs: + organization: + description: "GitHub organization to audit" + required: true + type: string + default: "github" + exempt_repos: + description: "Comma-separated list of repo names to skip" + required: false + type: string + default: "" + exempt_users: + description: "Comma-separated list of usernames to exempt (e.g. bots, outside collaborators)" + required: false + type: string + default: "" + dry_run: + description: "If true, log findings without creating an issue" + required: false + type: boolean + default: false + +permissions: + contents: read + issues: read + +engine: copilot +tools: + github: + toolsets: + - repos + - issues + bash: true + +safe-outputs: + create-issue: + max: 1 + title-prefix: "[Permissions Audit] " + labels: + - permissions-audit + +timeout-minutes: 30 +--- + +You are an assistant that audits GitHub repository permissions to ensure +team-based access management. Your goal is to identify repositories where +individual users have been granted direct collaborator access instead of +receiving access through team membership. + +## Inputs + +| Input | Default | +|---|---| +| `organization` | `github` | +| `exempt_repos` | _(none)_ | +| `exempt_users` | _(none)_ | +| `dry_run` | `false` | + +## Instructions + +### Step 1 — Enumerate repositories + +List all repositories in the provided organization. Skip any repository +that is archived. Also skip any repository whose name appears in the +`exempt_repos` input (comma-separated). + +### Step 2 — Identify direct collaborators + +For each repository, list collaborators with their permission level and +affiliation. Focus on users whose affiliation is "direct" — meaning they +were added individually rather than through a team. Also identify outside +collaborators (affiliation "outside"). Exclude any username that appears +in the `exempt_users` input. + +### Step 3 — List team access + +For each repository, list all teams that have access and their +corresponding permission levels. This context helps determine whether a +direct collaborator's access is redundant with existing team grants. + +### Step 4 — Flag direct access grants + +For each repository, flag individual users who have direct access that +could instead be managed through a team. If a user already has access via +a team at the same or higher permission level, their direct grant is +redundant and should be removed. If no suitable team exists, suggest +creating one or adding the user to an existing team. + +### Step 5 — Handle outside collaborators separately + +Outside collaborators cannot be added to organization teams. Flag these +users in a separate section of the report with a note that individual +access is expected and required for outside collaborators. + +### Step 6 — Generate report + +Produce a report with the following structure: + +**Summary line:** "Found N repos with M direct collaborator grants" + +**Direct collaborator table:** + +| Repository | User | Permission | Affiliation | Suggested Action | +|------------|------|------------|-------------|------------------| +| repo-name | @user | write | direct | Remove — already covered by team [team-name] | + +Populate the Suggested Action column with one of: +- "Remove — already covered by team [team-name]" +- "Add to team [team-name] and remove direct grant" +- "Create a team for this access pattern" + +**Outside collaborators section (informational):** + +List outside collaborators grouped by repository with their permission +levels. Note that these require individual access grants and are not +actionable findings. + +### Step 7 — Output results + +If `dry_run` is true, output the full report to the workflow logs only. +Do not create or update any issue. + +If `dry_run` is false, search for an existing open issue with the label +`permissions-audit`. If one exists, update its body with the new report. +If none exists, create a new issue titled +"[Permissions Audit] Direct collaborator access report" with the label +`permissions-audit` and the report as the body. From 28c3bf948f7d2ba61b272f56ea4bd13952f2962a Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 15:55:45 -0800 Subject: [PATCH 08/17] chore: remove dora-metrics and team-permissions-audit workflows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/README.md | 2 - agentic-workflows/ospo/dora-metrics.md | 173 ------------------ .../ospo/team-permissions-audit.md | 138 -------------- 3 files changed, 313 deletions(-) delete mode 100644 agentic-workflows/ospo/dora-metrics.md delete mode 100644 agentic-workflows/ospo/team-permissions-audit.md diff --git a/agentic-workflows/ospo/README.md b/agentic-workflows/ospo/README.md index b0fc026f2..c0583a9ba 100644 --- a/agentic-workflows/ospo/README.md +++ b/agentic-workflows/ospo/README.md @@ -14,8 +14,6 @@ These workflows automate common OSPO tasks using [GitHub Agentic Workflows](../R | [**contributors-report**](contributors-report.md) | Monthly (1st) | New vs. returning contributor metrics, commit counts, optional Sponsors info | | [**release-compliance-checker**](release-compliance-checker.md) | On issue open | Audits a repo for OSS release readiness — required files, security config, license compliance, risk assessment | | [**stale-repos**](stale-repos.md) | Monthly (1st) | Finds repositories with no activity in X days (default: 365) | -| [**dora-metrics**](dora-metrics.md) | Monthly (1st) | DORA engineering metrics — deploy frequency, lead time, change failure rate, MTTR | -| [**team-permissions-audit**](team-permissions-audit.md) | Monthly (1st) | Flags direct (non-team) collaborator access for better security | ## Quick Start diff --git a/agentic-workflows/ospo/dora-metrics.md b/agentic-workflows/ospo/dora-metrics.md deleted file mode 100644 index ca37662be..000000000 --- a/agentic-workflows/ospo/dora-metrics.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -name: DORA Metrics Report -on: - schedule: - - cron: "3 2 1 * *" - workflow_dispatch: - inputs: - organization: - description: "GitHub organization to analyze" - required: true - type: string - default: "github" - repositories: - description: "Comma-separated list of repos to analyze (leave empty for org-wide)" - required: false - type: string - default: "" - time_period: - description: "Time period to analyze" - required: false - type: choice - options: - - 30d - - 90d - - 6m - - 1y - default: 90d - incident_label: - description: "Issue label that identifies production incidents" - required: false - type: string - default: "incident" - dry_run: - description: "If true, log findings without creating an issue" - required: false - type: boolean - default: false - -permissions: - contents: read - issues: read - pull-requests: read - -engine: copilot -tools: - github: - toolsets: - - repos - - issues - - pull_requests - bash: true - -safe-outputs: - create-issue: - max: 1 - title-prefix: "[DORA Metrics] " - labels: - - dora-metrics - -timeout-minutes: 45 ---- - -You are an assistant that calculates DORA metrics for a GitHub organization. - -## Inputs - -| Input | Default | -|---|---| -| `organization` | `github` | -| `repositories` | _(all repos)_ | -| `time_period` | `90d` | -| `incident_label` | `incident` | -| `dry_run` | `false` | - -Use the workflow dispatch inputs if provided; otherwise fall back to the defaults above. - -## Instructions - -### 1. Determine scope and time window - -Parse `time_period` into a calendar duration: `30d` = 30 days, `90d` = 90 days, `6m` = 180 days, `1y` = 365 days. Compute the **start date** by subtracting that duration from today. - -If `repositories` is non-empty, split it by comma and analyze only those repos. Otherwise, list **all non-archived** repositories in the `organization` and analyze each one. - -### 2. Deployment Frequency - -For each repository, use the Releases API to list all releases published on or after the start date. Count the total releases per repo within the time window. - -Classify each repo: - -| Level | Criteria | -|---|---| -| Elite | On-demand / multiple deploys per day (avg ≥ 1 release per day) | -| High | Between once per week and once per month | -| Medium | Between once per month and once every 6 months | -| Low | Fewer than once every 6 months | - -### 3. Lead Time for Changes - -For each repository, list pull requests merged on or after the start date. For each merged PR, find the earliest commit in that PR and compute the elapsed time from that commit's author date to the PR merge date. - -Compute the **median lead time** across all merged PRs for that repo. - -| Level | Criteria | -|---|---| -| Elite | Median < 1 day (24 hours) | -| High | Median between 1 day and 1 week | -| Medium | Median between 1 week and 1 month | -| Low | Median > 1 month | - -### 4. Change Failure Rate - -For each repository, examine every release published within the time window. For each release, check whether an issue with the `incident_label` label was opened in that repository within **3 days** after the release's published date. If so, count that release as a failure. - -Compute: **Change Failure Rate = (failure releases / total releases) × 100%**. - -| Level | Criteria | -|---|---| -| Elite | 0–5% | -| High | 5–10% | -| Medium | 10–15% | -| Low | > 15% | - -### 5. Time to Restore Service (MTTR) - -For each repository, list all **closed** issues with the `incident_label` label that were opened on or after the start date. For each, compute the duration from when the issue was opened to when it was closed. - -Compute the **median time to restore** across all incident issues for that repo. - -| Level | Criteria | -|---|---| -| Elite | Median < 1 hour | -| High | Median < 1 day (24 hours) | -| Medium | Median < 1 week | -| Low | Median > 1 week | - -### 6. Generate report - -Build a **Markdown report** with: - -**Summary header:** -> **DORA Metrics Report — \** -> Organization: **\** | Period: **\** | Repos analyzed: **N** - -**Per-repository breakdown table:** - -| Repository | Deploy Freq | Lead Time | Change Failure Rate | MTTR | Overall | -|---|---|---|---|---|---| -| [owner/repo](url) | 12 releases (High) | 2.3 days (High) | 4.2% (Elite) | 3.1h (High) | High | - -The **Overall** level for each repo is the lowest (worst) level among its four metrics (excluding N/A values). - -**Org-wide summary:** - -| Metric | Org-Wide Value | Level | -|---|---|---| -| Deployment Frequency | X releases / period | High | -| Lead Time for Changes | X days | Medium | -| Change Failure Rate | X% | Elite | -| Time to Restore Service | X hours | High | -| **Overall** | | **Medium** | - -### 7. Create or update issue - -If `dry_run` is true, log the full report to the workflow output and stop. - -Otherwise, search for an existing **open** issue with the label `dora-metrics` and a title starting with `[DORA Metrics]`. - -- If found, **update its body** with the new report. -- If not found, **create a new issue** with: - - Title: `[DORA Metrics] Organization Performance Report — ` - - Label: `dora-metrics` - - Body: the full report. diff --git a/agentic-workflows/ospo/team-permissions-audit.md b/agentic-workflows/ospo/team-permissions-audit.md deleted file mode 100644 index 9b36b5532..000000000 --- a/agentic-workflows/ospo/team-permissions-audit.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -name: Team Permissions Audit -description: > - Scans organization repositories for direct (non-team) collaborator access - and reports findings. Helps enforce team-based permission management for - better security and maintainability. - -on: - schedule: - - cron: "3 2 1 * *" - workflow_dispatch: - inputs: - organization: - description: "GitHub organization to audit" - required: true - type: string - default: "github" - exempt_repos: - description: "Comma-separated list of repo names to skip" - required: false - type: string - default: "" - exempt_users: - description: "Comma-separated list of usernames to exempt (e.g. bots, outside collaborators)" - required: false - type: string - default: "" - dry_run: - description: "If true, log findings without creating an issue" - required: false - type: boolean - default: false - -permissions: - contents: read - issues: read - -engine: copilot -tools: - github: - toolsets: - - repos - - issues - bash: true - -safe-outputs: - create-issue: - max: 1 - title-prefix: "[Permissions Audit] " - labels: - - permissions-audit - -timeout-minutes: 30 ---- - -You are an assistant that audits GitHub repository permissions to ensure -team-based access management. Your goal is to identify repositories where -individual users have been granted direct collaborator access instead of -receiving access through team membership. - -## Inputs - -| Input | Default | -|---|---| -| `organization` | `github` | -| `exempt_repos` | _(none)_ | -| `exempt_users` | _(none)_ | -| `dry_run` | `false` | - -## Instructions - -### Step 1 — Enumerate repositories - -List all repositories in the provided organization. Skip any repository -that is archived. Also skip any repository whose name appears in the -`exempt_repos` input (comma-separated). - -### Step 2 — Identify direct collaborators - -For each repository, list collaborators with their permission level and -affiliation. Focus on users whose affiliation is "direct" — meaning they -were added individually rather than through a team. Also identify outside -collaborators (affiliation "outside"). Exclude any username that appears -in the `exempt_users` input. - -### Step 3 — List team access - -For each repository, list all teams that have access and their -corresponding permission levels. This context helps determine whether a -direct collaborator's access is redundant with existing team grants. - -### Step 4 — Flag direct access grants - -For each repository, flag individual users who have direct access that -could instead be managed through a team. If a user already has access via -a team at the same or higher permission level, their direct grant is -redundant and should be removed. If no suitable team exists, suggest -creating one or adding the user to an existing team. - -### Step 5 — Handle outside collaborators separately - -Outside collaborators cannot be added to organization teams. Flag these -users in a separate section of the report with a note that individual -access is expected and required for outside collaborators. - -### Step 6 — Generate report - -Produce a report with the following structure: - -**Summary line:** "Found N repos with M direct collaborator grants" - -**Direct collaborator table:** - -| Repository | User | Permission | Affiliation | Suggested Action | -|------------|------|------------|-------------|------------------| -| repo-name | @user | write | direct | Remove — already covered by team [team-name] | - -Populate the Suggested Action column with one of: -- "Remove — already covered by team [team-name]" -- "Add to team [team-name] and remove direct grant" -- "Create a team for this access pattern" - -**Outside collaborators section (informational):** - -List outside collaborators grouped by repository with their permission -levels. Note that these require individual access grants and are not -actionable findings. - -### Step 7 — Output results - -If `dry_run` is true, output the full report to the workflow logs only. -Do not create or update any issue. - -If `dry_run` is false, search for an existing open issue with the label -`permissions-audit`. If one exists, update its body with the new report. -If none exists, create a new issue titled -"[Permissions Audit] Direct collaborator access report" with the label -`permissions-audit` and the report as the body. From 6b7f4e7cf010ab5e0187215518593a99e7a8bff7 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 16:07:16 -0800 Subject: [PATCH 09/17] chore: trim READMEs and condense report templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove redundant safe-outputs section from top-level README (already in example) - Remove duplicate Quick Start from OSPO README - Condense org-health report template from 83-line example to 10-line section list - Condense compliance-checker report template similarly - Total: 1183 → 712 lines (-40%) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- agentic-workflows/README.md | 23 +--- agentic-workflows/ospo/README.md | 35 ++---- agentic-workflows/ospo/org-health.md | 100 +++--------------- .../ospo/release-compliance-checker.md | 62 ++--------- 4 files changed, 31 insertions(+), 189 deletions(-) diff --git a/agentic-workflows/README.md b/agentic-workflows/README.md index a0f0a1d88..c2706db45 100644 --- a/agentic-workflows/README.md +++ b/agentic-workflows/README.md @@ -75,33 +75,12 @@ Create a GitHub issue with the report. 4. **Commit both files** — the `.md` source and the generated `.lock.yml` 5. **Push** — the workflow runs on the triggers you defined -## Safe-Outputs: Built-in Guardrails - -Every agentic workflow declares `safe-outputs` in its frontmatter. These are hard limits on what the AI can do per run: - -```yaml -safe-outputs: - create-issue: - max: 1 # Create at most 1 issue - title-prefix: "[Report] " # Must start with this prefix - create-pull-request: - max: 3 - add-comment: - max: 5 - add-labels: - max: 10 -``` - -If the AI attempts to exceed these limits, the operation is blocked. This prevents runaway automation. - -## Available Workflow Categories +## Examples | Category | Description | |---|---| | **[OSPO](ospo/)** | Open Source Program Office — org health, contributor metrics, compliance, repo hygiene | -> More categories coming soon: DevRel, Security, InnerSource, DevOps - ## Learn More - [GitHub Agentic Workflows Documentation](https://githubnext.github.io/gh-aw/) diff --git a/agentic-workflows/ospo/README.md b/agentic-workflows/ospo/README.md index c0583a9ba..c8eea4963 100644 --- a/agentic-workflows/ospo/README.md +++ b/agentic-workflows/ospo/README.md @@ -2,9 +2,7 @@ > AI-powered automation for Open Source Program Offices — org health, contributor metrics, compliance, and more. -## Overview - -These workflows automate common OSPO tasks using [GitHub Agentic Workflows](../README.md). Copy any workflow into your repo's `.github/workflows/` directory, customize the organization name, compile with `gh aw compile`, and you're running. +These workflows automate common OSPO tasks using [GitHub Agentic Workflows](../README.md). Copy any workflow into your repo's `.github/workflows/` directory, customize the organization name, and compile with `gh aw compile`. ## Workflows @@ -15,33 +13,14 @@ These workflows automate common OSPO tasks using [GitHub Agentic Workflows](../R | [**release-compliance-checker**](release-compliance-checker.md) | On issue open | Audits a repo for OSS release readiness — required files, security config, license compliance, risk assessment | | [**stale-repos**](stale-repos.md) | Monthly (1st) | Finds repositories with no activity in X days (default: 365) | -## Quick Start - -```bash -# 1. Copy a workflow to your repo -cp agentic-workflows/ospo/org-health.md your-repo/.github/workflows/ - -# 2. Edit the workflow — change the organization name and any defaults -# (it's just Markdown — edit the plain English instructions) - -# 3. Compile to generate the Actions lock file -cd your-repo -gh aw compile org-health - -# 4. Commit both files -git add .github/workflows/org-health.md .github/workflows/org-health.lock.yml -git commit -m "feat: add org health agentic workflow" -git push -``` - -## Customization Tips +## Customization -- **Change the org**: Most workflows default to `"github"` — update this to your organization name -- **Adjust schedules**: Edit the `cron` expression in the YAML frontmatter -- **Tune thresholds**: Stale days, activity methods, exempt repos — all configurable via `workflow_dispatch` inputs -- **Add/remove checks**: Edit the Markdown instructions to add custom checks or remove ones you don't need +- **Change the org**: Most workflows default to `"github"` — update to your org name +- **Adjust schedules**: Edit the `cron` in the YAML frontmatter +- **Tune thresholds**: Stale days, exempt repos, activity methods — all configurable via `workflow_dispatch` inputs +- **Add/remove checks**: Edit the Markdown instructions directly ## See Also -- [ospo-readiness skill](../../skills/ospo-readiness/) — Interactive repo scanner (graded A–F) for use in Copilot chat +- [ospo-readiness skill](../../skills/ospo-readiness/) — Interactive repo scanner (graded A–F) for Copilot chat - [GitHub Agentic Workflows docs](https://githubnext.github.io/gh-aw/) diff --git a/agentic-workflows/ospo/org-health.md b/agentic-workflows/ospo/org-health.md index 09acd38fe..e8ac6ce9e 100644 --- a/agentic-workflows/ospo/org-health.md +++ b/agentic-workflows/ospo/org-health.md @@ -191,92 +191,20 @@ appropriate central repo) with the title: [Org Health] Weekly Report — ``` -Use this structure for the issue body: - -```markdown -# 🏥 Org Health Report: -**Period**: Last 30 days | **Generated**: - ---- - -## 🚨 Health Alerts & Trends - -| Indicator | Status | Value | -|-----------|--------|-------| -| Issue close rate | 🟢/🟡/🔴 | X closed / Y opened (Z%) | -| PR merge rate | 🟢/🟡/🔴 | X merged / Y opened (Z%) | -| Median merge time | 🟢/🟡/🔴 | Xh | -| Median first response | 🟢/🟡/🔴 | Xh | -| Stale issues | 🟢/🟡/🔴 | N | -| Stale PRs | 🟢/🟡/🔴 | N | - ---- - -## 🏆 Wins & Shoutouts - -- 🎉 **Fast merges**: List PRs merged in < 4h -- ⚡ **Quick closes**: Issues resolved in < 24h -- 🌟 **Top contributors**: @user1, @user2, @user3 - ---- - -## 📋 Action Items - -### Stale Issues Needing Review (Top 10 by Heat Score) -| # | Repo | Issue | Days Stale | 🔥 Heat | Labels | -|---|------|-------|------------|---------|--------| -| 1 | repo | #N title | Xd | Y comments | label1, label2 | - -### Stale PRs Needing Review (Top 10 by Heat Score) -| # | Repo | PR | Days Stale | 🔥 Heat | Author | -|---|------|----|------------|---------|--------| -| 1 | repo | #N title | Xd | Y comments | @user | - ---- - -## ⏱️ PR Merge Time Analysis - -| Percentile | Time | -|------------|------| -| p50 (median) | Xh | -| p75 | Xh | -| p95 | Xh | - ---- - -## ⚡ First Response Time - -| Category | Median First Response | -|----------|---------------------| -| Issues | Xh | -| Pull Requests | Xh | - ---- - -## 📊 Top 10 Active Repositories - -| # | Repository | Issues | PRs | Commits | Total Activity | -|---|------------|--------|-----|---------|---------------| -| 1 | repo-name | N | N | N | N | - ---- - -## 👥 Contributor Leaderboard - -| Rank | Contributor | Commits | Top Repo | -|------|-------------|---------|----------| -| 🥇 | @user1 | N | repo | -| 🥈 | @user2 | N | repo | -| 🥉 | @user3 | N | repo | - ---- - -## 😴 Inactive Repositories (0 activity in 30 days) - -| Repository | Last Push | Description | -|------------|-----------|-------------| -| repo-name | YYYY-MM-DD | Short description | -``` +The issue body should include these sections in order: + +1. **Header** — org name, period, generation date +2. **🚨 Health Alerts** — table of indicators with 🟢/🟡/🔴 status and values +3. **🏆 Wins & Shoutouts** — fast merges, quick closes, top contributors +4. **📋 Stale Issues** — top 10 by heat score (repo, issue, days stale, comment count, labels) +5. **📋 Stale PRs** — top 10 by heat score (repo, PR, days stale, comment count, author) +6. **⏱️ PR Merge Time** — p50, p75, p95 percentiles +7. **⚡ First Response Time** — median for issues and PRs +8. **📊 Top 10 Active Repos** — sorted by total activity (issues + PRs + commits) +9. **👥 Contributor Leaderboard** — top 10 by commits with 🥇🥈🥉 +10. **😴 Inactive Repos** — repos with 0 activity in 30 days + +Use markdown tables for all data sections. ## Important Notes diff --git a/agentic-workflows/ospo/release-compliance-checker.md b/agentic-workflows/ospo/release-compliance-checker.md index 167442fb8..511747851 100644 --- a/agentic-workflows/ospo/release-compliance-checker.md +++ b/agentic-workflows/ospo/release-compliance-checker.md @@ -111,61 +111,17 @@ to each of the following categories: ## 7. Generate Compliance Report -Post **one** comment on the triggering issue with this structure: +Post **one** comment on the triggering issue with these sections: -```markdown -## 🔍 OSS Release Compliance Report - -**Repository:** `owner/repo` -**Checked at:** -**Overall status:** PASS ✅ | NEEDS WORK ⚠️ | BLOCKED 🚫 - ---- - -### 📄 File Compliance - -| File | Status | Notes | -|------|--------|-------| -| LICENSE | ✅ / ❌ | ... | -| README.md | ✅ / ❌ | ... | -| ... | ... | ... | - -### 🔒 Security Configuration - -| Setting | Status | Notes | -|---------|--------|-------| -| Secret scanning | ✅ / ❌ | ... | -| ... | ... | ... | - -### ⚖️ License Analysis - -- **Declared license:** ... -- **LICENSE file match:** ✅ / ❌ -- **Copyleft flags:** ... - -### 📊 Risk Assessment - -| Category | Level | Details | -|----------|-------|---------| -| Business Risk | 🟢/🟡/🔴 | ... | -| Legal Risk | 🟢/🟡/🔴 | ... | -| Open Source Risk | 🟢/🟡/🔴 | ... | - -### 📋 Recommendations - -**🚫 Must Fix (blocking release)** -- ... - -**⚠️ Should Address (strongly recommended)** -- ... - -**💡 Nice to Have (polish)** -- ... -``` +1. **Header** — repo name, timestamp, overall status (PASS ✅ / NEEDS WORK ⚠️ / BLOCKED 🚫) +2. **📄 File Compliance** — table of 7 files with ✅/❌ status and notes +3. **🔒 Security Configuration** — table of 4 settings with status +4. **⚖️ License Analysis** — declared license, LICENSE file match, copyleft flags +5. **📊 Risk Assessment** — Business/Legal/Open Source risk levels (🟢/🟡/🔴) with details +6. **📋 Recommendations** — prioritized as Must Fix (blocking), Should Address, Nice to Have ### Tone Guidelines -- Be **constructive**. The goal is to help teams succeed, not to gatekeep. -- When something is missing, explain *why* it matters and link to relevant - guidance when possible. +- Be **constructive** — help teams succeed, don't gatekeep. +- Explain *why* missing items matter and link to guidance. - Celebrate what the team has already done well. From f33a2fb613da4048623aa52ffe4f872b9d15ec42 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 17:58:25 -0800 Subject: [PATCH 10/17] fix: replace internal org references with generic placeholder Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/README.md | 2 +- agentic-workflows/ospo/org-health.md | 8 ++++---- agentic-workflows/ospo/stale-repos.md | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/agentic-workflows/ospo/README.md b/agentic-workflows/ospo/README.md index c8eea4963..b6fb524b1 100644 --- a/agentic-workflows/ospo/README.md +++ b/agentic-workflows/ospo/README.md @@ -15,7 +15,7 @@ These workflows automate common OSPO tasks using [GitHub Agentic Workflows](../R ## Customization -- **Change the org**: Most workflows default to `"github"` — update to your org name +- **Change the org**: Most workflows default to `"my-org"` — update to your org name - **Adjust schedules**: Edit the `cron` in the YAML frontmatter - **Tune thresholds**: Stale days, exempt repos, activity methods — all configurable via `workflow_dispatch` inputs - **Add/remove checks**: Edit the Markdown instructions directly diff --git a/agentic-workflows/ospo/org-health.md b/agentic-workflows/ospo/org-health.md index e8ac6ce9e..33ecdaf29 100644 --- a/agentic-workflows/ospo/org-health.md +++ b/agentic-workflows/ospo/org-health.md @@ -46,8 +46,8 @@ network: --- You are an expert GitHub organization analyst. Your job is to produce a -comprehensive weekly health report for the **`github`** organization -(or the organization provided via workflow input). +comprehensive weekly health report for your GitHub organization +(provided via workflow input). ## Primary Goal @@ -59,7 +59,7 @@ provide actionable metrics so maintainers can prioritize their time. ## Step 1 — Determine the Organization ``` -ORG = inputs.organization OR "github" +ORG = inputs.organization OR "my-org" PERIOD_DAYS = 30 SINCE = date 30 days ago (ISO 8601) STALE_ISSUE_DAYS = 60 @@ -208,7 +208,7 @@ Use markdown tables for all data sections. ## Important Notes -- **Update `github`** to your organization name before use. +- **Update the organization name** in the frontmatter before use. - If any API call fails, note it in the report and continue with available data. Do not let a single failure block the entire report. - Keep the issue body under 65,000 characters (GitHub issue body limit). diff --git a/agentic-workflows/ospo/stale-repos.md b/agentic-workflows/ospo/stale-repos.md index 588d6b030..97b8c20a7 100644 --- a/agentic-workflows/ospo/stale-repos.md +++ b/agentic-workflows/ospo/stale-repos.md @@ -9,7 +9,7 @@ on: description: "GitHub organization to scan" required: true type: string - default: "github" + default: "my-org" inactive_days: description: "Number of days of inactivity before a repo is considered stale" required: false @@ -62,7 +62,7 @@ You are an assistant that audits GitHub repositories for staleness. | Input | Default | |---|---| -| `organization` | `github` | +| `organization` | `my-org` | | `inactive_days` | `365` | | `exempt_repos` | _(none)_ | | `exempt_topics` | _(none)_ | From d4c9d9011117cc34aedadf74f0769a64a5a97f0f Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:13:25 -0800 Subject: [PATCH 11/17] Update agentic-workflows/ospo/release-compliance-checker.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/release-compliance-checker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentic-workflows/ospo/release-compliance-checker.md b/agentic-workflows/ospo/release-compliance-checker.md index 511747851..c2a365a33 100644 --- a/agentic-workflows/ospo/release-compliance-checker.md +++ b/agentic-workflows/ospo/release-compliance-checker.md @@ -12,7 +12,7 @@ on: permissions: contents: read - issues: read + issues: write pull-requests: read actions: read From 41f9134650e4744e59424f69f8dcaae7690e8a7d Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:13:49 -0800 Subject: [PATCH 12/17] Update agentic-workflows/ospo/org-health.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/org-health.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/agentic-workflows/ospo/org-health.md b/agentic-workflows/ospo/org-health.md index 33ecdaf29..b08bc3188 100644 --- a/agentic-workflows/ospo/org-health.md +++ b/agentic-workflows/ospo/org-health.md @@ -119,16 +119,30 @@ Use bash with Python for percentile calculations: ```bash python3 -c " -import json, sys +import json, sys, math + times = json.loads(sys.stdin.read()) times.sort() n = len(times) + +def percentile(data, p): + if not data: + raise ValueError('percentile() arg is an empty sequence') + k = (len(data) - 1) * p + f = math.floor(k) + c = math.ceil(k) + if f == c: + return data[int(k)] + d0 = data[f] * (c - k) + d1 = data[c] * (k - f) + return d0 + d1 + if n == 0: print('No data') else: - p50 = times[int(n * 0.50)] - p75 = times[int(n * 0.75)] - p95 = times[int(n * 0.95)] if n >= 20 else times[-1] + p50 = percentile(times, 0.50) + p75 = percentile(times, 0.75) + p95 = percentile(times, 0.95) if n >= 20 else times[-1] print(f'p50={p50:.1f}h, p75={p75:.1f}h, p95={p95:.1f}h') " ``` From ad654f4e090592506e1d3ac4ce889955e942db27 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:14:02 -0800 Subject: [PATCH 13/17] Update skills/ospo-readiness/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- skills/ospo-readiness/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/ospo-readiness/SKILL.md b/skills/ospo-readiness/SKILL.md index 98a960047..930b23f06 100644 --- a/skills/ospo-readiness/SKILL.md +++ b/skills/ospo-readiness/SKILL.md @@ -1,6 +1,6 @@ --- name: ospo-readiness -description: Scan any GitHub repository for open source readiness. Evaluates LICENSE, CONTRIBUTING.md, dependency license compatibility, README quality, SECURITY.md, CODE_OF_CONDUCT.md, CI/CD workflows, and issue/PR templates. Produces a scored readiness report with a letter grade (A–F) and actionable recommendations. Use when evaluating a repo for open source compliance, OSPO review, or community health. Invoke by providing a GitHub owner/repo (e.g. "scan expressjs/express for open source readiness"). +description: 'Scan any GitHub repository for open source readiness. Evaluates LICENSE, CONTRIBUTING.md, dependency license compatibility, README quality, SECURITY.md, CODE_OF_CONDUCT.md, CI/CD workflows, and issue/PR templates. Produces a scored readiness report with a letter grade (A–F) and actionable recommendations. Use when evaluating a repo for open source compliance, OSPO review, or community health. Invoke by providing a GitHub owner/repo (e.g. "scan expressjs/express for open source readiness").' --- # Open Source Readiness Scanner From 9833be59ade6fa0d2311e60f27330ced60f9ee9b Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:14:14 -0800 Subject: [PATCH 14/17] Update agentic-workflows/ospo/org-health.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/org-health.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentic-workflows/ospo/org-health.md b/agentic-workflows/ospo/org-health.md index b08bc3188..2f6471f04 100644 --- a/agentic-workflows/ospo/org-health.md +++ b/agentic-workflows/ospo/org-health.md @@ -17,7 +17,7 @@ on: permissions: contents: read - issues: read + issues: write pull-requests: read actions: read From 9f413eeb74200740512e2eb8c2fc0ba9dca9fdc8 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:18:54 -0800 Subject: [PATCH 15/17] Update agentic-workflows/ospo/stale-repos.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/stale-repos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentic-workflows/ospo/stale-repos.md b/agentic-workflows/ospo/stale-repos.md index 97b8c20a7..3c6b13933 100644 --- a/agentic-workflows/ospo/stale-repos.md +++ b/agentic-workflows/ospo/stale-repos.md @@ -36,7 +36,7 @@ on: permissions: contents: read - issues: read + issues: write engine: copilot tools: From 4bb8453b359889eb82a47f411580ef3ecdf86ebb Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:19:46 -0800 Subject: [PATCH 16/17] Update agentic-workflows/ospo/contributors-report.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/contributors-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentic-workflows/ospo/contributors-report.md b/agentic-workflows/ospo/contributors-report.md index 42047d1cd..9a78834f7 100644 --- a/agentic-workflows/ospo/contributors-report.md +++ b/agentic-workflows/ospo/contributors-report.md @@ -29,7 +29,7 @@ on: permissions: contents: read - issues: read + issues: write pull-requests: read engine: copilot From a6f104441384edf19abc1ffcca34e077a1c8d622 Mon Sep 17 00:00:00 2001 From: Ashley Wolf Date: Mon, 23 Feb 2026 18:20:02 -0800 Subject: [PATCH 17/17] Update agentic-workflows/ospo/stale-repos.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agentic-workflows/ospo/stale-repos.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agentic-workflows/ospo/stale-repos.md b/agentic-workflows/ospo/stale-repos.md index 3c6b13933..fb579f5f9 100644 --- a/agentic-workflows/ospo/stale-repos.md +++ b/agentic-workflows/ospo/stale-repos.md @@ -13,8 +13,8 @@ on: inactive_days: description: "Number of days of inactivity before a repo is considered stale" required: false - type: number - default: 365 + type: string + default: "365" exempt_repos: description: "Comma-separated list of repos to exempt from the report" required: false