diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 00000000..422e8406 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,77 @@ +name: Bug report +description: Report a reproducible problem in CodeGraph +title: "[Bug]: " +body: + - type: markdown + attributes: + value: | + Thanks for reporting a problem. For security issues, use private vulnerability reporting instead of this form. + - type: input + id: version + attributes: + label: CodeGraph version or commit + description: Provide the npm version or full Git commit SHA. + placeholder: 0.1.0 or 0123456789abcdef... + validations: + required: true + - type: input + id: node + attributes: + label: Node.js version + placeholder: 22.14.0 + validations: + required: true + - type: input + id: platform + attributes: + label: Platform + description: Include the operating system and CPU architecture. + placeholder: macOS 15 arm64 + validations: + required: true + - type: dropdown + id: install + attributes: + label: Install method + options: + - npx or npm package + - Source checkout + - MCPB desktop extension + - Other + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction + description: Give the smallest complete sequence that reproduces the problem. + placeholder: Numbered commands and configuration, with secrets removed. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behavior + validations: + required: true + - type: textarea + id: actual + attributes: + label: Actual behavior + validations: + required: true + - type: textarea + id: logs + attributes: + label: Redacted logs + description: Remove tokens, credentials, private source code, personal data, and local usernames. + render: shell + validations: + required: true + - type: checkboxes + id: safety + attributes: + label: Sensitive information + options: + - label: I removed credentials, private source code, personal data, and other sensitive information. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..ef4598c1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Security vulnerability + url: https://github.com/Phoenixrr2113/codebase-graph/security/advisories/new + about: Report vulnerabilities privately. Do not include exploit details in a public issue. + - name: Questions and ideas + url: https://github.com/Phoenixrr2113/codebase-graph/discussions + about: Ask for help or discuss ideas that are not yet actionable issues. diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 00000000..616d1a09 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,32 @@ +name: Feature request +description: Propose an outcome that would improve CodeGraph +title: "[Feature]: " +body: + - type: textarea + id: problem + attributes: + label: Problem + description: What user or developer problem needs to be solved? + validations: + required: true + - type: textarea + id: outcome + attributes: + label: Proposed outcome + description: Describe the observable result, not only an implementation. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: What workarounds or different approaches have you tried? + validations: + required: true + - type: textarea + id: scope + attributes: + label: Scope + description: Which package, interface, or workflow would this affect? Include compatibility or migration concerns. + validations: + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2a1e26a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,23 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 5 + labels: + - dependencies + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 5 + labels: + - dependencies + groups: + actions: + patterns: + - "*" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..eec680b5 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,23 @@ +## What changed + +Describe the problem and the smallest complete change that solves it. + +## Related issue + +Closes # + +## Security impact + +Describe affected inputs, access paths, dependencies, secrets, and data. Write "None" only after checking them. + +## Verification + +List the exact commands you ran and their results. + +## Checklist + +- [ ] Tests cover new behavior and regressions. +- [ ] `pnpm lint`, `pnpm typecheck`, `pnpm test`, and `pnpm build` pass. +- [ ] User-facing documentation is updated, or no documentation change is needed. +- [ ] Release impact is documented, or this change does not affect published artifacts. +- [ ] No secrets, generated `dist` trees, or local `.codegraph` data are included. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26f46865..121a2c69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,26 +14,22 @@ concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + CODEGRAPH_EMBEDDING_PROVIDER: none + jobs: - # Hard gate: must be green for a PR to merge. - # Builds every package (tsc, so this also typechecks the whole monorepo) - # and runs @codegraph/core's suite, which is green without any API keys - # or services. - build-and-test: - name: Build & unit tests + repository: + name: Repository runs-on: ubuntu-latest - env: - # Documented offline/CI mode (see README): skip vector indexes so no - # embedding API key is required. - CODEGRAPH_EMBEDDING_PROVIDER: none steps: - - uses: actions/checkout@v4 + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install pnpm - uses: pnpm/action-setup@v4 # version comes from package.json "packageManager" + uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 - - name: Setup Node - uses: actions/setup-node@v4 + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: pnpm @@ -41,56 +37,49 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Build & typecheck library packages - # Excludes @codegraph/mcp (release-only esbuild + native-module - # packaging via packages/npm-package/build.mjs — not a correctness - # check, and needs a populated tree) and codegraph-landing (the - # marketing app, already gated by Vercel). Everything else is tsc. - run: pnpm turbo build --filter='!@codegraph/mcp' --filter='!codegraph-landing' - - - name: Unit tests (core) - run: pnpm turbo test --filter=@codegraph/core - - # Non-blocking smoke run against a live FalkorDB. Surfaces graph/plugin-nlp - # status without gating merges, because the suite still has pre-existing - # failures that need triage (integration tests that require an embedding - # provider + LLM/Voyage credentials, a few legacy tests referencing removed - # APIs, and packages lacking --passWithNoTests). Once those are resolved, - # drop `continue-on-error` and fold these filters into build-and-test. - integration-smoke: - name: Integration smoke (FalkorDB, non-blocking) + - name: Audit production dependencies + run: pnpm audit:prod + + - name: Lint + run: pnpm lint + + - name: Typecheck + run: pnpm typecheck + + - name: Test + run: pnpm test + + - name: Build + run: pnpm build + + - name: Build desktop extension + run: pnpm build:mcpb + + integration: + name: Integration (FalkorDB) runs-on: ubuntu-latest - continue-on-error: true env: - CODEGRAPH_EMBEDDING_PROVIDER: none FALKORDB_HOST: localhost + FALKORDB_PORT: 16379 services: falkordb: - image: falkordb/falkordb:latest + image: falkordb/falkordb@sha256:52b6583afe7b5ba6bbf5b5f0290bdaa765bd97477b310a590771dc33ebc7b5f5 ports: - - 6379:6379 - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 10 - cgbench-falkordb: - image: falkordb/falkordb:latest - ports: - - 6380:6379 + - 16379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 10 steps: - - uses: actions/checkout@v4 + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 - - name: Setup Node - uses: actions/setup-node@v4 + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: pnpm @@ -98,7 +87,75 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Graph + NLP tests (informational) - # turbo builds the needed deps automatically (test depends on build); - # this never triggers the @codegraph/mcp packaging build. - run: pnpm turbo test --filter=@codegraph/graph --filter=@codegraph/plugin-nlp + - name: Build packages + run: pnpm build + + - name: Run service-backed integration tests + run: pnpm test:integration + + - name: Test repository scripts + run: pnpm test:scripts + + package-build: + name: Build package artifact + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Install pnpm + uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build npm package + run: pnpm build:npm + + - name: Validate npm package + run: pnpm validate:npm + + - name: Upload exact package artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: codegraph-mcp-package + path: tmp/release + if-no-files-found: error + retention-days: 3 + + package: + name: Package (${{ matrix.os }}) + needs: package-build + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + package-manager-cache: false + + - name: Download exact package artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: codegraph-mcp-package + path: tmp/release + + - name: Install macOS embedded runtime libraries + if: runner.os == 'macOS' + run: brew install libomp openssl@3 + + - name: Test package in a fresh consumer + run: node scripts/release/smoke-package.mjs tmp/release/package-result.json diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..880deab4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,35 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "23 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + packages: read + security-events: write + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Initialize CodeQL + uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4 + with: + languages: javascript-typescript + + - name: Analyze + uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..12a520c4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,327 @@ +name: Release + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + bootstrap_version: + description: "Existing npm version to finalize as the one-time bootstrap release" + required: true + type: string + bootstrap_commit: + description: "Full reviewed commit SHA used for the manual npm publication" + required: true + type: string + +permissions: {} + +concurrency: + group: npm-release + cancel-in-progress: false + +jobs: + validate: + name: Validate release + runs-on: ubuntu-latest + permissions: + contents: read + env: + CODEGRAPH_EMBEDDING_PROVIDER: none + FALKORDB_HOST: localhost + FALKORDB_PORT: 16379 + services: + falkordb: + image: falkordb/falkordb@sha256:52b6583afe7b5ba6bbf5b5f0290bdaa765bd97477b310a590771dc33ebc7b5f5 + ports: + - 16379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 10 + steps: + - name: Check out exact tag + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.bootstrap_commit || github.ref }} + + - name: Install pnpm + uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22.14.0 + package-manager-cache: false + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Verify annotated release tag + if: github.event_name == 'push' + shell: bash + run: | + set -euo pipefail + if [[ "$(git cat-file -t "$GITHUB_REF")" != "tag" ]]; then + echo "Release tag must be annotated: $GITHUB_REF" >&2 + exit 1 + fi + git fetch --no-tags origin main:refs/remotes/origin/main + release_commit="$(git rev-list -n 1 "$GITHUB_REF")" + if ! git merge-base --is-ancestor "$release_commit" origin/main; then + echo "Release tag commit must be reachable from origin/main" >&2 + exit 1 + fi + + - name: Verify release request and npm state + env: + BOOTSTRAP_COMMIT: ${{ inputs.bootstrap_commit }} + BOOTSTRAP_VERSION: ${{ inputs.bootstrap_version }} + run: node scripts/release/verify-release-tag.mjs + + - name: Verify bootstrap source commit + if: github.event_name == 'workflow_dispatch' + shell: bash + env: + REVIEWED_COMMIT: ${{ inputs.bootstrap_commit }} + run: | + set -euo pipefail + if [[ "$(git rev-parse HEAD)" != "$REVIEWED_COMMIT" ]]; then + echo "Checked-out commit does not match bootstrap_commit" >&2 + exit 1 + fi + git fetch --no-tags origin main:refs/remotes/origin/main + if ! git merge-base --is-ancestor "$REVIEWED_COMMIT" origin/main; then + echo "Bootstrap commit must be reachable from origin/main" >&2 + exit 1 + fi + + - name: Verify bootstrap tag is unused + if: github.event_name == 'workflow_dispatch' + shell: bash + env: + VERSION: ${{ inputs.bootstrap_version }} + run: | + set -euo pipefail + if git rev-parse --verify "refs/tags/v$VERSION" >/dev/null 2>&1; then + echo "Bootstrap tag v$VERSION already exists locally" >&2 + exit 1 + fi + if [[ -n "$(git ls-remote --tags origin "refs/tags/v$VERSION")" ]]; then + echo "Bootstrap tag v$VERSION already exists on origin" >&2 + exit 1 + fi + + - name: Audit production dependencies + run: pnpm audit:prod + + - name: Lint + run: pnpm lint + + - name: Typecheck + run: pnpm typecheck + + - name: Test + run: pnpm test + + - name: Integration test + run: pnpm test:integration + + - name: Build + run: pnpm build + + - name: Test repository scripts + run: pnpm test:scripts + + - name: Build desktop extension + run: pnpm build:mcpb + + - name: Build, validate, and smoke npm artifact + run: pnpm release:check + + - name: Upload verified npm artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: codegraph-release-package + path: tmp/release + if-no-files-found: error + retention-days: 3 + + publish: + name: Publish npm package + if: github.event_name == 'push' + needs: validate + runs-on: ubuntu-latest + environment: npm + permissions: + contents: write + id-token: write + steps: + - name: Check out exact tag + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + ref: ${{ github.ref }} + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22.14.0 + package-manager-cache: false + + - name: Install trusted-publishing npm version + run: npm install --global --ignore-scripts npm@11.5.1 + + - name: Download verified npm artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: codegraph-release-package + path: tmp/release + + - name: Read release metadata + id: metadata + shell: bash + run: | + echo "version=$(node -p "require('./tmp/release/package-result.json').version")" >> "$GITHUB_OUTPUT" + echo "filename=$(node -p "const p=require('./tmp/release/package-result.json'); p.filename")" >> "$GITHUB_OUTPUT" + + - name: Publish with trusted publishing + env: + FILENAME: ${{ steps.metadata.outputs.filename }} + run: npm publish "tmp/release/$FILENAME" --access public + + - name: Wait for registry propagation + shell: bash + env: + VERSION: ${{ steps.metadata.outputs.version }} + run: | + for attempt in 1 2 3 4 5 6; do + if [[ "$(npm view "codegraph-mcp@$VERSION" version --json 2>/dev/null)" == "\"$VERSION\"" ]]; then + exit 0 + fi + if [[ "$attempt" == "6" ]]; then + echo "codegraph-mcp@$VERSION did not become visible after six attempts" >&2 + exit 1 + fi + sleep 10 + done + + - name: Verify registry package + shell: bash + env: + VERSION: ${{ steps.metadata.outputs.version }} + run: | + mkdir -p tmp/registry + npm pack "codegraph-mcp@$VERSION" --pack-destination tmp/registry + node scripts/release/smoke-package.mjs \ + --tarball "tmp/registry/codegraph-mcp-$VERSION.tgz" \ + --version "$VERSION" + + - name: Create package checksum + shell: bash + env: + FILENAME: ${{ steps.metadata.outputs.filename }} + run: | + cd tmp/registry + sha256sum "$FILENAME" > "$FILENAME.sha256" + + - name: Create verified GitHub release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + FILENAME: ${{ steps.metadata.outputs.filename }} + VERSION: ${{ steps.metadata.outputs.version }} + run: | + gh release create "v$VERSION" \ + "tmp/registry/$FILENAME" \ + "tmp/registry/$FILENAME.sha256" \ + --verify-tag \ + --generate-notes \ + --title "v$VERSION" + + bootstrap-finalize: + name: Finalize bootstrap release + if: github.event_name == 'workflow_dispatch' + needs: validate + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out reviewed bootstrap commit + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + ref: ${{ inputs.bootstrap_commit }} + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22.14.0 + package-manager-cache: false + + - name: Download verified npm artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: codegraph-release-package + path: tmp/release + + - name: Read release metadata + id: metadata + shell: bash + run: | + echo "version=$(node -p "require('./tmp/release/package-result.json').version")" >> "$GITHUB_OUTPUT" + echo "filename=$(node -p "const p=require('./tmp/release/package-result.json'); p.filename")" >> "$GITHUB_OUTPUT" + + - name: Download and verify registry package + shell: bash + env: + FILENAME: ${{ steps.metadata.outputs.filename }} + VERSION: ${{ steps.metadata.outputs.version }} + run: | + mkdir -p tmp/registry + npm pack "codegraph-mcp@$VERSION" --pack-destination tmp/registry + if ! cmp -s "tmp/release/$FILENAME" "tmp/registry/$FILENAME"; then + echo "Registry tarball does not match the artifact built from bootstrap_commit" >&2 + sha256sum "tmp/release/$FILENAME" "tmp/registry/$FILENAME" >&2 + exit 1 + fi + node scripts/release/smoke-package.mjs \ + --tarball "tmp/registry/codegraph-mcp-$VERSION.tgz" \ + --version "$VERSION" + + - name: Create package checksum + shell: bash + env: + FILENAME: ${{ steps.metadata.outputs.filename }} + run: | + cd tmp/registry + sha256sum "$FILENAME" > "$FILENAME.sha256" + + - name: Create annotated bootstrap tag + shell: bash + env: + VERSION: ${{ steps.metadata.outputs.version }} + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -a "v$VERSION" -m "Release v$VERSION" + git push origin "v$VERSION" + + - name: Create verified GitHub release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + FILENAME: ${{ steps.metadata.outputs.filename }} + VERSION: ${{ steps.metadata.outputs.version }} + run: | + gh release create "v$VERSION" \ + "tmp/registry/$FILENAME" \ + "tmp/registry/$FILENAME.sha256" \ + --verify-tag \ + --generate-notes \ + --title "v$VERSION" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..b72fd9f8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported through the contact options on the [maintainer's GitHub profile](https://github.com/Phoenixrr2113). Security-sensitive reports must use the repository's [private vulnerability reporting form](https://github.com/Phoenixrr2113/codebase-graph/security/advisories/new). All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence:** A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact:** A violation through a single incident or series of actions. + +**Consequence:** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period. This includes avoiding interactions in community spaces and external channels such as social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact:** A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence:** A temporary ban from any sort of interaction or public communication with the community for a specified period. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact:** Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence:** A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html). + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). + +For answers to common questions, see the [Contributor Covenant FAQ](https://www.contributor-covenant.org/faq). [Translations](https://www.contributor-covenant.org/translations) are also available. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..4d55e87e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing to CodeGraph + +Thanks for helping improve CodeGraph. Bug reports, focused feature proposals, documentation fixes, and tested pull requests are welcome. + +## Development setup + +CodeGraph requires Node.js 22 and the pnpm version declared in the root `package.json` `packageManager` field. Corepack can install that exact pnpm release. +Docker supplies the external FalkorDB integration service. FalkorDBLite's supported platform binaries are installed with the workspace dependencies. Apple silicon also requires Homebrew `libomp` and `openssl@3` for the embedded integration suite. + +```bash +corepack enable +git clone https://github.com/Phoenixrr2113/codebase-graph.git +cd codebase-graph +pnpm install --frozen-lockfile +``` + +Fork the repository, create a short-lived branch from `main`, and keep each pull request focused on one outcome. Add or update tests before changing behavior. + +## Required checks + +Run these commands before opening a pull request: + +```bash +pnpm audit:prod +pnpm lint +pnpm typecheck +pnpm test +pnpm build +pnpm docker:db +pnpm test:integration +pnpm test:scripts +``` + +If a change affects the npm package, MCP server entry point, dependency graph, or release scripts, also run: + +```bash +pnpm release:check +``` + +If a change affects the desktop extension, also run: + +```bash +pnpm build:mcpb +``` + +Include the commands and results in the pull request. CI repeats the repository checks and tests the exact npm tarball on Linux, macOS, and Windows. + +## Pull requests + +- Link the issue or explain the problem the change solves. +- Keep public functions typed and validate data at system boundaries. +- Add tests for new behavior and regressions. +- Update user-facing documentation when commands, configuration, or behavior changes. +- Call out security, compatibility, migration, and release effects. +- Never commit generated `dist` directories, secrets, `.env` files, local `.codegraph` data, or benchmark output containing local paths. + +By participating, you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md). Report security issues through the [private vulnerability reporting form](https://github.com/Phoenixrr2113/codebase-graph/security/advisories/new), not a public issue. diff --git a/README.md b/README.md index c57efb25..e4bd7fb9 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,174 @@ # CodeGraph -A code knowledge graph and search system for AI agents. Indexes your codebase into a graph database, embeds symbols and documentation, and exposes search through a Model Context Protocol (MCP) server. +[![CI](https://github.com/Phoenixrr2113/codebase-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/Phoenixrr2113/codebase-graph/actions/workflows/ci.yml) +[![CodeQL](https://github.com/Phoenixrr2113/codebase-graph/actions/workflows/codeql.yml/badge.svg)](https://github.com/Phoenixrr2113/codebase-graph/actions/workflows/codeql.yml) +[![GitHub stars](https://img.shields.io/github/stars/Phoenixrr2113/codebase-graph?style=flat)](https://github.com/Phoenixrr2113/codebase-graph/stargazers) +[![MIT license](https://img.shields.io/github/license/Phoenixrr2113/codebase-graph)](LICENSE) + +CodeGraph turns source code and project knowledge into a searchable graph for AI agents. It parses code with tree-sitter, stores structural and temporal relationships in FalkorDB, and exposes four focused tools through the Model Context Protocol (MCP). + +## Access the project + +- [Live application](https://v0-landing-page-build-kappa-virid.vercel.app) +- [Source code](https://github.com/Phoenixrr2113/codebase-graph) +- [Issues](https://github.com/Phoenixrr2113/codebase-graph/issues) +- [Discussions](https://github.com/Phoenixrr2113/codebase-graph/discussions) +- [Contribution guide](CONTRIBUTING.md) +- [Security policy](SECURITY.md) +- [MIT license](LICENSE) + +The public npm package is named `codegraph-mcp`. Its npm link, version badge, and weekly-download badge will be added after the one-time `0.1.0` bootstrap publish is verified against the registry. ## What it does -- **Search code by meaning** — vector embeddings + cross-encoder reranking find the function, class, or interface you describe, even when you don't know the name. Internal benchmark: MRR 0.969, Success@1 94%, Success@5 100%, ~447ms latency on a project of ~2.3K nodes. -- **Understand structure** — tree-sitter parsers extract Functions, Classes, Interfaces, Variables, and Types across 5 first-class languages (TypeScript, Python, Go, Rust, Markdown), with tree-sitter coverage for additional languages via the generic plugin. -- **Track decisions over time** — bitemporal knowledge graph stores facts with `valid_at` / `invalid_at` timestamps, supporting point-in-time queries ("what was true on March 1st?"). -- **Plug into AI agents** — exposes 4 MCP tool groups (`search`, `knowledge`, `codebase`, `query`) for use in Claude Desktop, Cursor, Claude Code, or any MCP client. +- Searches code by symbol, structure, and meaning. +- Extracts functions, classes, interfaces, variables, types, imports, calls, and other relationships. +- Stores project facts with `valid_at` and `invalid_at` timestamps for point-in-time queries. +- Supports first-class TypeScript, JavaScript, Python, Go, Rust, and Markdown parsing, with generic tree-sitter support for additional languages. +- Runs with embedded FalkorDBLite on Linux x64 and Apple silicon macOS, or an external FalkorDB service on any supported Node.js platform. Apple silicon requires Homebrew `libomp` and `openssl@3` runtime libraries. +- Exposes `search`, `knowledge`, `codebase`, and `query` MCP tools. + +## Install from source -## Quickstart +Requirements: Node.js 22, Corepack, and Docker for the external FalkorDB quickstart. ```bash git clone https://github.com/Phoenixrr2113/codebase-graph.git cd codebase-graph -pnpm install +corepack enable +pnpm install --frozen-lockfile pnpm build - -# Option A — embedded database (no Docker required) -brew install redis # macOS — FalkorDBLite needs redis-server -echo "CODEGRAPH_DRIVER=falkordblite" > .env -echo "CODEGRAPH_DB_PATH=.codegraph/falkordb" >> .env - -# Option B — FalkorDB via Docker -# pnpm docker:db -# echo "CODEGRAPH_DRIVER=falkordb" > .env - -# Index a project -pnpm --filter @codegraph/cli start configure --projects /path/to/your/project -pnpm --filter @codegraph/cli start reindex - -# Run the MCP server (stdio transport) -pnpm --filter @codegraph/mcp-server start +pnpm docker:db ``` +Use `CODEGRAPH_EMBEDDING_PROVIDER=none` for structural search without an API key. Configure a supported embedding provider later if you want semantic vector search. + ## Use with an MCP client -### Claude Desktop +### Source checkout -Add to `~/Library/Application Support/Claude/claude_desktop_config.json`: +After building the repository, point the client at the generated server entry point. Replace both absolute paths with paths on your machine. ```json { "mcpServers": { "codegraph": { "command": "node", - "args": ["/absolute/path/to/codebase-graph/packages/mcp-server/dist/index.js"], + "args": [ + "/absolute/path/to/codebase-graph/packages/mcp-server/dist/index.js" + ], "env": { - "VOYAGE_API_KEY": "your-key", - "JINA_API_KEY": "your-key" + "CODEGRAPH_EMBEDDING_PROVIDER": "none", + "CODEGRAPH_DRIVER": "falkordb", + "FALKORDB_HOST": "localhost", + "FALKORDB_PORT": "6379" } } } } ``` -### Claude Code +For Claude Code: ```bash -claude mcp add codegraph node /absolute/path/to/codebase-graph/packages/mcp-server/dist/index.js +claude mcp add codegraph \ + --env CODEGRAPH_EMBEDDING_PROVIDER=none \ + --env CODEGRAPH_DRIVER=falkordb \ + --env FALKORDB_HOST=localhost \ + --env FALKORDB_PORT=6379 \ + -- node /absolute/path/to/codebase-graph/packages/mcp-server/dist/index.js ``` -## MCP tools - -Four persona-based tool groups by default. Set `CODEGRAPH_RAW_TOOLS=1` to expose the underlying handlers individually. +### npm package after bootstrap -| Tool | What it does | -|------|--------------| -| **search** | Find code/symbols by name or meaning; get context for a file or symbol | -| **knowledge** | Store and recall entities, relationships, and facts (with bitemporal queries) | -| **codebase** | Configure projects, reindex, check status/stats, read source code | -| **query** | Execute read-only Cypher against the graph (power users) | +After `codegraph-mcp@0.1.0` is visible on npm, clients can run the server without a source checkout: -See [CLAUDE.md](./CLAUDE.md) for the complete tool reference (parameters, examples, workflows). +```json +{ + "mcpServers": { + "codegraph": { + "command": "npx", + "args": ["-y", "codegraph-mcp"], + "env": { + "CODEGRAPH_EMBEDDING_PROVIDER": "none" + } + } + } +} +``` -## Architecture +The first conversation can configure and index a project through the `codebase` tool: -- **Graph storage:** FalkorDB (Docker) or FalkorDBLite (embedded), with HNSW vector indexes per node type. -- **Embeddings:** pluggable — Voyage AI (`voyage-code-3`, 1024-dim), OpenRouter, or local nomic-embed via `@huggingface/transformers` (768-dim, runs on CPU). -- **Reranker:** cross-encoder via Jina (`jina-reranker-v2-base-multilingual`) or Voyage. -- **Indexer:** tree-sitter for AST parsing, SHA-256 file-hash incremental change detection. -- **MCP server:** 4 persona tools by default; raw mode exposes the underlying handlers. +```json +{ "action": "configure", "projectAction": "set", "projects": ["/absolute/path/to/project"] } +``` -## Configuration +```json +{ "action": "reindex", "mode": "full" } +``` -Environment variables (set in `.env` at the repo root): +Embedded storage is selected automatically on Linux x64. On Apple silicon macOS, install its native runtime libraries first with `brew install libomp openssl@3`; CodeGraph otherwise falls back to external FalkorDB. Windows, Intel macOS, and Linux arm64 require an external FalkorDB service. Set `CODEGRAPH_DRIVER=falkordb`, `FALKORDB_HOST`, and `FALKORDB_PORT` in the MCP client environment on those platforms. -```bash -# Embedding provider (auto-detected from API keys) -CODEGRAPH_EMBEDDING_PROVIDER=voyage # voyage | local | openrouter -VOYAGE_API_KEY=... +## MCP tools -# Reranker provider (auto-detected from API keys) -CODEGRAPH_RERANK_PROVIDER=jina # jina | voyage -JINA_API_KEY=... +| Tool | Purpose | +| --- | --- | +| `search` | Find code and project knowledge by name, structure, or meaning | +| `knowledge` | Store and recall entities, relationships, facts, and documents | +| `codebase` | Configure projects, index code, inspect status, and read source | +| `query` | Run read-only Cypher queries against the graph | -# LLM (for knowledge extraction + chain-of-thought search) -LLM_PROVIDER=cerebras -CEREBRAS_API_KEY=... +Set `CODEGRAPH_RAW_TOOLS=1` to expose the lower-level handlers instead of the four grouped tools. -# Graph driver -CODEGRAPH_DRIVER=falkordblite # falkordblite | falkordb -CODEGRAPH_DB_PATH=.codegraph/falkordb # for falkordblite -``` +## Configuration -## Packages +| Variable | Purpose | +| --- | --- | +| `CODEGRAPH_DRIVER` | `falkordblite` for embedded storage or `falkordb` for an external service | +| `CODEGRAPH_DB_PATH` | Embedded FalkorDBLite data path | +| `FALKORDB_HOST` | External FalkorDB host, default `localhost` | +| `FALKORDB_PORT` | External FalkorDB port, default `6379` | +| `FALKORDB_GRAPH` | Graph name, default `codegraph` | +| `CODEGRAPH_EMBEDDING_PROVIDER` | `none`, `local`, `voyage`, or `openrouter` | +| `VOYAGE_API_KEY` | Voyage embeddings and optional reranking | +| `OPENROUTER_API_KEY` | OpenRouter embeddings or LLM features | +| `CEREBRAS_API_KEY` | Optional LLM-backed knowledge extraction | -| Package | Description | -|---------|-------------| -| [`@codegraph/core`](packages/core/) | Indexer, search pipelines, service layer, git sync | -| [`@codegraph/graph`](packages/graph/) | Graph DB driver abstraction, knowledge operations, Cypher templates | -| [`@codegraph/plugin-nlp`](packages/plugin-nlp/) | Embeddings, reranker, entity resolution, conversation/document ingestion | -| [`@codegraph/mcp-server`](packages/mcp-server/) | MCP server with 4 persona tools | -| [`@codegraph/api`](packages/api/) | Express REST API for the dashboard | -| [`@codegraph/cli`](packages/cli/) | CLI wrapper around the core service | -| [`@codegraph/plugin-typescript`](packages/plugin-typescript/) | TS/JS/JSX tree-sitter plugin | -| [`@codegraph/plugin-python`](packages/plugin-python/) | Python tree-sitter plugin | -| [`@codegraph/plugin-go`](packages/plugin-go/) | Go tree-sitter plugin | -| [`@codegraph/plugin-rust`](packages/plugin-rust/) | Rust tree-sitter plugin | -| [`@codegraph/plugin-markdown`](packages/plugin-markdown/) | Markdown parser | -| [`@codegraph/plugin-generic`](packages/plugin-generic/) | Tree-sitter fallback for additional languages | -| [`@codegraph/plugin-common`](packages/plugin-common/) | Shared extraction utilities (complexity, AST helpers) | -| [`@codegraph/plugin-languages`](packages/plugin-languages/) | Plugin registry coordination | -| [`@codegraph/logger`](packages/logger/) | Structured logging + tracing decorator | -| [`@codegraph/types`](packages/types/) | Shared TypeScript type definitions | - -Plus `apps/web` (Next.js dashboard with Graph Explorer + Operations tabs at `localhost:3000`). +Never commit provider keys. Put secrets in the MCP client's protected environment configuration or a local ignored `.env` file. ## Development ```bash -pnpm install # Install dependencies -pnpm build # Build all packages -pnpm dev # Start dev mode -pnpm test # Run all tests -pnpm docker:db # Start FalkorDB via Docker +pnpm install --frozen-lockfile +pnpm audit:prod +pnpm lint +pnpm typecheck +pnpm test +pnpm build +pnpm docker:db +pnpm test:integration +pnpm test:scripts +pnpm build:mcpb +pnpm release:check ``` -## Status +See [CONTRIBUTING.md](CONTRIBUTING.md) for the pull request workflow and required evidence. +FalkorDBLite's Linux x64 and Apple silicon macOS binaries are installed with the workspace dependencies. Apple silicon also requires Homebrew `libomp` and `openssl@3`. + +## Packages + +| Package | Responsibility | +| --- | --- | +| [`@codegraph/core`](packages/core/) | Indexing, search pipelines, services, and git synchronization | +| [`@codegraph/graph`](packages/graph/) | FalkorDB and FalkorDBLite drivers, graph queries, and knowledge operations | +| [`@codegraph/plugin-nlp`](packages/plugin-nlp/) | Embeddings, reranking, entity resolution, and document ingestion | +| [`@codegraph/mcp-server`](packages/mcp-server/) | MCP transport and the four public tool groups | +| [`@codegraph/cli`](packages/cli/) | Source-checkout command-line tools | +| [`codegraph-mcp`](packages/npm-package/) | Public npm distribution staging and entry point | +| [`@codegraph/mcpb`](packages/mcpb/) | Platform-local MCPB desktop extension build | -Active development. Public on 2026-04-25. No releases yet — install from source. +The Next.js application lives in [`apps/web`](apps/web/), and the reproducible search benchmark lives in [`benchmarks/cgbench-v1`](benchmarks/cgbench-v1/). ## License -MIT — see [LICENSE](./LICENSE). +CodeGraph is available under the [MIT License](LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..45e91574 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +## Supported versions + +Security fixes are provided for the current minor release line. + +| Version | Supported | +| --- | --- | +| 0.1.x | Yes | +| Earlier versions | No | + +## Report a vulnerability + +Use GitHub's [private vulnerability reporting form](https://github.com/Phoenixrr2113/codebase-graph/security/advisories/new). Do not open a public issue containing exploit details, credentials, private source code, or other sensitive data. + +Include affected versions, impact, reproduction steps, and any suggested mitigation. Remove real credentials and personal data from logs or examples. + +The maintainer will aim to acknowledge a report within 72 hours, provide status updates while it is investigated, and coordinate disclosure after a fix is available. Response and remediation timing depend on severity and reproducibility. diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index c23c5a6a..7c732358 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -3,24 +3,6 @@ @custom-variant dark (&:is(.dark *)); -@font-face { - font-family: 'Geist'; - src: url('/fonts/GeistVF.woff2') format('woff2'); - font-display: swap; -} - -@font-face { - font-family: 'Geist Mono'; - src: url('/fonts/GeistMonoVF.woff2') format('woff2'); - font-display: swap; -} - -@font-face { - font-family: 'JetBrains Mono'; - src: url('/fonts/JetBrainsMonoVF.woff2') format('woff2'); - font-display: swap; -} - /* Dark-first developer tool theme - inspired by Linear, Vercel, Raycast */ :root { /* Light mode fallback */ @@ -84,8 +66,8 @@ } @theme inline { - --font-sans: 'Geist', 'Geist Fallback', system-ui, sans-serif; - --font-mono: 'JetBrains Mono', 'Geist Mono', 'Geist Mono Fallback', ui-monospace, monospace; + --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); @@ -160,7 +142,7 @@ display: inline; } -/* Wider panes (integrations tabs) keep strict pre wrapping — the box is +/* Wider panes (integrations tabs) keep strict pre wrapping: the box is wide enough that horizontal scroll is never triggered. */ .code-snippet--wide pre.shiki { white-space: pre; diff --git a/apps/web/components/dashboard/embedding-badge.tsx b/apps/web/components/dashboard/embedding-badge.tsx index 4bc13078..233efd8c 100644 --- a/apps/web/components/dashboard/embedding-badge.tsx +++ b/apps/web/components/dashboard/embedding-badge.tsx @@ -37,9 +37,12 @@ export function EmbeddingBadge() { }, []) useEffect(() => { - fetchStats() + const initialFetch = window.setTimeout(fetchStats, 0) const interval = setInterval(fetchStats, 30_000) - return () => clearInterval(interval) + return () => { + clearTimeout(initialFetch) + clearInterval(interval) + } }, [fetchStats]) const handleGenerate = useCallback(async () => { diff --git a/apps/web/components/dashboard/entity-detail.tsx b/apps/web/components/dashboard/entity-detail.tsx index 6b7fd551..eb69b718 100644 --- a/apps/web/components/dashboard/entity-detail.tsx +++ b/apps/web/components/dashboard/entity-detail.tsx @@ -56,9 +56,10 @@ export function EntityDetail({ node }: EntityDetailProps) { const isExported = props.isExported === true const isAsync = props.isAsync === true const isArrow = props.isArrow === true + const isAbstract = props.isAbstract === true + const extendsName = typeof props.extends === 'string' ? props.extends : undefined const docstring = props.docstring as string | undefined const bodySnippet = props.bodySnippet as string | undefined - const signature = props.signature as string | undefined const params = props.params const returnType = props.returnType as string | undefined @@ -122,9 +123,9 @@ export function EntityDetail({ node }: EntityDetailProps) { {node.type === 'Class' && (
}>
- {props.isAbstract && abstract } + {isAbstract && abstract } class {node.label} - {props.extends && extends {String(props.extends)}} + {extendsName && extends {extendsName}}
)} @@ -151,6 +152,7 @@ export function EntityDetail({ node }: EntityDetailProps) { {filePath && startLine != null && (
{ - setLoading(true) - setLines(null) - setHighlightedHtml(null) - const el = endLine ?? startLine fetch(`${apiUrl}/api/source?path=${encodeURIComponent(filePath)}&startLine=${startLine}&endLine=${el}&context=5`) .then(r => r.ok ? r.json() : null) diff --git a/apps/web/components/dashboard/graph-canvas.tsx b/apps/web/components/dashboard/graph-canvas.tsx index 08e22a5f..91b3d806 100644 --- a/apps/web/components/dashboard/graph-canvas.tsx +++ b/apps/web/components/dashboard/graph-canvas.tsx @@ -82,8 +82,8 @@ export function GraphCanvas({ apiUrl, onNodeSelect, highlightedNames, hiddenEdge const instance = cy({ container: containerRef.current, elements: [...nodes, ...edges], - style: cytoscapeStylesheet as cytoscape.Stylesheet[], - layout: LAYOUT_OPTIONS.cose as cytoscape.LayoutOptions, + style: cytoscapeStylesheet, + layout: LAYOUT_OPTIONS.cose, minZoom: 0.1, maxZoom: 5, }) @@ -224,7 +224,7 @@ export function GraphCanvas({ apiUrl, onNodeSelect, highlightedNames, hiddenEdge const handleRelayout = useCallback((newLayout?: LayoutName) => { const l = newLayout ?? layout if (newLayout) setLayout(l) - cyRef.current?.layout(LAYOUT_OPTIONS[l] as cytoscape.LayoutOptions).run() + cyRef.current?.layout(LAYOUT_OPTIONS[l]).run() }, [layout]) return ( diff --git a/apps/web/components/dashboard/query-panel.tsx b/apps/web/components/dashboard/query-panel.tsx index 10a35d17..88c01777 100644 --- a/apps/web/components/dashboard/query-panel.tsx +++ b/apps/web/components/dashboard/query-panel.tsx @@ -19,6 +19,20 @@ interface ResultItem { [key: string]: unknown } +function asString(value: unknown): string | undefined { + return typeof value === 'string' ? value : undefined +} + +function asFiniteNumber(value: unknown): number | undefined { + return typeof value === 'number' && Number.isFinite(value) ? value : undefined +} + +function asStringArray(value: unknown): string[] { + return Array.isArray(value) && value.every((item): item is string => typeof item === 'string') + ? value + : [] +} + export function QueryPanel({ apiUrl }: QueryPanelProps) { const [query, setQuery] = useState('') const [mode, setMode] = useState('cypher') @@ -125,6 +139,10 @@ export function QueryPanel({ apiUrl }: QueryPanelProps) { search: 'createUser authentication handler', natural: 'What functions call createOrder? Why does payment retry 3 times?', } + const routedTo = asString(meta?.routedTo) + const iterations = asFiniteNumber(meta?.iterations) + const queries = asStringArray(meta?.queries) + const total = asFiniteNumber(meta?.total) return (
@@ -192,16 +210,16 @@ export function QueryPanel({ apiUrl }: QueryPanelProps) { {results !== null ? (
{/* Meta info (routing, iterations) */} - {meta?.routedTo && ( + {routedTo && (
- {meta.routedTo as string} - {meta.iterations && {meta.iterations as number} iterations} + {routedTo} + {iterations !== undefined && {iterations} iterations} {durationMs != null && {durationMs}ms}
)} - {meta?.queries && (meta.queries as string[]).length > 1 && ( + {queries.length > 1 && (
- Queries: {(meta.queries as string[]).map((q, i) => ( + Queries: {queries.map((q, i) => ( {i > 0 && ' → '}{q} ))}
@@ -210,8 +228,8 @@ export function QueryPanel({ apiUrl }: QueryPanelProps) { {/* Result count + copy */}
- {results.length} result{results.length !== 1 ? 's' : ''} - {durationMs != null && !meta?.routedTo && {durationMs}ms} + {total ?? results.length} result{(total ?? results.length) !== 1 ? 's' : ''} + {durationMs != null && !routedTo && {durationMs}ms}
- -
-
-
- -
- - - - - -
- - Sign in - -
- - Appearance settings - - - -
- -
-
- - -
-
- - - - - - -
-
- - - -
- - - - -
- - - - - -
- -

Search code, repositories, users, issues, pull requests...

-
- -
-
- -
-
-
- -
- - - -
-
-
-

- Provide feedback -

- -
-
- -
-
- -
- -
-

We read every piece of feedback, and take your input very seriously.

- - - -
-
- -
- - - - - -
-
-
-

- Saved searches -

-

Use saved searches to filter your results more quickly

-
-
- -
-
- -
- -
- - - -
-
-
- -
-
- -
-
-
-
- - - - - - -
- - Appearance settings - - - -
- - -
-
-
-
- - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
- - - -
-
- -
-
- 404 “This is not the web page you are looking for” - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
- -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - diff --git a/apps/web/public/fonts/GeistVF.woff2 b/apps/web/public/fonts/GeistVF.woff2 deleted file mode 100644 index 3f073885..00000000 --- a/apps/web/public/fonts/GeistVF.woff2 +++ /dev/null @@ -1,1468 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Page not found · GitHub · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
- - - -
-
- -
-
- 404 “This is not the web page you are looking for” - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
- -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - diff --git a/apps/web/public/fonts/JetBrainsMonoVF.woff2 b/apps/web/public/fonts/JetBrainsMonoVF.woff2 deleted file mode 100644 index 58cc4e2e..00000000 --- a/apps/web/public/fonts/JetBrainsMonoVF.woff2 +++ /dev/null @@ -1,1468 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Page not found · GitHub · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
- - - -
-
- -
-
- 404 “This is not the web page you are looking for” - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
- -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - diff --git a/benchmarks/cgbench-v1/package.json b/benchmarks/cgbench-v1/package.json index 36510a25..c9509ae0 100644 --- a/benchmarks/cgbench-v1/package.json +++ b/benchmarks/cgbench-v1/package.json @@ -4,7 +4,9 @@ "private": true, "type": "module", "scripts": { - "test": "vitest run --passWithNoTests", + "test": "vitest run", + "test:integration": "vitest run --config vitest.integration.config.ts", + "test:competitors": "vitest run --config vitest.competitors.config.ts", "test:watch": "vitest", "bench": "tsx src/cli.ts", "bench:clone-corpora": "tsx scripts/clone-corpora.ts", @@ -15,7 +17,7 @@ "@codegraph/core": "workspace:*", "@codegraph/graph": "workspace:*", "@codegraph/types": "workspace:*", - "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/sdk": "^1.30.0", "zod": "^3.25.76" }, "devDependencies": { diff --git a/benchmarks/cgbench-v1/vitest.competitors.config.ts b/benchmarks/cgbench-v1/vitest.competitors.config.ts new file mode 100644 index 00000000..81b2ea3d --- /dev/null +++ b/benchmarks/cgbench-v1/vitest.competitors.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['tests/adapters/**/*.smoke.test.ts'], + testTimeout: 600_000, + hookTimeout: 90_000, + }, +}); diff --git a/benchmarks/cgbench-v1/vitest.config.ts b/benchmarks/cgbench-v1/vitest.config.ts index b2084a44..6d878d1c 100644 --- a/benchmarks/cgbench-v1/vitest.config.ts +++ b/benchmarks/cgbench-v1/vitest.config.ts @@ -1,8 +1,15 @@ -import { defineConfig } from 'vitest/config'; +import { configDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: ['tests/**/*.test.ts'], + exclude: [ + ...configDefaults.exclude, + 'tests/**/*.integration.test.ts', + 'tests/**/*.smoke.test.ts', + 'tests/cli.test.ts', + 'tests/cli-run-all.test.ts', + ], testTimeout: 90_000, hookTimeout: 90_000, }, diff --git a/benchmarks/cgbench-v1/vitest.integration.config.ts b/benchmarks/cgbench-v1/vitest.integration.config.ts new file mode 100644 index 00000000..59110b32 --- /dev/null +++ b/benchmarks/cgbench-v1/vitest.integration.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + env: { + CODEGRAPH_DRIVER: 'falkordb', + CODEGRAPH_EMBEDDING_PROVIDER: 'none', + FALKORDB_HOST: 'localhost', + }, + include: [ + 'tests/adapters/codegraph.integration.test.ts', + 'tests/runner.integration.test.ts', + 'tests/cli.test.ts', + 'tests/cli-run-all.test.ts', + ], + pool: 'forks', + poolOptions: { forks: { singleFork: true } }, + testTimeout: 180_000, + hookTimeout: 90_000, + }, +}); diff --git a/docs/DISTRIBUTION-SETUP.md b/docs/DISTRIBUTION-SETUP.md new file mode 100644 index 00000000..f9ab0957 --- /dev/null +++ b/docs/DISTRIBUTION-SETUP.md @@ -0,0 +1,128 @@ +# Distribution and Release Setup + +This is the operator guide for the public `codegraph-mcp` npm package and the platform-local MCPB desktop extension. The canonical source is [Phoenixrr2113/codebase-graph](https://github.com/Phoenixrr2113/codebase-graph). + +## Release model + +- `main` is the source of truth. +- CI validates the repository and tests one exact npm tarball on Linux, macOS, and Windows. Linux x64 and Apple silicon macOS also exercise a database-backed MCP call through embedded FalkorDBLite; the macOS job installs the module's required Homebrew `libomp` and `openssl@3` libraries first. +- The first `0.1.0` npm publication is a manual authenticated bootstrap, followed by a one-time Release workflow run that verifies the registry package and creates its annotated tag and GitHub release. +- Later annotated `vX.Y.Z` tags publish through npm trusted publishing with GitHub Actions OIDC. +- The release workflow creates a GitHub release only after the registry package passes the CLI and MCP handshake smoke tests. +- MCPB artifacts are built for the current runner platform. They are not claimed to be portable across operating systems. + +## Prerequisites + +- Node.js 22 +- The pnpm version declared in the root `package.json` +- npm account access for the one-time bootstrap +- Repository administration access for the `npm` environment and security settings + +Do not create an npm automation token for this project. The steady-state workflow uses a short-lived OIDC identity. + +## One-time `0.1.0` bootstrap + +Use a clean checkout of the reviewed commit. Confirm authentication without displaying configuration or token data: + +```bash +git status --short +git rev-parse HEAD +npm whoami +npm view codegraph-mcp version --json +``` + +The status output must be empty. Save the full 40-character commit SHA as `BOOTSTRAP_COMMIT`; it identifies the reviewed source used to build the registry package. An npm `E404` response is expected before the first publication. Then run the full local gate: + +```bash +pnpm install --frozen-lockfile +pnpm audit:prod +pnpm lint +pnpm typecheck +pnpm test +pnpm build +pnpm docker:db +pnpm test:integration +pnpm test:scripts +pnpm build:mcpb +pnpm release:check +``` + +Publish only the exact tarball created and verified by `pnpm release:check`: + +```bash +npm publish tmp/release/codegraph-mcp-0.1.0.tgz --access public +``` + +The authenticated bootstrap cannot use trusted-publishing provenance because the npm package does not exist yet. Later releases use the trusted publisher and receive automatic provenance from npm. + +If `npm whoami` fails, run `npm login` in your terminal and repeat the identity check. Never paste an npm token into GitHub, a shell command, an issue, or a chat. + +## Verify the bootstrap package + +From the repository root: + +```bash +npm view codegraph-mcp@0.1.0 name version license repository bin dist --json +mkdir -p tmp/registry +npm pack codegraph-mcp@0.1.0 --pack-destination tmp/registry +node scripts/release/smoke-package.mjs \ + --tarball tmp/registry/codegraph-mcp-0.1.0.tgz \ + --version 0.1.0 +``` + +The smoke test creates a temporary consumer, installs the registry tarball without lifecycle scripts, checks `codegraph-mcp --version`, opens an MCP stdio connection, and verifies the `search`, `knowledge`, `codebase`, and `query` tools. On Linux x64 and Apple silicon macOS it also stores and reads an isolated verification entity through embedded FalkorDBLite. Apple silicon requires `brew install libomp openssl@3`; without those libraries CodeGraph falls back to external FalkorDB. Other platforms require an external FalkorDB service for database operations. + +After the registry smoke passes, create the GitHub `npm` environment for later tag releases. In GitHub Actions, open the Release workflow, choose **Run workflow** from `main`, enter `0.1.0` as `bootstrap_version`, and enter the saved full SHA as `bootstrap_commit`. This one-time path accepts only the `0.1.0` package version, checks out that exact commit, requires it to be reachable from `main`, reruns the full release gate, confirms that the exact version already exists on npm, requires the registry tarball to be byte-for-byte identical to the artifact rebuilt from `bootstrap_commit`, creates the annotated `v0.1.0` tag on that commit, and publishes the tarball plus checksum as a GitHub release. It does not use the `npm` environment, request an OIDC token, or call `npm publish` again. + +Do not push `v0.1.0` yourself after the manual npm publication. A normal tag-triggered release correctly requires its version to be unpublished; the bootstrap workflow dispatch owns the initial tag and avoids a duplicate publication attempt. + +## Configure trusted publishing + +After `codegraph-mcp` exists on npm, open its package settings and add a GitHub Actions trusted publisher with: + +| Field | Value | +| --- | --- | +| Owner | `Phoenixrr2113` | +| Repository | `codebase-graph` | +| Workflow filename | `release.yml` | +| Environment | `npm` | + +In GitHub, create the `npm` environment with no deployment branch pattern broader than version tags. The release workflow already grants only `contents: write` and `id-token: write`. + +After a trusted release succeeds, configure npm publishing access to require two-factor authentication and disallow token-based publication. The trusted publisher remains able to publish with OIDC. + +See the [npm trusted publishing documentation](https://docs.npmjs.com/trusted-publishers/) for the current registry requirements. + +## Publish later versions + +Start from a clean, current `main`. Choose `patch`, `minor`, or `major` based on the compatibility change. This example creates the next patch commit and annotated tag: + +```bash +cd packages/npm-package +npm version patch +cd ../.. +git push origin HEAD +git push origin vX.Y.Z +``` + +Replace `X.Y.Z` with the version printed by `npm version`. Do not hand-edit the tag. The release preflight rejects a tag that does not exactly match the source package version, a lightweight tag, a prerelease version, a commit outside `main`, or a version that already exists on npm. + +The workflow runs the repository gate, package gate, publication, bounded registry polling, registry smoke test, checksum generation, and GitHub release creation in that order. + +## Recovery + +- If tag validation, audit, tests, build, package validation, or package smoke fails before publication, fix the branch and create a new version commit and tag. +- If npm publication succeeds but registry verification or GitHub release creation fails, do not try to publish the same version again. Verify the existing registry artifact, fix the automation, and create the missing GitHub release manually or ship a new patch version. +- If the manual `0.1.0` publication succeeds but bootstrap finalization fails before the tag is created, fix the workflow and rerun it with `bootstrap_version` set to `0.1.0`. If the tag exists, do not rerun the bootstrap path; verify the registry artifact and create only the missing GitHub release. +- Do not unpublish a valid public release to reuse its version. npm versions are immutable release identifiers. +- If trusted publishing fails, confirm the npm owner, repository, workflow filename, and `npm` environment match exactly. Do not fall back to a long-lived token. + +## MCPB artifact + +Build and validate the desktop extension on the platform where it will be installed: + +```bash +pnpm build:mcpb +``` + +The packed artifact is written to `packages/mcpb/dist.mcpb`. It includes locked native parser dependencies for the build platform and expects an external FalkorDB service, so publish separate assets only after testing them on their matching platform. diff --git a/docs/commercial-distribution-strategy.md b/docs/commercial-distribution-strategy.md new file mode 100644 index 00000000..5bd16d37 --- /dev/null +++ b/docs/commercial-distribution-strategy.md @@ -0,0 +1,29 @@ +# Historical Commercial Distribution Strategy + +> Superseded on 2026-08-18 by the [publication-ready baseline](superpowers/specs/2026-08-18-publication-ready-baseline-design.md). This file is retained only as decision history. It is not an active product, licensing, packaging, or release plan. + +## Previous direction + +The original March 2026 proposal assumed a private source repository, Bun-compiled platform binaries, paid license keys, and Polar-hosted downloads. It explored source protection, per-seat pricing, Merchant of Record services, cached online license validation, and later marketplace distribution. + +## Why it was replaced + +The repository is now public under the MIT License. The active baseline favors: + +- a public `codegraph-mcp` npm package; +- source and issue tracking in `Phoenixrr2113/codebase-graph`; +- reproducible tarball validation and cross-platform consumer smoke tests; +- a platform-local MCPB artifact; +- npm trusted publishing through GitHub Actions OIDC; +- no runtime license key, payment gate, or closed-binary claim. + +The abandoned plan's useful lesson is that distribution must be tested as an installed artifact, not inferred from a source build. That principle remains in the npm and MCPB release gates. + +## Current authority + +- [Publication baseline design](superpowers/specs/2026-08-18-publication-ready-baseline-design.md) +- [Distribution and release setup](DISTRIBUTION-SETUP.md) +- [Launch checklist](distribution/launch-checklist.md) +- [Root README](../README.md) + +Any references elsewhere to Polar, commercial license keys, a private repository, or `codegraph.dev` are historical unless a future approved design explicitly restores them. diff --git a/docs/distribution/launch-checklist.md b/docs/distribution/launch-checklist.md new file mode 100644 index 00000000..6b410067 --- /dev/null +++ b/docs/distribution/launch-checklist.md @@ -0,0 +1,48 @@ +# Launch Checklist + +Use this checklist after the publication baseline pull request is green and merged. + +## Repository baseline + +- [ ] CI repository check passes on the reviewed commit. +- [ ] The exact npm tarball passes consumer smoke tests on Linux, macOS, and Windows. +- [ ] CodeQL analysis passes. +- [ ] Production audit has no high or critical findings. +- [ ] Community files, issue forms, security policy, license, and developer access links render on GitHub. +- [ ] Discussions, private vulnerability reporting, vulnerability alerts, automated security fixes, and supported secret protection are enabled. +- [ ] `main` requires the verified CI and CodeQL checks, pull requests, and resolved conversations. + +## npm bootstrap + +- [ ] `npm whoami` confirms the intended account without exposing credentials. +- [ ] `codegraph-mcp@0.1.0` is still unpublished. +- [ ] The full release gate passes from a clean checkout of the reviewed commit. +- [ ] `packages/npm-package/dist` is published with public access using the intended npm owner account. +- [ ] Registry metadata reports the expected name, version, MIT license, repository, and binary. +- [ ] A fresh registry install reports version `0.1.0` and completes the four-tool MCP handshake. +- [ ] npm trusted publishing is configured for `Phoenixrr2113/codebase-graph`, `release.yml`, and the `npm` environment. +- [ ] A later trusted release includes npm provenance. +- [ ] Token-based publication is disabled after a trusted release succeeds. + +## Public documentation + +- [ ] README links to the npm package. +- [ ] npm version and weekly-download badges both return HTTP 200. +- [ ] Source, live application, issues, Discussions, contribution, security, and license links work. +- [ ] A fresh user can follow the npm MCP client configuration without a source checkout. +- [ ] The release operator guide matches the actual tag workflow. + +## Release evidence + +- [ ] GitHub release `v0.1.0` exists with the npm tarball and SHA-256 checksum. +- [ ] The release verification document records the merged commit, UTC timestamps, gate results, package size, npm integrity, provenance, and GitHub settings. +- [ ] A fresh clone passes install, audit, lint, typecheck, tests, build, MCPB build, and release checks. + +## Distribution follow-up + +- [ ] Submit to relevant MCP directories only after the registry artifact is verified. +- [ ] Publish a short demo using the exact public install path. +- [ ] Respond to security reports privately and issues publicly. +- [ ] Review npm weekly downloads, GitHub clones, stars, issues, and contributors once a week for the first month. + +Use npm weekly downloads as the primary install signal. Treat GitHub stars as interest, not usage. Do not add pricing, licensing, or a hosted tier until observed demand supports that decision. diff --git a/docs/superpowers/plans/2026-08-18-publication-distribution-baseline.md b/docs/superpowers/plans/2026-08-18-publication-distribution-baseline.md new file mode 100644 index 00000000..fbc4feca --- /dev/null +++ b/docs/superpowers/plans/2026-08-18-publication-distribution-baseline.md @@ -0,0 +1,357 @@ +# Publication Distribution Baseline Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Produce a deterministic MIT npm tarball that installs the correct native dependencies on each consumer platform and passes an MCP runtime smoke test. + +**Architecture:** Bundle internal workspace modules from the built MCP entry point, externalize platform-sensitive public dependencies, generate a clean staging tree from one source manifest, and validate the packed artifact in a temporary consumer. MCPB remains a separate platform-local build. + +**Tech Stack:** Node 22, esbuild 0.27, npm pack, MCP SDK 1.30, pnpm 9, Vitest 3 + +**Spec:** `docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md` + +## Global Constraints + +- Canonical npm name is `codegraph-mcp` while it remains available. +- The package and all active distribution copy use MIT licensing. +- `packages/npm-package/dist` is deleted and recreated on every build. +- The tarball contains no `node_modules`, `.node` binaries, workspace protocol references, secrets, or absolute source paths. +- Compressed tarball budget is 15 MB. +- Node 20 remains the consumer engine floor; Node 22 is the release runtime. + +--- + +### Task 1: Make package metadata canonical and testable + +**Files:** +- Modify: `packages/npm-package/package.json` +- Modify: `packages/npm-package/bin/codegraph-mcp.mjs` +- Delete: `packages/npm-package/postinstall.mjs` +- Create: `packages/npm-package/__tests__/cli.test.ts` + +**Interfaces:** +- Consumes: package manifest adjacent to the installed `bin` directory +- Produces: `codegraph-mcp --version` and MIT public package metadata + +- [ ] **Step 1: Write the failing CLI version test** + +The test copies the bin file and a fixture package manifest into a temporary +directory, runs `node bin/codegraph-mcp.mjs --version`, and asserts stdout is +exactly `9.8.7\n` with exit code 0. + +- [ ] **Step 2: Verify the test fails** + +Run: + +```bash +pnpm --filter @codegraph/mcp exec vitest run __tests__/cli.test.ts +``` + +Expected: failure because the current bin imports the server instead of +handling `--version`. + +- [ ] **Step 3: Read the installed version dynamically** + +At the start of the bin file, read `../package.json` relative to +`import.meta.url`, validate that `name === 'codegraph-mcp'`, and print its +string version when `process.argv` contains `--version` or `-v`. A missing or +invalid manifest writes a concise error to stderr and exits 1. + +- [ ] **Step 4: Replace the source manifest** + +Set these canonical fields: + +```json +{ + "name": "codegraph-mcp", + "version": "0.1.0", + "license": "MIT", + "homepage": "https://v0-landing-page-build-kappa-virid.vercel.app", + "repository": { + "type": "git", + "url": "git+https://github.com/Phoenixrr2113/codebase-graph.git" + }, + "bugs": { + "url": "https://github.com/Phoenixrr2113/codebase-graph/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "engines": { + "node": ">=20.0.0" + } +} +``` + +Keep the bin mapping, remove the postinstall script, and add `esbuild` and +`vitest` as development dependencies. Remove all `codegraph.dev`, Polar, and +commercial-license fields. + +- [ ] **Step 5: Delete the commercial postinstall file and verify the test** + +Run the CLI test again. Expected: pass with no attempt to import the server for +`--version`. + +### Task 2: Build npm directly from the MCP entry point + +**Files:** +- Rewrite: `packages/npm-package/build.mjs` +- Create: `packages/npm-package/lib/package-metadata.mjs` +- Create: `packages/npm-package/__tests__/package-metadata.test.ts` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** +- Consumes: built `packages/mcp-server/dist/index.js` and source workspace manifests +- Produces: clean `packages/npm-package/dist` staging directory + +- [ ] **Step 1: Write metadata unit tests** + +Export this interface from `package-metadata.mjs`: + +```js +export function createPublishedManifest({ packageManifest, dependencyManifests }) +``` + +Tests assert that the result: + +- Preserves canonical name, version, description, license, URLs, bin, engines, + keywords, and publishConfig. +- Has no build or postinstall scripts. +- Contains no `workspace:` versions. +- Reads dependency ranges for `@huggingface/transformers`, + `@modelcontextprotocol/sdk`, `tree-sitter`, `tree-sitter-go`, + `tree-sitter-python`, `tree-sitter-rust`, and `tree-sitter-typescript` from + their owning workspace manifests. +- Places `falkordblite` in `optionalDependencies` using the graph workspace's + development range while that optional driver is advertised. + +- [ ] **Step 2: Verify the metadata tests fail** + +Run: `pnpm --filter codegraph-mcp exec vitest run __tests__/package-metadata.test.ts` + +Expected: failure because the module does not exist. + +- [ ] **Step 3: Implement metadata generation with runtime validation** + +Validate every input as an object, require all named string fields, and throw +an error naming the missing package and dependency. Return a plain JSON-safe +object. Do not use `any` in TypeScript tests; narrow imported JavaScript values +as `unknown`. + +- [ ] **Step 4: Rewrite the build pipeline using esbuild's JavaScript API** + +The builder must: + +1. Remove `packages/npm-package/dist` recursively. +2. Verify `packages/mcp-server/dist/index.js` exists. +3. Bundle that entry to `dist/server/index.mjs` with `platform: 'node'`, + `target: 'node20'`, `format: 'esm'`, and sourcemaps disabled. +4. Mark only the published native/runtime dependencies from Task 2 external. +5. Copy the bin file and root `LICENSE`. +6. Generate `dist/package.json` through `createPublishedManifest`. +7. Generate an MIT README with verified GitHub, installation, configuration, + and environment-variable links. +8. Set the bin file mode to `0o755`. + +The build must not read or copy `packages/mcpb/dist`. + +- [ ] **Step 5: Verify deterministic clean staging** + +Create `dist/sentinel.txt`, rerun the builder, and verify the sentinel is gone. +Run the builder twice and compare SHA-256 hashes for `server/index.mjs`, +`package.json`, `LICENSE`, and `README.md`. Expected: hashes match. + +### Task 3: Validate the staged and packed package + +**Files:** +- Create: `scripts/release/validate-package.mjs` +- Create: `scripts/release/__tests__/validate-package.test.ts` +- Modify: `package.json` + +**Interfaces:** +- Consumes: a staging directory path and npm pack JSON +- Produces: exit 0 only for a policy-compliant artifact + +- [ ] **Step 1: Write rejection tests** + +Export: + +```js +export async function validatePackageDirectory(directoryUrl) +export function validatePackReport(report) +``` + +Tests build temporary directories and assert rejection for each of these: + +- A manifest with `workspace:*`. +- A `node_modules` directory. +- A `.node` file. +- A source map containing the repository's absolute path. +- Missing or non-executable bin file. +- Non-MIT license or incorrect repository URL. +- Pack report `size` greater than `15 * 1024 * 1024`. + +A valid fixture passes and returns its name, version, file count, packed size, +and unpacked size. + +- [ ] **Step 2: Run tests and verify they fail before implementation** + +Run: `pnpm exec vitest run scripts/release/__tests__/validate-package.test.ts` + +- [ ] **Step 3: Implement recursive validation** + +Use `node:fs/promises`, `node:path`, and explicit guards. Never follow symlinks +outside the staging directory. Report every violation in one thrown error so a +release run gives a complete correction list. + +- [ ] **Step 4: Add the non-publishing pack command** + +Add root scripts: + +```json +"build:npm": "pnpm turbo run build --filter=!codegraph-mcp && node packages/npm-package/build.mjs", +"pack:npm": "npm pack --dry-run --json --prefix packages/npm-package/dist", +"validate:npm": "node scripts/release/validate-package.mjs packages/npm-package/dist" +``` + +The validator CLI must run directory validation, execute a real non-dry npm +pack into a temporary output directory, parse npm's JSON report, validate size +and contents, print the tarball path, and never publish. + +### Task 4: Smoke-test a real consumer installation and MCP handshake + +**Files:** +- Create: `scripts/release/smoke-package.mjs` +- Create: `scripts/release/__tests__/smoke-package.test.ts` +- Modify: `package.json` + +**Interfaces:** +- Consumes: tarball path printed by the validator +- Produces: verified CLI version and MCP initialize/list-tools/shutdown exchange + +- [ ] **Step 1: Write the process-contract tests** + +Unit-test that the smoke runner rejects a missing tarball, a version mismatch, +a non-zero npm install, and an MCP child that writes non-JSON data to stdout. +Inject the command runner into the exported function rather than mocking global +process functions. Define the JavaScript contract with JSDoc: + +```js +/** + * @typedef {{ + * run(command: string, args: string[], options: import('node:child_process').SpawnSyncOptionsWithStringEncoding): import('node:child_process').SpawnSyncReturns + * }} CommandRunner + */ +``` + +- [ ] **Step 2: Implement the temporary consumer flow** + +The script creates a directory with `mkdtemp`, writes a minimal package.json, +runs `npm install --ignore-scripts`, then verifies +`node_modules/.bin/codegraph-mcp --version` equals the tarball version. + +Use `@modelcontextprotocol/sdk/client/index.js` and +`@modelcontextprotocol/sdk/client/stdio.js` from the consumer installation to +start the installed bin with: + +```text +CODEGRAPH_EMBEDDING_PROVIDER=none +CODEGRAPH_LOG_STDERR=true +``` + +Connect a client, call `listTools`, require the expected `search`, `knowledge`, +`codebase`, and `query` tools, close the client, and verify the child exits. +Always remove the temporary directory in `finally`. + +- [ ] **Step 3: Add the release check aggregator** + +Add: + +```json +"smoke:npm": "node scripts/release/smoke-package.mjs", +"release:check": "pnpm build:npm && pnpm validate:npm && pnpm smoke:npm" +``` + +Pass the generated tarball path through a small JSON result file inside an +ignored temporary directory, not through command substitution. + +- [ ] **Step 4: Run the full local release gate** + +Run: `pnpm release:check` + +Expected: clean build, policy validation, tarball below 15 MB, successful +temporary install, correct `0.1.0` version, and successful MCP tool listing. + +### Task 5: Make MCPB portable but independent + +**Files:** +- Create: `packages/mcpb/package.json` +- Modify: `packages/mcpb/build.mjs` +- Modify: `packages/mcpb/manifest.json` +- Modify: `packages/mcpb/README.md` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** +- Consumes: built MCP server and local platform dependencies +- Produces: clean platform-local MCPB staging directory + +- [ ] **Step 1: Add MCPB's declared build dependency** + +Create a private workspace manifest with `esbuild: ^0.27.7` as a development +dependency and `build: node build.mjs`. + +- [ ] **Step 2: Replace the hardcoded esbuild binary invocation** + +Import `build` from `esbuild` and pass the existing bundle options through its +JavaScript API. Pass the external package array directly. Remove the shell-built +command string and the hardcoded Darwin path. + +- [ ] **Step 3: Generate truthful platform metadata** + +When copying the manifest into `dist`, set its version from the npm source +manifest, set repository/homepage to canonical URLs, remove commercial API-key +requirements that are optional in offline mode, and set compatibility platforms +to `[process.platform]`. + +- [ ] **Step 4: Verify from clean output** + +Run: + +```bash +pnpm install --frozen-lockfile +pnpm build:mcpb +``` + +Expected: build succeeds without a hardcoded esbuild path, removes an injected +sentinel from its output, and reports only the current platform in the generated +manifest. + +### Task 6: Commit the distribution slice + +**Files:** +- Modify: all files from Tasks 1 through 5 + +**Interfaces:** +- Consumes: passing package and MCPB gates +- Produces: independently reviewable distribution baseline commit + +- [ ] **Step 1: Run final distribution verification** + +Run: + +```bash +pnpm exec vitest run packages/npm-package/__tests__ scripts/release/__tests__ +pnpm release:check +pnpm build:mcpb +git diff --check +``` + +Expected: every command exits 0. + +- [ ] **Step 2: Commit** + +```bash +git add package.json pnpm-lock.yaml packages/npm-package packages/mcpb scripts/release +git commit -m "feat: build portable npm distribution" +``` diff --git a/docs/superpowers/plans/2026-08-18-publication-repository-release.md b/docs/superpowers/plans/2026-08-18-publication-repository-release.md new file mode 100644 index 00000000..85fa8ef1 --- /dev/null +++ b/docs/superpowers/plans/2026-08-18-publication-repository-release.md @@ -0,0 +1,354 @@ +# Publication Repository and Release Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make GitHub the trustworthy public entry point and automate verified npm releases after one authenticated bootstrap publish. + +**Architecture:** CI calls the root repository and release contracts, a cross-platform matrix tests the exact tarball, GitHub community files explain contribution and security paths, and release tags publish through npm OIDC. Repository protections are enabled only after the corresponding checks succeed. + +**Tech Stack:** GitHub Actions, CodeQL, Dependabot, npm trusted publishing, shields.io badges, GitHub REST API + +**Spec:** `docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md` + +## Global Constraints + +- Workflows use least privilege and GitHub-hosted runners. +- Third-party actions are pinned to full commit SHAs. +- Job names required by branch protection are unique across workflows. +- No npm token is stored after trusted publishing is configured. +- The first publish is the only manual registry bootstrap. +- npm badges are not added until the package URL resolves. + +--- + +### Task 1: Add public contribution and security surfaces + +**Files:** +- Create: `CONTRIBUTING.md` +- Create: `SECURITY.md` +- Create: `CODE_OF_CONDUCT.md` +- Create: `.github/ISSUE_TEMPLATE/bug.yml` +- Create: `.github/ISSUE_TEMPLATE/feature.yml` +- Create: `.github/ISSUE_TEMPLATE/config.yml` +- Create: `.github/pull_request_template.md` + +**Interfaces:** +- Consumes: root pnpm commands and canonical GitHub URLs +- Produces: GitHub community-profile documents and issue forms + +- [ ] **Step 1: Write the contribution path** + +Document Node 22, pnpm from `packageManager`, fork/branch workflow, frozen +install, `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build`, and +`pnpm release:check` for distribution changes. State that generated `dist` +trees, secrets, and local `.codegraph` data must not be committed. + +- [ ] **Step 2: Write the security policy** + +Support the current minor release line, direct reporters to GitHub private +vulnerability reporting, state a 72-hour initial response target, and prohibit +public issues containing exploit details or credentials. Link only to the +canonical repository security advisory page. + +- [ ] **Step 3: Add the code of conduct** + +Use Contributor Covenant 2.1 with the maintainer contact routed through the +repository's private reporting or maintainer profile, not an invented support +email. + +- [ ] **Step 4: Add structured issue and PR forms** + +Bug form required fields: version/commit, Node version, platform, install +method, reproduction, expected behavior, actual behavior, and redacted logs. +Feature form required fields: problem, proposed outcome, alternatives, and +scope. Disable blank issues. PR template includes linked issue, change summary, +security impact, test evidence, and checklist for docs and release impact. + +- [ ] **Step 5: Validate form YAML and links** + +Run a Node script using the repository's YAML parser dependency or Ruby's +standard YAML parser to parse every issue form. Run `git diff --check` and use +`curl --fail --location --head` on every canonical external link. + +### Task 2: Replace partial CI with the baseline gates + +**Files:** +- Rewrite: `.github/workflows/ci.yml` +- Create: `.github/workflows/codeql.yml` +- Create: `.github/dependabot.yml` + +**Interfaces:** +- Consumes: `pnpm audit:prod`, lint, typecheck, test, build, and release scripts +- Produces: `CI / Repository`, `CI / Package (ubuntu-latest)`, `CI / Package (macos-latest)`, `CI / Package (windows-latest)`, and `CodeQL / Analyze` checks + +- [ ] **Step 1: Pin current official actions** + +Resolve the full commit SHAs for the current major releases of +`actions/checkout`, `actions/setup-node`, `pnpm/action-setup`, +`github/codeql-action/init`, and `github/codeql-action/analyze` from their +official repositories. Keep a version comment beside each SHA. + +- [ ] **Step 2: Create the repository job** + +On pushes and pull requests to `main`, use Node 22 and a frozen pnpm install, +then run: + +```bash +pnpm audit:prod +pnpm lint +pnpm typecheck +pnpm test +pnpm build +pnpm build:mcpb +``` + +Set `CODEGRAPH_EMBEDDING_PROVIDER=none`. Remove the existing exclusions and all +`continue-on-error` behavior. + +- [ ] **Step 3: Create the package matrix** + +Build the tarball once on Ubuntu and upload it as an artifact. Matrix jobs on +Ubuntu, macOS, and Windows download that exact tarball and run the consumer +smoke script without rebuilding it. Artifact names and paths must not contain +shell-expanded globs. + +- [ ] **Step 4: Add CodeQL** + +Use JavaScript/TypeScript analysis on pull requests, pushes to `main`, and a +weekly schedule. Grant only `security-events: write`, `packages: read`, and +`contents: read` as required by the official action. + +- [ ] **Step 5: Add Dependabot** + +Configure weekly updates for the pnpm workspace root and GitHub Actions. +Group patch/minor pnpm updates separately from majors. Limit open pull requests +to five per ecosystem and label them `dependencies`. + +- [ ] **Step 6: Validate workflow syntax locally** + +Parse all workflow and Dependabot YAML files, run actionlint if available, and +verify every `uses:` value is a 40-character SHA with a human-readable version +comment. + +### Task 3: Add tag-driven trusted publication + +**Files:** +- Create: `.github/workflows/release.yml` +- Create: `scripts/release/verify-release-tag.mjs` +- Create: `scripts/release/__tests__/verify-release-tag.test.ts` +- Modify: `package.json` + +**Interfaces:** +- Consumes: annotated `vX.Y.Z` tag and source npm manifest +- Produces: npm publication with provenance and matching GitHub release + +- [ ] **Step 1: Test tag/version validation** + +Export: + +```js +export function verifyReleaseTag(tag, packageName, packageVersion) +``` + +Accept only `refs/tags/v${packageVersion}` for package `codegraph-mcp`. Reject a +missing `v`, prerelease mismatch, wrong package name, or non-semver version with +an actionable error. + +- [ ] **Step 2: Implement the release preflight** + +The CLI reads `GITHUB_REF` and `packages/npm-package/package.json`, validates +the tag, then runs `npm view codegraph-mcp@ version --json`. Exit 1 if +the version already exists. Treat npm E404 as the expected unpublished state. + +- [ ] **Step 3: Create the release workflow** + +Trigger on `v*` tags. Configure: + +```yaml +permissions: + contents: write + id-token: write +concurrency: + group: npm-release + cancel-in-progress: false +``` + +Use a protected `npm` environment. Check out the exact tag, use Node 22.14 or +newer and npm 11.5.1 or newer, disable release caching, install with frozen +pnpm, run the tag preflight, full repository gate, and `pnpm release:check`. +Publish from the generated staging directory with `npm publish --access public`. +Trusted publishing supplies OIDC authentication and automatic provenance. + +- [ ] **Step 4: Verify the registry artifact before creating the release** + +Poll `npm view codegraph-mcp@ version --json` with a bounded retry of +six attempts and ten seconds between attempts. Install +`codegraph-mcp@` into a fresh temporary consumer and run the same CLI +and MCP smoke checks. Only then create the GitHub release and attach the local +tarball plus its SHA-256 checksum. + +- [ ] **Step 5: Add the versioning operator command to documentation** + +The release procedure is: + +```bash +cd packages/npm-package +npm version patch +git push origin HEAD +git push origin vX.Y.Z +``` + +The operator replaces `X.Y.Z` with the version printed by `npm version`; the +workflow itself rejects any mismatch. Do not hand-edit a release version. + +### Task 4: Rewrite the README around verified access paths + +**Files:** +- Modify: `README.md` +- Rewrite: `docs/DISTRIBUTION-SETUP.md` +- Modify: `docs/distribution/launch-checklist.md` +- Modify: `docs/commercial-distribution-strategy.md` + +**Interfaces:** +- Consumes: verified local commands, GitHub URL, Vercel URL, and npm package URL +- Produces: accurate developer entry points and release operator guide + +- [ ] **Step 1: Add real pre-publication badges** + +Add badges for CI, CodeQL, GitHub stars, and MIT license. Each badge links to +its corresponding GitHub workflow, stargazers page, or license file. + +- [ ] **Step 2: Add the developer access section** + +Link clearly to: + +- Live application: `https://v0-landing-page-build-kappa-virid.vercel.app` +- Source: `https://github.com/Phoenixrr2113/codebase-graph` +- Issues: `https://github.com/Phoenixrr2113/codebase-graph/issues` +- Discussions: `https://github.com/Phoenixrr2113/codebase-graph/discussions` +- Contribution guide, security policy, and MIT license +- npm: `https://www.npmjs.com/package/codegraph-mcp` after bootstrap + +- [ ] **Step 3: Replace stale install and configuration copy** + +Use `npx codegraph-mcp` and the installed `codegraph-mcp` bin. Remove +`@codegraph/mcp`, `randywilson/codegraph`, `codegraph.dev`, Polar, commercial +license keys, and closed-binary language from active instructions. + +- [ ] **Step 4: Make old commercial planning explicitly historical** + +Add a top-level superseded notice to the commercial strategy that links to the +publication baseline spec and states it is retained only as decision history. +Rewrite distribution setup for npm bootstrap, trusted publisher configuration, +tagging, registry smoke verification, and recovery. Update the launch checklist +to use npm downloads as the post-publication usage metric. + +- [ ] **Step 5: Verify every active URL and command** + +Run link checks for active README and setup URLs. Run every documented local +command exactly as written. Searches for stale identifiers must return only the +clearly marked historical document: + +```bash +rg -n '@codegraph/mcp|randywilson/codegraph|codegraph\.dev|polar\.sh|CODEGRAPH_LICENSE' README.md docs packages/npm-package packages/mcpb +``` + +### Task 5: Bootstrap npm and enable repository settings + +**Files:** +- No repository files after prior tasks +- Modify external state: npm package settings and GitHub repository settings + +**Interfaces:** +- Consumes: passing local release gate and merged GitHub CI +- Produces: first npm version, trusted publisher, protected `main`, Discussions, and security settings + +- [ ] **Step 1: Push the branch and verify GitHub checks** + +Push `cleanup/publication-ready-baseline`, open a pull request, and wait for +every CI and CodeQL job. Fix failures on the branch. Do not enable required +checks until the exact job names have completed successfully once. + +- [ ] **Step 2: Perform the one-time authenticated bootstrap publish** + +Verify `npm whoami` and package availability without printing token data. From +a clean checkout of the reviewed commit, run the full release gate, then: + +```bash +cd packages/npm-package/dist +npm publish --access public --provenance +``` + +Immediately verify `npm view codegraph-mcp@0.1.0`, install the registry package +in a fresh temporary project, run `codegraph-mcp --version`, and complete the +MCP smoke test. If npm authentication is absent, stop at this exact command and +request login rather than creating or exposing a token. + +- [ ] **Step 3: Configure npm trusted publishing** + +In package settings, authorize GitHub user `Phoenixrr2113`, repository +`codebase-graph`, workflow filename `release.yml`, environment `npm`, and action +`npm publish`. Then set publishing access to require 2FA and disallow tokens. + +- [ ] **Step 4: Add npm badges after the package resolves** + +Add linked npm version and npm weekly-download badges to README and verify both +badge image endpoints return HTTP 200. + +- [ ] **Step 5: Enable GitHub collaboration and security settings** + +Enable Discussions, automatic head-branch deletion, vulnerability alerts, +automated security fixes, private vulnerability reporting, and secret push +protection where the account supports them. + +Protect `main` with strict required checks for the exact Repository, +Integration (FalkorDB), Build package artifact, three package matrix, and +Analyze job names. Require pull requests and conversation +resolution with zero required approving reviews. Block force pushes and branch +deletion. Apply the rule to administrators only after confirming the solo +maintainer can merge a green pull request without self-approval. + +- [ ] **Step 6: Verify external state through APIs** + +Use GitHub APIs to verify Discussions, delete-on-merge, security features, +workflow runs, and branch protection. Use npm registry metadata to verify name, +version, license, repository, bin, provenance, and download endpoint. + +### Task 6: Fresh-clone completion audit and commit + +**Files:** +- Create: `docs/releases/0.1.0-verification.md` +- Modify: `README.md` for npm badges from Task 5 + +**Interfaces:** +- Consumes: merged commit, registry package, GitHub settings, and release workflow +- Produces: requirement-by-requirement publication evidence + +- [ ] **Step 1: Verify from a fresh temporary clone** + +Clone the GitHub branch into a directory created by `mktemp -d`. Run frozen +install, audit, lint, typecheck, tests, build, MCPB build, and release check. +Record command, UTC timestamp, commit SHA, exit code, test count, tarball sizes, +and package smoke results. Do not record machine secrets or environment values. + +- [ ] **Step 2: Verify the registry artifact separately** + +Install `codegraph-mcp@0.1.0` from npm in a second empty temporary consumer, +verify version and MCP handshake, and record the npm integrity and provenance +URLs. + +- [ ] **Step 3: Verify GitHub state** + +Record zero open secret alerts, successful CI and CodeQL, enabled Dependabot, +branch protection contexts, Discussions, community profile health, and the +GitHub release asset checksums. + +- [ ] **Step 4: Commit the evidence** + +```bash +git add README.md docs/releases/0.1.0-verification.md +git commit -m "docs: record publication verification" +``` + +Expected: the verification document maps all 14 acceptance criteria in the +design spec to current evidence. diff --git a/docs/superpowers/plans/2026-08-18-publication-security-baseline.md b/docs/superpowers/plans/2026-08-18-publication-security-baseline.md new file mode 100644 index 00000000..67cf7c8f --- /dev/null +++ b/docs/superpowers/plans/2026-08-18-publication-security-baseline.md @@ -0,0 +1,244 @@ +# Publication Security Baseline Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Remove unexplained secret alerts and all critical or high production dependency advisories without broad modernization. + +**Architecture:** Remediate direct dependencies first, use documented pnpm overrides only for residual transitive advisories, then resolve the historical test-fixture alert through GitHub. The lockfile and audit output are the authoritative dependency evidence. + +**Tech Stack:** pnpm 9, npm advisory database, GitHub secret scanning API, Vitest + +**Spec:** `docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md` + +## Global Constraints + +- Production audit ends with zero critical and high advisories. +- Do not introduce a major dependency upgrade unless no compatible security patch exists. +- Never print the matched secret-scanning value. +- Do not rewrite Git history for the historical synthetic fixture. +- Keep the current package names and workspace boundaries during this plan. + +--- + +### Task 1: Establish the reproducible security failure + +**Files:** +- Modify: `package.json` +- Generated: `pnpm-lock.yaml` + +**Interfaces:** +- Consumes: pnpm audit JSON from the current lockfile +- Produces: root command `pnpm audit:prod` + +- [ ] **Step 1: Add the production audit contract** + +Add this script to the root `package.json`: + +```json +"audit:prod": "pnpm audit --prod --audit-level high" +``` + +- [ ] **Step 2: Run the audit and verify the baseline fails** + +Run: `pnpm audit:prod` + +Expected: non-zero exit with at least one critical or high advisory, including +the current `tar`, `next`, or `sharp` paths. + +- [ ] **Step 3: Capture the unique vulnerable modules** + +Run: + +```bash +pnpm audit --prod --json | jq -r '.advisories[] | select(.severity == "critical" or .severity == "high") | [.module_name, .severity, .patched_versions] | @tsv' | sort -u +``` + +Expected: a finite module list that can be mapped to a direct parent or a +targeted override. Do not copy advisory fixture values or environment data. + +### Task 2: Upgrade compatible direct parents + +**Files:** +- Modify: `apps/web/package.json` +- Modify: `packages/mcp-server/package.json` +- Modify: `benchmarks/cgbench-v1/package.json` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** +- Consumes: the vulnerable dependency paths from Task 1 +- Produces: patched Next.js and MCP dependency trees + +- [ ] **Step 1: Upgrade the landing application within current majors** + +Run: + +```bash +pnpm --filter codegraph-landing up next@16.3.1 react@19.2.8 react-dom@19.2.8 postcss@8.5.18 +``` + +Expected: manifest and lockfile use the stated versions without changing React +or Next major versions. + +- [ ] **Step 2: Upgrade the MCP SDK in both consumers** + +Run: + +```bash +pnpm --filter @codegraph/mcp-server up @modelcontextprotocol/sdk@1.30.0 +pnpm --filter @codegraph/cgbench-v1 up @modelcontextprotocol/sdk@1.30.0 +``` + +Expected: both manifests resolve MCP SDK 1.30.0 and the lockfile refreshes its +Hono, AJV, URL, and IP dependency paths where supported upstream. + +- [ ] **Step 3: Verify the direct upgrades compile before adding overrides** + +Run: + +```bash +pnpm --filter codegraph-landing exec tsc --noEmit -p tsconfig.json +pnpm --filter @codegraph/mcp-server build +pnpm --filter @codegraph/cgbench-v1 build +``` + +Expected: existing landing type defects may still fail and are owned by the +verification plan. The MCP server and benchmark builds must pass. Any new error +introduced by the upgrades must be fixed before continuing. + +### Task 3: Patch residual transitive advisories narrowly + +**Files:** +- Modify: `package.json` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** +- Consumes: residual audit paths after Task 2 +- Produces: root `pnpm.overrides` security floor map + +- [ ] **Step 1: Add patch-level security floors for residual paths** + +Add the following root field, retaining only entries still required by the +post-upgrade audit: + +```json +"pnpm": { + "overrides": { + "brace-expansion@>=2.0.0 <2.1.4": "2.1.4", + "fast-uri@>=3.0.0 <3.1.5": "3.1.5", + "hono@<4.12.25": "4.12.25", + "ip-address@<=10.3.0": "10.3.1", + "js-yaml@>=3.0.0 <3.15.1": "3.15.1", + "nanoid@<3.3.18": "3.3.18", + "postcss@<=8.5.17": "8.5.18", + "sharp@<0.35.0": "0.35.0", + "tar@<=7.5.18": "7.5.19", + "undici@>=7.0.0 <7.29.0": "7.29.0" + } +} +``` + +Do not keep an override when Task 2 already resolves every vulnerable path for +that module. + +- [ ] **Step 2: Regenerate dependencies from the manifest** + +Run: `pnpm install --lockfile-only` + +Expected: success with no peer-dependency regression hidden in the output. + +- [ ] **Step 3: Verify the security gate** + +Run: `pnpm audit:prod` + +Expected: exit 0 with zero critical and zero high production advisories. + +- [ ] **Step 4: Verify dependency consumers** + +Run: + +```bash +pnpm --filter @codegraph/mcp-server build +pnpm --filter @codegraph/plugin-nlp exec vitest run +pnpm --filter codegraph-landing build +``` + +Expected: MCP and NLP pass. Landing may still expose the already-recorded type +errors, but it must not show a dependency-resolution or runtime-package error. + +### Task 4: Resolve the historical secret-scanning alert + +**Files:** +- No repository files +- Modify external state: GitHub secret-scanning alert 2 + +**Interfaces:** +- Consumes: redacted alert metadata for commit `f09a02ee568219f2b3693bd018b00a30669e75d6` +- Produces: resolved GitHub alert with resolution `used_in_tests` + +- [ ] **Step 1: Reconfirm the alert without requesting the secret field** + +Run: + +```bash +gh api repos/Phoenixrr2113/codebase-graph/secret-scanning/alerts/2 --jq '{number,state,secret_type,resolution,created_at}' +``` + +Expected: alert 2 is open and its type is `stripe_webhook_signing_secret`. + +- [ ] **Step 2: Reconfirm the current tree does not contain the old fixture** + +Run: + +```bash +git ls-tree -r --name-only HEAD | rg 'packages/parser|payment\.test\.ts' +``` + +Expected: no output. + +- [ ] **Step 3: Resolve the alert as historical test data** + +Run: + +```bash +gh api --method PATCH repos/Phoenixrr2113/codebase-graph/secret-scanning/alerts/2 -f state=resolved -f resolution=used_in_tests -f resolution_comment='Synthetic Stripe-shaped parser fixture in a historical test file; the file is absent from the current tree.' +``` + +Expected: response state `resolved`, without displaying the secret field. + +- [ ] **Step 4: Verify no unexplained alert remains** + +Run: + +```bash +gh api repos/Phoenixrr2113/codebase-graph/secret-scanning/alerts --paginate --jq '[.[] | select(.state == "open") | {number,secret_type,created_at}]' +``` + +Expected: `[]`. + +### Task 5: Commit the security slice + +**Files:** +- Modify: files changed by Tasks 1 through 3 + +**Interfaces:** +- Consumes: passing production audit and targeted builds +- Produces: independently reviewable security baseline commit + +- [ ] **Step 1: Run the final slice checks** + +Run: + +```bash +pnpm install --frozen-lockfile +pnpm audit:prod +git diff --check +``` + +Expected: every command exits 0. + +- [ ] **Step 2: Commit** + +```bash +git add package.json pnpm-lock.yaml apps/web/package.json packages/mcp-server/package.json benchmarks/cgbench-v1/package.json +git commit -m "fix: establish production security baseline" +``` diff --git a/docs/superpowers/plans/2026-08-18-publication-verification-baseline.md b/docs/superpowers/plans/2026-08-18-publication-verification-baseline.md new file mode 100644 index 00000000..da440aa1 --- /dev/null +++ b/docs/superpowers/plans/2026-08-18-publication-verification-baseline.md @@ -0,0 +1,407 @@ +# Publication Verification Baseline Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make lint, type-check, tests, integration checks, and builds report the repository's real state without suppressions or missed tests. + +**Architecture:** Fix the known application type boundaries, install a supported ESLint 9 flat configuration, remove invalid assets, give package tests a shared configuration, and repair the PDF loader against the installed typed API. Root commands then aggregate the same checks CI will run. + +**Tech Stack:** TypeScript 5, Next.js 16, React 19, ESLint 9, Vitest 3, Cytoscape 3, pdf-parse 2 + +**Spec:** `docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md` + +## Global Constraints + +- No `any`, ignored TypeScript build errors, or swallowed exceptions. +- Node 22 is the local and CI verification runtime. +- Test commands must either discover owned tests or explicitly identify that a package owns none. +- The website must build without downloading fonts from the network. +- Existing user-facing behavior is preserved while boundary data is narrowed safely. + +--- + +### Task 1: Type the dashboard data boundaries + +**Files:** +- Modify: `apps/web/components/dashboard/entity-detail.tsx` +- Modify: `apps/web/components/dashboard/query-panel.tsx` + +**Interfaces:** +- Consumes: `Record` API and graph properties +- Produces: render-safe scalar guards with no `unknown` React children + +- [ ] **Step 1: Verify the current type failures** + +Run: `pnpm --filter codegraph-landing exec tsc --noEmit -p tsconfig.json` + +Expected: failures in `entity-detail.tsx` and `query-panel.tsx` where unknown +properties are used as JSX conditions or children. + +- [ ] **Step 2: Add render-safe scalar helpers to QueryPanel** + +Add these non-exported helpers above the component: + +```ts +function asString(value: unknown): string | undefined { + return typeof value === 'string' ? value : undefined +} + +function asFiniteNumber(value: unknown): number | undefined { + return typeof value === 'number' && Number.isFinite(value) ? value : undefined +} + +function asStringArray(value: unknown): string[] { + return Array.isArray(value) && value.every((item): item is string => typeof item === 'string') + ? value + : [] +} +``` + +Normalize `routedTo`, `iterations`, `queries`, and `total` before JSX. Render +only the normalized values. Normalize each result's `nodeType` with +`asString(r.nodeType) ?? r.type`. + +- [ ] **Step 3: Narrow entity class properties explicitly** + +In `EntityDetail`, derive: + +```ts +const isAbstract = props.isAbstract === true +const extendsName = typeof props.extends === 'string' ? props.extends : undefined +``` + +Use these variables in JSX instead of using unknown property values as +conditions. + +- [ ] **Step 4: Verify this boundary is clean** + +Run: `pnpm --filter codegraph-landing exec tsc --noEmit -p tsconfig.json` + +Expected: no errors from `entity-detail.tsx` or `query-panel.tsx`; Cytoscape +errors remain until Task 2. + +### Task 2: Type Cytoscape configuration once + +**Files:** +- Modify: `apps/web/lib/cytoscape-config.ts` +- Modify: `apps/web/components/dashboard/graph-canvas.tsx` +- Modify: `apps/web/components/landing/hero-graph-demo.tsx` + +**Interfaces:** +- Consumes: Cytoscape's installed `StylesheetJson` and `LayoutOptions` types +- Produces: `cytoscapeStylesheet: cytoscape.StylesheetJson` and `LAYOUT_OPTIONS: Record` + +- [ ] **Step 1: Type the shared exports at their source** + +Add `import type cytoscape from 'cytoscape'` to the config module. Give +`nodeStyle` and `edgeStyle` explicit `cytoscape.StylesheetJsonBlock` return +types, type `cytoscapeStylesheet` as `cytoscape.StylesheetJson`, and define: + +```ts +export const LAYOUT_OPTIONS: Record = { + cose: { name: 'cose', /* retain existing options */ }, + concentric: { name: 'concentric', /* retain existing options */ }, + breadthfirst: { name: 'breadthfirst', /* retain existing options */ }, +} +``` + +Replace the generic `extra` style argument with a Cytoscape edge-style type +accepted by `StylesheetJsonBlock`; do not cast through `unknown`. + +- [ ] **Step 2: Remove consumer casts** + +Pass `cytoscapeStylesheet` and `LAYOUT_OPTIONS[...]` directly to Cytoscape in +both components. The preset hero layout is already a valid literal and should +use `satisfies cytoscape.PresetLayoutOptions` if inference needs help. + +- [ ] **Step 3: Verify all landing types** + +Run: `pnpm --filter codegraph-landing exec tsc --noEmit -p tsconfig.json` + +Expected: exit 0 with no TypeScript errors. + +### Task 3: Restore real Next.js lint and build gates + +**Files:** +- Create: `apps/web/eslint.config.mjs` +- Modify: `apps/web/package.json` +- Modify: `apps/web/next.config.mjs` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** +- Consumes: Next.js 16 flat-config exports +- Produces: `pnpm --filter codegraph-landing lint`, real Next type validation + +- [ ] **Step 1: Install the matching lint toolchain** + +Run: + +```bash +pnpm --filter codegraph-landing add -D eslint@^9 eslint-config-next@16.3.1 +``` + +- [ ] **Step 2: Add the flat configuration** + +Create `apps/web/eslint.config.mjs`: + +```js +import { defineConfig, globalIgnores } from 'eslint/config' +import nextVitals from 'eslint-config-next/core-web-vitals' +import nextTypescript from 'eslint-config-next/typescript' + +export default defineConfig([ + ...nextVitals, + ...nextTypescript, + globalIgnores(['.next/**', 'out/**', 'build/**', 'next-env.d.ts']), +]) +``` + +- [ ] **Step 3: Remove the TypeScript suppression** + +Delete the `typescript.ignoreBuildErrors` block from `next.config.mjs`. Retain +the existing image behavior. + +- [ ] **Step 4: Run lint and fix every reported source violation** + +Run: `pnpm --filter codegraph-landing lint` + +Expected before fixes: non-zero with concrete source locations. Fix the source +violations without blanket rule disables. Run the command again and expect exit +0. + +- [ ] **Step 5: Verify the production build performs type validation** + +Run: `pnpm --filter codegraph-landing build` + +Expected: exit 0 and no `Skipping validation of types` message. + +### Task 4: Remove invalid font assets without network coupling + +**Files:** +- Modify: `apps/web/app/globals.css` +- Delete: `apps/web/public/fonts/GeistVF.woff2` +- Delete: `apps/web/public/fonts/GeistMonoVF.woff2` +- Delete: `apps/web/public/fonts/JetBrainsMonoVF.woff2` + +**Interfaces:** +- Consumes: browser system font stacks +- Produces: valid offline CSS with no corrupted asset requests + +- [ ] **Step 1: Prove the current assets are not fonts** + +Run: `file apps/web/public/fonts/*.woff2` + +Expected: each file is reported as HTML, not Web Open Font Format data. + +- [ ] **Step 2: Remove the three `@font-face` blocks and tracked files** + +Change the theme font variables to: + +```css +--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; +--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; +``` + +Delete the three invalid files. Do not fetch replacements during the build. + +- [ ] **Step 3: Verify there are no dead font references** + +Run: + +```bash +rg -n 'Geist|JetBrainsMono|/fonts/' apps/web +pnpm --filter codegraph-landing build +``` + +Expected: the search has no active source references and the build exits 0. + +### Task 5: Make every package test discover its owned files + +**Files:** +- Create: `vitest.package.config.ts` +- Modify: `packages/logger/package.json` +- Modify: `packages/plugin-common/package.json` +- Modify: `packages/plugin-go/package.json` +- Modify: `packages/plugin-languages/package.json` +- Modify: `packages/plugin-python/package.json` +- Modify: `packages/plugin-rust/package.json` +- Modify: `packages/plugin-typescript/package.json` + +**Interfaces:** +- Consumes: package-local `--root .` +- Produces: shared package test discovery config + +- [ ] **Step 1: Add a package-scoped Vitest config** + +Create `vitest.package.config.ts`: + +```ts +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts', 'src/__tests__/**/*.test.ts', '__tests__/**/*.test.ts'], + passWithNoTests: false, + }, +}) +``` + +- [ ] **Step 2: Point packages without local configs at the shared contract** + +Set each listed package's test script to: + +```json +"test": "vitest run --root . --config ../../vitest.package.config.ts" +``` + +- [ ] **Step 3: Verify each suite reports a non-zero test count** + +Run each package with `pnpm --filter test`. Expected counts are +at least: logger 10, plugin-common 3 files, Go 1 file, languages 3 files, Python +1 file, Rust 1 file, and TypeScript 2 files. A zero-file suite is a failure. + +- [ ] **Step 4: Fix discovered test failures at the behavior boundary** + +If logger output tests fail, preserve the MCP rule that all logger output uses +stderr and update assertions to spy on `console.error` or `process.stderr.write` +according to the branch under test. Do not change production logging to stdout. + +### Task 6: Repair real PDF extraction + +**Files:** +- Modify: `packages/plugin-nlp/src/loaders/pdf.ts` +- Modify: `packages/plugin-nlp/src/__tests__/loaders.test.ts` + +**Interfaces:** +- Consumes: `PDFParse` from `pdf-parse` 2.4.5 +- Produces: `PDFLoader.extract(input): Promise` with typed text, title, and page count + +- [ ] **Step 1: Replace the skipped test with a real PDF fixture** + +Store a minimal one-page PDF fixture as a base64 string in the test, decode it +with `Buffer.from(fixture, 'base64')`, and assert: + +```ts +const result = await PDFLoader.extract(pdfBuffer) +expect(result.text).toContain('CodeGraph PDF fixture') +expect(result.metadata.format).toBe('pdf') +expect(result.metadata.pageCount).toBe(1) +``` + +- [ ] **Step 2: Run the test and verify the old callable API fails** + +Run: + +```bash +pnpm --filter @codegraph/plugin-nlp exec vitest run src/__tests__/loaders.test.ts +``` + +Expected: failure showing the imported module is not callable. + +- [ ] **Step 3: Implement the typed pdf-parse 2 API** + +Use the installed API and always release parser resources: + +```ts +const { PDFParse } = await import('pdf-parse') +const parser = new PDFParse({ data: buffer }) + +try { + const [textResult, infoResult] = await Promise.all([ + parser.getText(), + parser.getInfo(), + ]) + const title = typeof infoResult.info?.Title === 'string' + ? infoResult.info.Title + : undefined + + return { + text: textResult.text, + metadata: { + format: 'pdf', + pageCount: textResult.total, + ...(title ? { title } : {}), + }, + } +} finally { + await parser.destroy() +} +``` + +- [ ] **Step 4: Verify PDF and URL ingestion suites** + +Run: + +```bash +pnpm --filter @codegraph/plugin-nlp exec vitest run src/__tests__/loaders.test.ts +pnpm --filter @codegraph/core exec vitest run src/__tests__/url-ingestion.test.ts src/__tests__/document-ingestion.test.ts +``` + +Expected: all tests pass and no `pdfParse is not a function` warning appears. + +### Task 7: Define and run the truthful root contracts + +**Files:** +- Modify: `package.json` +- Modify: `turbo.json` +- Modify: `apps/web/package.json` +- Modify: `packages/core/package.json` +- Modify: `packages/graph/package.json` +- Modify: `packages/logger/package.json` +- Modify: `packages/plugin-nlp/package.json` +- Modify: `packages/types/package.json` + +**Interfaces:** +- Consumes: package scripts repaired in Tasks 1 through 6 +- Produces: root `typecheck` and deterministic lint/test/build contracts + +- [ ] **Step 1: Replace the narrow typecheck script** + +Set root scripts to: + +```json +"typecheck": "turbo run typecheck", +"lint": "turbo run lint", +"test": "turbo run test", +"build": "turbo run build" +``` + +Add `"typecheck": "tsc --noEmit"` to the landing, core, graph, logger, +plugin-nlp, and types manifests. All other TypeScript workspaces already expose +that script. The npm distribution workspace contains JavaScript build tooling +and is verified by its Vitest and release checks instead. + +- [ ] **Step 2: Add Turbo's typecheck task** + +Add: + +```json +"typecheck": { + "dependsOn": ["^typecheck"], + "outputs": [] +} +``` + +Keep lint dependent on upstream builds only where generated declarations are +required. + +- [ ] **Step 3: Run the repository gate uncached** + +Run: + +```bash +pnpm turbo run lint --force +pnpm turbo run typecheck --force +pnpm turbo run test --force +pnpm turbo run build --force +``` + +Expected: all commands exit 0, every owned test suite reports tests, and the +landing build does not skip type validation. + +- [ ] **Step 4: Commit** + +```bash +git add package.json pnpm-lock.yaml turbo.json vitest.package.config.ts apps/web packages/core/package.json packages/graph/package.json packages/logger/package.json packages/plugin-common/package.json packages/plugin-go/package.json packages/plugin-languages/package.json packages/plugin-nlp packages/plugin-python/package.json packages/plugin-rust/package.json packages/plugin-typescript/package.json packages/types/package.json +git commit -m "fix: make repository verification truthful" +``` diff --git a/docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md b/docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md new file mode 100644 index 00000000..d0c72843 --- /dev/null +++ b/docs/superpowers/specs/2026-08-18-publication-ready-baseline-design.md @@ -0,0 +1,323 @@ +# Publication-Ready Baseline Design + +**Date:** 2026-08-18 +**Status:** Approved +**Repository:** `Phoenixrr2113/codebase-graph` + +## Purpose + +Establish a trustworthy public baseline for CodeGraph before its first npm +release. The repository must be secure, reproducible, understandable to a new +developer, and able to publish from GitHub without a long-lived registry token. + +The baseline covers four sequential slices: + +1. Security and dependency health. +2. Truthful local and CI verification. +3. Deterministic, cross-platform npm distribution. +4. Public repository hygiene, documentation, and release automation. + +Each slice must leave the branch in a reviewable state. Major dependency +upgrades and unrelated refactors are out of scope unless they are the smallest +safe route to a required security patch. + +## Current-State Problems + +- Production dependency audit reports one critical and 33 high advisories. +- GitHub secret scanning has an open alert caused by a Stripe-shaped test + fixture. +- CI omits the landing application and the npm package. +- The landing build ignores TypeScript errors, direct type-checking fails, and + the lint script has no installed linter. +- Some package test scripts do not discover their tests. +- Three tracked `.woff2` files contain HTML instead of font data. +- The MCPB builder hardcodes a macOS esbuild binary path. +- The npm builder may reuse stale MCPB output and copies the publishing + machine's native `node_modules` tree. +- The resulting package is roughly 57 MB compressed and 614 MB unpacked. +- Package metadata points at repositories and domains that are not canonical. +- The generated npm package uses a proprietary license and claims a required + runtime license key even though the current server has no license gate, the + public project is MIT, and the commercial binary plan is retired. +- The public repository lacks standard contribution and security guidance, + automated dependency maintenance, code scanning, and branch protection. + +## Decisions + +### Product and license + +CodeGraph is an MIT-licensed open-source project. The npm artifact will include +the repository's MIT license. The abandoned Polar licensing copy, stale runtime +license instructions, commercial postinstall output, and commercial +distribution instructions will be removed or explicitly archived as historical +material. + +The canonical project locations are: + +- Source, issues, and contribution: the current GitHub repository. +- Live application: the current Vercel deployment recorded in GitHub. +- Package documentation: the repository README until a real custom domain is + registered and verified. + +No unverified `codegraph.dev`, Polar, or old GitHub owner URL may appear in +active package metadata or setup instructions. + +### Package identity + +Use the unscoped npm name `codegraph-mcp` unless the registry reports that it +became unavailable before the bootstrap publish. The scoped name +`@codegraph/mcp` requires ownership of the `codegraph` npm scope, which is not +currently authenticated or proven. A registry conflict is a hard stop; the +workflow must not silently choose another name. + +The package manifest is the single source of truth for package name and +version. Generated manifests, the CLI `--version` output, the MCPB manifest, +the Git tag, and the GitHub release must agree with it. + +### Release model + +The first npm release is a one-time authenticated bootstrap because npm trusted +publishers can only be configured from an existing package's settings. After +that bootstrap, GitHub Actions publishes with npm trusted publishing through +OIDC. No `NPM_TOKEN` is stored in GitHub. + +Subsequent releases use an annotated `vX.Y.Z` tag that matches the package +version. A release workflow rebuilds from a clean checkout, runs the full +repository and release gates, publishes to npm, verifies the registry artifact, +and creates a GitHub release. A mismatched tag, dirty generated metadata, failed +check, or existing registry version fails before publication. + +## Architecture and Data Flow + +The root package scripts are the public verification interface. Developers and +GitHub Actions run the same commands. + +```text +frozen install + -> production security audit + -> lint + -> type-check + -> unit and integration tests + -> monorepo build + -> clean npm staging build + -> package metadata and contents validation + -> npm pack + -> temporary consumer install + -> CLI version and MCP handshake smoke tests +``` + +The CI workflow has unique, stable job names so branch protection can require +them without ambiguity. It contains: + +- A repository verification job on Linux. +- A package install and runtime smoke matrix on Linux, macOS, and Windows. +- A FalkorDB integration job that becomes blocking once its documented suite + is deterministic. +- CodeQL analysis in a dedicated workflow. + +No job may use `continue-on-error` for a baseline requirement. An intentionally +optional test must identify its prerequisite and report a skip explicitly. + +## Security Baseline + +### Secret scanning + +The Stripe-shaped parser fixture exists only in historical commit +`f09a02ee568219f2b3693bd018b00a30669e75d6`; its source file is no longer in the +current tree. The alert will be resolved as test data after its redacted commit +location is recorded. No history rewrite is required because the detected value +was a synthetic scanner test, not a credential. The actual matched value will +never be printed in logs or documentation. + +### Dependencies + +Prefer upgrading a direct dependency that introduces a vulnerable transitive +package. Use a pnpm override only when the direct upstream has no compatible +release and the overridden version satisfies the parent's contract. Every +override must include a short reason and a targeted verification command. + +The production baseline is zero unresolved critical and high advisories. A +moderate or low advisory may remain only when its reachable behavior and +mitigation are documented in the design's implementation record. Dependabot +will check pnpm and GitHub Actions weekly, with safe patch and minor updates +grouped separately from majors. + +### Dependency override record + +The publication baseline applies compatible transitive security floors for `@hono/node-server` 1.19.15, Hono 4.12.34, PostCSS 8.5.23, protobufjs 7.6.5, and node-tar 7.5.21. Their direct parents allow these patch versions but had not yet updated every resolved path. `pnpm install --frozen-lockfile`, `pnpm audit:prod`, the full unit and integration suites, and the npm consumer smoke verify the overrides. The overrides should be removed when direct dependency updates resolve the same versions without them. + +### GitHub hardening + +After the new CI jobs pass on the branch, protect `main` with strict required +status checks, pull requests, conversation resolution, and blocked force pushes +and deletion. Do not require a second reviewer because this is currently a +single-maintainer repository. Enable dependency security updates, secret push +protection when available, private vulnerability reporting, and CodeQL default +or workflow analysis. + +Workflow permissions use least privilege. Third-party actions are pinned to +full commit SHAs and maintained by Dependabot. + +## Truthful Verification + +### Landing application + +Remove `typescript.ignoreBuildErrors`. Fix every direct TypeScript error rather +than changing types to `any`. Add a supported ESLint configuration and ensure +the lint command is installed and non-interactive. Replace the invalid font +files with valid local assets from their licensed source or switch to a +documented system/font package path that builds without network access. + +### Packages and tests + +Every workspace package must either run its owned tests or intentionally use +`--passWithNoTests` when it truly has no test files. Package-local Vitest +configuration must not accidentally inherit the root scripts-only include. + +The PDF loader warning is treated as a real boundary defect until an explicit +PDF ingestion test proves the current `pdf-parse` API works. Integration tests +that need FalkorDB use the CI service container and deterministic environment +configuration. + +### Root commands + +The baseline exposes and validates these root contracts: + +- `pnpm lint` +- `pnpm typecheck` +- `pnpm test` +- `pnpm build` +- `pnpm audit:prod` +- `pnpm release:check` + +`release:check` performs the package build, validation, pack, temporary install, +and runtime smoke sequence. It must be safe to run repeatedly and must never +publish. + +## npm Package Design + +The npm package is built directly from the MCP server entry point. It no longer +copies MCPB output. + +Internal `@codegraph/*` workspace modules are bundled into JavaScript. Native +or platform-sensitive dependencies are external and declared in the published +manifest so npm installs the correct build for the consumer platform. This +includes Tree-sitter and the required grammars, the MCP SDK where bundling is +unsupported, and the transformer/runtime packages required by NLP features. +FalkorDBLite remains optional and is represented as an optional dependency if +the embedded driver remains advertised. + +The builder uses esbuild's JavaScript API from the declared dependency. It +deletes and recreates its staging directory every time, reads versions from +source manifests, copies the root MIT license, and generates no runtime secrets +or machine-specific paths. + +The package validator rejects: + +- Incorrect name, version, license, repository, bugs, homepage, or executable. +- Missing runtime files or an invalid executable mode. +- Workspace protocol references. +- Bundled `node_modules`, `.node` binaries, secrets, caches, source maps with + absolute paths, or unrelated repository files. +- An unexpectedly large tarball. The initial compressed budget is 15 MB and + may only be raised with measured justification. +- A CLI whose `--version` does not equal the package version. +- A server that cannot complete an MCP initialize and shutdown exchange in a + temporary consumer project. + +The cross-platform CI matrix installs the tarball with the platform's npm and +runs the version and MCP smoke checks. This validates the package users receive, +not the monorepo's linked dependency tree. + +## MCPB Boundary + +MCPB is a separate platform-local artifact because it includes native modules. +Its builder will use the same portable esbuild API and clean-output rules, but +the npm package will not depend on MCPB output. Active documentation will stop +claiming that one native MCPB bundle supports all operating systems unless a +platform matrix proves that claim. + +An MCPB build smoke check is part of repository verification. Publishing MCPB +assets to a marketplace is not required for the first npm release. + +## Repository and Developer Experience + +The README will lead with the verified installation and development paths. It +will link to the live application, GitHub source, issues, discussions if +enabled, npm package, contribution guide, security policy, and license. + +Badges will include CI, CodeQL, npm version, npm downloads, GitHub stars, and +MIT license. npm badges are added only when their targets resolve after the +bootstrap publication. Before publication, GitHub stars and CI provide real +usage and health signals without inventing download data. + +Add: + +- `CONTRIBUTING.md` +- `SECURITY.md` +- `CODE_OF_CONDUCT.md` +- Issue forms for bugs and features +- A pull request template +- Dependabot configuration +- Release and CodeQL workflows + +Repository settings will enable automatic head-branch deletion and Discussions +if the current account supports them. Existing stashes are user-owned and will +not be deleted as part of cleanup. + +## Error Handling and Safety + +- Build and validation scripts use explicit errors with actionable messages. +- External command failures preserve their exit code and do not fall through to + publication. +- Registry identity, version, and authentication are checked before a publish + attempt. +- Release workflows use a protected `npm` environment and concurrency control + so only one publish can run at a time. +- The workflow checks whether a version already exists and exits safely instead + of attempting a duplicate publish. +- No build step logs environment variables, tokens, credential files, or secret + scanner values. +- GitHub setting changes are applied only after their required checks exist and + have succeeded at least once. + +## Acceptance Criteria + +The baseline is publication-ready only when all of the following are proven: + +1. Local `main` ancestry and the target GitHub branch are understood, with no + user work overwritten. +2. Production audit has zero critical and high advisories. +3. GitHub secret scanning has no unexplained open alerts. +4. Lint, type-check, tests, builds, and integration checks pass without ignored + failures. +5. Landing build performs real TypeScript validation and uses valid assets. +6. MCPB builds from a clean checkout without a platform-specific hardcoded tool + path. +7. npm staging is recreated from source and contains no copied `node_modules` or + native binaries. +8. `npm pack --dry-run`, package validation, temporary installation, CLI version, + and MCP handshake checks pass. +9. The tarball installs and passes smoke tests on Linux, macOS, and Windows CI. +10. Package metadata and active documentation use the canonical GitHub and live + application URLs and the MIT license. +11. CI, CodeQL, Dependabot, contribution templates, security guidance, and + branch protection are present and verified in GitHub. +12. The release workflow validates tags, publishes with trusted OIDC after the + one-time bootstrap, provides provenance, verifies the registry artifact, + and creates a GitHub release. +13. README developer links and real badges resolve. npm version and download + badges are added after the package exists. +14. A fresh-clone verification run documents the exact commands and results. + +## Rollout + +Implementation proceeds in the four slices listed in this design. Each slice +gets its own focused commit after its tests pass. Repository settings are +changed last, after the branch demonstrates the checks they will require. + +The only expected external handoff is npm bootstrap ownership. If no local npm +session can claim `codegraph-mcp`, all code, CI, documentation, and dry-run +verification still proceed. The final bootstrap publish pauses at the login or +registry ownership boundary and reports the exact remaining action without +weakening the release workflow. diff --git a/package.json b/package.json index f626a1a5..3db5934a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "dev": "turbo run dev --concurrency 22", "lint": "turbo run lint", "test": "turbo run test", + "test:integration": "pnpm --filter @codegraph/graph test:integration && pnpm --filter @codegraph/plugin-nlp test:integration && pnpm --filter @codegraph/mcp-server test:integration", + "audit:prod": "pnpm audit --prod --audit-level high", "test:e2e": "playwright test", "test:scripts": "vitest run --config vitest.config.ts", "test:e2e:ui": "playwright test --ui", @@ -22,9 +24,14 @@ "docker:reset": "docker-compose down -v && docker-compose up -d falkordb", "start": "docker-compose up -d falkordb && turbo run dev --concurrency 15", "stop": "docker-compose down", - "typecheck": "turbo run build --filter=@codegraph/types", - "build:mcpb": "turbo run build && node packages/mcpb/build.mjs && cd packages/mcpb/dist && mcpb pack", - "build:npm": "turbo run build && node packages/mcpb/build.mjs && node packages/npm-package/build.mjs" + "typecheck": "turbo run typecheck", + "build:mcpb": "pnpm turbo run build --filter=@codegraph/mcpb && pnpm --filter @codegraph/mcpb exec mcpb validate dist && pnpm --filter @codegraph/mcpb exec mcpb pack dist", + "build:npm": "pnpm turbo run build --filter=@codegraph/mcp-server... && node packages/npm-package/build.mjs", + "pack:npm": "npm pack --dry-run --json packages/npm-package/dist", + "validate:npm": "node scripts/release/validate-package.mjs packages/npm-package/dist", + "smoke:npm": "node scripts/release/smoke-package.mjs", + "verify:release-tag": "node scripts/release/verify-release-tag.mjs", + "release:check": "pnpm build:npm && pnpm validate:npm && pnpm smoke:npm" }, "devDependencies": { "@huggingface/transformers": "^3.8.1", @@ -40,5 +47,18 @@ "packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0", "engines": { "node": ">=20.0.0" + }, + "pnpm": { + "overrides": { + "brace-expansion@>=2.0.0 <2.1.4": "2.1.4", + "@hono/node-server@<1.19.15": "1.19.15", + "hono@<4.12.34": "4.12.34", + "js-yaml@>=3.0.0 <3.15.1": "3.15.1", + "postcss@<8.5.23": "8.5.23", + "protobufjs@<7.6.5": "7.6.5", + "sharp@<0.35.0": "0.35.0", + "tar@<7.5.21": "7.5.21", + "undici@>=7.0.0 <7.29.0": "7.29.0" + } } } diff --git a/packages/core/package.json b/packages/core/package.json index c28cd9f8..1c7e76bc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -15,6 +15,7 @@ "build": "tsc", "dev": "tsc --watch", "test": "vitest", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist" }, "dependencies": { @@ -36,6 +37,9 @@ "tree-sitter": "^0.22.4", "zod": "^3.25.76" }, + "optionalDependencies": { + "@codegraph/plugin-languages": "workspace:*" + }, "devDependencies": { "typescript": "^5.9.3", "vitest": "^3.2.4" diff --git a/packages/core/src/__tests__/config.test.ts b/packages/core/src/__tests__/config.test.ts index 4e2490df..e0a83a07 100644 --- a/packages/core/src/__tests__/config.test.ts +++ b/packages/core/src/__tests__/config.test.ts @@ -146,6 +146,27 @@ describe('Core Config', () => { expect(existsSync(CONFIG_FILE + '.tmp')).toBe(false); expect(existsSync(CONFIG_FILE)).toBe(true); }); + + it('uses distinct temp files for concurrent writes in the same millisecond', async () => { + const now = vi.spyOn(Date, 'now').mockReturnValue(1_234_567); + + try { + await expect(Promise.all([ + saveConfig({ + activeProjects: ['/concurrent/a'], + lastUpdated: new Date().toISOString(), + setupComplete: true, + }), + saveConfig({ + activeProjects: ['/concurrent/b'], + lastUpdated: new Date().toISOString(), + setupComplete: true, + }), + ])).resolves.toEqual([undefined, undefined]); + } finally { + now.mockRestore(); + } + }); }); // ============================================================ diff --git a/packages/core/src/__tests__/graph-client.test.ts b/packages/core/src/__tests__/graph-client.test.ts new file mode 100644 index 00000000..c67a4223 --- /dev/null +++ b/packages/core/src/__tests__/graph-client.test.ts @@ -0,0 +1,65 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import type { GraphClient } from '@codegraph/graph'; + +const createClientMock = vi.hoisted(() => vi.fn()); + +vi.mock('@codegraph/graph', () => ({ + createClient: createClientMock, +})); + +import { closeGraphClient, getGraphClient } from '../graphClient'; + +function createGraphClientFixture(): GraphClient { + return { + close: vi.fn().mockResolvedValue(undefined), + } as unknown as GraphClient; +} + +afterEach(async () => { + await closeGraphClient(); + createClientMock.mockReset(); +}); + +describe('getGraphClient', () => { + it('shares one in-flight connection across concurrent callers', async () => { + const client = createGraphClientFixture(); + let resolveConnection: ((value: GraphClient) => void) | undefined; + const connection = new Promise((resolve) => { + resolveConnection = resolve; + }); + createClientMock.mockReturnValue(connection); + + const first = getGraphClient(); + const second = getGraphClient(); + + expect(createClientMock).toHaveBeenCalledTimes(1); + resolveConnection?.(client); + await expect(Promise.all([first, second])).resolves.toEqual([client, client]); + }); + + it('allows a retry after connection creation fails', async () => { + const client = createGraphClientFixture(); + createClientMock + .mockRejectedValueOnce(new Error('connection failed')) + .mockResolvedValueOnce(client); + + await expect(getGraphClient()).rejects.toThrow('connection failed'); + await expect(getGraphClient()).resolves.toBe(client); + expect(createClientMock).toHaveBeenCalledTimes(2); + }); + + it('allows shutdown to finish while an in-flight connection fails', async () => { + let rejectConnection: ((reason: Error) => void) | undefined; + const connection = new Promise((_resolve, reject) => { + rejectConnection = reject; + }); + createClientMock.mockReturnValue(connection); + + const clientRequest = getGraphClient(); + const shutdown = closeGraphClient(); + rejectConnection?.(new Error('startup disconnected')); + + await expect(clientRequest).rejects.toThrow('startup disconnected'); + await expect(shutdown).resolves.toBeUndefined(); + }); +}); diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 8a8941b5..8b7cc0cb 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -7,6 +7,7 @@ import { homedir } from 'os'; import { join } from 'path'; +import { randomUUID } from 'node:crypto'; import { readFile, writeFile, mkdir, rename } from 'fs/promises'; import { existsSync } from 'fs'; import { createLogger } from '@codegraph/logger'; @@ -80,7 +81,7 @@ export async function saveConfig(config: MCPContextConfig): Promise { } // Atomic write: write to unique temp file, then rename. // Unique suffix prevents concurrent saveConfig calls from clobbering each other's temp files. - const tmpFile = `${CONFIG_FILE}.tmp.${process.pid}.${Date.now()}`; + const tmpFile = `${CONFIG_FILE}.tmp.${process.pid}.${randomUUID()}`; await writeFile(tmpFile, JSON.stringify(config, null, 2)); await rename(tmpFile, CONFIG_FILE); logger.info('Config saved', { projects: config.activeProjects }); diff --git a/packages/core/src/graphClient.ts b/packages/core/src/graphClient.ts index c372b3c2..58526ff6 100644 --- a/packages/core/src/graphClient.ts +++ b/packages/core/src/graphClient.ts @@ -8,16 +8,32 @@ import { createClient, type GraphClient } from '@codegraph/graph'; let graphClient: GraphClient | null = null; +let graphClientPromise: Promise | null = null; /** * Get the shared graph client instance. * Creates the client on first call, returns cached instance thereafter. */ export async function getGraphClient(): Promise { - if (!graphClient) { - graphClient = await createClient(); + if (graphClient) { + return graphClient; + } + if (!graphClientPromise) { + const connection = createClient().then((client) => { + graphClient = client; + return client; + }); + graphClientPromise = connection; + void connection.then( + () => { + if (graphClientPromise === connection) graphClientPromise = null; + }, + () => { + if (graphClientPromise === connection) graphClientPromise = null; + }, + ); } - return graphClient; + return graphClientPromise; } /** @@ -25,8 +41,20 @@ export async function getGraphClient(): Promise { * Call this when shutting down. */ export async function closeGraphClient(): Promise { + if (graphClientPromise) { + const connection = graphClientPromise; + try { + await connection; + } catch { + // The original getGraphClient caller receives the connection error. + // Shutdown only needs to ensure no client was left open. + } finally { + if (graphClientPromise === connection) graphClientPromise = null; + } + } if (graphClient) { - await graphClient.close(); + const client = graphClient; graphClient = null; + await client.close(); } } diff --git a/packages/graph/package.json b/packages/graph/package.json index 427ccc60..e6998a3b 100644 --- a/packages/graph/package.json +++ b/packages/graph/package.json @@ -14,17 +14,23 @@ "scripts": { "build": "tsc", "dev": "tsc --watch", - "test": "vitest", + "test": "vitest run", + "test:integration": "vitest run --config vitest.integration.config.ts && vitest run --config vitest.lite.integration.config.ts", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist" }, "dependencies": { "@codegraph/logger": "workspace:*", "@codegraph/types": "workspace:*", - "falkordb": "^6.6.2" + "falkordb": "^6.7.0" }, "devDependencies": { "falkordblite": "^0.2.0", "typescript": "^5.9.3", "vitest": "^3.2.4" + }, + "optionalDependencies": { + "@falkordblite/darwin-arm64": "8.2.3-falkordb.4.16.3", + "@falkordblite/linux-x64": "8.2.3-falkordb.4.16.3" } } diff --git a/packages/graph/src/__tests__/about-edge-score.test.ts b/packages/graph/src/__tests__/about-edge-score.test.ts index 3da43877..a1e63576 100644 --- a/packages/graph/src/__tests__/about-edge-score.test.ts +++ b/packages/graph/src/__tests__/about-edge-score.test.ts @@ -5,7 +5,7 @@ import type { GraphClient } from '../client'; import type { KnowledgeOperations } from '../knowledge-operations'; const TEST_HOST = process.env['FALKORDB_HOST'] ?? 'localhost'; -const TEST_PORT = process.env['FALKORDB_PORT'] ?? '6380'; +const TEST_PORT = process.env['FALKORDB_PORT'] ?? '6379'; describe('AboutEdgeInput.crossEncoderScore', () => { let client: GraphClient; @@ -54,7 +54,7 @@ describe('AboutEdgeInput.crossEncoderScore', () => { }); it('defaults to null when crossEncoderScore is omitted (legacy compat)', async () => { - // Same edge as test 1 — MERGE + ON MATCH SET overwrites crossEncoderScore back to null. + // Same edge as test 1: MERGE + ON MATCH SET overwrites crossEncoderScore back to null. await kgOps.createAboutEdge({ entityText: 'redirect logic', entityType: 'Concept', diff --git a/packages/graph/src/__tests__/client-platform.test.ts b/packages/graph/src/__tests__/client-platform.test.ts new file mode 100644 index 00000000..d1eb4c37 --- /dev/null +++ b/packages/graph/src/__tests__/client-platform.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from 'vitest'; +import { supportsEmbeddedPlatform } from '../client'; + +describe('supportsEmbeddedPlatform', () => { + it('accepts platforms with binaries and required runtime libraries', () => { + expect(supportsEmbeddedPlatform('darwin', 'arm64', () => true)).toBe(true); + expect(supportsEmbeddedPlatform('linux', 'x64')).toBe(true); + }); + + it('rejects Apple silicon when a Homebrew runtime library is missing', () => { + const availableLibraries = new Set(['/opt/homebrew/opt/libomp/lib/libomp.dylib']); + + expect(supportsEmbeddedPlatform( + 'darwin', + 'arm64', + (path) => availableLibraries.has(path), + )).toBe(false); + }); + + it('rejects platforms without published FalkorDBLite binaries', () => { + expect(supportsEmbeddedPlatform('win32', 'x64')).toBe(false); + expect(supportsEmbeddedPlatform('darwin', 'x64')).toBe(false); + expect(supportsEmbeddedPlatform('linux', 'arm64')).toBe(false); + }); +}); diff --git a/packages/graph/src/__tests__/falkordb-git-operations.test.ts b/packages/graph/src/__tests__/falkordb-git-operations.test.ts index 4c77e148..722875b0 100644 --- a/packages/graph/src/__tests__/falkordb-git-operations.test.ts +++ b/packages/graph/src/__tests__/falkordb-git-operations.test.ts @@ -1,5 +1,5 @@ /** - * Git History Operations — FalkorDB Integration Tests + * Git History Operations: FalkorDB Integration Tests * * Tests commit upserts, temporal edge creation (MODIFIED_IN, INTRODUCED_IN, * DELETED_IN), Metadata node operations, and index creation against a real @@ -23,6 +23,8 @@ import type { } from '@codegraph/types'; const GRAPH_NAME = `test_git_${Date.now()}`; +const TEST_HOST = process.env['FALKORDB_HOST'] ?? 'localhost'; +const TEST_PORT = Number(process.env['FALKORDB_PORT'] ?? '6379'); // ============================================================================ // Test Fixtures @@ -89,12 +91,12 @@ describe('Git History Operations (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: TEST_HOST, + port: TEST_PORT, graphName: GRAPH_NAME, }); } catch (error) { - console.error('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.error('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); throw error; } @@ -368,7 +370,7 @@ describe('Git History Operations (FalkorDB)', () => { }); it('should handle MODIFIED_IN for non-existent file gracefully', async () => { - // Should not throw — the MATCH just won't find anything + // Should not throw: the MATCH just won't find anything await ops.createModifiedInEdge('/nonexistent/file.ts', commitHash, 1, 0); const result = await client.roQuery<{ count: number }>( @@ -436,7 +438,7 @@ describe('Git History Operations (FalkorDB)', () => { it('should support check-then-insert pattern', async () => { const key = 'newMeta:test1'; - // Check — should not exist + // Check: should not exist const check = await client.roQuery<{ value: string }>( `MATCH (m:Metadata {key: $key}) RETURN m.value as value`, { params: { key } }, diff --git a/packages/graph/src/__tests__/falkordb-knowledge-operations.test.ts b/packages/graph/src/__tests__/falkordb-knowledge-operations.test.ts index ab755263..b4d1f0ce 100644 --- a/packages/graph/src/__tests__/falkordb-knowledge-operations.test.ts +++ b/packages/graph/src/__tests__/falkordb-knowledge-operations.test.ts @@ -1,5 +1,5 @@ /** - * Knowledge Graph Operations — FalkorDB Integration Tests + * Knowledge Graph Operations: FalkorDB Integration Tests * * Tests Entity + RELATES_TO CRUD, temporal memory, and vector search * against a real FalkorDB Docker instance (localhost:6379). @@ -11,6 +11,8 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { createClient, type GraphClient, createKnowledgeOperations, type KnowledgeOperations } from '../index'; const GRAPH_NAME = `test_kg_${Date.now()}`; +const TEST_HOST = process.env['FALKORDB_HOST'] ?? 'localhost'; +const TEST_PORT = Number(process.env['FALKORDB_PORT'] ?? '6379'); describe('Knowledge Graph Operations (FalkorDB)', () => { let client: GraphClient; @@ -20,12 +22,12 @@ describe('Knowledge Graph Operations (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: TEST_HOST, + port: TEST_PORT, graphName: GRAPH_NAME, }); } catch (error) { - console.error('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.error('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); throw error; } @@ -206,8 +208,8 @@ describe('Knowledge Graph Operations (FalkorDB)', () => { }; const emb1 = makeEmbedding(1.0); // "payment" entity - const emb2 = makeEmbedding(1.05); // "billing" entity — close to payment - const emb3 = makeEmbedding(5.0); // "authentication" entity — far from payment + const emb2 = makeEmbedding(1.05); // "billing" entity: close to payment + const emb3 = makeEmbedding(5.0); // "authentication" entity: far from payment await ops.createEntity({ text: 'processPayment', diff --git a/packages/graph/src/__tests__/falkordb-operations.test.ts b/packages/graph/src/__tests__/falkordb-operations.test.ts index dacc4e01..0aa85325 100644 --- a/packages/graph/src/__tests__/falkordb-operations.test.ts +++ b/packages/graph/src/__tests__/falkordb-operations.test.ts @@ -1,5 +1,5 @@ /** - * Graph CRUD Operations — FalkorDB Integration Tests + * Graph CRUD Operations: FalkorDB Integration Tests * * Tests entity upserts, edge creation, batchUpsert, project operations, * vector search, and clearAll against a real FalkorDB Docker instance. @@ -25,6 +25,8 @@ import type { } from '@codegraph/types'; const GRAPH_NAME = `test_ops_${Date.now()}`; +const TEST_HOST = process.env['FALKORDB_HOST'] ?? 'localhost'; +const TEST_PORT = Number(process.env['FALKORDB_PORT'] ?? '6379'); // ============================================================================ // Test Fixtures @@ -113,12 +115,12 @@ describe('Graph CRUD Operations (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: TEST_HOST, + port: TEST_PORT, graphName: GRAPH_NAME, }); } catch (error) { - console.error('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.error('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); throw error; } @@ -419,10 +421,16 @@ describe('Graph CRUD Operations (FalkorDB)', () => { extendsEdges: [], implementsEdges: [], rendersEdges: [], + hasMethodEdges: [], + hasPropertyEdges: [], + typeRefs: [], + hasParamEdges: [], + returnsEdges: [], + usesTypeEdges: [], }; } - it('full ParsedFileEntities round-trip — creates file, functions, classes', async () => { + it('full ParsedFileEntities round-trip: creates file, functions, classes', async () => { const entities = makeBatchEntities('/src/batch-roundtrip.ts'); await ops.batchUpsert(entities); @@ -457,7 +465,7 @@ describe('Graph CRUD Operations (FalkorDB)', () => { expect(typeCount.data[0]?.count).toBe(1); }); - it('batchUpsert is idempotent — second call does not create duplicates', async () => { + it('batchUpsert is idempotent: second call does not create duplicates', async () => { const entities = makeBatchEntities('/src/batch-idempotent.ts'); await ops.batchUpsert(entities); await ops.batchUpsert(entities); @@ -507,6 +515,12 @@ describe('Graph CRUD Operations (FalkorDB)', () => { extendsEdges: [], implementsEdges: [], rendersEdges: [], + hasMethodEdges: [], + hasPropertyEdges: [], + typeRefs: [], + hasParamEdges: [], + returnsEdges: [], + usesTypeEdges: [], }; await ops.batchUpsert(entities); @@ -643,7 +657,7 @@ describe('Graph CRUD Operations (FalkorDB)', () => { ); expect(edgeBefore.data[0]?.count).toBe(1); - // Remove the CALLEE file — the function should be preserved because fnCaller still points to it + // Remove the CALLEE file: the function should be preserved because fnCaller still points to it await ops.removeFileAndCleanup('/src/perf4-callee.ts'); // File node should be gone @@ -676,7 +690,7 @@ describe('Graph CRUD Operations (FalkorDB)', () => { // Create cross-file EXTENDS edge: ClassChild → ClassBase await ops.createExtendsEdge('ClassChild', '/src/perf4-child.ts', 'ClassBase', '/src/perf4-base.ts'); - // Remove the BASE file — ClassBase should be preserved due to incoming EXTENDS + // Remove the BASE file: ClassBase should be preserved due to incoming EXTENDS await ops.removeFileAndCleanup('/src/perf4-base.ts'); // ClassBase should still exist @@ -702,7 +716,7 @@ describe('Graph CRUD Operations (FalkorDB)', () => { await ops.createCallEdge('fnSrc', '/src/perf4-src.ts', 'fnDst', '/src/perf4-dst.ts', 10); - // Remove the CALLER file — fnSrc has no incoming edges, so it should be removed + // Remove the CALLER file: fnSrc has no incoming edges, so it should be removed await ops.removeFileAndCleanup('/src/perf4-src.ts'); // fnSrc should be gone (no incoming edges) @@ -772,12 +786,12 @@ describe('Vector Search (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: TEST_HOST, + port: TEST_PORT, graphName: VECTOR_GRAPH, }); } catch (error) { - console.error('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.error('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); throw error; } @@ -927,12 +941,12 @@ describe('Provenance Stamping (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: TEST_HOST, + port: TEST_PORT, graphName: PROV_GRAPH, }); } catch (error) { - console.error('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.error('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); throw error; } diff --git a/packages/graph/src/__tests__/falkordblite-binaries.test.ts b/packages/graph/src/__tests__/falkordblite-binaries.test.ts new file mode 100644 index 00000000..dc1ad3cf --- /dev/null +++ b/packages/graph/src/__tests__/falkordblite-binaries.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it, vi } from 'vitest'; +import { resolveEmbeddedBinaryPaths } from '../drivers/falkordblite'; + +describe('resolveEmbeddedBinaryPaths', () => { + it('resolves the pinned direct platform package on Apple silicon', () => { + const resolvePackage = vi.fn().mockReturnValue( + '/runtime/@falkordblite/darwin-arm64/package.json', + ); + + expect(resolveEmbeddedBinaryPaths('darwin', 'arm64', resolvePackage)).toEqual({ + redisServerPath: '/runtime/@falkordblite/darwin-arm64/bin/redis-server', + modulePath: '/runtime/@falkordblite/darwin-arm64/bin/falkordb.so', + }); + expect(resolvePackage).toHaveBeenCalledWith('@falkordblite/darwin-arm64/package.json'); + }); + + it('leaves unsupported platforms to the upstream error path', () => { + const resolvePackage = vi.fn(); + + expect(resolveEmbeddedBinaryPaths('win32', 'x64', resolvePackage)).toBeUndefined(); + expect(resolvePackage).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/graph/src/client.ts b/packages/graph/src/client.ts index 2db8cc58..c1de4703 100644 --- a/packages/graph/src/client.ts +++ b/packages/graph/src/client.ts @@ -4,6 +4,7 @@ */ import type { Graph } from 'falkordb'; +import { existsSync } from 'node:fs'; import { trace, toErrorMessage } from '@codegraph/logger'; import type { DatabaseDriver, DriverConfig, CypherDialect } from './driver'; import { FalkorDBDriver } from './drivers/falkordb'; @@ -271,11 +272,29 @@ async function loadConfigFile(): Promise> { * Detect the best default driver. Prefers FalkorDBLite (embedded, no Docker) * when the package is installed; falls back to FalkorDB (remote) otherwise. */ +export function supportsEmbeddedPlatform( + platform: NodeJS.Platform = process.platform, + architecture: string = process.arch, + fileExists: (path: string) => boolean = existsSync, +): boolean { + if (platform === 'linux' && architecture === 'x64') return true; + if (platform !== 'darwin' || architecture !== 'arm64') return false; + + return [ + '/opt/homebrew/opt/libomp/lib/libomp.dylib', + '/opt/homebrew/opt/openssl@3/lib/libssl.3.dylib', + '/opt/homebrew/opt/openssl@3/lib/libcrypto.3.dylib', + ].every(fileExists); +} + async function detectDefaultDriver(): Promise<'falkordb' | 'falkordblite'> { // If remote connection is configured, use the remote driver if (process.env['FALKORDB_URL'] || process.env['FALKORDB_HOST']) { return 'falkordb'; } + if (!supportsEmbeddedPlatform()) { + return 'falkordb'; + } try { await import('falkordblite'); return 'falkordblite'; diff --git a/packages/graph/src/drivers/falkordblite.ts b/packages/graph/src/drivers/falkordblite.ts index 962ba8c9..092aeb90 100644 --- a/packages/graph/src/drivers/falkordblite.ts +++ b/packages/graph/src/drivers/falkordblite.ts @@ -10,13 +10,56 @@ * to the remote FalkorDBDriver. */ -import { resolve } from 'node:path'; +import { createRequire } from 'node:module'; +import { dirname, resolve } from 'node:path'; import type { Graph } from 'falkordb'; import type { DatabaseDriver, DriverConfig, CypherDialect } from '../driver'; import type { QueryParams } from '../client'; import { falkorDialect } from './falkordb'; import { executeQuery, executeRoQuery, ensureSchemaImpl } from './falkordb-shared'; +type FalkorDBLiteModule = typeof import('falkordblite'); +type FalkorDBLiteInstance = Awaited>; + +const shutdownSignals = ['SIGINT', 'SIGTERM'] as const; +const embeddedPlatformPackages: Readonly> = { + 'darwin-arm64': '@falkordblite/darwin-arm64', + 'linux-x64': '@falkordblite/linux-x64', +}; +const runtimeRequire = createRequire(import.meta.url); + +export function resolveEmbeddedBinaryPaths( + platform: NodeJS.Platform = process.platform, + architecture: string = process.arch, + resolvePackage: (specifier: string) => string = (specifier) => runtimeRequire.resolve(specifier), +): { redisServerPath: string; modulePath: string } | undefined { + const packageName = embeddedPlatformPackages[`${platform}-${architecture}`]; + if (!packageName) return undefined; + + const packageDirectory = dirname(resolvePackage(`${packageName}/package.json`)); + return { + redisServerPath: resolve(packageDirectory, 'bin', 'redis-server'), + modulePath: resolve(packageDirectory, 'bin', 'falkordb.so'), + }; +} + +function captureSignalListeners(): Map> { + return new Map(shutdownSignals.map((signal) => [signal, new Set(process.listeners(signal))])); +} + +function removeAddedSignalListeners( + listenersBeforeOpen: Map>, +): void { + for (const signal of shutdownSignals) { + const previousListeners = listenersBeforeOpen.get(signal) ?? new Set(); + for (const listener of process.listeners(signal)) { + if (!previousListeners.has(listener)) { + process.removeListener(signal, listener); + } + } + } +} + // ============================================================================ // FalkorDBLite Driver // ============================================================================ @@ -34,10 +77,7 @@ export interface FalkorDBLiteConfig { } export class FalkorDBLiteDriver implements DatabaseDriver { - // Use `any` for the FalkorDBLite db instance to avoid requiring the - // falkordblite types at compile time (it's a lazy/optional dependency) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private db: any = null; + private db: FalkorDBLiteInstance | null = null; private graph: Graph | null = null; readonly dialect: CypherDialect = falkorDialect; @@ -51,8 +91,16 @@ export class FalkorDBLiteDriver implements DatabaseDriver { ?? '.codegraph/falkordb'; const dataPath = resolve(rawPath); - // Open embedded FalkorDB instance - this.db = await FalkorDBLite.open({ path: dataPath }); + // The driver owns shutdown through close(). Keep the embedded wrapper from + // installing competing signal handlers that can stop Redis before its + // client disconnects. + const binaryPaths = resolveEmbeddedBinaryPaths(); + const signalListenersBeforeOpen = captureSignalListeners(); + try { + this.db = await FalkorDBLite.open({ path: dataPath, ...(binaryPaths ?? {}) }); + } finally { + removeAddedSignalListeners(signalListenersBeforeOpen); + } // Select the graph (same API as remote FalkorDB) const graphName = config.graphName ?? process.env['FALKORDB_GRAPH'] ?? 'codegraph'; diff --git a/packages/graph/vitest.config.ts b/packages/graph/vitest.config.ts index 0ecb8403..c77be6b3 100644 --- a/packages/graph/vitest.config.ts +++ b/packages/graph/vitest.config.ts @@ -1,14 +1,17 @@ -import { defineConfig } from 'vitest/config'; +import { configDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ test: { - // Integration tests hit a real Kuzu database - // Use separate forks so Kuzu native module crashes on close are isolated per file pool: 'forks', poolOptions: { forks: { singleFork: false } }, testTimeout: 30_000, hookTimeout: 30_000, - // Only run .test.ts files in __tests__ directories include: ['src/__tests__/**/*.test.ts', 'src/**/__tests__/**/*.test.ts'], + exclude: [ + ...configDefaults.exclude, + 'src/__tests__/about*.test.ts', + 'src/__tests__/{conversation-said,entity-id-persistence,falkordblite,temporal-queries,v5-features}.test.ts', + 'src/__tests__/falkordb-{operations,git-operations,knowledge-operations}.test.ts', + ], }, }); diff --git a/packages/graph/vitest.integration.config.ts b/packages/graph/vitest.integration.config.ts new file mode 100644 index 00000000..b96ef918 --- /dev/null +++ b/packages/graph/vitest.integration.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + pool: 'forks', + poolOptions: { forks: { singleFork: false } }, + testTimeout: 30_000, + hookTimeout: 30_000, + include: [ + 'src/__tests__/about*.test.ts', + 'src/__tests__/falkordb-{operations,git-operations,knowledge-operations}.test.ts', + ], + env: { + CODEGRAPH_EMBEDDING_PROVIDER: 'local', + }, + }, +}); diff --git a/packages/graph/vitest.lite.integration.config.ts b/packages/graph/vitest.lite.integration.config.ts new file mode 100644 index 00000000..fe7f283e --- /dev/null +++ b/packages/graph/vitest.lite.integration.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + pool: 'forks', + poolOptions: { forks: { singleFork: false } }, + testTimeout: 30_000, + hookTimeout: 30_000, + include: [ + 'src/__tests__/{conversation-said,entity-id-persistence,falkordblite,temporal-queries,v5-features}.test.ts', + ], + env: { + CODEGRAPH_EMBEDDING_PROVIDER: 'local', + }, + }, +}); diff --git a/packages/logger/package.json b/packages/logger/package.json index 94822584..8fda3d6a 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -14,7 +14,8 @@ "scripts": { "build": "tsc", "dev": "tsc --watch", - "test": "vitest", + "test": "vitest run --root . --config ../../vitest.package.config.ts", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist" }, "devDependencies": { diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index a51c44a2..2c0aa84c 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -20,6 +20,7 @@ "dev": "tsx src/index.ts", "start": "node dist/index.js", "test": "vitest run", + "test:integration": "vitest run --config vitest.integration.config.ts", "typecheck": "tsc --noEmit" }, "dependencies": { @@ -27,11 +28,12 @@ "@codegraph/logger": "workspace:*", "@codegraph/plugin-nlp": "workspace:*", "@modelcontextprotocol/ext-apps": "^1.7.2", - "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/sdk": "^1.30.0", "glob": "^10.5.0" }, "devDependencies": { "@types/node": "^22.19.19", + "ai": "^6.0.193", "esbuild": "^0.27.7", "tsx": "^4.22.3", "typescript": "^5.9.3", diff --git a/packages/mcp-server/src/__tests__/consolidated.test.ts b/packages/mcp-server/src/__tests__/consolidated.test.ts index ad149ea1..5176b554 100644 --- a/packages/mcp-server/src/__tests__/consolidated.test.ts +++ b/packages/mcp-server/src/__tests__/consolidated.test.ts @@ -1,151 +1,159 @@ /** * Consolidated MCP Tool Tests * - * Tests the 5 consolidated tools: ping, configure_projects, search, get_context, query - * Runs against whichever backend is configured (.codegraph/config.json or env vars). + * Tests the 4 public persona tools against an isolated indexed fixture. */ -import { describe, it, expect, afterAll } from 'vitest'; +import { describe, it, expect, afterAll, beforeAll } from 'vitest'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; import { handleToolCall } from '../tools/router'; -import { - SRC_DIR, - KNOWN_SYMBOL, - KNOWN_FILE, - teardownGraphClient, - assertNoError, -} from './helpers'; +import { setActiveProjects } from '@codegraph/core'; +import { triggerReindex } from '../tools/reindex'; +import { teardownGraphClient, assertNoError } from './helpers'; + +let fixtureDirectory: string; +let fixtureFile: string; +let previousEmbeddingProvider: string | undefined; + +beforeAll(async () => { + previousEmbeddingProvider = process.env['CODEGRAPH_EMBEDDING_PROVIDER']; + process.env['CODEGRAPH_EMBEDDING_PROVIDER'] = 'local'; + fixtureDirectory = mkdtempSync(join(tmpdir(), 'codegraph-mcp-personas-')); + const sourceDirectory = join(fixtureDirectory, 'src'); + mkdirSync(sourceDirectory); + fixtureFile = join(sourceDirectory, 'widget.ts'); + writeFileSync( + fixtureFile, + [ + 'export class Widget {}', + 'export function buildWidget(): Widget {', + ' return new Widget();', + '}', + ].join('\n'), + ); + + await setActiveProjects([fixtureDirectory]); + const result = await triggerReindex({ + scope: fixtureDirectory, + mode: 'full', + deferEmbeddings: false, + }); + if (!result.success) { + throw new Error(`Unable to index MCP persona fixture: ${result.errors.join('; ')}`); + } +}); afterAll(async () => { + await setActiveProjects([]); await teardownGraphClient(); + if (previousEmbeddingProvider === undefined) { + delete process.env['CODEGRAPH_EMBEDDING_PROVIDER']; + } else { + process.env['CODEGRAPH_EMBEDDING_PROVIDER'] = previousEmbeddingProvider; + } + rmSync(fixtureDirectory, { recursive: true, force: true }); }); // ─── ping ──────────────────────────────────────────────────────────────────── -describe('ping', () => { +describe('codebase persona', () => { it('returns ok status with timestamp', async () => { - const result = (await handleToolCall('ping', {})) as Record; + const result = (await handleToolCall('codebase', { + action: 'ping', + })) as Record; expect(result.status).toBe('ok'); expect(result.message).toContain('running'); expect(result.timestamp).toBeDefined(); }); -}); - -// ─── configure_projects ────────────────────────────────────────────────────── -describe('configure_projects', () => { it('returns status with active projects', async () => { - const result = (await handleToolCall('configure_projects', { - action: 'status', + const result = (await handleToolCall('codebase', { + action: 'configure', + projectAction: 'status', })) as Record; - assertNoError(result, 'configure_projects status'); + assertNoError(result, 'codebase configure status'); expect(result.setupComplete).toBeDefined(); - // Should have at least the codebase-graph project - expect(Array.isArray(result.activeProjects)).toBe(true); + expect(result.activeProjects).toEqual([fixtureDirectory]); }); }); // ─── search ────────────────────────────────────────────────────────────────── describe('search', () => { - it('finds symbols matching a keyword (all types)', async () => { + it('finds symbols in the indexed fixture', async () => { const result = (await handleToolCall('search', { - query: 'create', + action: 'find', + query: 'buildWidget', })) as Record; - assertNoError(result, 'search all'); + assertNoError(result, 'search find'); expect(result.total).toBeGreaterThan(0); const results = result.results as Array>; expect(results.length).toBeGreaterThan(0); - // Every result should have required fields - for (const r of results) { - expect(r.name).toBeDefined(); - expect(r.type).toBeDefined(); - expect(typeof r.type).toBe('string'); - expect((r.type as string).length).toBeGreaterThan(1); // not truncated - } - }); - - it('filters by type: function', async () => { - const result = (await handleToolCall('search', { - query: 'build', - type: 'function', - })) as Record; - - assertNoError(result, 'search function'); - const results = result.results as Array>; - for (const r of results) { - expect(r.type).toBe('Function'); - } - }); - - it('filters by type: file', async () => { - const result = (await handleToolCall('search', { - query: 'client', - type: 'file', - })) as Record; - - assertNoError(result, 'search file'); - const results = result.results as Array>; - expect(results.length).toBeGreaterThan(0); - for (const r of results) { - expect(r.type).toBe('File'); - } + expect(result._meta).toMatchObject({ action: 'find', toolUsed: 'search_code' }); }); - it('returns empty results for nonexistent term', async () => { + it('rejects an empty search query', async () => { const result = (await handleToolCall('search', { - query: 'xyzNonexistentTerm12345', + action: 'find', + query: ' ', })) as Record; - assertNoError(result, 'search empty'); + expect(result.error).toContain('required'); expect(result.total).toBe(0); }); }); -// ─── get_context ───────────────────────────────────────────────────────────── +// ─── search context ───────────────────────────────────────────────────────── -describe('get_context', () => { +describe('search context', () => { it('returns file context with entities', async () => { - const result = (await handleToolCall('get_context', { - file: KNOWN_FILE, + const result = (await handleToolCall('search', { + action: 'context', + file: fixtureFile, })) as Record; - assertNoError(result, 'get_context file'); + assertNoError(result, 'search context file'); expect(result.file).toBeDefined(); const file = result.file as Record; - expect(file.path).toBe(KNOWN_FILE); + expect(file.path).toBe(fixtureFile); expect(Array.isArray(file.entities)).toBe(true); expect((file.entities as unknown[]).length).toBeGreaterThan(0); }); it('returns symbol context with type and location', async () => { - const result = (await handleToolCall('get_context', { - symbol: KNOWN_SYMBOL, + const result = (await handleToolCall('search', { + action: 'context', + symbol: 'buildWidget', })) as Record; - assertNoError(result, 'get_context symbol'); + assertNoError(result, 'search context symbol'); expect(result.entity).toBeDefined(); const entity = result.entity as Record; - expect(entity.name).toBe(KNOWN_SYMBOL); - expect(entity.type).toBe('Function'); + expect(entity.name).toBe('buildWidget'); + expect(entity.type).toBe('function'); expect(typeof entity.startLine).toBe('number'); }); it('returns symbol context scoped to file', async () => { - const result = (await handleToolCall('get_context', { - symbol: KNOWN_SYMBOL, - file: KNOWN_FILE, + const result = (await handleToolCall('search', { + action: 'context', + symbol: 'buildWidget', + file: fixtureFile, })) as Record; - assertNoError(result, 'get_context sym+file'); + assertNoError(result, 'search context symbol and file'); const entity = result.entity as Record; - expect(entity.name).toBe(KNOWN_SYMBOL); - expect(entity.filePath).toBe(KNOWN_FILE); + expect(entity.name).toBe('buildWidget'); + expect(entity.filePath).toBe(fixtureFile); }); it('returns error for missing symbol', async () => { - const result = (await handleToolCall('get_context', { + const result = (await handleToolCall('search', { + action: 'context', symbol: 'xyzNonexistent999', })) as Record; diff --git a/packages/mcp-server/src/__tests__/e2e-knowledge.test.ts b/packages/mcp-server/src/__tests__/e2e-knowledge.test.ts index 43d693ab..ce57f362 100644 --- a/packages/mcp-server/src/__tests__/e2e-knowledge.test.ts +++ b/packages/mcp-server/src/__tests__/e2e-knowledge.test.ts @@ -182,8 +182,10 @@ describe('E2E: NLP extraction → knowledge graph → MCP recall', () => { modelId: 'test-model', doGenerate: { content: [{ - type: 'text' as const, - text: JSON.stringify({ + type: 'tool-call' as const, + toolCallId: 'e2e-extraction', + toolName: 'emit_extraction', + input: JSON.stringify({ entities: [ { text: 'Charlie', type: 'Person' }, { text: 'GraphProject', type: 'Project' }, @@ -193,10 +195,10 @@ describe('E2E: NLP extraction → knowledge graph → MCP recall', () => { ], }), }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, + finishReason: { unified: 'tool-calls' as const, raw: 'tool-calls' }, usage: { inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 10, text: 10, reasoning: 0 }, + outputTokens: { total: 10, text: 0, reasoning: 0 }, }, warnings: [], }, diff --git a/packages/mcp-server/src/__tests__/legacy.test.ts b/packages/mcp-server/src/__tests__/legacy.test.ts index eda99e74..12b73876 100644 --- a/packages/mcp-server/src/__tests__/legacy.test.ts +++ b/packages/mcp-server/src/__tests__/legacy.test.ts @@ -6,22 +6,49 @@ */ import { describe, it, expect, afterAll, beforeAll } from 'vitest'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; import { handleToolCall } from '../tools/router'; import { registerPlugins } from '@codegraph/core'; -import { - SRC_DIR, - KNOWN_SYMBOL, - KNOWN_FILE, - teardownGraphClient, - assertNoError, -} from './helpers'; - -beforeAll(() => { +import { triggerReindex } from '../tools/reindex'; +import { teardownGraphClient, assertNoError } from './helpers'; + +let fixtureDirectory: string; +let fixtureFile: string; +let previousEmbeddingProvider: string | undefined; + +beforeAll(async () => { + previousEmbeddingProvider = process.env['CODEGRAPH_EMBEDDING_PROVIDER']; + process.env['CODEGRAPH_EMBEDDING_PROVIDER'] = 'local'; registerPlugins(); + fixtureDirectory = mkdtempSync(join(tmpdir(), 'codegraph-mcp-raw-')); + const sourceDirectory = join(fixtureDirectory, 'src'); + mkdirSync(sourceDirectory); + fixtureFile = join(sourceDirectory, 'legacy-widget.ts'); + writeFileSync( + fixtureFile, + 'export function createLegacyWidget(): string { return "legacy-widget"; }\n', + ); + + const result = await triggerReindex({ + scope: fixtureDirectory, + mode: 'full', + deferEmbeddings: false, + }); + if (!result.success) { + throw new Error(`Unable to index raw tool fixture: ${result.errors.join('; ')}`); + } }); afterAll(async () => { await teardownGraphClient(); + if (previousEmbeddingProvider === undefined) { + delete process.env['CODEGRAPH_EMBEDDING_PROVIDER']; + } else { + process.env['CODEGRAPH_EMBEDDING_PROVIDER'] = previousEmbeddingProvider; + } + rmSync(fixtureDirectory, { recursive: true, force: true }); }); // ─── ping ──────────────────────────────────────────────────────────────────── @@ -80,7 +107,7 @@ describe('trigger_reindex', () => { it('can index a single file', async () => { const result = (await handleToolCall('trigger_reindex', { mode: 'full', - scope: KNOWN_FILE, + scope: fixtureFile, })) as Record; expect(result.success).toBe(true); diff --git a/packages/mcp-server/src/__tests__/reindex.test.ts b/packages/mcp-server/src/__tests__/reindex.test.ts index 044198a9..a38c1367 100644 --- a/packages/mcp-server/src/__tests__/reindex.test.ts +++ b/packages/mcp-server/src/__tests__/reindex.test.ts @@ -3,27 +3,7 @@ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { triggerReindex } from '../tools/reindex'; -import { closeGraphClient, createClient } from '@codegraph/core'; - -const FALKORDB_HOST = process.env['FALKORDB_HOST'] ?? 'localhost'; -const FALKORDB_PORT = process.env['FALKORDB_PORT'] ?? '6379'; - -// Check if FalkorDB is reachable before running tests -let isAvailable = false; -beforeAll(async () => { - try { - const client = await createClient({ - driver: 'falkordb', - host: FALKORDB_HOST, - port: Number(FALKORDB_PORT), - graphName: `skip-check-${Date.now()}`, - }); - isAvailable = true; - await client.close(); - } catch { - isAvailable = false; - } -}); +import { closeGraphClient } from '@codegraph/core'; // Tiny in-memory corpus so reindex completes in seconds. function makeFixture(): string { @@ -36,13 +16,9 @@ function makeFixture(): string { return dir; } -describe.skipIf(!isAvailable)('triggerReindex — blocks on embeddings by default', () => { +describe('triggerReindex blocks on embeddings by default', () => { let fixture: string; beforeAll(() => { - process.env['FALKORDB_HOST'] = FALKORDB_HOST; - process.env['FALKORDB_PORT'] = FALKORDB_PORT; - process.env['CODEGRAPH_DRIVER'] = 'falkordb'; - process.env['FALKORDB_GRAPH'] = 'reindex-test-' + Date.now(); process.env['CODEGRAPH_EMBEDDING_PROVIDER'] = 'local'; fixture = makeFixture(); }); @@ -51,6 +27,7 @@ describe.skipIf(!isAvailable)('triggerReindex — blocks on embeddings by defaul }); afterAll(async () => { await closeGraphClient(); + process.env['CODEGRAPH_EMBEDDING_PROVIDER'] = 'none'; rmSync(fixture, { recursive: true, force: true }); }); @@ -63,7 +40,6 @@ describe.skipIf(!isAvailable)('triggerReindex — blocks on embeddings by defaul }, 120_000); it('respects deferEmbeddings=true override (returns embeddingsDeferred=true)', async () => { - process.env['FALKORDB_GRAPH'] = 'reindex-test-defer-' + Date.now(); const fixture2 = makeFixture(); try { const result = await triggerReindex({ scope: fixture2, mode: 'full', deferEmbeddings: true }); diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 4c2c8e4e..c3e94065 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -104,18 +104,23 @@ async function startAutoReindex(): Promise { async function main(): Promise { const server = createMCPServer(); + let shutdownPromise: Promise | null = null; // Handle graceful shutdown - const shutdown = async () => { - logger.info('Shutting down...'); - await stopWatching(); - await closeGraphClient(); - await server.stop(); - process.exit(0); + const shutdown = (): Promise => { + shutdownPromise ??= (async () => { + logger.info('Shutting down...'); + await stopWatching(); + await closeGraphClient(); + await server.stop(); + process.exit(0); + })(); + return shutdownPromise; }; - process.on('SIGINT', shutdown); - process.on('SIGTERM', shutdown); + process.once('SIGINT', () => void shutdown()); + process.once('SIGTERM', () => void shutdown()); + process.stdin.once('end', () => void shutdown()); try { await server.start(); diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 04fbd987..f29f881f 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -3,13 +3,13 @@ * Implements Model Context Protocol for AI assistant integration */ -import { Server } from '@modelcontextprotocol/sdk/server'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, type Tool, -} from '@modelcontextprotocol/sdk/types'; +} from '@modelcontextprotocol/sdk/types.js'; import { createLogger, toErrorMessage } from '@codegraph/logger'; import { getTools, handleToolCall, staticTools } from './tools/router'; import { createRequire } from 'node:module'; @@ -113,7 +113,7 @@ export class CodeGraphMCPServer { transport: 'stdio', }); - // Server started — config sync handled by tools on first use + // Server started: config sync handled by tools on first use } /** diff --git a/packages/mcp-server/vitest.config.ts b/packages/mcp-server/vitest.config.ts index b04d80bd..14d31bd2 100644 --- a/packages/mcp-server/vitest.config.ts +++ b/packages/mcp-server/vitest.config.ts @@ -1,18 +1,18 @@ -import { defineConfig } from 'vitest/config'; +import { configDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ test: { - // Use Docker FalkorDB for integration tests (avoids falkordblite socket path issues) - env: { - CODEGRAPH_DRIVER: 'falkordb', - FALKORDB_HOST: 'localhost', - }, - // Integration tests hit a real FalkorDB database — run sequentially pool: 'forks', - poolOptions: { forks: { singleFork: true } }, testTimeout: 30_000, hookTimeout: 30_000, - // Only run .test.ts files in __tests__ directory include: ['src/__tests__/**/*.test.ts'], + exclude: [ + ...configDefaults.exclude, + 'src/__tests__/consolidated.test.ts', + 'src/__tests__/e2e-knowledge.test.ts', + 'src/__tests__/knowledge.test.ts', + 'src/__tests__/legacy.test.ts', + 'src/__tests__/reindex.test.ts', + ], }, }); diff --git a/packages/mcp-server/vitest.integration.config.ts b/packages/mcp-server/vitest.integration.config.ts new file mode 100644 index 00000000..c2fd81fc --- /dev/null +++ b/packages/mcp-server/vitest.integration.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'vitest/config'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; + +export default defineConfig({ + test: { + env: { + CODEGRAPH_DRIVER: 'falkordb', + CODEGRAPH_EMBEDDING_PROVIDER: 'none', + CODEGRAPH_DATA_DIR: join(tmpdir(), 'codegraph-mcp-integration'), + FALKORDB_HOST: 'localhost', + FALKORDB_GRAPH: 'codegraph-mcp-integration', + }, + pool: 'forks', + poolOptions: { forks: { singleFork: true } }, + testTimeout: 30_000, + hookTimeout: 30_000, + include: [ + 'src/__tests__/consolidated.test.ts', + 'src/__tests__/e2e-knowledge.test.ts', + 'src/__tests__/knowledge.test.ts', + 'src/__tests__/legacy.test.ts', + 'src/__tests__/reindex.test.ts', + ], + }, +}); diff --git a/packages/mcpb/README.md b/packages/mcpb/README.md index 8db818c6..51d109f6 100644 --- a/packages/mcpb/README.md +++ b/packages/mcpb/README.md @@ -1,6 +1,6 @@ # @codegraph/mcpb -MCP Bundle (MCPB) -- a pre-built, distributable bundle of the CodeGraph MCP server for Claude Desktop and other MCP clients. +MCP Bundle (MCPB) for the CodeGraph server in Claude Desktop and other compatible MCP clients. This is a **build artifact**, not a development package. It bundles the MCP server and all dependencies into a single deployable unit. @@ -15,43 +15,40 @@ dist/ icon.png # Extension icon server/ index.mjs # esbuild-bundled MCP server (single file) - node_modules/ # Native modules (tree-sitter grammars, MCP SDK) + node_modules/ # Locked tree-sitter and MCP SDK runtime packages ``` ## Build Process 1. **esbuild** bundles `packages/mcp-server/dist/index.js` into a single ESM file targeting Node 20 -2. Native modules that cannot be bundled are kept external and copied separately: - - `tree-sitter` + all grammar packages (native `.node` bindings) - - `@huggingface/transformers` + `onnxruntime-node` (ONNX runtime) - - `@modelcontextprotocol/sdk` (wildcard exports incompatible with bundling) - - `falkordblite` (optional native dependency) -3. MCP SDK runtime dependencies are installed via `npm install --production` into the bundle -4. MCP SDK imports in the bundle are patched to add `.js` extensions for Node ESM resolution -5. `manifest.json` and `icon.png` are copied into the output +2. `tree-sitter`, grammar packages, the MCP SDK, and their runtime dependency closures are copied from the frozen pnpm workspace install. +3. MCP SDK imports in the bundle are patched to add `.js` extensions for Node ESM resolution. +4. `manifest.json` and `icon.png` are copied into the output. + +The desktop bundle defaults to structural search with an external FalkorDB service. It does not package optional local Transformer models or embedded FalkorDBLite. Configure the FalkorDB host and port when installing the extension. ## manifest.json Defines the extension metadata, tools, user configuration, and server entry point. Key sections: - **tools**: `search`, `codebase`, `knowledge`, `query` -- **user_config**: Prompts for Voyage API key, Jina API key, project paths, FalkorDB host/port +- **user_config**: Prompts for project paths and optional external FalkorDB host/port - **server.mcp_config**: The `node` command and environment variables used to launch the server -- **compatibility**: Node >= 20, platforms: macOS, Windows, Linux +- **compatibility**: Node >= 20 and the platform where the bundle was built + +The generated bundle defaults to `CODEGRAPH_EMBEDDING_PROVIDER=none`, so API keys are not required for structural search. Its FalkorDB host and port settings point the bundle at an external service. ## How to Build ```bash -# From the monorepo root -- build the MCP server first, then the bundle -pnpm turbo build --filter=@codegraph/mcp-server -node packages/mcpb/build.mjs +# From the monorepo root: build the MCP server first, then the bundle +pnpm --filter @codegraph/mcpb build ``` ## How to Pack ```bash -cd packages/mcpb/dist -mcpb pack +pnpm exec mcpb pack packages/mcpb/dist # Produces codegraph-0.1.0.mcpb ``` diff --git a/packages/mcpb/build.mjs b/packages/mcpb/build.mjs index 8ec1ac3e..12c6ed99 100644 --- a/packages/mcpb/build.mjs +++ b/packages/mcpb/build.mjs @@ -6,10 +6,11 @@ * with tree-sitter native modules kept external and copied separately. */ -import { cpSync, mkdirSync, rmSync, existsSync, readdirSync, readFileSync, writeFileSync, statSync, symlinkSync } from 'node:fs'; -import { resolve, dirname } from 'node:path'; +import { cpSync, mkdirSync, rmSync, existsSync, readdirSync, readFileSync, realpathSync, writeFileSync, statSync } from 'node:fs'; +import { resolve, dirname, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { execSync } from 'node:child_process'; +import { createRequire } from 'node:module'; +import { build } from 'esbuild'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, '../..'); @@ -63,7 +64,7 @@ const externalPackages = [ '@huggingface/transformers', 'onnxruntime-node', 'falkordblite', - // MCP SDK has wildcard exports that esbuild can't resolve — we externalize + // MCP SDK has wildcard exports that esbuild can't resolve: we externalize // and copy it, then patch the imports to add .js extensions post-build '@modelcontextprotocol/sdk', '@modelcontextprotocol/sdk/*', @@ -72,49 +73,30 @@ const externalPackages = [ console.log(`Found ${treeSitterGrammars.length} tree-sitter grammars`); console.log(`Bundling with ${externalPackages.length} external packages...`); -// Build external args for esbuild CLI -const externalArgs = externalPackages.map(p => `--external:${p}`).join(' '); - -// Run esbuild via CLI — use the native binary from pnpm's store -const esbuildBin = resolve(ROOT, 'node_modules/.pnpm/@esbuild+darwin-arm64@0.27.4/node_modules/@esbuild/darwin-arm64/bin/esbuild'); -const esbuildCmd = [ - esbuildBin, - resolve(ROOT, 'packages/mcp-server/dist/index.js'), - '--bundle', - '--platform=node', - '--target=node20', - '--format=esm', - `--outfile=${resolve(SERVER_DIR, 'index.mjs')}`, - '--log-level=info', - '--conditions=import,node', - '--resolve-extensions=.js,.mjs,.ts,.tsx,.json', - '--banner:js=\'import { createRequire as __bundleRequire } from "module"; const require = __bundleRequire(import.meta.url);\'', - externalArgs, -].join(' '); - console.log('Running esbuild...'); -execSync(esbuildCmd, { stdio: 'inherit', cwd: ROOT }); - -console.log('Bundle created. Installing MCP SDK dependencies...'); - -// Install MCP SDK + all transitive deps FIRST (before copying native modules) -const sdkPkg = { dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } }; -writeFileSync(resolve(SERVER_DIR, 'package.json'), JSON.stringify(sdkPkg)); -execSync('npm install --production --no-optional --no-audit --no-fund 2>&1', { - cwd: SERVER_DIR, - stdio: 'pipe', +await build({ + entryPoints: [resolve(ROOT, 'packages/mcp-server/dist/index.js')], + outfile: resolve(SERVER_DIR, 'index.mjs'), + bundle: true, + platform: 'node', + target: 'node20', + format: 'esm', + logLevel: 'info', + conditions: ['import', 'node'], + resolveExtensions: ['.js', '.mjs', '.ts', '.tsx', '.json'], + banner: { + js: 'import { createRequire as __bundleRequire } from "node:module"; const require = __bundleRequire(import.meta.url);', + }, + external: externalPackages, }); -rmSync(resolve(SERVER_DIR, 'package.json'), { force: true }); -rmSync(resolve(SERVER_DIR, 'package-lock.json'), { force: true }); -console.log('Copying native modules...'); +console.log('Copying locked runtime dependencies...'); -// Copy tree-sitter and grammar native modules ON TOP of the installed deps const nmDest = resolve(SERVER_DIR, 'node_modules'); mkdirSync(nmDest, { recursive: true }); function resolveRealPath(pkgName) { - // pnpm uses symlinks — resolve through them + // pnpm uses symlinks: resolve through them const candidates = [ resolve(ROOT, 'node_modules', pkgName), resolve(ROOT, 'packages/core/node_modules', pkgName), @@ -144,39 +126,120 @@ function resolveRealPath(pkgName) { return null; } -// tree-sitter-cli is a CLI tool, not a grammar — don't bundle it -const skipPackages = new Set(['tree-sitter-cli']); +function packageRootFromEntry(entryPath, packageName) { + let current = dirname(entryPath); + while (current !== dirname(current)) { + const manifestPath = resolve(current, 'package.json'); + if (existsSync(manifestPath)) { + const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + if (manifest.name === packageName) return current; + } + current = dirname(current); + } + return null; +} + +function resolveDependencyFrom(packageRoot, dependencyName) { + const dependencyRequire = createRequire(resolve(packageRoot, 'package.json')); + try { + return dirname(dependencyRequire.resolve(`${dependencyName}/package.json`)); + } catch { + try { + const entryPath = dependencyRequire.resolve(dependencyName); + return packageRootFromEntry(entryPath, dependencyName); + } catch { + return null; + } + } +} + +const rootPackageSources = new Map(); +const copiedDestinations = new Map(); + +function copyPackageClosure(packageName, sourceOverride, destinationRoot = nmDest) { + const source = sourceOverride ?? resolveRealPath(packageName); + if (!source) { + throw new Error(`Required MCPB runtime package is unavailable: ${packageName}`); + } + const sourceDirectory = statSync(source).isDirectory() ? source : dirname(source); + const realSource = realpathSync(sourceDirectory); + const manifest = JSON.parse(readFileSync(resolve(realSource, 'package.json'), 'utf8')); + const destination = resolve(destinationRoot, packageName); + const priorSource = copiedDestinations.get(destination); + if (priorSource && priorSource !== realSource) { + throw new Error(`MCPB runtime destination collision for ${packageName}`); + } + if (priorSource) return; + + copiedDestinations.set(destination, realSource); + if (destinationRoot === nmDest) rootPackageSources.set(packageName, realSource); + mkdirSync(dirname(destination), { recursive: true }); + cpSync(realSource, destination, { + recursive: true, + dereference: true, + filter: (sourcePath) => !relative(realSource, sourcePath) + .split(/[/\\]/) + .includes('node_modules'), + }); -let copiedCount = 0; -for (const pkg of ['tree-sitter', ...treeSitterGrammars.filter(g => !skipPackages.has(g))]) { - const src = resolveRealPath(pkg); - if (src) { - const dest = resolve(nmDest, pkg); - cpSync(src, dest, { recursive: true, dereference: true }); - // Remove unnecessary files to reduce size - for (const unnecessary of ['src', 'test', 'tests', '.github', 'binding.gyp', 'Cargo.toml', 'Cargo.lock', 'grammar.js']) { - const p = resolve(dest, unnecessary); - if (existsSync(p)) rmSync(p, { recursive: true, force: true }); + const dependencyNames = new Set([ + ...Object.keys(manifest.dependencies ?? {}), + ...Object.keys(manifest.optionalDependencies ?? {}), + ]); + for (const dependencyName of dependencyNames) { + const dependencySource = resolveDependencyFrom(realSource, dependencyName); + if (!dependencySource) continue; + const realDependencySource = realpathSync(dependencySource); + const rootSource = rootPackageSources.get(dependencyName); + if (!rootSource) { + copyPackageClosure(dependencyName, realDependencySource); + } else if (rootSource !== realDependencySource) { + copyPackageClosure( + dependencyName, + realDependencySource, + resolve(destination, 'node_modules'), + ); } - copiedCount++; - } else { - console.warn(`⚠ ${pkg} not found, skipping`); } } -// Copy MCP SDK and patch wildcard exports -const mcpSdkSrc = resolveRealPath('@modelcontextprotocol/sdk'); -if (mcpSdkSrc) { - mkdirSync(resolve(nmDest, '@modelcontextprotocol'), { recursive: true }); - cpSync(mcpSdkSrc, resolve(nmDest, '@modelcontextprotocol/sdk'), { recursive: true, dereference: true }); - copiedCount++; +const skipPackages = new Set(['tree-sitter-cli']); +const runtimeRootPackages = [ + 'tree-sitter', + ...treeSitterGrammars.filter(g => !skipPackages.has(g)), + '@modelcontextprotocol/sdk', +]; +for (const packageName of runtimeRootPackages) { + const source = resolveRealPath(packageName); + if (!source) throw new Error(`Required MCPB runtime package is unavailable: ${packageName}`); + rootPackageSources.set(packageName, realpathSync(source)); +} +for (const packageName of runtimeRootPackages) { + copyPackageClosure(packageName, rootPackageSources.get(packageName)); +} + +for (const pkg of runtimeRootPackages.filter((name) => name.startsWith('tree-sitter'))) { + const destination = resolve(nmDest, pkg); + for (const unnecessary of [ + 'src', + 'test', + 'tests', + '.github', + 'binding.gyp', + 'Cargo.toml', + 'Cargo.lock', + 'grammar.js', + ]) { + const path = resolve(destination, unnecessary); + if (existsSync(path)) rmSync(path, { recursive: true, force: true }); + } } // Patch MCP SDK imports in the bundle to add .js extensions for wildcard exports. // The SDK has explicit exports (./server, ./client, ./types, etc.) that Node resolves // correctly, but wildcard "./*" exports need .js suffix for Node ESM resolution. // Explicit export entries: client, server, validation, validation/ajv, validation/cfworker, -// experimental, experimental/tasks — these DON'T need patching. +// experimental, experimental/tasks: these DON'T need patching. const bundlePath = resolve(SERVER_DIR, 'index.mjs'); let bundleContent = readFileSync(bundlePath, 'utf-8'); const explicitExports = new Set([ @@ -193,48 +256,56 @@ bundleContent = bundleContent.replace( ); writeFileSync(bundlePath, bundleContent); -// MCP SDK already installed above — just copy if not present -const mcpSdkDest = resolve(nmDest, '@modelcontextprotocol/sdk'); -if (!existsSync(mcpSdkDest)) { - const mcpSdkSrc = resolveRealPath('@modelcontextprotocol/sdk'); - if (mcpSdkSrc) { - mkdirSync(resolve(nmDest, '@modelcontextprotocol'), { recursive: true }); - cpSync(mcpSdkSrc, mcpSdkDest, { recursive: true, dereference: true }); - } -} - -// Copy runtime deps needed by tree-sitter -for (const dep of ['node-addon-api', 'prebuild-install', 'node-gyp-build']) { - const src = resolveRealPath(dep); - if (src) { - cpSync(src, resolve(nmDest, dep), { recursive: true, dereference: true }); - } -} - -// Copy manifest.json and create package.json for the bundle -cpSync(resolve(__dirname, 'manifest.json'), resolve(OUT, 'manifest.json')); +// Generate platform-local metadata from the canonical npm package version. +const npmPackage = JSON.parse( + readFileSync(resolve(ROOT, 'packages/npm-package/package.json'), 'utf8'), +); +const manifest = JSON.parse(readFileSync(resolve(__dirname, 'manifest.json'), 'utf8')); +manifest.version = npmPackage.version; +manifest.author.url = 'https://github.com/Phoenixrr2113'; +manifest.repository = { + type: 'git', + url: 'https://github.com/Phoenixrr2113/codebase-graph', +}; +manifest.homepage = 'https://v0-landing-page-build-kappa-virid.vercel.app'; +manifest.long_description = 'CodeGraph indexes source code into a graph and exposes search, codebase, knowledge, and Cypher tools through MCP. Offline structural search works without API keys by setting the embedding provider to none.'; +delete manifest.user_config.voyage_api_key; +delete manifest.user_config.jina_api_key; +delete manifest.server.mcp_config.env.VOYAGE_API_KEY; +delete manifest.server.mcp_config.env.JINA_API_KEY; +manifest.server.mcp_config.env.CODEGRAPH_EMBEDDING_PROVIDER = 'none'; +manifest.compatibility.platforms = [process.platform]; +writeFileSync(resolve(OUT, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`); writeFileSync(resolve(OUT, 'package.json'), JSON.stringify({ name: 'codegraph-mcpb', - version: '0.1.0', + version: npmPackage.version, type: 'module', private: true, -})); +}, null, 2)); +cpSync(resolve(__dirname, 'README.md'), resolve(OUT, 'README.md')); // Copy icon if it exists const iconSrc = resolve(__dirname, 'icon.png'); if (existsSync(iconSrc)) { cpSync(iconSrc, resolve(OUT, 'icon.png')); } else { - console.warn('⚠ No icon.png found — add one for the extension listing'); + console.warn('⚠ No icon.png found: add one for the extension listing'); +} + +function directorySize(directory) { + let total = 0; + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const path = resolve(directory, entry.name); + total += entry.isDirectory() ? directorySize(path) : statSync(path).size; + } + return total; } -// Calculate sizes const bundleSize = readFileSync(resolve(SERVER_DIR, 'index.mjs')).length; -const totalNativeSize = execSync(`du -sh ${nmDest} 2>/dev/null || echo "unknown"`) - .toString().trim().split('\t')[0]; +const runtimeSize = directorySize(nmDest); console.log(`\n✅ MCPB build complete!`); console.log(` Bundle: ${(bundleSize / 1024 / 1024).toFixed(1)} MB`); -console.log(` Native modules: ${copiedCount} packages (${totalNativeSize})`); +console.log(` Runtime: ${copiedDestinations.size} locked packages (${(runtimeSize / 1024 / 1024).toFixed(1)} MB)`); console.log(` Output: ${OUT}`); console.log(`\nTo pack: cd ${OUT} && mcpb pack`); diff --git a/packages/mcpb/manifest.json b/packages/mcpb/manifest.json index b5c8f090..33406fe6 100644 --- a/packages/mcpb/manifest.json +++ b/packages/mcpb/manifest.json @@ -4,16 +4,16 @@ "display_name": "CodeGraph", "version": "0.1.0", "description": "Index any codebase into a graph database. Search by meaning, trace relationships, and get AI-powered context for your code.", - "long_description": "CodeGraph indexes your codebase into a graph database (FalkorDB) and provides tools for semantic code search, relationship tracing, and knowledge management. Supports 42+ languages via Tree-sitter.\n\n**Tools:**\n- `search` — Find code by meaning (vector + reranker)\n- `codebase` — Index management, status, source reading\n- `knowledge` — Store and recall project knowledge\n- `query` — Raw Cypher queries against the code graph\n\n**Requirements:**\n- Docker (for FalkorDB) or `redis-server` (for embedded mode)\n- Voyage AI API key (for embeddings)\n- Jina AI API key (for reranking)", + "long_description": "CodeGraph indexes source code into a graph and exposes search, codebase, knowledge, and Cypher tools through MCP. Offline structural search works without API keys by setting the embedding provider to none.", "author": { "name": "Randy Wilson", - "url": "https://codegraph.dev" + "url": "https://github.com/Phoenixrr2113" }, "repository": { "type": "git", - "url": "https://github.com/randywilson/codegraph" + "url": "https://github.com/Phoenixrr2113/codebase-graph" }, - "homepage": "https://codegraph.dev", + "homepage": "https://v0-landing-page-build-kappa-virid.vercel.app", "icon": "icon.png", "server": { "type": "node", @@ -24,8 +24,7 @@ "${__dirname}/server/index.mjs" ], "env": { - "VOYAGE_API_KEY": "${user_config.voyage_api_key}", - "JINA_API_KEY": "${user_config.jina_api_key}", + "CODEGRAPH_EMBEDDING_PROVIDER": "none", "CODEGRAPH_PROJECTS": "${user_config.project_paths}", "FALKORDB_HOST": "${user_config.falkordb_host}", "FALKORDB_PORT": "${user_config.falkordb_port}" @@ -39,11 +38,11 @@ }, { "name": "codebase", - "description": "Manage codebase indexing — configure projects, reindex, check status, read source" + "description": "Manage codebase indexing: configure projects, reindex, check status, read source" }, { "name": "knowledge", - "description": "Store and recall project knowledge — entities, relationships, and facts" + "description": "Store and recall project knowledge: entities, relationships, and facts" }, { "name": "query", @@ -62,20 +61,6 @@ ], "license": "MIT", "user_config": { - "voyage_api_key": { - "type": "string", - "title": "Voyage AI API Key", - "description": "API key for Voyage AI embeddings (get one at dash.voyageai.com)", - "sensitive": true, - "required": true - }, - "jina_api_key": { - "type": "string", - "title": "Jina AI API Key", - "description": "API key for Jina reranker (get one at jina.ai)", - "sensitive": true, - "required": true - }, "project_paths": { "type": "directory", "title": "Project Directory", diff --git a/packages/mcpb/package.json b/packages/mcpb/package.json new file mode 100644 index 00000000..a6121a16 --- /dev/null +++ b/packages/mcpb/package.json @@ -0,0 +1,14 @@ +{ + "name": "@codegraph/mcpb", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "build": "node build.mjs" + }, + "devDependencies": { + "@anthropic-ai/mcpb": "^2.1.2", + "@codegraph/mcp-server": "workspace:*", + "esbuild": "^0.27.7" + } +} diff --git a/packages/npm-package/__tests__/cli.test.ts b/packages/npm-package/__tests__/cli.test.ts new file mode 100644 index 00000000..2601eac8 --- /dev/null +++ b/packages/npm-package/__tests__/cli.test.ts @@ -0,0 +1,70 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; + +const packageDirectory = dirname(dirname(fileURLToPath(import.meta.url))); +const temporaryDirectories: string[] = []; + +afterEach(() => { + for (const directory of temporaryDirectories.splice(0)) { + rmSync(directory, { recursive: true, force: true }); + } +}); + +describe('codegraph-mcp CLI', () => { + it('reads --version from the adjacent package manifest', () => { + const fixtureDirectory = mkdtempSync(join(tmpdir(), 'codegraph-cli-')); + temporaryDirectories.push(fixtureDirectory); + mkdirSync(join(fixtureDirectory, 'bin')); + copyFileSync( + join(packageDirectory, 'bin', 'codegraph-mcp.mjs'), + join(fixtureDirectory, 'bin', 'codegraph-mcp.mjs'), + ); + writeFileSync( + join(fixtureDirectory, 'package.json'), + JSON.stringify({ name: 'codegraph-mcp', version: '9.8.7', type: 'module' }), + ); + + const result = spawnSync( + process.execPath, + [join(fixtureDirectory, 'bin', 'codegraph-mcp.mjs'), '--version'], + { encoding: 'utf8' }, + ); + + expect(result.status).toBe(0); + expect(result.stdout).toBe('9.8.7\n'); + expect(result.stderr).toBe(''); + }); + + it('loads the adjacent server entry module', () => { + const fixtureDirectory = mkdtempSync(join(tmpdir(), 'codegraph-cli-')); + temporaryDirectories.push(fixtureDirectory); + mkdirSync(join(fixtureDirectory, 'bin')); + mkdirSync(join(fixtureDirectory, 'server')); + copyFileSync( + join(packageDirectory, 'bin', 'codegraph-mcp.mjs'), + join(fixtureDirectory, 'bin', 'codegraph-mcp.mjs'), + ); + writeFileSync( + join(fixtureDirectory, 'package.json'), + JSON.stringify({ name: 'codegraph-mcp', version: '9.8.7', type: 'module' }), + ); + writeFileSync( + join(fixtureDirectory, 'server', 'index.mjs'), + "process.stderr.write('fixture server loaded\\n');\n", + ); + + const result = spawnSync( + process.execPath, + [join(fixtureDirectory, 'bin', 'codegraph-mcp.mjs')], + { encoding: 'utf8' }, + ); + + expect(result.status).toBe(0); + expect(result.stdout).toBe(''); + expect(result.stderr).toBe('fixture server loaded\n'); + }); +}); diff --git a/packages/npm-package/__tests__/package-metadata.test.ts b/packages/npm-package/__tests__/package-metadata.test.ts new file mode 100644 index 00000000..b3651a71 --- /dev/null +++ b/packages/npm-package/__tests__/package-metadata.test.ts @@ -0,0 +1,127 @@ +import { describe, expect, it } from 'vitest'; +import { createPublishedManifest } from '../lib/package-metadata.mjs'; + +const packageManifest = { + name: 'codegraph-mcp', + version: '0.1.0', + description: 'CodeGraph MCP Server', + type: 'module', + bin: { 'codegraph-mcp': 'bin/codegraph-mcp.mjs' }, + keywords: ['mcp', 'code-search'], + author: { name: 'Randy Wilson' }, + license: 'MIT', + homepage: 'https://v0-landing-page-build-kappa-virid.vercel.app', + repository: { + type: 'git', + url: 'git+https://github.com/Phoenixrr2113/codebase-graph.git', + }, + bugs: { url: 'https://github.com/Phoenixrr2113/codebase-graph/issues' }, + publishConfig: { access: 'public', provenance: true }, + engines: { node: '>=20.0.0' }, + scripts: { build: 'node build.mjs', postinstall: 'node postinstall.mjs' }, +}; + +const dependencyManifests = { + '@codegraph/mcp-server': { + name: '@codegraph/mcp-server', + dependencies: { '@modelcontextprotocol/sdk': '^1.30.0' }, + }, + '@codegraph/plugin-nlp': { + name: '@codegraph/plugin-nlp', + dependencies: { '@huggingface/transformers': '^3.8.1' }, + }, + '@codegraph/plugin-go': { + name: '@codegraph/plugin-go', + dependencies: { 'tree-sitter': '^0.22.4', 'tree-sitter-go': '^0.23.4' }, + }, + '@codegraph/plugin-python': { + name: '@codegraph/plugin-python', + dependencies: { 'tree-sitter-python': '^0.21.0' }, + }, + '@codegraph/plugin-rust': { + name: '@codegraph/plugin-rust', + dependencies: { 'tree-sitter-rust': '0.23.1' }, + }, + '@codegraph/plugin-typescript': { + name: '@codegraph/plugin-typescript', + dependencies: { 'tree-sitter-typescript': '^0.23.2' }, + }, + '@codegraph/plugin-languages': { + name: '@codegraph/plugin-languages', + dependencies: { + 'tree-sitter-c-sharp': '^0.21.3', + 'tree-sitter-java': '^0.23.5', + 'tree-sitter-php': '^0.23.12', + }, + optionalDependencies: { 'tree-sitter-bash': '^0.23.3' }, + }, + '@codegraph/graph': { + name: '@codegraph/graph', + devDependencies: { falkordblite: '^0.2.0' }, + optionalDependencies: { + '@falkordblite/darwin-arm64': '8.2.3-falkordb.4.16.3', + '@falkordblite/linux-x64': '8.2.3-falkordb.4.16.3', + }, + }, +}; + +describe('createPublishedManifest', () => { + it('preserves canonical public metadata and removes build hooks', () => { + const manifest = createPublishedManifest({ packageManifest, dependencyManifests }); + + expect(manifest).toMatchObject({ + name: 'codegraph-mcp', + version: '0.1.0', + description: 'CodeGraph MCP Server', + license: 'MIT', + homepage: packageManifest.homepage, + repository: packageManifest.repository, + bugs: packageManifest.bugs, + publishConfig: { access: 'public' }, + bin: { 'codegraph-mcp': 'bin/codegraph-mcp.mjs' }, + engines: packageManifest.engines, + keywords: packageManifest.keywords, + }); + expect(manifest.scripts).toBeUndefined(); + expect(manifest.publishConfig).not.toHaveProperty('provenance'); + }); + + it('publishes runtime and native dependencies without workspace ranges', () => { + const manifest = createPublishedManifest({ packageManifest, dependencyManifests }); + + expect(manifest.dependencies).toMatchObject({ + '@huggingface/transformers': '^3.8.1', + '@modelcontextprotocol/sdk': '^1.30.0', + 'tree-sitter': '^0.22.4', + 'tree-sitter-go': '^0.23.4', + 'tree-sitter-python': '^0.21.0', + 'tree-sitter-rust': '0.23.1', + 'tree-sitter-typescript': '^0.23.2', + 'tree-sitter-c-sharp': '^0.21.3', + 'tree-sitter-java': '^0.23.5', + 'tree-sitter-php': '^0.23.12', + }); + expect(manifest.optionalDependencies).toMatchObject({ + '@falkordblite/darwin-arm64': '8.2.3-falkordb.4.16.3', + '@falkordblite/linux-x64': '8.2.3-falkordb.4.16.3', + falkordblite: '^0.2.0', + 'tree-sitter-bash': '^0.23.3', + }); + expect(JSON.stringify(manifest)).not.toContain('workspace:'); + }); + + it('names a missing dependency in validation errors', () => { + const missingSdk = { + ...dependencyManifests, + '@codegraph/mcp-server': { + name: '@codegraph/mcp-server', + dependencies: {}, + }, + }; + + expect(() => createPublishedManifest({ + packageManifest, + dependencyManifests: missingSdk, + })).toThrow('@modelcontextprotocol/sdk'); + }); +}); diff --git a/packages/npm-package/bin/codegraph-mcp.mjs b/packages/npm-package/bin/codegraph-mcp.mjs index 1fed5225..a2b42330 100644 --- a/packages/npm-package/bin/codegraph-mcp.mjs +++ b/packages/npm-package/bin/codegraph-mcp.mjs @@ -1,27 +1,49 @@ #!/usr/bin/env node /** - * CodeGraph MCP Server — CLI entry point + * CodeGraph MCP Server CLI entry point * * Usage: * codegraph-mcp # start MCP server (stdio transport) - * npx @codegraph/mcp # run without global install + * npx codegraph-mcp # run without global install * * Environment: - * CODEGRAPH_LICENSE — License key (required, purchase at polar.sh/codegraph) - * VOYAGE_API_KEY — Voyage AI API key (for embeddings) - * JINA_API_KEY — Jina AI API key (for reranking) - * CODEGRAPH_DRIVER — Database driver: falkordb (default) or falkordblite - * CODEGRAPH_DB_PATH — Database path for falkordblite (default: .codegraph/falkordb) + * CODEGRAPH_EMBEDDING_PROVIDER Embedding provider or "none" for offline mode + * CODEGRAPH_DRIVER Database driver: falkordb or falkordblite + * CODEGRAPH_DB_PATH Database path for falkordblite */ -import { fileURLToPath } from 'node:url'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { dirname, join } from 'node:path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const serverPath = join(__dirname, '..', 'server', 'index.mjs'); -// Force logs to stderr (MCP stdio requires clean stdout) -process.env.CODEGRAPH_LOG_STDERR = 'true'; +function readPackageVersion() { + const manifest = JSON.parse( + readFileSync(new URL('../package.json', import.meta.url), 'utf8'), + ); + if ( + typeof manifest !== 'object' || + manifest === null || + manifest.name !== 'codegraph-mcp' || + typeof manifest.version !== 'string' + ) { + throw new Error('invalid package manifest'); + } + return manifest.version; +} -// Import and run -await import(serverPath); +if (process.argv.includes('--version') || process.argv.includes('-v')) { + try { + process.stdout.write(`${readPackageVersion()}\n`); + } catch { + process.stderr.write('codegraph-mcp: unable to read package version\n'); + process.exitCode = 1; + } +} else { + // MCP stdio reserves stdout for protocol messages. + process.env.CODEGRAPH_LOG_STDERR = 'true'; + + await import(pathToFileURL(serverPath).href); +} diff --git a/packages/npm-package/build.mjs b/packages/npm-package/build.mjs index b2f45333..a779bdf7 100644 --- a/packages/npm-package/build.mjs +++ b/packages/npm-package/build.mjs @@ -1,127 +1,129 @@ #!/usr/bin/env node -/** - * Build script for CodeGraph npm distribution package. - * - * Reuses the MCPB esbuild pipeline (packages/mcpb/build.mjs) to produce - * a bundled server, then packages it for npm publishing. - * - * Run from repo root: node packages/npm-package/build.mjs - * Or: pnpm build:npm - */ - -import { cpSync, mkdirSync, rmSync, existsSync, readFileSync, writeFileSync, chmodSync } from 'node:fs'; -import { resolve, dirname } from 'node:path'; + +import { + chmodSync, + cpSync, + existsSync, + mkdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { execSync } from 'node:child_process'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const ROOT = resolve(__dirname, '../..'); -const MCPB_DIST = resolve(ROOT, 'packages/mcpb/dist'); -const NPM_DIST = resolve(__dirname, 'dist'); - -// Step 1: Ensure MCPB is built (reuse its bundling) -const mcpbBundle = resolve(MCPB_DIST, 'server/index.mjs'); -if (!existsSync(mcpbBundle)) { - console.log('MCPB bundle not found — building first...'); - execSync('node packages/mcpb/build.mjs', { cwd: ROOT, stdio: 'inherit' }); +import { build } from 'esbuild'; +import { createPublishedManifest } from './lib/package-metadata.mjs'; + +const packageDirectory = dirname(fileURLToPath(import.meta.url)); +const rootDirectory = resolve(packageDirectory, '../..'); +const outputDirectory = resolve(packageDirectory, 'dist'); +const serverEntry = resolve(rootDirectory, 'packages/mcp-server/dist/index.js'); + +function readManifest(relativePath) { + const path = resolve(rootDirectory, relativePath); + const parsed = JSON.parse(readFileSync(path, 'utf8')); + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + throw new TypeError(`${relativePath} must contain a JSON object`); + } + return parsed; } -// Step 2: Clean and create npm dist -if (existsSync(NPM_DIST)) rmSync(NPM_DIST, { recursive: true }); -mkdirSync(resolve(NPM_DIST, 'server'), { recursive: true }); -mkdirSync(resolve(NPM_DIST, 'bin'), { recursive: true }); - -// Step 3: Copy bundled server + native modules from MCPB -cpSync(resolve(MCPB_DIST, 'server'), resolve(NPM_DIST, 'server'), { recursive: true }); -console.log('Copied bundled server from MCPB build'); - -// Step 4: Copy bin entry point -cpSync(resolve(__dirname, 'bin/codegraph-mcp.mjs'), resolve(NPM_DIST, 'bin/codegraph-mcp.mjs')); -chmodSync(resolve(NPM_DIST, 'bin/codegraph-mcp.mjs'), 0o755); - -// Step 5: Copy package files -cpSync(resolve(__dirname, 'postinstall.mjs'), resolve(NPM_DIST, 'postinstall.mjs')); - -// Step 6: Create package.json for publishing (read from source, adjust paths) -const pkgSource = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf-8')); -// Remove build script from published package -delete pkgSource.scripts.build; -writeFileSync(resolve(NPM_DIST, 'package.json'), JSON.stringify(pkgSource, null, 2)); - -// Step 7: Create LICENSE -writeFileSync(resolve(NPM_DIST, 'LICENSE'), `CodeGraph Commercial License - -Copyright (c) ${new Date().getFullYear()} Randy Wilson. All rights reserved. - -This software is licensed, not sold. You must purchase a valid license key -from https://polar.sh/codegraph to use this software. - -Unauthorized copying, redistribution, or reverse engineering of this -software is prohibited. - -For licensing inquiries, contact: support@codegraph.dev -`); - -// Step 8: Create README -writeFileSync(resolve(NPM_DIST, 'README.md'), `# CodeGraph MCP Server - -Index any codebase into a graph database. Search by meaning, trace relationships, and manage project knowledge. +if (!existsSync(serverEntry)) { + throw new Error( + 'Missing packages/mcp-server/dist/index.js. Build workspace packages before creating the npm distribution.', + ); +} -## Installation +const packageManifest = readManifest('packages/npm-package/package.json'); +const dependencyManifests = Object.fromEntries( + [ + 'packages/mcp-server/package.json', + 'packages/plugin-nlp/package.json', + 'packages/plugin-go/package.json', + 'packages/plugin-python/package.json', + 'packages/plugin-rust/package.json', + 'packages/plugin-typescript/package.json', + 'packages/plugin-languages/package.json', + 'packages/graph/package.json', + ].map((path) => { + const manifest = readManifest(path); + if (typeof manifest.name !== 'string') { + throw new TypeError(`${path} must define a package name`); + } + return [manifest.name, manifest]; + }), +); +const publishedManifest = createPublishedManifest({ packageManifest, dependencyManifests }); +const externalPackages = [ + ...Object.keys(publishedManifest.dependencies), + ...Object.keys(publishedManifest.optionalDependencies), +]; + +rmSync(outputDirectory, { recursive: true, force: true }); +mkdirSync(resolve(outputDirectory, 'server'), { recursive: true }); +mkdirSync(resolve(outputDirectory, 'bin'), { recursive: true }); + +await build({ + entryPoints: [serverEntry], + outfile: resolve(outputDirectory, 'server/index.mjs'), + bundle: true, + platform: 'node', + target: 'node20', + format: 'esm', + sourcemap: false, + conditions: ['import', 'node'], + banner: { + js: 'import { createRequire as __bundleRequire } from "node:module"; const require = __bundleRequire(import.meta.url);', + }, + external: externalPackages, + logLevel: 'info', +}); + +const binSource = resolve(packageDirectory, 'bin/codegraph-mcp.mjs'); +const binDestination = resolve(outputDirectory, 'bin/codegraph-mcp.mjs'); +cpSync(binSource, binDestination); +chmodSync(binDestination, 0o755); +cpSync(resolve(rootDirectory, 'LICENSE'), resolve(outputDirectory, 'LICENSE')); + +writeFileSync( + resolve(outputDirectory, 'package.json'), + `${JSON.stringify(publishedManifest, null, 2)}\n`, +); +writeFileSync( + resolve(outputDirectory, 'README.md'), + `# CodeGraph MCP Server + +Index code into a graph and expose search, knowledge, codebase, and Cypher tools through the Model Context Protocol. + +## Install \`\`\`bash -npm install -g @codegraph/mcp +npm install --global codegraph-mcp \`\`\` -## Quick Start - -1. Get a license key at [polar.sh/codegraph](https://polar.sh/codegraph) -2. Get API keys from [Voyage AI](https://dash.voyageai.com) and [Jina AI](https://jina.ai) -3. Add to your \`.mcp.json\`: - -\`\`\`json -{ - "mcpServers": { - "codegraph": { - "command": "codegraph-mcp", - "env": { - "CODEGRAPH_LICENSE": "your-license-key", - "VOYAGE_API_KEY": "your-voyage-key", - "JINA_API_KEY": "your-jina-key" - } - } - } -} -\`\`\` +Then configure an MCP client to run \`codegraph-mcp\`. The server uses stdio and keeps logs on stderr. -## Tools +## Offline start -- **search** — Find code by meaning (vector + cross-encoder reranking) -- **knowledge** — Store and recall project knowledge -- **codebase** — Index management, status, source reading -- **query** — Raw Cypher queries against the code graph +\`\`\`bash +CODEGRAPH_EMBEDDING_PROVIDER=none codegraph-mcp +\`\`\` -## Features +This structural-search mode requires no API keys. Embedded FalkorDBLite is available on Linux x64. Apple silicon macOS also requires Homebrew \`libomp\` and \`openssl@3\`; CodeGraph falls back to external FalkorDB when they are absent. Other platforms require an external FalkorDB service. -- 42+ languages via Tree-sitter -- Vector search with cross-encoder reranking (94.4% MRR) -- FalkorDB graph database (Docker or embedded) -- Knowledge graph for storing project context +## Project links -## Docs +- [Source and quickstart](https://github.com/Phoenixrr2113/codebase-graph#install-from-source) +- [MCP client setup](https://github.com/Phoenixrr2113/codebase-graph#use-with-an-mcp-client) +- [Configuration and environment variables](https://github.com/Phoenixrr2113/codebase-graph#configuration) +- [Issue tracker](https://github.com/Phoenixrr2113/codebase-graph/issues) +- [Web app](https://v0-landing-page-build-kappa-virid.vercel.app) -[codegraph.dev/docs](https://codegraph.dev/docs) -`); +## License -// Report -const serverSize = readFileSync(resolve(NPM_DIST, 'server/index.mjs')).length; -const nmSize = execSync(`du -sh ${resolve(NPM_DIST, 'server/node_modules')} 2>/dev/null || echo "0\t-"`) - .toString().trim().split('\t')[0]; +MIT +`, +); -console.log(`\n✅ npm package built!`); -console.log(` Bundle: ${(serverSize / 1024 / 1024).toFixed(1)} MB`); -console.log(` Native modules: ${nmSize}`); -console.log(` Output: ${NPM_DIST}`); -console.log(`\nTo publish:`); -console.log(` cd ${NPM_DIST}`); -console.log(` npm publish --access public`); +const bundleBytes = readFileSync(resolve(outputDirectory, 'server/index.mjs')).byteLength; +console.log(`Built codegraph-mcp staging directory (${(bundleBytes / 1024 / 1024).toFixed(1)} MB bundle).`); diff --git a/packages/npm-package/lib/package-metadata.mjs b/packages/npm-package/lib/package-metadata.mjs new file mode 100644 index 00000000..3ce5442c --- /dev/null +++ b/packages/npm-package/lib/package-metadata.mjs @@ -0,0 +1,123 @@ +const dependencySources = [ + ['@huggingface/transformers', '@codegraph/plugin-nlp', 'dependencies'], + ['@modelcontextprotocol/sdk', '@codegraph/mcp-server', 'dependencies'], + ['tree-sitter', '@codegraph/plugin-go', 'dependencies'], + ['tree-sitter-go', '@codegraph/plugin-go', 'dependencies'], + ['tree-sitter-python', '@codegraph/plugin-python', 'dependencies'], + ['tree-sitter-rust', '@codegraph/plugin-rust', 'dependencies'], + ['tree-sitter-typescript', '@codegraph/plugin-typescript', 'dependencies'], + ['tree-sitter-c-sharp', '@codegraph/plugin-languages', 'dependencies'], + ['tree-sitter-java', '@codegraph/plugin-languages', 'dependencies'], + ['tree-sitter-php', '@codegraph/plugin-languages', 'dependencies'], +]; + +const embeddedPlatformPackages = [ + '@falkordblite/darwin-arm64', + '@falkordblite/linux-x64', +]; + +function requireRecord(value, label) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new TypeError(`${label} must be an object`); + } + return value; +} + +function requireString(record, key, label) { + const value = record[key]; + if (typeof value !== 'string' || value.length === 0) { + throw new TypeError(`${label}.${key} must be a non-empty string`); + } + return value; +} + +function requireManifest(manifests, packageName) { + const manifest = requireRecord(manifests[packageName], `dependencyManifests.${packageName}`); + if (requireString(manifest, 'name', packageName) !== packageName) { + throw new TypeError(`${packageName}.name must match its workspace key`); + } + return manifest; +} + +function requireDependencyRange(manifests, dependencyName, packageName, sectionName) { + const manifest = requireManifest(manifests, packageName); + const section = requireRecord(manifest[sectionName], `${packageName}.${sectionName}`); + const range = section[dependencyName]; + if (typeof range !== 'string' || range.length === 0 || range.startsWith('workspace:')) { + throw new TypeError(`${packageName} must provide a publishable ${dependencyName} range`); + } + return range; +} + +function cloneRecord(record, key, label) { + return structuredClone(requireRecord(record[key], `${label}.${key}`)); +} + +function sortedRecord(entries) { + return Object.fromEntries([...entries].sort(([left], [right]) => left.localeCompare(right))); +} + +export function createPublishedManifest({ packageManifest, dependencyManifests }) { + const source = requireRecord(packageManifest, 'packageManifest'); + const manifests = requireRecord(dependencyManifests, 'dependencyManifests'); + const dependencies = new Map(); + + for (const [dependencyName, packageName, sectionName] of dependencySources) { + dependencies.set( + dependencyName, + requireDependencyRange(manifests, dependencyName, packageName, sectionName), + ); + } + + const languageManifest = requireManifest(manifests, '@codegraph/plugin-languages'); + const languageOptionals = requireRecord( + languageManifest.optionalDependencies, + '@codegraph/plugin-languages.optionalDependencies', + ); + const optionalDependencies = new Map(); + for (const [name, range] of Object.entries(languageOptionals)) { + if (typeof range !== 'string' || range.length === 0 || range.startsWith('workspace:')) { + throw new TypeError(`@codegraph/plugin-languages must provide a publishable ${name} range`); + } + optionalDependencies.set(name, range); + } + optionalDependencies.set( + 'falkordblite', + requireDependencyRange(manifests, 'falkordblite', '@codegraph/graph', 'devDependencies'), + ); + for (const packageName of embeddedPlatformPackages) { + optionalDependencies.set( + packageName, + requireDependencyRange(manifests, packageName, '@codegraph/graph', 'optionalDependencies'), + ); + } + + const name = requireString(source, 'name', 'packageManifest'); + if (name !== 'codegraph-mcp') { + throw new TypeError('packageManifest.name must be codegraph-mcp'); + } + const publishConfig = cloneRecord(source, 'publishConfig', 'packageManifest'); + if (publishConfig.access !== 'public') { + throw new TypeError('packageManifest.publishConfig.access must be public'); + } + + return { + name, + version: requireString(source, 'version', 'packageManifest'), + description: requireString(source, 'description', 'packageManifest'), + type: 'module', + main: './server/index.mjs', + bin: cloneRecord(source, 'bin', 'packageManifest'), + keywords: structuredClone(source.keywords), + author: cloneRecord(source, 'author', 'packageManifest'), + license: requireString(source, 'license', 'packageManifest'), + homepage: requireString(source, 'homepage', 'packageManifest'), + repository: cloneRecord(source, 'repository', 'packageManifest'), + bugs: cloneRecord(source, 'bugs', 'packageManifest'), + publishConfig: { access: 'public' }, + engines: cloneRecord(source, 'engines', 'packageManifest'), + files: ['bin/', 'server/', 'LICENSE', 'README.md'], + dependencies: sortedRecord(dependencies), + optionalDependencies: sortedRecord(optionalDependencies), + }; +} diff --git a/packages/npm-package/package.json b/packages/npm-package/package.json index 46cad5d7..8cfbe378 100644 --- a/packages/npm-package/package.json +++ b/packages/npm-package/package.json @@ -1,15 +1,15 @@ { - "name": "@codegraph/mcp", + "name": "codegraph-mcp", "version": "0.1.0", - "description": "CodeGraph MCP Server — Index any codebase into a graph database. Search by meaning, trace relationships, and manage project knowledge.", + "description": "CodeGraph MCP Server: Index any codebase into a graph database. Search by meaning, trace relationships, and manage project knowledge.", "type": "module", "bin": { - "codegraph-mcp": "./bin/codegraph-mcp.mjs" + "codegraph-mcp": "bin/codegraph-mcp.mjs" }, "main": "./server/index.mjs", "scripts": { "build": "node build.mjs", - "postinstall": "node postinstall.mjs || true" + "test": "vitest run" }, "keywords": [ "mcp", @@ -24,13 +24,19 @@ ], "author": { "name": "Randy Wilson", - "url": "https://codegraph.dev" + "url": "https://github.com/Phoenixrr2113" }, - "license": "SEE LICENSE IN LICENSE", - "homepage": "https://codegraph.dev", + "license": "MIT", + "homepage": "https://v0-landing-page-build-kappa-virid.vercel.app", "repository": { "type": "git", - "url": "https://github.com/randywilson/codegraph" + "url": "git+https://github.com/Phoenixrr2113/codebase-graph.git" + }, + "bugs": { + "url": "https://github.com/Phoenixrr2113/codebase-graph/issues" + }, + "publishConfig": { + "access": "public" }, "engines": { "node": ">=20.0.0" @@ -39,7 +45,11 @@ "bin/", "server/", "LICENSE", - "README.md", - "postinstall.mjs" - ] + "README.md" + ], + "devDependencies": { + "@codegraph/mcp-server": "workspace:*", + "esbuild": "^0.27.7", + "vitest": "^3.2.4" + } } diff --git a/packages/npm-package/postinstall.mjs b/packages/npm-package/postinstall.mjs deleted file mode 100644 index 73a97de8..00000000 --- a/packages/npm-package/postinstall.mjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node -/** - * Post-install script — prints setup instructions after npm install. - */ - -const message = ` -╔══════════════════════════════════════════════════════════════╗ -║ CodeGraph MCP Server ║ -╠══════════════════════════════════════════════════════════════╣ -║ ║ -║ 1. Get a license key at https://polar.sh/codegraph ║ -║ 2. Get API keys: ║ -║ - Voyage AI: https://dash.voyageai.com (embeddings) ║ -║ - Jina AI: https://jina.ai (reranking) ║ -║ 3. Add to your .mcp.json: ║ -║ ║ -║ { ║ -║ "mcpServers": { ║ -║ "codegraph": { ║ -║ "command": "codegraph-mcp", ║ -║ "env": { ║ -║ "CODEGRAPH_LICENSE": "your-key", ║ -║ "VOYAGE_API_KEY": "your-key", ║ -║ "JINA_API_KEY": "your-key" ║ -║ } ║ -║ } ║ -║ } ║ -║ } ║ -║ ║ -║ Docs: https://codegraph.dev/docs ║ -║ ║ -╚══════════════════════════════════════════════════════════════╝ -`; - -console.log(message); diff --git a/packages/npm-package/vitest.config.ts b/packages/npm-package/vitest.config.ts new file mode 100644 index 00000000..168aefc2 --- /dev/null +++ b/packages/npm-package/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['__tests__/**/*.test.ts'], + }, +}); diff --git a/packages/plugin-common/package.json b/packages/plugin-common/package.json index cad090f4..d84e0733 100644 --- a/packages/plugin-common/package.json +++ b/packages/plugin-common/package.json @@ -16,14 +16,14 @@ "dev": "tsc --watch", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", - "test": "vitest" + "test": "vitest run --root . --config ../../vitest.package.config.ts" }, "dependencies": { "@codegraph/types": "workspace:*" }, "devDependencies": { "tree-sitter": "^0.22.4", - "tree-sitter-c-sharp": "^0.23.5", + "tree-sitter-c-sharp": "^0.21.3", "tree-sitter-go": "^0.23.4", "tree-sitter-java": "^0.23.5", "tree-sitter-php": "^0.23.12", diff --git a/packages/plugin-go/package.json b/packages/plugin-go/package.json index d39e790b..af476d22 100644 --- a/packages/plugin-go/package.json +++ b/packages/plugin-go/package.json @@ -16,7 +16,7 @@ "dev": "tsc --watch", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", - "test": "vitest run" + "test": "vitest run --root . --config ../../vitest.package.config.ts" }, "dependencies": { "@codegraph/logger": "workspace:*", diff --git a/packages/plugin-languages/package.json b/packages/plugin-languages/package.json index ecb549c4..27e95fdc 100644 --- a/packages/plugin-languages/package.json +++ b/packages/plugin-languages/package.json @@ -1,7 +1,7 @@ { "name": "@codegraph/plugin-languages", "version": "0.1.0", - "description": "Tier-2 language plugins for CodeGraph — config-only definitions with lazy-loaded grammars", + "description": "Tier-2 language plugins for CodeGraph: config-only definitions with lazy-loaded grammars", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -16,7 +16,7 @@ "dev": "tsc --watch", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", - "test": "vitest run --passWithNoTests" + "test": "vitest run --root . --config ../../vitest.package.config.ts" }, "dependencies": { "@codegraph/plugin-common": "workspace:*", diff --git a/packages/plugin-languages/src/__tests__/registration-concurrency.test.ts b/packages/plugin-languages/src/__tests__/registration-concurrency.test.ts new file mode 100644 index 00000000..4625ff5e --- /dev/null +++ b/packages/plugin-languages/src/__tests__/registration-concurrency.test.ts @@ -0,0 +1,51 @@ +import type { LanguagePlugin } from '@codegraph/types'; +import { describe, expect, it, vi } from 'vitest'; + +const grammarLoaderMock = vi.hoisted(() => ({ + clearGrammarCache: vi.fn(), + loadGrammar: vi.fn(), +})); + +vi.mock('../grammar-loader', () => grammarLoaderMock); + +import { allLanguageEntries, registerAllLanguages } from '../index'; + +class MockRegistry { + readonly registered: LanguagePlugin[] = []; + + register(plugin: LanguagePlugin): void { + this.registered.push(plugin); + } +} + +describe('registerAllLanguages concurrency', () => { + it('starts grammar loads concurrently while preserving registration order', async () => { + let startedLoads = 0; + let releaseLoads: (() => void) | undefined; + const loadersCanFinish = new Promise((resolve) => { + releaseLoads = resolve; + }); + + grammarLoaderMock.loadGrammar.mockImplementation(async (grammarPackage: string) => { + startedLoads += 1; + if (startedLoads === 2) releaseLoads?.(); + await loadersCanFinish; + + return grammarPackage === 'tree-sitter-php' ? { php: {} } : {}; + }); + + const registry = new MockRegistry(); + const registration = registerAllLanguages(registry); + + try { + expect(startedLoads).toBe(allLanguageEntries.length); + } finally { + releaseLoads?.(); + await registration; + } + + const result = await registration; + expect(result.registered).toEqual(allLanguageEntries.map((entry) => entry.config.id)); + expect(registry.registered.map((plugin) => plugin.id)).toEqual(result.registered); + }); +}); diff --git a/packages/plugin-languages/src/__tests__/registration.test.ts b/packages/plugin-languages/src/__tests__/registration.test.ts index 44395d22..3ef2b27a 100644 --- a/packages/plugin-languages/src/__tests__/registration.test.ts +++ b/packages/plugin-languages/src/__tests__/registration.test.ts @@ -6,6 +6,8 @@ import { registerAllLanguages, registerLanguage, allLanguageEntries } from '../i import { clearGrammarCache } from '../grammar-loader'; import type { LanguagePlugin } from '@codegraph/types'; +const COLD_GRAMMAR_IMPORT_TIMEOUT_MS = 30_000; + /** Mock registry that tracks registrations */ class MockRegistry { registered: LanguagePlugin[] = []; @@ -21,7 +23,7 @@ describe('Language Registration', () => { }); describe('registerAllLanguages()', () => { - it('should return registered and skipped arrays', async () => { + it('should return registered and skipped arrays', { timeout: COLD_GRAMMAR_IMPORT_TIMEOUT_MS }, async () => { const registry = new MockRegistry(); const result = await registerAllLanguages(registry); @@ -34,7 +36,7 @@ describe('Language Registration', () => { ); }); - it('should skip languages with unavailable grammars', async () => { + it('should skip languages with unavailable grammars', { timeout: COLD_GRAMMAR_IMPORT_TIMEOUT_MS }, async () => { const registry = new MockRegistry(); const result = await registerAllLanguages(registry); @@ -43,7 +45,7 @@ describe('Language Registration', () => { expect(result.skipped.length).toBeGreaterThan(0); }); - it('should register plugins in the provided registry', async () => { + it('should register plugins in the provided registry', { timeout: COLD_GRAMMAR_IMPORT_TIMEOUT_MS }, async () => { const registry = new MockRegistry(); const result = await registerAllLanguages(registry); diff --git a/packages/plugin-languages/src/index.ts b/packages/plugin-languages/src/index.ts index b6ad666f..f6423594 100644 --- a/packages/plugin-languages/src/index.ts +++ b/packages/plugin-languages/src/index.ts @@ -167,8 +167,15 @@ export async function registerAllLanguages(registry: PluginRegistry): Promise<{ const registered: string[] = []; const skipped: string[] = []; - for (const entry of allLanguageEntries) { - let grammar = await loadGrammar(entry.grammarPackage); + const loadedEntries = await Promise.all( + allLanguageEntries.map(async (entry) => ({ + entry, + grammar: await loadGrammar(entry.grammarPackage), + })) + ); + + for (const { entry, grammar: loadedGrammar } of loadedEntries) { + let grammar = loadedGrammar; if (grammar && entry.grammarTransform) grammar = entry.grammarTransform(grammar); if (grammar) { diff --git a/packages/plugin-nlp/package.json b/packages/plugin-nlp/package.json index 083d975e..70f59cd5 100644 --- a/packages/plugin-nlp/package.json +++ b/packages/plugin-nlp/package.json @@ -15,7 +15,9 @@ "scripts": { "build": "tsc", "dev": "tsc --watch", - "test": "vitest", + "test": "vitest run", + "test:integration": "vitest run --config vitest.integration.config.ts", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist" }, "dependencies": { @@ -35,6 +37,6 @@ "@types/node": "^22.19.19", "@types/pdf-parse": "^1.1.5", "typescript": "^5.9.3", - "vitest": "^4.1.7" + "vitest": "^3.2.4" } } diff --git a/packages/plugin-nlp/src/__tests__/bridge-linker-embedding.test.ts b/packages/plugin-nlp/src/__tests__/bridge-linker-embedding.test.ts index 2b2c4dbe..42472340 100644 --- a/packages/plugin-nlp/src/__tests__/bridge-linker-embedding.test.ts +++ b/packages/plugin-nlp/src/__tests__/bridge-linker-embedding.test.ts @@ -1,5 +1,5 @@ /** - * Bridge-Linker Embedding Similarity — Focused Unit Tests + * Bridge-Linker Embedding Similarity: Focused Unit Tests * * Spec reference: docs/superpowers/specs/2026-04-27-pre-benchmark-fixes-design.md §4.7 * @@ -20,7 +20,7 @@ * node types). Scenario 3 from the spec is documented here as a gap test that * asserts the current behavior (1 edge), not the spec's hoped-for behavior (K edges). * - * Uses vi.mock to control embeddings — no real embedding model needed. + * Uses vi.mock to control embeddings: no real embedding model needed. * Uses FalkorDB Docker for graph storage. Requires: docker compose up -d falkordb */ @@ -86,12 +86,12 @@ describe('Bridge-Linker Embedding Similarity', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: process.env['FALKORDB_HOST'] ?? 'localhost', + port: Number(process.env['FALKORDB_PORT'] ?? '6379'), graphName: GRAPH_NAME, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailable = false; return; } @@ -109,7 +109,7 @@ describe('Bridge-Linker Embedding Similarity', () => { loc: 100, lastModified: '2025-01-01', hash: 'pay001', }); - // Payment cluster — dim 0 + // Payment cluster: dim 0 await ops.upsertFunction({ name: 'processPayment', filePath: '/src/payments.ts', startLine: 1, endLine: 20, @@ -121,7 +121,7 @@ describe('Bridge-Linker Embedding Similarity', () => { isExported: true, isAsync: false, isArrow: false, params: [], }); - // Chart cluster — dim 1 + // Chart cluster: dim 1 await ops.upsertFunction({ name: 'renderChart', filePath: '/src/payments.ts', startLine: 42, endLine: 60, @@ -160,7 +160,7 @@ describe('Bridge-Linker Embedding Similarity', () => { beforeEach(async (ctx) => { if (!falkordbAvailable) { - ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); return; } // Remove all Entity nodes and ABOUT edges between tests @@ -219,7 +219,7 @@ describe('Bridge-Linker Embedding Similarity', () => { }); const result = await linkByEmbedding(client, kg, { - threshold: 0.99, // very high — nothing will match + threshold: 0.99, // very high: nothing will match force: true, }); @@ -242,7 +242,7 @@ describe('Bridge-Linker Embedding Similarity', () => { // Entity "payment work" is in the middle of the payment cluster await kg.createEntity({ text: 'payment work', type: 'Task', confidence: 0.9 }); - // Mock: embedding near dim 0 — both processPayment and validatePayment are candidates + // Mock: embedding near dim 0: both processPayment and validatePayment are candidates vi.mocked(generateEmbedding).mockResolvedValue({ embedding: makeVec(0, 0.92), dimensions: DIM, @@ -261,7 +261,7 @@ describe('Bridge-Linker Embedding Similarity', () => { }); // ========================================================================== - // Scenario 4 / 5: Threshold tuning — lower threshold → more edges + // Scenario 4 / 5: Threshold tuning: lower threshold → more edges // ========================================================================== it('lowering threshold from 0.99 to 0.7 increases linked edge count', async () => { @@ -275,7 +275,7 @@ describe('Bridge-Linker Embedding Similarity', () => { callCount++; const dim = callCount % 2 === 1 ? 0 : 1; return { - embedding: makeVec(dim, 0.93), + embedding: mixedVec(dim, 0.9, 100, 0.4358898943540673), dimensions: DIM, provider: 'test', }; @@ -297,7 +297,7 @@ describe('Bridge-Linker Embedding Similarity', () => { }); // ========================================================================== - // Scenario 6: Skip-list — Person/Organization/etc. are not linked + // Scenario 6: Skip-list: Person/Organization/etc. are not linked // ========================================================================== it('respects the skip-list: Person, Organization, Event, Document, and similar types are not linked', async () => { @@ -315,7 +315,7 @@ describe('Bridge-Linker Embedding Similarity', () => { }); const result = await linkByEmbedding(client, kg, { - threshold: 0.5, // very permissive — would match if not skipped + threshold: 0.5, // very permissive: would match if not skipped force: true, }); diff --git a/packages/plugin-nlp/src/__tests__/bridge-linker.test.ts b/packages/plugin-nlp/src/__tests__/bridge-linker.test.ts index ae58c681..43d67721 100644 --- a/packages/plugin-nlp/src/__tests__/bridge-linker.test.ts +++ b/packages/plugin-nlp/src/__tests__/bridge-linker.test.ts @@ -1,5 +1,5 @@ /** - * Bridge Linker — Integration Tests + * Bridge Linker: Integration Tests * * Tests auto-creation of ABOUT edges from knowledge entities to code graph nodes * via name matching. Runs against FalkorDB Docker. @@ -90,7 +90,7 @@ describe('Bridge Linker (name matching)', () => { graphName: TEST_GRAPH, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailableNameMatching = false; return; } @@ -129,7 +129,7 @@ describe('Bridge Linker (name matching)', () => { }, 30_000); beforeEach((ctx) => { - if (!falkordbAvailableNameMatching) ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + if (!falkordbAvailableNameMatching) ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); }); afterAll(async () => { @@ -262,7 +262,7 @@ describe('Bridge Linker (name matching)', () => { expect(funcEdge!.confidence).toBe(1.0); }); - it('should create ABOUT edges that are queryable via getAboutEdgesForCodeNode', async () => { + it('should create ABOUT edges that are queryable from a code node', async () => { // Link a class entity await linkEntitiesToCode( [{ text: 'PaymentService', type: 'Technology' }], @@ -270,9 +270,14 @@ describe('Bridge Linker (name matching)', () => { kg, ); - const edges = await kg.getAboutEdgesForCodeNode('Class', 'PaymentService'); - expect(edges.length).toBeGreaterThanOrEqual(1); - expect(edges[0]!.entityText).toBe('PaymentService'); + const edges = await client.roQuery<{ entityText: string }>( + `MATCH (e:Entity)-[:ABOUT]->(target:Class) + WHERE target.name = $targetValue + RETURN e.text AS entityText`, + { params: { targetValue: 'PaymentService' } }, + ); + expect(edges.data.length).toBeGreaterThanOrEqual(1); + expect(edges.data[0]!.entityText).toBe('PaymentService'); }); // ---------- Contained match ---------- @@ -349,12 +354,12 @@ describe('Bridge Linker (embedding similarity)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: process.env['FALKORDB_HOST'] ?? 'localhost', + port: Number(process.env['FALKORDB_PORT'] ?? '6379'), graphName: GRAPH_NAME, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailableEmbedding = false; return; } @@ -382,7 +387,7 @@ describe('Bridge Linker (embedding similarity)', () => { startLine: 40, endLine: 50, isExported: true, isAsync: false, isArrow: false, params: [], }); - // Set embeddings on code nodes — "payment" cluster near dim 0, "chart" near dim 1 + // Set embeddings on code nodes: "payment" cluster near dim 0, "chart" near dim 1 const RETRY_VEC = makeVec({ 0: 0.85, 1: 0.05, 2: 0.1 }); const PAYMENT_VEC = makeVec({ 0: 0.95, 1: 0.0, 2: 0.05 }); const CHART_VEC = makeVec({ 0: 0.05, 1: 0.95, 2: 0.0 }); @@ -398,7 +403,7 @@ describe('Bridge Linker (embedding similarity)', () => { }, 30_000); beforeEach((ctx) => { - if (!falkordbAvailableEmbedding) ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + if (!falkordbAvailableEmbedding) ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); }); afterAll(async () => { @@ -461,7 +466,7 @@ describe('Bridge Linker (embedding similarity)', () => { }); const result = await linkByEmbedding(client, kg, { - threshold: 0.99, // very high threshold — nothing should match + threshold: 0.99, // very high threshold: nothing should match force: true, }); @@ -500,13 +505,7 @@ describe('Bridge Linker (embedding similarity)', () => { it('should create ABOUT edges with method=embedding_similarity', async () => { // Clean up any ABOUT edges from previous tests - const entities = await kg.searchEntities({ limit: 100 }); - for (const e of entities) { - const edges = await kg.getAboutEdgesForEntity(e.text, e.type, 100); - for (const edge of edges) { - await kg.deleteAboutEdge(e.text, e.type, edge.targetLabel, edge.targetValue); - } - } + await client.query('MATCH ()-[r:ABOUT]->() DELETE r', { params: {} }); vi.mocked(isEmbeddingAvailable).mockReturnValue(true); vi.mocked(generateEmbedding).mockResolvedValue({ diff --git a/packages/plugin-nlp/src/__tests__/conflict-resolution.test.ts b/packages/plugin-nlp/src/__tests__/conflict-resolution.test.ts index dbcf6576..554b1f5d 100644 --- a/packages/plugin-nlp/src/__tests__/conflict-resolution.test.ts +++ b/packages/plugin-nlp/src/__tests__/conflict-resolution.test.ts @@ -1,5 +1,5 @@ /** - * Temporal Conflict Resolution — Integration Tests + * Temporal Conflict Resolution: Integration Tests * * Tests the full conflict resolution pipeline (WS9): * - Contradicting facts → old invalidated, new stored @@ -91,12 +91,12 @@ describe('Temporal Conflict Resolution (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: process.env['FALKORDB_HOST'] ?? 'localhost', + port: Number(process.env['FALKORDB_PORT'] ?? '6379'), graphName: GRAPH_NAME, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailable = false; return; } @@ -107,7 +107,7 @@ describe('Temporal Conflict Resolution (FalkorDB)', () => { beforeEach(async (ctx) => { if (!falkordbAvailable) { - ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); return; } try { @@ -238,7 +238,7 @@ describe('Temporal Conflict Resolution (FalkorDB)', () => { // Mock LLM that says NO_CONTRADICTION const mockLlm = makeContradictionMock(false); - // New fact about Sarah — not contradicting + // New fact about Sarah: not contradicting const result = await checkAndResolveConflicts(ops, { headText: 'Sarah', headType: 'Person', @@ -276,7 +276,7 @@ describe('Temporal Conflict Resolution (FalkorDB)', () => { confidence: 0.9, }); - // No LLM — should return empty result + // No LLM: should return empty result const result = await checkAndResolveConflicts(ops, { headText: 'team', headType: 'Organization', @@ -303,7 +303,7 @@ describe('Temporal Conflict Resolution (FalkorDB)', () => { await ops.createEntity({ text: 'NewProject', type: 'Project', confidence: 0.9 }); await ops.createEntity({ text: 'Go', type: 'Technology', confidence: 0.9 }); - // No existing relationships — new fact is first + // No existing relationships: new fact is first const mockLlm = makeContradictionMock(true); const result = await checkAndResolveConflicts(ops, { headText: 'NewProject', @@ -353,12 +353,12 @@ describe('Temporal Conflict Resolution (FalkorDB)', () => { // Invalidate the old $50k relationship await ops.invalidateRelationship('budget', 'Concept', '$50k', 'Amount', 'IS'); - // Default recall — only valid facts + // Default recall: only valid facts const validRels = await ops.getRelationships({ entityText: 'budget' }); expect(validRels.length).toBe(1); expect(validRels[0]!.tailText).toBe('$75k'); - // History recall — all facts including invalidated + // History recall: all facts including invalidated const allRels = await ops.getRelationships({ entityText: 'budget', includeInvalidated: true, diff --git a/packages/plugin-nlp/src/__tests__/conversation.test.ts b/packages/plugin-nlp/src/__tests__/conversation.test.ts index 8b130f2f..c7d1d716 100644 --- a/packages/plugin-nlp/src/__tests__/conversation.test.ts +++ b/packages/plugin-nlp/src/__tests__/conversation.test.ts @@ -198,6 +198,17 @@ describe('Auto-detection', () => { // ============================================================================ describe('Edge cases', () => { + it('rejects an adversarial timestamp-shaped line within a bounded time', () => { + const text = '[\\] ' + ' '.repeat(40_000) + 'x'; + const startedAt = performance.now(); + + const result = chunkConversation(text); + + expect(performance.now() - startedAt).toBeLessThan(250); + expect(result.format).toBe('paragraphs'); + expect(result.episodes).toHaveLength(1); + }); + it('handles empty input', () => { const result = chunkConversation(''); expect(result.episodes.length).toBe(0); diff --git a/packages/plugin-nlp/src/__tests__/entity-resolution.test.ts b/packages/plugin-nlp/src/__tests__/entity-resolution.test.ts index 7167f59e..b2ee305f 100644 --- a/packages/plugin-nlp/src/__tests__/entity-resolution.test.ts +++ b/packages/plugin-nlp/src/__tests__/entity-resolution.test.ts @@ -1,5 +1,5 @@ /** - * Entity Resolution — Tests + * Entity Resolution: Tests * * Tests the three-tier entity resolution strategy: * Tier 1: Exact text match (case-insensitive) @@ -11,8 +11,20 @@ import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest'; -// These tests use local embeddings -vi.stubEnv('CODEGRAPH_EMBEDDING_PROVIDER', 'local'); +vi.mock('../embeddings', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + isEmbeddingAvailable: vi.fn(() => true), + generateEmbedding: vi.fn(async (text: string) => { + const embedding = new Array(768).fill(0); + const dimension = [...text].reduce((sum, character) => sum + character.charCodeAt(0), 0) % 768; + embedding[dimension] = 1; + return { embedding, dimensions: 768, provider: 'test' }; + }), + }; +}); + import { MockLanguageModelV3 } from 'ai/test'; import { createClient, @@ -33,11 +45,22 @@ const GRAPH_NAME = `test_entity_res_${Date.now()}`; * By default answers YES (entities are the same). */ function makeLlmMock(answer: 'YES' | 'NO' = 'YES') { + const response = answer === 'YES' + ? { + op: 'merge', + canonical: 'Sarah Chen', + duplicate: 'Sarah', + reason: 'Both names refer to the same person.', + } + : { + op: 'keep', + reason: 'The concepts describe different components.', + }; return new MockLanguageModelV3({ provider: 'test', modelId: 'test-entity-res', doGenerate: { - content: [{ type: 'text' as const, text: answer }], + content: [{ type: 'text' as const, text: JSON.stringify(response) }], finishReason: { unified: 'stop' as const, raw: 'stop' }, usage: { inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, @@ -62,12 +85,12 @@ describe('Entity Resolution (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: process.env['FALKORDB_HOST'] ?? 'localhost', + port: Number(process.env['FALKORDB_PORT'] ?? '6379'), graphName: GRAPH_NAME, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailable = false; return; } @@ -78,7 +101,7 @@ describe('Entity Resolution (FalkorDB)', () => { beforeEach(async (ctx) => { if (!falkordbAvailable) { - ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); return; } // Clean state before each test @@ -144,8 +167,11 @@ describe('Entity Resolution (FalkorDB)', () => { expect(rels.some((r) => r.relationType === 'CREATED')).toBe(true); // Verify duplicate 'alice' no longer exists - const duplicate = await ops.getEntityByText('alice', 'Person'); - expect(duplicate).toBeNull(); + const duplicate = await client.roQuery<{ count: number }>( + 'MATCH (e:Entity {text: $text, type: $type}) RETURN count(e) AS count', + { params: { text: 'alice', type: 'Person' } }, + ); + expect(duplicate.data[0]?.count).toBe(0); }); it('Tier 1: does not merge entities of different types', async () => { diff --git a/packages/plugin-nlp/src/__tests__/episodic-extraction.test.ts b/packages/plugin-nlp/src/__tests__/episodic-extraction.test.ts index ae8fe292..e090e0f9 100644 --- a/packages/plugin-nlp/src/__tests__/episodic-extraction.test.ts +++ b/packages/plugin-nlp/src/__tests__/episodic-extraction.test.ts @@ -1,5 +1,5 @@ /** - * Episodic Extraction — Unit Tests + * Episodic Extraction: Unit Tests * * Tests the conversation episodic extraction pipeline: * 1. Context window builds correct prior episode context @@ -13,7 +13,32 @@ * Prerequisites: docker compose up -d falkordb */ -import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest'; + +vi.mock('../embeddings', async (importOriginal) => { + const actual = await importOriginal(); + const createEmbedding = (text: string): number[] => { + const embedding = new Array(768).fill(0); + const dimension = [...text].reduce((sum, character) => sum + character.charCodeAt(0), 0) % 768; + embedding[dimension] = 1; + return embedding; + }; + return { + ...actual, + isEmbeddingAvailable: vi.fn(() => true), + generateEmbedding: vi.fn(async (text: string) => ({ + embedding: createEmbedding(text), + dimensions: 768, + provider: 'test', + })), + generateEmbeddings: vi.fn(async (texts: string[]) => ({ + embeddings: texts.map(createEmbedding), + dimensions: 768, + provider: 'test', + })), + }; +}); + import { MockLanguageModelV3 } from 'ai/test'; import { createClient, @@ -23,6 +48,7 @@ import { } from '@codegraph/graph'; import { chunkConversation } from '../conversation'; import { extractConversation } from '../extract-and-store'; +import { makeToolCallResult } from './helpers/mock-tool-call-model'; // ============================================================================ // Helpers @@ -97,15 +123,7 @@ function makeMockModel() { // (This is what the real parseResponse does via indexOf) const responseJson = { entities, relationships }; - return { - content: [{ type: 'text' as const, text: JSON.stringify(responseJson) }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, - usage: { - inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 10, text: 10, reasoning: 0 }, - }, - warnings: [], - }; + return makeToolCallResult(responseJson); }, }); } @@ -124,12 +142,12 @@ describe('Episodic Extraction (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: process.env['FALKORDB_HOST'] ?? 'localhost', + port: Number(process.env['FALKORDB_PORT'] ?? '6379'), graphName: GRAPH_NAME, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailable = false; return; } @@ -139,7 +157,7 @@ describe('Episodic Extraction (FalkorDB)', () => { }, 30_000); beforeEach((ctx) => { - if (!falkordbAvailable) ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + if (!falkordbAvailable) ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); }); afterAll(async () => { diff --git a/packages/plugin-nlp/src/__tests__/extractor.test.ts b/packages/plugin-nlp/src/__tests__/extractor.test.ts index 5cb4878e..b0732187 100644 --- a/packages/plugin-nlp/src/__tests__/extractor.test.ts +++ b/packages/plugin-nlp/src/__tests__/extractor.test.ts @@ -1,5 +1,5 @@ /** - * EntityExtractor — Unit Tests + * EntityExtractor: Unit Tests * * Uses MockLanguageModelV3 from ai/test to mock LLM responses. * Tests zero-shot, few-shot, and batch extraction modes. @@ -9,27 +9,12 @@ import { describe, it, expect } from 'vitest'; import { MockLanguageModelV3 } from 'ai/test'; import { EntityExtractor } from '../extractor'; import type { Sample, AnnotatedSample } from '@codegraph/types'; +import { makeToolCallModel } from './helpers/mock-tool-call-model'; // ============================================================================ // Helpers // ============================================================================ -function makeMockModel(responseJson: object) { - return new MockLanguageModelV3({ - provider: 'test', - modelId: 'test-model', - doGenerate: { - content: [{ type: 'text' as const, text: JSON.stringify(responseJson) }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, - usage: { - inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 10, text: 10, reasoning: 0 }, - }, - warnings: [], - }, - }); -} - function makeSample(text: string, id?: string): Sample { return { id: id ?? 'test-sample', text }; } @@ -38,9 +23,9 @@ function makeSample(text: string, id?: string): Sample { // Zero-shot extraction // ============================================================================ -describe('EntityExtractor — zero-shot', () => { +describe('EntityExtractor: zero-shot', () => { it('should extract entities and relationships from text', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Randy', type: 'Person' }, { text: 'Kuzu', type: 'CodeEntity' }, @@ -68,7 +53,7 @@ describe('EntityExtractor — zero-shot', () => { }); it('should normalize entity type synonyms', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Randy', type: 'Person' }, { text: 'something', type: 'defect' }, @@ -79,14 +64,14 @@ describe('EntityExtractor — zero-shot', () => { const extractor = new EntityExtractor({ languageModel: mockModel }); const result = await extractor.extract(makeSample('Randy found something')); - // Both entities should pass — synonym "defect" normalizes to "Bug" + // Both entities should pass: synonym "defect" normalizes to "Bug" expect(result.entities).toHaveLength(2); expect(result.entities[0]!.type).toBe('Person'); expect(result.entities[1]!.type).toBe('Bug'); }); it('should pass through novel entity and relationship types', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Alice', type: 'Person' }, { text: 'Bob', type: 'Person' }, @@ -110,7 +95,7 @@ describe('EntityExtractor — zero-shot', () => { }); it('should normalize relationship type synonyms', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Alice', type: 'Person' }, { text: 'Bob', type: 'Person' }, @@ -131,7 +116,7 @@ describe('EntityExtractor — zero-shot', () => { }); it('should skip entities whose text is not found in the sample', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Randy', type: 'Person' }, { text: 'NotInText', type: 'Concept' }, @@ -170,7 +155,7 @@ describe('EntityExtractor — zero-shot', () => { it('should compute correct start/end offsets for entities', async () => { const text = 'Alice met Bob at the conference'; - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Alice', type: 'Person' }, { text: 'Bob', type: 'Person' }, @@ -195,7 +180,7 @@ describe('EntityExtractor — zero-shot', () => { // Few-shot extraction // ============================================================================ -describe('EntityExtractor — few-shot (extractWithExamples)', () => { +describe('EntityExtractor: few-shot (extractWithExamples)', () => { const exampleSample: AnnotatedSample = { id: 'example-1', text: 'John decided to use React', @@ -211,7 +196,7 @@ describe('EntityExtractor — few-shot (extractWithExamples)', () => { }; it('should extract using few-shot examples', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Sarah', type: 'Person' }, { text: 'Vue', type: 'CodeEntity' }, @@ -231,7 +216,7 @@ describe('EntityExtractor — few-shot (extractWithExamples)', () => { }); it('should fall back to zero-shot when no examples given', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [{ text: 'test', type: 'Concept' }], relationships: [], }); @@ -263,11 +248,16 @@ describe('EntityExtractor — few-shot (extractWithExamples)', () => { } return { - content: [{ type: 'text' as const, text: '{"entities":[],"relationships":[]}' }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, + content: [{ + type: 'tool-call' as const, + toolCallId: 'test-tool-call-1', + toolName: 'emit_extraction', + input: '{"entities":[],"relationships":[]}', + }], + finishReason: { unified: 'tool-calls' as const, raw: 'tool-calls' }, usage: { inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 5, text: 5, reasoning: 0 }, + outputTokens: { total: 5, text: 0, reasoning: 0 }, }, warnings: [], }; @@ -290,9 +280,9 @@ describe('EntityExtractor — few-shot (extractWithExamples)', () => { // Batch extraction // ============================================================================ -describe('EntityExtractor — batch', () => { +describe('EntityExtractor: batch', () => { it('should extract from multiple samples in one call', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ results: [ { sampleId: 's1', @@ -305,7 +295,7 @@ describe('EntityExtractor — batch', () => { relationships: [], }, ], - }); + }, 'emit_batch'); const extractor = new EntityExtractor({ languageModel: mockModel }); const results = await extractor.extractBatch([ diff --git a/packages/plugin-nlp/src/__tests__/forget-after.test.ts b/packages/plugin-nlp/src/__tests__/forget-after.test.ts index 4007ff38..7835a9f6 100644 --- a/packages/plugin-nlp/src/__tests__/forget-after.test.ts +++ b/packages/plugin-nlp/src/__tests__/forget-after.test.ts @@ -1,5 +1,5 @@ /** - * forgetAfter — Unit Tests + * forgetAfter: Unit Tests * * Verifies that: * 1. LLM-provided forgetAfter + forgetReason land on the RelationshipAnnotation returned @@ -10,32 +10,16 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { MockLanguageModelV3 } from 'ai/test'; import { EntityExtractor } from '../extractor'; import { extractAndStore } from '../extract-and-store'; import type { KnowledgeOperations, KnowledgeEntity, KnowledgeRelationship } from '@codegraph/graph'; import type { Sample } from '@codegraph/types'; +import { makeToolCallModel } from './helpers/mock-tool-call-model'; // ============================================================================ // Helpers // ============================================================================ -function makeMockModel(responseJson: object) { - return new MockLanguageModelV3({ - provider: 'test', - modelId: 'test-model', - doGenerate: { - content: [{ type: 'text' as const, text: JSON.stringify(responseJson) }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, - usage: { - inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 10, text: 10, reasoning: 0 }, - }, - warnings: [], - }, - }); -} - function makeSample(text: string): Sample { return { id: `test-${Math.random().toString(36).slice(2, 10)}`, @@ -96,13 +80,13 @@ function makeMockOps(): KnowledgeOperations & { } // ============================================================================ -// EntityExtractor — forgetAfter propagation to RelationshipAnnotation +// EntityExtractor: forgetAfter propagation to RelationshipAnnotation // ============================================================================ -describe('EntityExtractor — forgetAfter', () => { +describe('EntityExtractor: forgetAfter', () => { it('should preserve forgetAfter and forgetReason on RelationshipAnnotation when LLM provides them', async () => { const forgetAfterTs = '2026-05-01T15:00:00Z'; - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Alice', type: 'Person' }, { text: 'standup meeting', type: 'Event' }, @@ -129,7 +113,7 @@ describe('EntityExtractor — forgetAfter', () => { }); it('should leave forgetAfter undefined when LLM omits it for a permanent fact', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Randy', type: 'Person' }, { text: 'FalkorDB', type: 'Technology' }, @@ -155,7 +139,7 @@ describe('EntityExtractor — forgetAfter', () => { }); it('should treat explicit null forgetAfter as permanent fact', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Randy', type: 'Person' }, { text: 'codebase-graph', type: 'Project' }, @@ -184,13 +168,13 @@ describe('EntityExtractor — forgetAfter', () => { }); // ============================================================================ -// extractAndStore — forgetAfter propagation to KnowledgeRelationship +// extractAndStore: forgetAfter propagation to KnowledgeRelationship // ============================================================================ -describe('extractAndStore — forgetAfter persistence', () => { +describe('extractAndStore: forgetAfter persistence', () => { it('should pass forgetAfter and forgetReason to importEntitiesAndRelationships', async () => { const forgetAfterTs = '2026-06-15T09:00:00Z'; - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Bob', type: 'Person' }, { text: 'sprint review', type: 'Event' }, @@ -219,7 +203,7 @@ describe('extractAndStore — forgetAfter persistence', () => { }); it('should leave forgetAfter absent on KnowledgeRelationship when LLM omits it', async () => { - const mockModel = makeMockModel({ + const mockModel = makeToolCallModel({ entities: [ { text: 'Alice', type: 'Person' }, { text: 'codegraph', type: 'Project' }, @@ -242,7 +226,7 @@ describe('extractAndStore — forgetAfter persistence', () => { expect(ops.capturedRelationships).toHaveLength(1); const rel = ops.capturedRelationships[0]!; - // forgetAfter should be absent (undefined or null — not set to a value) + // forgetAfter should be absent (undefined or null: not set to a value) expect(rel.forgetAfter == null).toBe(true); }); }); diff --git a/packages/plugin-nlp/src/__tests__/helpers/mock-tool-call-model.ts b/packages/plugin-nlp/src/__tests__/helpers/mock-tool-call-model.ts new file mode 100644 index 00000000..53604ddd --- /dev/null +++ b/packages/plugin-nlp/src/__tests__/helpers/mock-tool-call-model.ts @@ -0,0 +1,36 @@ +import { MockLanguageModelV3 } from 'ai/test'; + +type ExtractionToolName = 'emit_extraction' | 'emit_batch'; + +export function makeToolCallResult( + response: object, + toolName: ExtractionToolName = 'emit_extraction', +) { + return { + content: [ + { + type: 'tool-call' as const, + toolCallId: 'test-tool-call-1', + toolName, + input: JSON.stringify(response), + }, + ], + finishReason: { unified: 'tool-calls' as const, raw: 'tool-calls' }, + usage: { + inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, + outputTokens: { total: 10, text: 0, reasoning: 0 }, + }, + warnings: [], + }; +} + +export function makeToolCallModel( + response: object, + toolName: ExtractionToolName = 'emit_extraction', +): MockLanguageModelV3 { + return new MockLanguageModelV3({ + provider: 'test', + modelId: 'test-model', + doGenerate: makeToolCallResult(response, toolName), + }); +} diff --git a/packages/plugin-nlp/src/__tests__/ingest-conversation.test.ts b/packages/plugin-nlp/src/__tests__/ingest-conversation.test.ts index 1f58342f..362dc338 100644 --- a/packages/plugin-nlp/src/__tests__/ingest-conversation.test.ts +++ b/packages/plugin-nlp/src/__tests__/ingest-conversation.test.ts @@ -1,5 +1,5 @@ /** - * ingestConversation — Integration Tests + * ingestConversation: Integration Tests * * Tests the full ingestion pipeline: text → chunk → extract → store → resolve. * This covers WS8.4 + WS8.5 acceptance criteria: @@ -15,7 +15,32 @@ * Prerequisites: docker compose up -d falkordb */ -import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest'; + +vi.mock('../embeddings', async (importOriginal) => { + const actual = await importOriginal(); + const createEmbedding = (text: string): number[] => { + const embedding = new Array(768).fill(0); + const dimension = [...text].reduce((sum, character) => sum + character.charCodeAt(0), 0) % 768; + embedding[dimension] = 1; + return embedding; + }; + return { + ...actual, + isEmbeddingAvailable: vi.fn(() => true), + generateEmbedding: vi.fn(async (text: string) => ({ + embedding: createEmbedding(text), + dimensions: 768, + provider: 'test', + })), + generateEmbeddings: vi.fn(async (texts: string[]) => ({ + embeddings: texts.map(createEmbedding), + dimensions: 768, + provider: 'test', + })), + }; +}); + import { MockLanguageModelV3 } from 'ai/test'; import { createClient, @@ -24,6 +49,7 @@ import { type KnowledgeOperations, } from '@codegraph/graph'; import { ingestConversation } from '../extract-and-store'; +import { makeToolCallResult } from './helpers/mock-tool-call-model'; // ============================================================================ // Helpers @@ -64,7 +90,7 @@ function makeMockModel() { const entities: Array<{ text: string; type: string }> = []; const relationships: Array<{ headText: string; tailText: string; type: string }> = []; - // Persons — extract speaker names from "CURRENT MESSAGE" patterns + // Persons: extract speaker names from "CURRENT MESSAGE" patterns if (promptText.includes('Alice')) entities.push({ text: 'Alice', type: 'Person' }); if (promptText.includes('Bob')) entities.push({ text: 'Bob', type: 'Person' }); if (promptText.includes('Charlie')) entities.push({ text: 'Charlie', type: 'Person' }); @@ -115,15 +141,7 @@ function makeMockModel() { }); const responseJson = { entities: dedupedEntities, relationships }; - return { - content: [{ type: 'text' as const, text: JSON.stringify(responseJson) }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, - usage: { - inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 10, text: 10, reasoning: 0 }, - }, - warnings: [], - }; + return makeToolCallResult(responseJson); }, }); } @@ -142,12 +160,12 @@ describe('ingestConversation (FalkorDB)', () => { try { client = await createClient({ driver: 'falkordb', - host: 'localhost', - port: 6379, + host: process.env['FALKORDB_HOST'] ?? 'localhost', + port: Number(process.env['FALKORDB_PORT'] ?? '6379'), graphName: GRAPH_NAME, }); } catch { - console.warn('FalkorDB not available — skipping tests. Run: docker compose up -d falkordb'); + console.warn('FalkorDB not available: skipping tests. Run: docker compose up -d falkordb'); falkordbAvailable = false; return; } @@ -158,7 +176,7 @@ describe('ingestConversation (FalkorDB)', () => { beforeEach(async (ctx) => { if (!falkordbAvailable) { - ctx.skip('FalkorDB not available — run: docker compose up -d falkordb'); + ctx.skip('FalkorDB not available: run: docker compose up -d falkordb'); return; } // Clean the graph between tests to prevent cross-test interference @@ -254,7 +272,7 @@ describe('ingestConversation (FalkorDB)', () => { const mockModel = makeMockModel(); const result = await ingestConversation(chatText, ops, { - // format intentionally omitted — should auto-detect as 'chat' + // format intentionally omitted: should auto-detect as 'chat' extractor: { languageModel: mockModel }, resolve: false, }); diff --git a/packages/plugin-nlp/src/__tests__/loaders.test.ts b/packages/plugin-nlp/src/__tests__/loaders.test.ts index bd7ba16e..036cfeb9 100644 --- a/packages/plugin-nlp/src/__tests__/loaders.test.ts +++ b/packages/plugin-nlp/src/__tests__/loaders.test.ts @@ -1,16 +1,19 @@ /** - * File-to-Text Loaders — Unit Tests + * File-to-Text Loaders: Unit Tests * * Registry: extension lookup, case-insensitive, unsupported types. * CSV: key-value conversion, quoted fields, empty file. * HTML: body text extraction, nav/footer/script removal, title capture. - * PDF/DOCX: skipped (fixture-free) — covered by integration smoke test in Task 5. + * PDF: real one-page fixture. DOCX remains covered by integration smoke tests. */ import { describe, it, expect } from 'vitest'; import { getLoaderForExtension } from '../loaders/registry'; import { CSVLoader } from '../loaders/csv'; import { HTMLLoader } from '../loaders/html'; +import { PDFLoader } from '../loaders/pdf'; + +const PDF_FIXTURE_BASE64 = 'JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA2MTIgNzkyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSA0IDAgUiA+PiA+PiAvQ29udGVudHMgNSAwIFIgPj4KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNTMgPj4Kc3RyZWFtCkJUIC9GMSAxOCBUZiA3MiA3MjAgVGQgKENvZGVHcmFwaCBQREYgZml4dHVyZSkgVGogRVQKZW5kc3RyZWFtCmVuZG9iagp4cmVmCjAgNgowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMDkgMDAwMDAgbiAKMDAwMDAwMDA1OCAwMDAwMCBuIAowMDAwMDAwMTE1IDAwMDAwIG4gCjAwMDAwMDAyNDEgMDAwMDAgbiAKMDAwMDAwMDMxMSAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDYgL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjQxMwolJUVPRgo='; // ============================================================================ // Registry @@ -138,17 +141,23 @@ describe('html loader', () => { }); // ============================================================================ -// PDF + DOCX — skipped (no fixture files; covered by Task 5 integration smoke test) +// PDF + DOCX // ============================================================================ -describe.skip('pdf loader (integration)', () => { - it('extracts text from a PDF file', async () => { - // Requires fixture file — test deferred to Task 5 integration smoke test +describe('pdf loader', () => { + it('extracts text and page metadata from a one-page PDF', async () => { + const pdfBuffer = Buffer.from(PDF_FIXTURE_BASE64, 'base64'); + + const result = await PDFLoader.extract(pdfBuffer); + + expect(result.text).toContain('CodeGraph PDF fixture'); + expect(result.metadata.format).toBe('pdf'); + expect(result.metadata.pageCount).toBe(1); }); }); describe.skip('docx loader (integration)', () => { it('extracts text from a DOCX file', async () => { - // Requires fixture file — test deferred to Task 5 integration smoke test + // Requires fixture file: test deferred to Task 5 integration smoke test }); }); diff --git a/packages/plugin-nlp/src/__tests__/speaker-entities.test.ts b/packages/plugin-nlp/src/__tests__/speaker-entities.test.ts index 7c919f13..f9b9a558 100644 --- a/packages/plugin-nlp/src/__tests__/speaker-entities.test.ts +++ b/packages/plugin-nlp/src/__tests__/speaker-entities.test.ts @@ -1,5 +1,5 @@ /** - * Speaker Entities + SAID Edges — Unit Tests (Task 6) + * Speaker Entities + SAID Edges: Unit Tests (Task 6) * * Verifies that conversation ingestion creates Person entities for speakers * and links them to extracted fact entities via SAID edges. @@ -7,18 +7,18 @@ * Implementation location: packages/plugin-nlp/src/extract-and-store.ts * The speaker attribution block is at lines 489-514 of extractConversation(). * - * Uses MockLanguageModelV3 from ai/test to mock the LLM — no network calls. - * Uses vi.fn() ops mock to capture DB writes — no FalkorDB required. + * Uses MockLanguageModelV3 from ai/test to mock the LLM: no network calls. + * Uses vi.fn() ops mock to capture DB writes: no FalkorDB required. * * Integration tests (with real FalkorDB) live in: * src/__tests__/ingest-conversation.test.ts */ import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { MockLanguageModelV3 } from 'ai/test'; import { extractConversation } from '../extract-and-store'; import { chunkConversation } from '../conversation'; import type { KnowledgeOperations } from '@codegraph/graph'; +import { makeToolCallModel } from './helpers/mock-tool-call-model'; // --------------------------------------------------------------------------- // Helpers @@ -29,37 +29,22 @@ import type { KnowledgeOperations } from '@codegraph/graph'; * Returns Redis and JWT as Technology entities for any input. */ function makeMockModel() { - return new MockLanguageModelV3({ - provider: 'test', - modelId: 'test-speaker-model', - doGenerate: async () => { - const response = { - entities: [ - { text: 'Redis', type: 'Technology', confidence: 0.9 }, - { text: 'JWT', type: 'Technology', confidence: 0.85 }, - ], - relationships: [], - }; - return { - content: [{ type: 'text' as const, text: JSON.stringify(response) }], - finishReason: { unified: 'stop' as const, raw: 'stop' }, - usage: { - inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 }, - outputTokens: { total: 10, text: 10, reasoning: 0 }, - }, - warnings: [], - }; - }, + return makeToolCallModel({ + entities: [ + { text: 'Redis', type: 'Technology', confidence: 0.9 }, + { text: 'JWT', type: 'Technology', confidence: 0.85 }, + ], + relationships: [], }); } -/** Minimal mock for KnowledgeOperations — captures createEntity/createRelationship calls */ +/** Minimal mock for KnowledgeOperations: captures createEntity/createRelationship calls */ function makeMockOps(): KnowledgeOperations { return { createEntity: vi.fn().mockResolvedValue('mock-entity-id'), createRelationship: vi.fn().mockResolvedValue(undefined), createEntities: vi.fn().mockResolvedValue([]), - // importEntitiesAndRelationships is called by extractAndStore — return non-zero to trigger speaker attribution + // importEntitiesAndRelationships is called by extractAndStore: return non-zero to trigger speaker attribution importEntitiesAndRelationships: vi.fn().mockResolvedValue({ entities: 2, relationships: 0 }), searchEntities: vi.fn().mockResolvedValue([]), getEntity: vi.fn().mockResolvedValue(null), diff --git a/packages/plugin-nlp/src/conversation.ts b/packages/plugin-nlp/src/conversation.ts index a9fd194e..61aef845 100644 --- a/packages/plugin-nlp/src/conversation.ts +++ b/packages/plugin-nlp/src/conversation.ts @@ -61,14 +61,48 @@ export interface ChunkResult { // Format Detection // ============================================================================ +interface TimestampedLine { + timestamp: string; + speaker: string; + message: string; +} + /** - * Regex patterns for each format. + * Parse a timestamped line without a backtracking regular expression. * * Timestamped: [2024-01-15 10:30] Speaker: message * [2024-01-15T10:30:00Z] Speaker: message * [10:30 AM] Speaker: message */ -const TIMESTAMPED_LINE = /^\[([^\]]+)\]\s+([^:]+):\s*(.*)/; +function parseTimestampedLine(line: string): TimestampedLine | null { + if (line[0] !== '[') return null; + + const closingBracket = line.indexOf(']', 1); + if (closingBracket <= 1) return null; + + let speakerStart = closingBracket + 1; + if (speakerStart >= line.length || line[speakerStart]!.trim().length !== 0) { + return null; + } + + while (speakerStart < line.length && line[speakerStart]!.trim().length === 0) { + speakerStart++; + } + + const colon = line.indexOf(':', speakerStart); + if (colon <= speakerStart) return null; + + let messageStart = colon + 1; + while (messageStart < line.length && line[messageStart]!.trim().length === 0) { + messageStart++; + } + + return { + timestamp: line.slice(1, closingBracket).trim(), + speaker: line.slice(speakerStart, colon).trim(), + message: line.slice(messageStart), + }; +} /** * Chat-style: Speaker: message @@ -89,7 +123,7 @@ function detectFormat(text: string): ConversationFormat { let chatCount = 0; for (const line of lines) { - if (TIMESTAMPED_LINE.test(line)) timestampedCount++; + if (parseTimestampedLine(line)) timestampedCount++; else if (CHAT_LINE.test(line)) chatCount++; } @@ -119,7 +153,7 @@ function parseTimestamped(text: string, options: Required): Episod let current: { speaker?: string; timestamp?: string; lines: string[] } | null = null; for (const line of lines) { - const match = TIMESTAMPED_LINE.exec(line.trim()); + const match = parseTimestampedLine(line.trim()); if (match) { // Flush previous episode @@ -136,9 +170,9 @@ function parseTimestamped(text: string, options: Required): Episod } current = { - speaker: match[2]!.trim(), - timestamp: match[1]!.trim(), - lines: match[3] ? [match[3]] : [], + speaker: match.speaker, + timestamp: match.timestamp, + lines: match.message ? [match.message] : [], }; } else if (current && line.trim().length > 0) { // Continuation line for current message diff --git a/packages/plugin-nlp/src/loaders/pdf.ts b/packages/plugin-nlp/src/loaders/pdf.ts index eac8815a..710550f4 100644 --- a/packages/plugin-nlp/src/loaders/pdf.ts +++ b/packages/plugin-nlp/src/loaders/pdf.ts @@ -1,5 +1,5 @@ /** - * PDF Loader — extracts text from PDF files using pdf-parse. + * PDF Loader: extracts text from PDF files using pdf-parse. */ import type { TextLoader, LoaderResult } from './index'; @@ -8,11 +8,6 @@ export const PDFLoader: TextLoader = { extensions: ['pdf'], async extract(input: string | Buffer): Promise { - // Dynamic import — pdf-parse is optional - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const pdfParseModule = await import('pdf-parse') as any; - const pdfParse = pdfParseModule.default ?? pdfParseModule; - let buffer: Buffer; if (typeof input === 'string') { const { readFile } = await import('node:fs/promises'); @@ -21,17 +16,25 @@ export const PDFLoader: TextLoader = { buffer = input; } - const data = await pdfParse(buffer) as { text: string; numpages: number; info?: Record }; + const { PDFParse } = await import('pdf-parse'); + const parser = new PDFParse({ data: buffer }); - const title = data.info?.Title as string | undefined; + try { + const textResult = await parser.getText(); + const infoResult = await parser.getInfo(); + const rawTitle: unknown = infoResult.info?.Title; + const title = typeof rawTitle === 'string' ? rawTitle : undefined; - return { - text: data.text, - metadata: { - format: 'pdf', - pageCount: data.numpages, - ...(title != null ? { title } : {}), - }, - }; + return { + text: textResult.text, + metadata: { + format: 'pdf', + pageCount: textResult.total, + ...(title ? { title } : {}), + }, + }; + } finally { + await parser.destroy(); + } }, }; diff --git a/packages/plugin-nlp/vitest.config.ts b/packages/plugin-nlp/vitest.config.ts index 11e0ec86..df5c0d77 100644 --- a/packages/plugin-nlp/vitest.config.ts +++ b/packages/plugin-nlp/vitest.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vitest/config'; +import { configDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ test: { @@ -6,5 +6,14 @@ export default defineConfig({ testTimeout: 30_000, hookTimeout: 30_000, include: ['src/__tests__/**/*.test.ts'], + exclude: [ + ...configDefaults.exclude, + 'src/__tests__/bridge-linker-embedding.test.ts', + 'src/__tests__/bridge-linker.test.ts', + 'src/__tests__/conflict-resolution.test.ts', + 'src/__tests__/entity-resolution.test.ts', + 'src/__tests__/episodic-extraction.test.ts', + 'src/__tests__/ingest-conversation.test.ts', + ], }, }); diff --git a/packages/plugin-nlp/vitest.integration.config.ts b/packages/plugin-nlp/vitest.integration.config.ts new file mode 100644 index 00000000..0a3430ef --- /dev/null +++ b/packages/plugin-nlp/vitest.integration.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + pool: 'forks', + testTimeout: 30_000, + hookTimeout: 30_000, + include: [ + 'src/__tests__/bridge-linker-embedding.test.ts', + 'src/__tests__/bridge-linker.test.ts', + 'src/__tests__/conflict-resolution.test.ts', + 'src/__tests__/entity-resolution.test.ts', + 'src/__tests__/episodic-extraction.test.ts', + 'src/__tests__/ingest-conversation.test.ts', + ], + env: { + CODEGRAPH_EMBEDDING_PROVIDER: 'local', + }, + }, +}); diff --git a/packages/plugin-python/package.json b/packages/plugin-python/package.json index c7e5da08..4630ae7e 100644 --- a/packages/plugin-python/package.json +++ b/packages/plugin-python/package.json @@ -16,7 +16,7 @@ "dev": "tsc --watch", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", - "test": "vitest run" + "test": "vitest run --root . --config ../../vitest.package.config.ts" }, "dependencies": { "@codegraph/logger": "workspace:*", diff --git a/packages/plugin-rust/package.json b/packages/plugin-rust/package.json index e2428386..88b5c74b 100644 --- a/packages/plugin-rust/package.json +++ b/packages/plugin-rust/package.json @@ -16,7 +16,7 @@ "dev": "tsc --watch", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", - "test": "vitest run" + "test": "vitest run --root . --config ../../vitest.package.config.ts" }, "dependencies": { "@codegraph/logger": "workspace:*", diff --git a/packages/plugin-typescript/package.json b/packages/plugin-typescript/package.json index 1d9d30c3..6d1dfa15 100644 --- a/packages/plugin-typescript/package.json +++ b/packages/plugin-typescript/package.json @@ -16,7 +16,7 @@ "dev": "tsc --watch", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", - "test": "vitest run" + "test": "vitest run --root . --config ../../vitest.package.config.ts" }, "dependencies": { "@codegraph/logger": "workspace:*", diff --git a/packages/types/package.json b/packages/types/package.json index 649e0b4e..d55db309 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -14,6 +14,7 @@ "scripts": { "build": "tsc", "dev": "tsc --watch", + "typecheck": "tsc --noEmit", "clean": "rm -rf dist" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f63d1fa..764d5259 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,17 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + brace-expansion@>=2.0.0 <2.1.4: 2.1.4 + '@hono/node-server@<1.19.15': 1.19.15 + hono@<4.12.34: 4.12.34 + js-yaml@>=3.0.0 <3.15.1: 3.15.1 + postcss@<8.5.23: 8.5.23 + protobufjs@<7.6.5: 7.6.5 + sharp@<0.35.0: 0.35.0 + tar@<7.5.21: 7.5.21 + undici@>=7.0.0 <7.29.0: 7.29.0 + importers: .: @@ -40,97 +51,97 @@ importers: dependencies: '@hookform/resolvers': specifier: ^3.10.0 - version: 3.10.0(react-hook-form@7.76.1(react@19.2.4)) + version: 3.10.0(react-hook-form@7.76.1(react@19.2.8)) '@radix-ui/react-accordion': specifier: 1.2.12 - version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-alert-dialog': specifier: 1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-aspect-ratio': specifier: 1.1.8 - version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-avatar': specifier: 1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-checkbox': specifier: 1.3.3 - version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-collapsible': specifier: 1.1.12 - version: 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-context-menu': specifier: 2.2.16 - version: 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-dialog': specifier: 1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-dropdown-menu': specifier: 2.1.16 - version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-hover-card': specifier: 1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-label': specifier: 2.1.8 - version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-menubar': specifier: 1.1.16 - version: 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-navigation-menu': specifier: 1.2.14 - version: 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-popover': specifier: 1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-progress': specifier: 1.1.8 - version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-radio-group': specifier: 1.3.8 - version: 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-scroll-area': specifier: 1.2.10 - version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-select': specifier: 2.2.6 - version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-separator': specifier: 1.1.8 - version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slider': specifier: 1.3.6 - version: 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': specifier: 1.2.4 - version: 1.2.4(@types/react@19.2.14)(react@19.2.4) + version: 1.2.4(@types/react@19.2.14)(react@19.2.8) '@radix-ui/react-switch': specifier: 1.2.6 - version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-tabs': specifier: 1.1.13 - version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-toast': specifier: 1.2.15 - version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-toggle': specifier: 1.1.10 - version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-toggle-group': specifier: 1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-tooltip': specifier: 1.2.8 - version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@types/cytoscape': specifier: ^3.31.0 version: 3.31.0 '@vercel/analytics': specifier: 1.6.1 - version: 1.6.1(next@16.1.6(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + version: 1.6.1(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(@types/node@22.19.19)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) autoprefixer: specifier: ^10.5.0 - version: 10.5.0(postcss@8.5.15) + version: 10.5.0(postcss@8.5.23) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -139,7 +150,7 @@ importers: version: 2.1.1 cmdk: specifier: 1.1.1 - version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) cytoscape: specifier: ^3.33.4 version: 3.33.4 @@ -148,52 +159,52 @@ importers: version: 4.1.0 embla-carousel-react: specifier: 8.6.0 - version: 8.6.0(react@19.2.4) + version: 8.6.0(react@19.2.8) framer-motion: specifier: ^12.40.0 - version: 12.40.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 12.40.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) input-otp: specifier: 1.4.2 - version: 1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) lucide-react: specifier: ^0.564.0 - version: 0.564.0(react@19.2.4) + version: 0.564.0(react@19.2.8) next: - specifier: 16.1.6 - version: 16.1.6(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 16.3.1 + version: 16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(@types/node@22.19.19)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) next-themes: specifier: ^0.4.6 - version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: - specifier: 19.2.4 - version: 19.2.4 + specifier: 19.2.8 + version: 19.2.8 react-day-picker: specifier: 9.13.2 - version: 9.13.2(react@19.2.4) + version: 9.13.2(react@19.2.8) react-dom: - specifier: 19.2.4 - version: 19.2.4(react@19.2.4) + specifier: 19.2.8 + version: 19.2.8(react@19.2.8) react-hook-form: specifier: ^7.76.1 - version: 7.76.1(react@19.2.4) + version: 7.76.1(react@19.2.8) react-resizable-panels: specifier: ^2.1.9 - version: 2.1.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) recharts: specifier: 2.15.0 - version: 2.15.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.15.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) shiki: specifier: ^4.1.0 version: 4.1.0 sonner: specifier: ^1.7.4 - version: 1.7.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.7.4(react-dom@19.2.8(react@19.2.8))(react@19.2.8) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 vaul: specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) zod: specifier: ^3.25.76 version: 3.25.76 @@ -210,9 +221,15 @@ importers: '@types/react-dom': specifier: 19.2.3 version: 19.2.3(@types/react@19.2.14) + eslint: + specifier: ^9 + version: 9.39.5(jiti@2.7.0) + eslint-config-next: + specifier: 16.3.1 + version: 16.3.1(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) postcss: - specifier: ^8.5.15 - version: 8.5.15 + specifier: 8.5.23 + version: 8.5.23 tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -235,8 +252,8 @@ importers: specifier: workspace:* version: link:../../packages/types '@modelcontextprotocol/sdk': - specifier: ^1.29.0 - version: 1.29.0(zod@3.25.76) + specifier: ^1.30.0 + version: 1.30.0(zod@3.25.76) zod: specifier: ^3.25.76 version: 3.25.76 @@ -266,11 +283,11 @@ importers: specifier: workspace:* version: link:../logger '@hono/node-server': - specifier: ^1.19.14 - version: 1.19.14(hono@4.12.23) + specifier: 1.19.15 + version: 1.19.15(hono@4.12.34) hono: - specifier: ^4.12.23 - version: 4.12.23 + specifier: 4.12.34 + version: 4.12.34 devDependencies: '@types/node': specifier: ^22.19.19 @@ -394,6 +411,10 @@ importers: zod: specifier: ^3.25.76 version: 3.25.76 + optionalDependencies: + '@codegraph/plugin-languages': + specifier: workspace:* + version: link:../plugin-languages devDependencies: typescript: specifier: ^5.9.3 @@ -411,12 +432,19 @@ importers: specifier: workspace:* version: link:../types falkordb: - specifier: ^6.6.2 - version: 6.6.2(@opentelemetry/api@1.9.1) + specifier: ^6.7.0 + version: 6.7.0(@opentelemetry/api@1.9.1) + optionalDependencies: + '@falkordblite/darwin-arm64': + specifier: 8.2.3-falkordb.4.16.3 + version: 8.2.3-falkordb.4.16.3 + '@falkordblite/linux-x64': + specifier: 8.2.3-falkordb.4.16.3 + version: 8.2.3-falkordb.4.16.3 devDependencies: falkordblite: specifier: ^0.2.0 - version: 0.2.0(falkordb@6.6.2(@opentelemetry/api@1.9.1)) + version: 0.2.0(falkordb@6.7.0(@opentelemetry/api@1.9.1)) typescript: specifier: ^5.9.3 version: 5.9.3 @@ -446,10 +474,10 @@ importers: version: link:../plugin-nlp '@modelcontextprotocol/ext-apps': specifier: ^1.7.2 - version: 1.7.2(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@4.3.5) + version: 1.7.2(@modelcontextprotocol/sdk@1.30.0(zod@4.3.5))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.3.5) '@modelcontextprotocol/sdk': - specifier: ^1.29.0 - version: 1.29.0(zod@4.3.5) + specifier: ^1.30.0 + version: 1.30.0(zod@4.3.5) glob: specifier: ^10.5.0 version: 10.5.0 @@ -457,6 +485,9 @@ importers: '@types/node': specifier: ^22.19.19 version: 22.19.19 + ai: + specifier: ^6.0.193 + version: 6.0.193(zod@4.3.5) esbuild: specifier: ^0.27.7 version: 0.27.7 @@ -470,7 +501,29 @@ importers: specifier: ^3.2.4 version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3) - packages/npm-package: {} + packages/mcpb: + devDependencies: + '@anthropic-ai/mcpb': + specifier: ^2.1.2 + version: 2.1.2 + '@codegraph/mcp-server': + specifier: workspace:* + version: link:../mcp-server + esbuild: + specifier: ^0.27.7 + version: 0.27.7 + + packages/npm-package: + devDependencies: + '@codegraph/mcp-server': + specifier: workspace:* + version: link:../mcp-server + esbuild: + specifier: ^0.27.7 + version: 0.27.7 + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3) packages/plugin-common: dependencies: @@ -482,8 +535,8 @@ importers: specifier: ^0.22.4 version: 0.22.4 tree-sitter-c-sharp: - specifier: ^0.23.5 - version: 0.23.5(tree-sitter@0.22.4) + specifier: ^0.21.3 + version: 0.21.3(tree-sitter@0.22.4) tree-sitter-go: specifier: ^0.23.4 version: 0.23.4(tree-sitter@0.22.4) @@ -563,7 +616,7 @@ importers: version: link:../types tree-sitter-c-sharp: specifier: ^0.21.3 - version: 0.21.3 + version: 0.21.3(tree-sitter@0.22.4) tree-sitter-java: specifier: ^0.23.5 version: 0.23.5(tree-sitter@0.22.4) @@ -728,8 +781,8 @@ importers: specifier: ^5.9.3 version: 5.9.3 vitest: - specifier: ^4.1.7 - version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(vite@7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)) + specifier: ^3.2.4 + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3) packages/plugin-python: dependencies: @@ -846,16 +899,96 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@anthropic-ai/mcpb@2.1.2': + resolution: {integrity: sha512-goRbBC8ySo7SWb7tRzr+tL6FxDc4JPTRCdgfD2omba7freofvjq5rom1lBnYHZHo6Mizs1jAHJeN53aZbDoy8A==} + hasBin: true + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/runtime@7.29.7': resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + '@date-fns/tz@1.5.0': resolution: {integrity: sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} @@ -1168,6 +1301,60 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.6': + resolution: {integrity: sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.5': + resolution: {integrity: sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@falkordblite/darwin-arm64@8.2.3-falkordb.4.16.3': + resolution: {integrity: sha512-ySmVhKThk8SU/99BSvT7wyN7z15rS6xjt2k8YsDhHZS1H8V2ExANXjOyto7j34Owrnq7Qn5rE1+eialnWz2Dgw==} + cpu: [arm64] + os: [darwin] + + '@falkordblite/linux-x64@8.2.3-falkordb.4.16.3': + resolution: {integrity: sha512-0X4Olb3lBnMkxvGsRiTTT4q/SNTkDPaNPBGWNm8qSBoWkbY6VxgCs9jHRkkZWB11hIzjLRJbcoVSjjGuroXp6w==} + cpu: [x64] + os: [linux] + '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -1183,11 +1370,11 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@hono/node-server@1.19.14': - resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + '@hono/node-server@1.19.15': + resolution: {integrity: sha512-Za2ai6TLdKjUvnur+eenO6nuYYipVAEhyCAdaV8IRvmU9kK8crOZUSYvIXn72E4f8fJqyAbpcJuTsYYmZp9Deg==} engines: {node: '>=18.14.1'} peerDependencies: - hono: ^4 + hono: 4.12.34 '@hookform/resolvers@3.10.0': resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} @@ -1201,143 +1388,370 @@ packages: '@huggingface/transformers@3.8.1': resolution: {integrity: sha512-tsTk4zVjImqdqjS8/AOZg2yNLd1z9S5v+7oUPpXaasDRwEDhB+xnglK1k5cad26lL5/ZIaeREgWWy0bs9y9pPA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.0': + resolution: {integrity: sha512-ZgaYEwaj+lx/5n4W8GmZ2IYz0PQHjN5eqRcfijWGB+2Aq7ZInZGa0qJyAn6DEtyLuWHRSrmWOqT9q3qqTBvmUQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.0': + resolution: {integrity: sha512-c1z9LFpKB0slQW3RchwBE8iSVzGp70TNjUUO9k4BZwwW4HH7JBGHeIy4b+kk4n/kcBASb9evKCE3/7Slmslgiw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.0': + resolution: {integrity: sha512-Li2KTev0H90kEtnJHkI9xQojXt1AqWmFBMXiPw5kqd1jQgP7gi5HVK/qC5Rmh/59NuAwUuPzzPITmX22NomYYQ==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.0': + resolution: {integrity: sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.0': + resolution: {integrity: sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.0': + resolution: {integrity: sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.0': + resolution: {integrity: sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.0': + resolution: {integrity: sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==} cpu: [ppc64] os: [linux] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.3.0': + resolution: {integrity: sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} cpu: [riscv64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.0': + resolution: {integrity: sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.0': + resolution: {integrity: sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + resolution: {integrity: sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.3.0': + resolution: {integrity: sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.0': + resolution: {integrity: sha512-4+4XHLNT5wDT0roYlHTEmH9lDKt0acf9Tv+3hM3iceOirkxrR404/3WjAYZ9F9CkHrxeRcGLJXbi4vluMZ9O+A==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.0': + resolution: {integrity: sha512-VVlpEWwizEFIOom0zdoeKuO5nuTswzVE5uHcBNvHzmeHUpNFajY3HFfbQ+zIH4E2kVaZ/yVxmsShW56TtEy4uA==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.0': + resolution: {integrity: sha512-N3hzbEpUTJC8pWpPVJvgzGxM+so/MAXc8O2s/53B0LL9ZGpfXpME7Wizkc5d/8fRBlBtkDjzoZGDCqqNDHqLEw==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.0': + resolution: {integrity: sha512-l6vmKVPnbS0RhVMbyxP5meAARsbhCnBN4fy31qz0+3a6Rv4jEqfzDrT89y6ZPkCi0AJGnwp2En528yXo401Hpw==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.0': + resolution: {integrity: sha512-MYlMiPFiv/EKPAHnp3yNZ9AAWFsxga9c5Bkc6wkar6bqzHLlkGVJHRm0u1ei+VXnZxp3Mz9MG9ZIsI8vSOf3sQ==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.0': + resolution: {integrity: sha512-TYaItB5oj1ioXjhyn2xrR208vf+YuIIcHptQWRRaBmFhvIvL9D72DXN8w75xup0KXA8UdEAhQ9Qb2S49FD/9Cw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.0': + resolution: {integrity: sha512-DSTb6ijQzqe6DdAaOBVqJ/SYf1vO8EW5bK6X6LRXufEBebf2722VCdvBUtZ3rtV0x2ApfPNDy/p7LrrjaWjiyQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.0': + resolution: {integrity: sha512-K7ykQ+26Rt6+4BTU80AuGgTPIYX86UxiAKT4rcXX/WNTo7k1ZxpKz+TguHnwVpCqQK3B5PK0vZ0ZBe6nz/ib1w==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.0': + resolution: {integrity: sha512-9woLIFORERCr+6cWu87dQ22J34EExkhc73U1kZW0c+RclQqWetoodByp4dWZ/hN8/KVmTRAx2HOnUwib8AwZdA==} + engines: {node: '>=20.9.0'} + + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.0': + resolution: {integrity: sha512-t+kie1TOyaDM6Dho+f+y0VqIUNhYQaKCUahuZVi0E0frgdiaOaPsDxDW3wfKacUdaNBCnK/ZDBMg33ydvHj8uA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.0': + resolution: {integrity: sha512-M5eKxug0dabbaWgFKvPa3odNs2OpaP+81NASfGKkt4GcYXpNhSu7CaeYxWkLNV6vHmUp4hnCxnxrUyhUJhXbKA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.0': + resolution: {integrity: sha512-z0+pZ03QCDvdVN0Ez9IX/yjWC19ikMlXrmdYMwYNLTh2BLPx3hXWPvyqWfquZ0BTO9O6GVOjIVoTcyyacMnWlQ==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.0': + resolution: {integrity: sha512-feNnlz5ZHKr0MY1LPHvZQyJeBkbo4ctsn0D8FvA53VTw5TC63rfEL2UrWbkSBR19htSE7Mw78xYVwdJqoMWVHw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] + '@inquirer/checkbox@3.0.1': + resolution: {integrity: sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@4.0.1': + resolution: {integrity: sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==} + engines: {node: '>=18'} + + '@inquirer/core@9.2.1': + resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==} + engines: {node: '>=18'} + + '@inquirer/editor@3.0.1': + resolution: {integrity: sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==} + engines: {node: '>=18'} + + '@inquirer/expand@3.0.1': + resolution: {integrity: sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==} + engines: {node: '>=18'} + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/input@3.0.1': + resolution: {integrity: sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==} + engines: {node: '>=18'} + + '@inquirer/number@2.0.1': + resolution: {integrity: sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==} + engines: {node: '>=18'} + + '@inquirer/password@3.0.1': + resolution: {integrity: sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==} + engines: {node: '>=18'} + + '@inquirer/prompts@6.0.1': + resolution: {integrity: sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==} + engines: {node: '>=18'} + + '@inquirer/rawlist@3.0.1': + resolution: {integrity: sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==} + engines: {node: '>=18'} + + '@inquirer/search@2.0.1': + resolution: {integrity: sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==} + engines: {node: '>=18'} + + '@inquirer/select@3.0.1': + resolution: {integrity: sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==} + engines: {node: '>=18'} + + '@inquirer/type@2.0.0': + resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==} + engines: {node: '>=18'} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1386,8 +1800,8 @@ packages: react-dom: optional: true - '@modelcontextprotocol/sdk@1.29.0': - resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -1460,53 +1874,63 @@ packages: resolution: {integrity: sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==} engines: {node: '>= 10'} - '@next/env@16.1.6': - resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + + '@next/env@16.3.1': + resolution: {integrity: sha512-35G3xwkQUb2oETSDjFXGrVugknoayLFBh7vSE+yAcl9IP2zT9wyGwq7297AYHR11kJld807t5f8AJBs6WBzXsQ==} + + '@next/eslint-plugin-next@16.3.1': + resolution: {integrity: sha512-B4SznlXwVpaLDa7Tbi6zLuueria2d/PmFDhXyDymPGrk2r1n/RMJmcn5FZq1L64k+Jsyte1lKvOr7lP9Xo80mQ==} - '@next/swc-darwin-arm64@16.1.6': - resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + '@next/swc-darwin-arm64@16.3.1': + resolution: {integrity: sha512-ABMIu2zQ7cnNIHm5ivKGwZwUrm0pAai3yiJ/gK/rF1c1VP9UOnj7XECbMKFdVKp9I9eMYq9NoDs1WXOoowxzJw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.6': - resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + '@next/swc-darwin-x64@16.3.1': + resolution: {integrity: sha512-gNG21e/UnrroeScbY/QndUEdl0mF1FRibW7BBeYUz/5ABCepjqDdEdgr592vpzMtCn/m7FTjYq3TN4TpyDnutw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.6': - resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + '@next/swc-linux-arm64-gnu@16.3.1': + resolution: {integrity: sha512-6B6Lw016iwNUQuaJoraMMTLh6TwHzFUtxipSScD1F3YyymcrRWkobodRS2ftIOkF5vrs4zNlyUrTC5YZQ9Lz5w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.1.6': - resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + '@next/swc-linux-arm64-musl@16.3.1': + resolution: {integrity: sha512-JUiPXZKK9wOhjf4MgDiH29GZLxfqOesbLtHq2pDxwH/WwscTRV2ToymnOTh1egzaZf0ueUf8T2+CeYTGHjW0Iw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@16.1.6': - resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + '@next/swc-linux-x64-gnu@16.3.1': + resolution: {integrity: sha512-Uog9jsrmIRIL/lfvIp9htmskSNC7JcQsMVucXL2V2YY1y/D9IUN3LPEafqy0zRJ2cIU1SQ0V6F6TlffQ+pLAGg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.1.6': - resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + '@next/swc-linux-x64-musl@16.3.1': + resolution: {integrity: sha512-6yy3FT13KgUFOj5H8bl8w/6nKiJwHIvbtwh1V+1acsu+7y4tJjnemSa6mhsh53BeoVrlozE+fMgZhXH46WmjMA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@16.1.6': - resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + '@next/swc-win32-arm64-msvc@16.3.1': + resolution: {integrity: sha512-iOoN1QecUoGNZik536U/vtK43YwgyrCsGIkth52yIkl612n+0C9MjSnJbQAikISpb+WYRooBVhaDlUW7iZoKog==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.6': - resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + '@next/swc-win32-x64-msvc@16.3.1': + resolution: {integrity: sha512-d/k+PpAriUPaeMJJOG7HUSdqfEX46FEPWU1p3/nm2ACmXhj9hFEWdFODUBIpkuijXYkfL90qZzTqVPRp4BW/hw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1523,6 +1947,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + '@openrouter/ai-sdk-provider@1.5.4': resolution: {integrity: sha512-xrSQPUIH8n9zuyYZR0XK7Ba0h2KsjJcMkxnwaYfmv13pKs3sDkjPzVPPhlhzqBGddHb5cFEwJ9VFuFeDcxCDSw==} engines: {node: '>=18'} @@ -1564,9 +1992,6 @@ packages: '@protobufjs/float@1.0.2': resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} - '@protobufjs/inquire@1.1.2': - resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} - '@protobufjs/path@1.1.2': resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} @@ -2393,6 +2818,9 @@ packages: cpu: [x64] os: [win32] + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@shikijs/core@4.1.0': resolution: {integrity: sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==} engines: {node: '>=20'} @@ -2433,8 +2861,8 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} '@tailwindcss/node@4.3.0': resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} @@ -2554,6 +2982,9 @@ packages: cpu: [arm64] os: [win32] + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -2603,12 +3034,21 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/mute-stream@0.0.4': + resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} + '@types/node@22.19.19': resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} @@ -2626,14 +3066,186 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/wrap-ansi@3.0.0': + resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} + + '@typescript-eslint/eslint-plugin@8.67.0': + resolution: {integrity: sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.67.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.67.0': + resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.67.0': + resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.67.0': + resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.67.0': + resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.67.0': + resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.67.0': + resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.67.0': + resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.67.0': + resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.67.0': + resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.1': resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} - '@vercel/analytics@1.6.1': - resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} - peerDependencies: - '@remix-run/react': ^2 - '@sveltejs/kit': ^1 || ^2 + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + + '@vercel/analytics@1.6.1': + resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} + peerDependencies: + '@remix-run/react': ^2 + '@sveltejs/kit': ^1 || ^2 next: '>= 13' react: ^18 || ^19 || ^19.0.0-rc svelte: '>= 4' @@ -2662,9 +3274,6 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.1.7': - resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} - '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: @@ -2676,55 +3285,40 @@ packages: vite: optional: true - '@vitest/mocker@4.1.7': - resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.1.7': - resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} - '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - '@vitest/runner@4.1.7': - resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} - '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - '@vitest/snapshot@4.1.7': - resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} - '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.1.7': - resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} - '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.1.7': - resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} - '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -2743,9 +3337,16 @@ packages: ajv: optional: true + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2773,14 +3374,60 @@ packages: argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -2789,30 +3436,46 @@ packages: engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - postcss: ^8.1.0 + postcss: 8.5.23 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.13.0: + resolution: {integrity: sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==} + engines: {node: '>=4'} axios@1.16.1: resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.32: - resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==} + baseline-browser-mapping@2.11.15: + resolution: {integrity: sha512-FwMjJJ7HnyZpWe+oWxegG0fezZyBZUagI5LZEoO3GCbtbKNwRfMH9Ue5d5v01PNePBy1QSfPSDTTeVL0Hb9EzA==} engines: {node: '>=6.0.0'} hasBin: true bluebird@3.4.7: resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} boolbase@1.0.0: @@ -2822,8 +3485,15 @@ packages: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - brace-expansion@2.1.1: - resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} + + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} + + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -2846,13 +3516,24 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + caniuse-lite@1.0.30001793: resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + caniuse-lite@1.0.30001809: + resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2860,9 +3541,9 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -2873,6 +3554,9 @@ packages: character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + check-error@2.1.3: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} @@ -2888,10 +3572,6 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -2899,6 +3579,10 @@ packages: class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -2947,6 +3631,13 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} @@ -2958,8 +3649,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - content-type@2.0.0: - resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} engines: {node: '>=18'} convert-source-map@2.0.0: @@ -3042,12 +3733,35 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + date-fns-jalali@4.1.0-0: resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -3071,6 +3785,9 @@ packages: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -3110,6 +3827,10 @@ packages: dingbat-to-unicode@1.0.1: resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==} + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} @@ -3184,6 +3905,14 @@ packages: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -3192,12 +3921,13 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-iterator-helpers@1.4.0: + resolution: {integrity: sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==} + engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} @@ -3206,6 +3936,14 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} + engines: {node: '>= 0.4'} + es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} @@ -3234,14 +3972,134 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} + eslint-config-next@16.3.1: + resolution: {integrity: sha512-0vtrpwFVHFEkycUgV/DyrG29OS+HSRdah5Yu8YuZoiBMtlAT6NIiWzaLwDkJZxr2kGfx+9LIvfQ7KHAlEs0VsA==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.14.0: + resolution: {integrity: sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.5: + resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -3249,8 +4107,8 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventsource-parser@3.1.0: - resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} engines: {node: '>=18.0.0'} eventsource@3.0.7: @@ -3261,8 +4119,8 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@8.5.2: - resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + express-rate-limit@8.6.2: + resolution: {integrity: sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -3278,9 +4136,13 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - falkordb@6.6.2: - resolution: {integrity: sha512-f1LUKA7DGXNUbdRQlB22UQdwRO3WHiXrAzKLNsKyvjLSVH3MTl2qcA+6w2juosPBV6sJiX9okBwbXSXlIHiXFA==} - engines: {node: '>=20.0.0'} + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + falkordb@6.7.0: + resolution: {integrity: sha512-02y7+fF19fgVPIt0zK9FJxiKJATSLZFHO8SuiscUbRPx/kfg3kRITsmjiR1q/0KuEW5FHfMuB73KQMFmqX7Www==} + engines: {node: '>=22'} falkordblite@0.2.0: resolution: {integrity: sha512-1MF9MPLOo0F0OWTrJkv/1tW/QyAjjMWY5+HliAQJZOOQvItsseSGGaD+t532OEXm9Nh4B3L9OfjPc/3WmOKdaQ==} @@ -3295,12 +4157,22 @@ packages: resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} engines: {node: '>=6.0.0'} + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -3317,6 +4189,13 @@ packages: picomatch: optional: true + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -3325,9 +4204,24 @@ packages: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + flatbuffers@25.9.23: resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + + flora-colossus@2.0.0: + resolution: {integrity: sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==} + engines: {node: '>= 12'} + follow-redirects@1.16.0: resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} @@ -3337,6 +4231,10 @@ packages: debug: optional: true + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -3374,14 +4272,14 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + fs-extra@11.3.5: resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} engines: {node: '>=14.14'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3395,15 +4293,34 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + galactus@1.0.0: + resolution: {integrity: sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==} + engines: {node: '>= 12'} + gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This package is no longer supported. + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + generic-pool@3.9.0: resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} engines: {node: '>= 4'} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3420,10 +4337,21 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.14.3: + resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} 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 @@ -3433,9 +4361,17 @@ packages: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} engines: {node: '>=10.0'} - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} @@ -3451,9 +4387,21 @@ packages: guid-typescript@1.0.9: resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -3475,8 +4423,14 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - hono@4.12.23: - resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + hono@4.12.34: + resolution: {integrity: sha512-GqXJqY/xJkJmuloTrnV1ZEXG3fqte+VjkUqoRNZXcrUidiUOP4fMSIHHY4tsqZBK++kVyWmt/AAfSUuy57/eSA==} engines: {node: '>=16.9.0'} html-void-elements@3.0.0: @@ -3493,14 +4447,22 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} @@ -3508,6 +4470,14 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3520,18 +4490,61 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} engines: {node: '>= 12'} ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -3540,14 +4553,34 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3559,12 +4592,55 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} @@ -3572,8 +4648,8 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jose@6.2.9: + resolution: {integrity: sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3581,13 +4657,28 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + js-yaml@3.15.1: + resolution: {integrity: sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==} + hasBin: true + + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true jsbi@4.3.2: resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} @@ -3597,15 +4688,34 @@ packages: json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -3614,6 +4724,17 @@ packages: resolution: {integrity: sha512-4+hD3Y+YMV3e0uiqTv1/GUal47D04l8qluw1WFWg8Nx3k7rLsHG1Pmq9WHIOlf1742svxQvTYQiuY6oS1qxAZA==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -3687,6 +4808,13 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} @@ -3709,6 +4837,9 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.564.0: resolution: {integrity: sha512-JJ8GVTQqFwuliifD48U6+h7DXEHdkhJ/E87kksGByII3qHxtPciVb8T8woQONHBQgHVOl7rSMrrip3SeVNy7Fg==} peerDependencies: @@ -3772,8 +4903,8 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} engines: {node: '>= 0.8'} memory-stream@1.0.0: @@ -3894,6 +5025,13 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -3901,31 +5039,14 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - minizlib@3.1.0: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - motion-dom@12.40.0: resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} @@ -3935,14 +5056,26 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + nan@2.27.0: resolution: {integrity: sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==} - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -3953,8 +5086,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@16.1.6: - resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + next@16.3.1: + resolution: {integrity: sha512-hsAp0i7Rh+/dhe7DGIeN2YlpLM1DP4MNxti9EtDMtqcO612X81MvvEj388/oTce9U1EcEIOWDlGq0zRwrBKvuA==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -3991,6 +5124,14 @@ packages: node-api-headers@1.9.0: resolution: {integrity: sha512-2oNILP4jXwRB4ywnYKjVk1YyJ96n2D4EOVJO6S3oYZ5PtbJrw3Yt9TpAuX3nBLMuzn74rnfGQrv13pS9vC+YiA==} + node-exports-info@1.6.2: + resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} + engines: {node: '>= 0.4'} + + node-forge@1.4.0: + resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} + engines: {node: '>= 6.13.0'} + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -4019,8 +5160,25 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} @@ -4051,12 +5209,36 @@ packages: option@0.2.4: resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + own-keys@1.0.2: + resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + parse5-htmlparser2-tree-adapter@7.1.0: resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} @@ -4070,6 +5252,10 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -4078,6 +5264,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -4129,22 +5318,30 @@ packages: engines: {node: '>=18'} hasBin: true + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} - engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} prettier@3.8.3: resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true + pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -4154,8 +5351,8 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - protobufjs@7.6.1: - resolution: {integrity: sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg==} + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} engines: {node: '>=12.0.0'} proxy-addr@2.0.7: @@ -4166,15 +5363,19 @@ packages: resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} engines: {node: '>=10'} - qs@6.15.2: - resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} engines: {node: '>=0.6'} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} engines: {node: '>= 0.6'} raw-body@3.0.2: @@ -4191,10 +5392,10 @@ packages: peerDependencies: react: '>=16.8.0' - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} peerDependencies: - react: ^19.2.4 + react: ^19.2.8 react-hook-form@7.76.1: resolution: {integrity: sha512-rYM7tPiWlu3nZchkR/ex7piyzui2vFPyaLnXnI/RnblB/L4qfMmyses8llJVtF1NpE9WBBsJlGtcSZzPCXW1qQ==} @@ -4256,8 +5457,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} engines: {node: '>=0.10.0'} readable-stream@2.3.8: @@ -4286,6 +5487,10 @@ packages: resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==} engines: {node: '>= 18.19.0'} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + regex-recursion@6.0.2: resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} @@ -4295,6 +5500,10 @@ packages: regex@6.1.0: resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + remark-frontmatter@5.0.0: resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} @@ -4315,6 +5524,18 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -4335,12 +5556,24 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -4354,11 +5587,20 @@ packages: semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + semver@7.8.1: resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} @@ -4374,15 +5616,36 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.0: + resolution: {integrity: sha512-BqvG5XbwPZ4NV0DK90d86leEECMsoa8bO0nqnKWlBDYxri4GJ7c4EDInaF6q20lTh/mATmnDIKWJFfXnoVfH5g==} + engines: {node: '>=20.9.0'} + + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -4408,8 +5671,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -4444,6 +5707,9 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -4454,8 +5720,9 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -4465,6 +5732,29 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -4486,10 +5776,18 @@ packages: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} engines: {node: '>=0.10.0'} + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} @@ -4506,6 +5804,14 @@ packages: babel-plugin-macros: optional: true + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + tailwind-merge@3.6.0: resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} @@ -4516,13 +5822,8 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - deprecated: Old versions of tar 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 - - tar@7.5.15: - resolution: {integrity: sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==} + tar@7.5.21: + resolution: {integrity: sha512-XdhtCvlMywwxpCW8YEq3lOXBJpUPTR2OHHcwLPO3HwsJqOHa2Ok/oJ7ruGzp+JrKoRPVCzJwAdEjqLW/vNRPHA==} engines: {node: '>=18'} tiny-invariant@1.3.3: @@ -4534,10 +5835,6 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.2.3: - resolution: {integrity: sha512-g62dB+w1/OEFnPvmX0yd/HnetYITOL+1nJW7kitOycOeAvmbWC/nu0fwmmQ/kupNojqExzyC/T++pST/jRJ2mQ==} - engines: {node: '>=18'} - tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -4550,14 +5847,14 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} - engines: {node: '>=14.0.0'} - tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -4583,14 +5880,6 @@ packages: tree_sitter: optional: true - tree-sitter-c-sharp@0.23.5: - resolution: {integrity: sha512-xJGOeXPMmld0nES5+080N/06yY6LQi+KWGWV4LfZaZe6srJPtUtfhIbRSN7EZN6IaauzW28v6W4QHFwmeUW6HQ==} - peerDependencies: - tree-sitter: ^0.25.0 - peerDependenciesMeta: - tree-sitter: - optional: true - tree-sitter-c@0.23.6: resolution: {integrity: sha512-0dxXKznVyUA0s6PjNolJNs2yF87O5aL538A/eR6njA5oqX3C3vH4vnx3QdOKwuUdpKEcFdHuiDpRKLLCA/tjvQ==} peerDependencies: @@ -4836,6 +6125,15 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -4851,14 +6149,45 @@ packages: tw-animate-css@1.3.3: resolution: {integrity: sha512-tXE2TRWrskc4TU3RDd7T8n8Np/wCfoeH9gz22c7PzYqNPQ9FBGFbWWzwL0JyHcFp+jHozmF76tbHfPAx22ua2Q==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + type-is@2.1.0: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.67.0: + resolution: {integrity: sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@5.7.3: resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} @@ -4869,14 +6198,18 @@ packages: engines: {node: '>=14.17'} hasBin: true + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + underscore@1.13.8: resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@7.26.0: - resolution: {integrity: sha512-3O9Tf67pGhgOv9jM35AbhkXAKi13f3oy3aE4CSgr+TckGeY+/iu97ZXN+J7DpHPzLbVApFd1IFhcnBjREYXYcg==} + undici@7.29.0: + resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} engines: {node: '>=20.18.1'} unified@11.0.5: @@ -4905,12 +6238,18 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} @@ -5034,59 +6373,34 @@ packages: jsdom: optional: true - vitest@4.1.7: - resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.7 - '@vitest/browser-preview': 4.1.7 - '@vitest/browser-webdriverio': 4.1.7 - '@vitest/coverage-istanbul': 4.1.7 - '@vitest/coverage-v8': 4.1.7 - '@vitest/ui': 4.1.7 - happy-dom: '*' - jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/coverage-istanbul': - optional: true - '@vitest/coverage-v8': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} hasBin: true why-is-node-running@2.3.0: @@ -5097,6 +6411,14 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5116,8 +6438,8 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} @@ -5131,11 +6453,25 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + zod-to-json-schema@3.25.2: resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: zod: ^3.25.28 || ^4 + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -5171,14 +6507,14 @@ snapshots: dependencies: '@ai-sdk/provider': 3.0.10 '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 zod: 3.25.76 '@ai-sdk/provider-utils@4.0.27(zod@4.3.5)': dependencies: '@ai-sdk/provider': 3.0.10 '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 zod: 4.3.5 '@ai-sdk/provider@3.0.10': @@ -5187,15 +6523,145 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@anthropic-ai/mcpb@2.1.2': + dependencies: + '@inquirer/prompts': 6.0.1 + commander: 13.1.0 + fflate: 0.8.3 + galactus: 1.0.0 + ignore: 7.0.5 + node-forge: 1.4.0 + pretty-bytes: 5.6.0 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + '@babel/runtime@7.29.7': {} + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@date-fns/tz@1.5.0': {} + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.27.7': optional: true @@ -5352,6 +6818,63 @@ snapshots: '@esbuild/win32-x64@0.28.0': optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0))': + dependencies: + eslint: 9.39.5(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.5(jiti@2.7.0))': + dependencies: + eslint: 9.39.5(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.6': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.3.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.5': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@falkordblite/darwin-arm64@8.2.3-falkordb.4.16.3': + optional: true + + '@falkordblite/linux-x64@8.2.3-falkordb.4.16.3': + optional: true + '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 @@ -5361,21 +6884,21 @@ snapshots: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/dom': 1.7.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) '@floating-ui/utils@0.2.11': {} - '@hono/node-server@1.19.14(hono@4.12.23)': + '@hono/node-server@1.19.15(hono@4.12.34)': dependencies: - hono: 4.12.23 + hono: 4.12.34 - '@hookform/resolvers@3.10.0(react-hook-form@7.76.1(react@19.2.4))': + '@hookform/resolvers@3.10.0(react-hook-form@7.76.1(react@19.2.8))': dependencies: - react-hook-form: 7.76.1(react@19.2.4) + react-hook-form: 7.76.1(react@19.2.8) '@huggingface/jinja@0.5.9': {} @@ -5384,104 +6907,330 @@ snapshots: '@huggingface/jinja': 0.5.9 onnxruntime-node: 1.21.0 onnxruntime-web: 1.22.0-dev.20250409-89f8206ba4 - sharp: 0.34.5 + sharp: 0.35.0 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.0 + optional: true + + '@img/sharp-darwin-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.2 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.0': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.0 + optional: true + + '@img/sharp-darwin-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.2 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.0': + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.0': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.0': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.2': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.0': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.2': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.0': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.2': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.0': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-linux-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.0 optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-linux-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.2 optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-linux-arm@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.0 optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-linux-arm@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.2 optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-linux-ppc64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.0 optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-linux-ppc64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.2 optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-linux-riscv64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.0 optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-linux-riscv64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.2 optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-s390x@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.0 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-s390x@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.2 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-x64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.0 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.2 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.0': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.0': dependencies: - '@emnapi/runtime': 1.10.0 + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-wasm32@0.35.3': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-win32-arm64@0.35.0': + optional: true + + '@img/sharp-win32-arm64@0.35.3': + optional: true + + '@img/sharp-win32-ia32@0.35.0': optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-win32-ia32@0.35.3': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-x64@0.35.0': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-x64@0.35.3': optional: true + '@inquirer/checkbox@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.3 + + '@inquirer/confirm@4.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/core@9.2.1': + dependencies: + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + '@types/mute-stream': 0.0.4 + '@types/node': 22.19.19 + '@types/wrap-ansi': 3.0.0 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 1.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/editor@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + external-editor: 3.1.0 + + '@inquirer/expand@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/figures@1.0.15': {} + + '@inquirer/input@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/number@2.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/password@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + + '@inquirer/prompts@6.0.1': + dependencies: + '@inquirer/checkbox': 3.0.1 + '@inquirer/confirm': 4.0.1 + '@inquirer/editor': 3.0.1 + '@inquirer/expand': 3.0.1 + '@inquirer/input': 3.0.1 + '@inquirer/number': 2.0.1 + '@inquirer/password': 3.0.1 + '@inquirer/rawlist': 3.0.1 + '@inquirer/search': 2.0.1 + '@inquirer/select': 3.0.1 + + '@inquirer/rawlist@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/search@2.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/select@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.3 + + '@inquirer/type@2.0.0': + dependencies: + mute-stream: 1.0.0 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -5526,29 +7275,29 @@ snapshots: '@kwsites/promise-deferred@1.1.1': {} - '@modelcontextprotocol/ext-apps@1.7.2(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@4.3.5)': + '@modelcontextprotocol/ext-apps@1.7.2(@modelcontextprotocol/sdk@1.30.0(zod@4.3.5))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.3.5)': dependencies: - '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.5) + '@modelcontextprotocol/sdk': 1.30.0(zod@4.3.5) '@standard-schema/spec': 1.1.0 zod: 4.3.5 optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) - '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.30.0(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.14(hono@4.12.23) + '@hono/node-server': 1.19.15(hono@4.12.34) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.23 - jose: 6.2.3 + express-rate-limit: 8.6.2(express@5.2.1) + hono: 4.12.34 + jose: 6.2.9 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 @@ -5557,20 +7306,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@modelcontextprotocol/sdk@1.29.0(zod@4.3.5)': + '@modelcontextprotocol/sdk@1.30.0(zod@4.3.5)': dependencies: - '@hono/node-server': 1.19.14(hono@4.12.23) + '@hono/node-server': 1.19.15(hono@4.12.34) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.23 - jose: 6.2.3 + express-rate-limit: 8.6.2(express@5.2.1) + hono: 4.12.34 + jose: 6.2.9 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 @@ -5622,30 +7371,44 @@ snapshots: '@napi-rs/canvas-linux-x64-musl': 0.1.80 '@napi-rs/canvas-win32-x64-msvc': 0.1.80 - '@next/env@16.1.6': {} + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@next/env@16.3.1': {} + + '@next/eslint-plugin-next@16.3.1(eslint@9.39.5(jiti@2.7.0))': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5(jiti@2.7.0)) + fast-glob: 3.3.1 + transitivePeerDependencies: + - eslint - '@next/swc-darwin-arm64@16.1.6': + '@next/swc-darwin-arm64@16.3.1': optional: true - '@next/swc-darwin-x64@16.1.6': + '@next/swc-darwin-x64@16.3.1': optional: true - '@next/swc-linux-arm64-gnu@16.1.6': + '@next/swc-linux-arm64-gnu@16.3.1': optional: true - '@next/swc-linux-arm64-musl@16.1.6': + '@next/swc-linux-arm64-musl@16.3.1': optional: true - '@next/swc-linux-x64-gnu@16.1.6': + '@next/swc-linux-x64-gnu@16.3.1': optional: true - '@next/swc-linux-x64-musl@16.1.6': + '@next/swc-linux-x64-musl@16.3.1': optional: true - '@next/swc-win32-arm64-msvc@16.1.6': + '@next/swc-win32-arm64-msvc@16.3.1': optional: true - '@next/swc-win32-x64-msvc@16.1.6': + '@next/swc-win32-x64-msvc@16.3.1': optional: true '@nodelib/fs.scandir@2.1.5': @@ -5660,6 +7423,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@nolyfill/is-core-module@1.0.39': {} + '@openrouter/ai-sdk-provider@1.5.4(ai@6.0.193(zod@3.25.76))(zod@3.25.76)': dependencies: '@openrouter/sdk': 0.1.27 @@ -5693,8 +7458,6 @@ snapshots: '@protobufjs/float@1.0.2': {} - '@protobufjs/inquire@1.1.2': {} - '@protobufjs/path@1.1.2': {} '@protobufjs/pool@1.1.0': {} @@ -5705,691 +7468,691 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-aspect-ratio@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-aspect-ratio@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-context@1.1.3(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-context@1.1.3(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.8) '@radix-ui/rect': 1.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-progress@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-progress@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.8 + use-sync-external-store: 1.6.0(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: '@radix-ui/rect': 1.1.1 - react: 19.2.4 + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.8) + react: 19.2.8 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) @@ -6493,6 +8256,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.60.4': optional: true + '@rtsao/scc@1.1.0': {} + '@shikijs/core@4.1.0': dependencies: '@shikijs/primitive': 4.1.0 @@ -6541,7 +8306,7 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@swc/helpers@0.5.15': + '@swc/helpers@0.5.23': dependencies: tslib: 2.8.1 @@ -6611,7 +8376,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 - postcss: 8.5.15 + postcss: 8.5.23 tailwindcss: 4.3.0 '@turbo/darwin-64@2.9.16': @@ -6632,10 +8397,15 @@ snapshots: '@turbo/windows-arm64@2.9.16': optional: true - '@types/chai@5.2.3': + '@tybys/wasm-util@0.10.3': dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 '@types/cytoscape@3.31.0': dependencies: @@ -6679,12 +8449,20 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 '@types/ms@2.1.0': {} + '@types/mute-stream@0.0.4': + dependencies: + '@types/node': 22.19.19 + '@types/node@22.19.19': dependencies: undici-types: 6.21.0 @@ -6703,12 +8481,175 @@ snapshots: '@types/unist@3.0.3': {} + '@types/wrap-ansi@3.0.0': {} + + '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/type-utils': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + '@typescript-eslint/utils': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.67.0 + eslint: 9.39.5(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.67.0 + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.67.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@5.7.3) + '@typescript-eslint/types': 8.67.0 + debug: 4.4.3 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.67.0': + dependencies: + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 + + '@typescript-eslint/tsconfig-utils@8.67.0(typescript@5.7.3)': + dependencies: + typescript: 5.7.3 + + '@typescript-eslint/type-utils@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.67.0': {} + + '@typescript-eslint/typescript-estree@8.67.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/project-service': 8.67.0(typescript@5.7.3) + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@5.7.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.7.3) + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.67.0': + dependencies: + '@typescript-eslint/types': 8.67.0 + eslint-visitor-keys: 5.0.1 + '@ungap/structured-clone@1.3.1': {} - '@vercel/analytics@1.6.1(next@16.1.6(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + '@vercel/analytics@1.6.1(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(@types/node@22.19.19)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)': optionalDependencies: - next: 16.1.6(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 + next: 16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(@types/node@22.19.19)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 '@vercel/oidc@3.2.0': {} @@ -6720,15 +8661,6 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.1.7': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.1.7 - '@vitest/utils': 4.1.7 - chai: 6.2.2 - tinyrainbow: 3.1.0 - '@vitest/mocker@3.2.4(vite@7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3))': dependencies: '@vitest/spy': 3.2.4 @@ -6737,64 +8669,32 @@ snapshots: optionalDependencies: vite: 7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3) - '@vitest/mocker@4.1.7(vite@7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3))': - dependencies: - '@vitest/spy': 4.1.7 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3) - '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.1.7': - dependencies: - tinyrainbow: 3.1.0 - '@vitest/runner@3.2.4': dependencies: '@vitest/utils': 3.2.4 pathe: 2.0.3 strip-literal: 3.1.0 - '@vitest/runner@4.1.7': - dependencies: - '@vitest/utils': 4.1.7 - pathe: 2.0.3 - '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/snapshot@4.1.7': - dependencies: - '@vitest/pretty-format': 4.1.7 - '@vitest/utils': 4.1.7 - magic-string: 0.30.21 - pathe: 2.0.3 - '@vitest/spy@3.2.4': dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.1.7': {} - '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.1.7': - dependencies: - '@vitest/pretty-format': 4.1.7 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 - '@xmldom/xmldom@0.8.13': {} accepts@2.0.0: @@ -6802,6 +8702,12 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn@8.18.0: {} + agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -6828,13 +8734,24 @@ snapshots: optionalDependencies: ajv: 8.20.0 + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -6856,23 +8773,104 @@ snapshots: dependencies: sprintf-js: 1.0.3 + argparse@2.0.1: {} + aria-hidden@1.2.6: dependencies: tslib: 2.8.1 + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + asynckit@0.4.0: {} - autoprefixer@10.5.0(postcss@8.5.15): + autoprefixer@10.5.0(postcss@8.5.23): dependencies: browserslist: 4.28.2 caniuse-lite: 1.0.30001793 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.15 + postcss: 8.5.23 postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.13.0: {} + axios@1.16.1(debug@4.4.3): dependencies: follow-redirects: 1.16.0(debug@4.4.3) @@ -6883,25 +8881,29 @@ snapshots: - debug - supports-color + axobject-query@4.1.0: {} + bail@2.0.2: {} balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-js@1.5.1: {} - baseline-browser-mapping@2.10.32: {} + baseline-browser-mapping@2.11.15: {} bluebird@3.4.7: {} - body-parser@2.2.2: + body-parser@2.3.0: dependencies: bytes: 3.1.2 - content-type: 1.0.5 + content-type: 2.1.0 debug: 4.4.3 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 on-finished: 2.4.1 - qs: 6.15.2 + qs: 6.15.3 raw-body: 3.0.2 type-is: 2.1.0 transitivePeerDependencies: @@ -6911,17 +8913,26 @@ snapshots: boolean@3.2.0: {} - brace-expansion@2.1.1: + brace-expansion@1.1.18: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.1.4: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.9: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.32 + baseline-browser-mapping: 2.11.15 caniuse-lite: 1.0.30001793 electron-to-chromium: 1.5.364 node-releases: 2.0.46 @@ -6936,13 +8947,24 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 + callsites@3.1.0: {} + caniuse-lite@1.0.30001793: {} + caniuse-lite@1.0.30001809: {} + ccount@2.0.1: {} chai@5.3.3: @@ -6953,7 +8975,10 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 - chai@6.2.2: {} + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 character-entities-html4@2.1.0: {} @@ -6961,6 +8986,8 @@ snapshots: character-entities@2.0.2: {} + chardet@0.7.0: {} + check-error@2.1.3: {} cheerio-select@2.1.0: @@ -6983,21 +9010,21 @@ snapshots: parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 parse5-parser-stream: 7.1.2 - undici: 7.26.0 + undici: 7.29.0 whatwg-mimetype: 4.0.0 chokidar@5.0.0: dependencies: readdirp: 5.0.0 - chownr@2.0.0: {} - chownr@3.0.0: {} class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 + cli-width@4.1.0: {} + client-only@0.0.1: {} cliui@8.0.1: @@ -7020,21 +9047,21 @@ snapshots: npmlog: 6.0.2 rc: 1.2.8 semver: 7.8.1 - tar: 6.2.1 + tar: 7.5.21 url-join: 4.0.1 which: 2.0.2 yargs: 17.7.2 transitivePeerDependencies: - supports-color - cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -7055,13 +9082,17 @@ snapshots: commander@12.1.0: {} + commander@13.1.0: {} + + concat-map@0.0.1: {} + console-control-strings@1.1.0: {} content-disposition@1.1.0: {} content-type@1.0.5: {} - content-type@2.0.0: {} + content-type@2.1.0: {} convert-source-map@2.0.0: {} @@ -7134,10 +9165,34 @@ snapshots: d3-timer@3.0.1: {} + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + date-fns-jalali@4.1.0-0: {} date-fns@4.1.0: {} + debug@3.2.7: + dependencies: + ms: 2.1.3 + debug@4.4.3: dependencies: ms: 2.1.3 @@ -7152,6 +9207,8 @@ snapshots: deep-extend@0.6.0: {} + deep-is@0.1.4: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -7184,6 +9241,10 @@ snapshots: dingbat-to-unicode@1.0.1: {} + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + dom-helpers@5.2.1: dependencies: '@babel/runtime': 7.29.7 @@ -7223,11 +9284,11 @@ snapshots: electron-to-chromium@1.5.364: {} - embla-carousel-react@8.6.0(react@19.2.4): + embla-carousel-react@8.6.0(react@19.2.8): dependencies: embla-carousel: 8.6.0 embla-carousel-reactive-utils: 8.6.0(embla-carousel@8.6.0) - react: 19.2.4 + react: 19.2.8 embla-carousel-reactive-utils@8.6.0(embla-carousel@8.6.0): dependencies: @@ -7257,13 +9318,94 @@ snapshots: entities@7.0.1: {} + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.4 + function.prototype.name: 1.2.0 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.2 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.8 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.22 + es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-iterator-helpers@1.4.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 - es-module-lexer@2.1.0: {} + es-module-lexer@1.7.0: {} es-object-atoms@1.1.2: dependencies: @@ -7276,6 +9418,19 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.4 + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.4 + + es-to-primitive@1.3.4: + dependencies: + es-abstract-get: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + es6-error@4.1.1: {} esbuild@0.27.7: @@ -7344,33 +9499,241 @@ snapshots: escape-string-regexp@5.0.0: {} + eslint-config-next@16.3.1(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3): + dependencies: + '@next/eslint-plugin-next': 16.3.1(eslint@9.39.5(jiti@2.7.0)) + eslint: 9.39.5(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5(jiti@2.7.0)) + globals: 16.4.0 + typescript-eslint: 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + optionalDependencies: + typescript: 5.7.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.2 + resolve: 2.0.0-next.7 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + get-tsconfig: 4.14.3 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.16 + unrs-resolver: 1.12.2 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + eslint: 9.39.5(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.5(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + hasown: 2.0.4 + is-core-module: 2.16.2 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.10 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5(jiti@2.7.0)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.13.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.5(jiti@2.7.0) + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.8 + eslint: 9.39.5(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 3.25.76 + zod-validation-error: 4.0.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.5(jiti@2.7.0)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.4.0 + eslint: 9.39.5(jiti@2.7.0) + estraverse: 5.3.0 + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.7 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.5(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.6 + '@eslint/js': 9.39.5 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 + esutils@2.0.3: {} + etag@1.8.1: {} eventemitter3@4.0.7: {} - eventsource-parser@3.1.0: {} + eventsource-parser@3.1.1: {} eventsource@3.0.7: dependencies: - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 expect-type@1.3.0: {} - express-rate-limit@8.5.2(express@5.2.1): + express-rate-limit@8.6.2(express@5.2.1): dependencies: + debug: 4.4.3 express: 5.2.1 - ip-address: 10.2.0 + ip-address: 10.5.0 + transitivePeerDependencies: + - supports-color express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.2.2 + body-parser: 2.3.0 content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 @@ -7389,8 +9752,8 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.15.2 - range-parser: 1.2.1 + qs: 6.15.3 + range-parser: 1.3.0 router: 2.2.0 send: 1.2.1 serve-static: 2.2.1 @@ -7406,7 +9769,13 @@ snapshots: extend@3.0.2: {} - falkordb@6.6.2(@opentelemetry/api@1.9.1): + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + falkordb@6.7.0(@opentelemetry/api@1.9.1): dependencies: '@js-temporal/polyfill': 0.5.1 '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) @@ -7418,14 +9787,22 @@ snapshots: - '@node-rs/xxhash' - '@opentelemetry/api' - falkordblite@0.2.0(falkordb@6.6.2(@opentelemetry/api@1.9.1)): + falkordblite@0.2.0(falkordb@6.7.0(@opentelemetry/api@1.9.1)): dependencies: - falkordb: 6.6.2(@opentelemetry/api@1.9.1) + falkordb: 6.7.0(@opentelemetry/api@1.9.1) fast-deep-equal@3.1.3: {} fast-equals@5.4.0: {} + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -7434,7 +9811,11 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-uri@3.1.2: {} + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.1.5: {} fastq@1.20.1: dependencies: @@ -7448,6 +9829,12 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + fflate@0.8.3: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -7463,12 +9850,35 @@ snapshots: transitivePeerDependencies: - supports-color + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.4 + keyv: 4.5.4 + flatbuffers@25.9.23: {} + flatted@3.4.4: {} + + flora-colossus@2.0.0: + dependencies: + debug: 4.4.3 + fs-extra: 10.1.0 + transitivePeerDependencies: + - supports-color + follow-redirects@1.16.0(debug@4.4.3): optionalDependencies: debug: 4.4.3 + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -7488,26 +9898,28 @@ snapshots: fraction.js@5.3.4: {} - framer-motion@12.40.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + framer-motion@12.40.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: motion-dom: 12.40.0 motion-utils: 12.39.0 tslib: 2.8.1 optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) fresh@2.0.0: {} - fs-extra@11.3.5: + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.1 universalify: 2.0.1 - fs-minipass@2.1.0: + fs-extra@11.3.5: dependencies: - minipass: 3.3.6 + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 fsevents@2.3.2: optional: true @@ -7517,6 +9929,28 @@ snapshots: function-bind@1.1.2: {} + function.prototype.name@1.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + es-define-property: 1.0.1 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 + is-callable: 1.2.7 + is-document.all: 1.0.0 + + functions-have-names@1.2.3: {} + + galactus@1.0.0: + dependencies: + debug: 4.4.3 + flora-colossus: 2.0.0 + fs-extra: 10.1.0 + transitivePeerDependencies: + - supports-color + gauge@4.0.4: dependencies: aproba: 2.1.0 @@ -7528,8 +9962,12 @@ snapshots: strip-ansi: 6.0.1 wide-align: 1.1.5 + generator-function@2.0.1: {} + generic-pool@3.9.0: {} + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} get-intrinsic@1.3.0: @@ -7552,10 +9990,24 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.2 + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.14.3: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -7571,9 +10023,13 @@ snapshots: es6-error: 4.1.1 matcher: 3.0.0 roarr: 2.15.4 - semver: 7.8.1 + semver: 7.8.5 serialize-error: 7.0.1 + globals@14.0.0: {} + + globals@16.4.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -7585,17 +10041,25 @@ snapshots: gray-matter@4.0.3: dependencies: - js-yaml: 3.14.2 + js-yaml: 3.15.1 kind-of: 6.0.3 section-matter: 1.0.0 strip-bom-string: 1.0.0 guid-typescript@1.0.9: {} + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + has-symbols@1.1.0: {} has-tostringtag@1.0.2: @@ -7626,7 +10090,13 @@ snapshots: dependencies: '@types/hast': 3.0.4 - hono@4.12.23: {} + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + hono@4.12.34: {} html-void-elements@3.0.0: {} @@ -7652,53 +10122,191 @@ snapshots: transitivePeerDependencies: - supports-color + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 + ignore@5.3.2: {} + ignore@7.0.5: {} immediate@3.0.6: {} + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + inherits@2.0.4: {} ini@1.3.8: {} - input-otp@1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + input-otp@1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.4 + side-channel: 1.1.1 internmap@2.0.3: {} - ip-address@10.2.0: {} + ip-address@10.5.0: {} ipaddr.js@1.9.1: {} + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.8.5 + + is-callable@1.2.7: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + is-extendable@0.1.1: {} is-extglob@2.1.1: {} + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-number@7.0.0: {} is-plain-obj@4.1.0: {} is-promise@4.0.0: {} + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.22 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + isarray@1.0.0: {} + isarray@2.0.5: {} + isexe@2.0.0: {} + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 @@ -7707,26 +10315,44 @@ snapshots: jiti@2.7.0: {} - jose@6.2.3: {} + jose@6.2.9: {} js-tokens@4.0.0: {} js-tokens@9.0.1: {} - js-yaml@3.14.2: + js-yaml@3.15.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 + js-yaml@4.3.1: + dependencies: + argparse: 2.0.1 + jsbi@4.3.2: {} + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} json-schema-typed@8.0.2: {} json-schema@0.4.0: {} - json-stringify-safe@5.0.1: {} + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} jsonfile@6.2.1: dependencies: @@ -7734,6 +10360,13 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + jszip@3.10.1: dependencies: lie: 3.3.0 @@ -7741,6 +10374,10 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + kind-of@6.0.3: {} kuzu@0.11.3: @@ -7750,6 +10387,17 @@ snapshots: transitivePeerDependencies: - supports-color + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -7803,6 +10451,12 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + lodash@4.18.1: {} long@5.3.2: {} @@ -7823,9 +10477,13 @@ snapshots: lru-cache@10.4.3: {} - lucide-react@0.564.0(react@19.2.4): + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.564.0(react@19.2.8): dependencies: - react: 19.2.4 + react: 19.2.8 magic-string@0.30.21: dependencies: @@ -7977,7 +10635,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 - media-typer@1.1.0: {} + media-typer@1.1.1: {} memory-stream@1.0.0: dependencies: @@ -8202,31 +10860,26 @@ snapshots: dependencies: mime-db: 1.54.0 - minimatch@9.0.9: + minimatch@10.2.6: dependencies: - brace-expansion: 2.1.1 + brace-expansion: 5.0.9 - minimist@1.2.8: {} + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.18 - minipass@3.3.6: + minimatch@9.0.9: dependencies: - yallist: 4.0.0 + brace-expansion: 2.1.4 - minipass@5.0.0: {} + minimist@1.2.8: {} minipass@7.1.3: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - minizlib@3.1.0: dependencies: minipass: 7.1.3 - mkdirp@1.0.4: {} - motion-dom@12.40.0: dependencies: motion-utils: 12.39.0 @@ -8235,42 +10888,49 @@ snapshots: ms@2.1.3: {} + mute-stream@1.0.0: {} + nan@2.27.0: optional: true - nanoid@3.3.12: {} + nanoid@3.3.18: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} negotiator@1.0.0: {} - next-themes@0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next-themes@0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) - next@16.1.6(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(@types/node@22.19.19)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@next/env': 16.1.6 - '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.32 - caniuse-lite: 1.0.30001793 - postcss: 8.4.31 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(react@19.2.4) + '@next/env': 16.3.1 + '@swc/helpers': 0.5.23 + baseline-browser-mapping: 2.11.15 + caniuse-lite: 1.0.30001809 + postcss: 8.5.23 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.8) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.6 - '@next/swc-darwin-x64': 16.1.6 - '@next/swc-linux-arm64-gnu': 16.1.6 - '@next/swc-linux-arm64-musl': 16.1.6 - '@next/swc-linux-x64-gnu': 16.1.6 - '@next/swc-linux-x64-musl': 16.1.6 - '@next/swc-win32-arm64-msvc': 16.1.6 - '@next/swc-win32-x64-msvc': 16.1.6 + '@next/swc-darwin-arm64': 16.3.1 + '@next/swc-darwin-x64': 16.3.1 + '@next/swc-linux-arm64-gnu': 16.3.1 + '@next/swc-linux-arm64-musl': 16.3.1 + '@next/swc-linux-x64-gnu': 16.3.1 + '@next/swc-linux-x64-musl': 16.3.1 + '@next/swc-win32-arm64-msvc': 16.3.1 + '@next/swc-win32-x64-msvc': 16.3.1 '@opentelemetry/api': 1.9.1 '@playwright/test': 1.60.0 - sharp: 0.34.5 + sharp: 0.35.3(@types/node@22.19.19) transitivePeerDependencies: - '@babel/core' + - '@types/node' - babel-plugin-macros node-addon-api@6.1.0: {} @@ -8284,6 +10944,15 @@ snapshots: node-api-headers@1.9.0: {} + node-exports-info@1.6.2: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-forge@1.4.0: {} + node-gyp-build@4.8.4: {} node-releases@2.0.46: {} @@ -8305,7 +10974,41 @@ snapshots: object-keys@1.1.1: {} - obug@2.1.1: {} + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 on-finished@2.4.1: dependencies: @@ -8331,7 +11034,7 @@ snapshots: dependencies: global-agent: 3.0.0 onnxruntime-common: 1.21.0 - tar: 7.5.15 + tar: 7.5.21 onnxruntime-web@1.22.0-dev.20250409-89f8206ba4: dependencies: @@ -8340,14 +11043,44 @@ snapshots: long: 5.3.2 onnxruntime-common: 1.22.0-dev.20250409-89f8206ba4 platform: 1.3.6 - protobufjs: 7.6.1 + protobufjs: 7.6.5 option@0.2.4: {} + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + os-tmpdir@1.0.2: {} + + own-keys@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + package-json-from-dist@1.0.1: {} pako@1.0.11: {} + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 @@ -8363,10 +11096,14 @@ snapshots: parseurl@1.3.3: {} + path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -8405,22 +11142,22 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + possible-typed-array-names@1.1.0: {} + postcss-value-parser@4.2.0: {} - postcss@8.4.31: + postcss@8.5.23: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.18 picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.15: - dependencies: - nanoid: 3.3.12 - picocolors: 1.1.1 - source-map-js: 1.2.1 + prelude-ls@1.2.1: {} prettier@3.8.3: {} + pretty-bytes@5.6.0: {} + process-nextick-args@2.0.1: {} prop-types@15.8.1: @@ -8431,7 +11168,7 @@ snapshots: property-information@7.1.0: {} - protobufjs@7.6.1: + protobufjs@7.6.5: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 @@ -8439,7 +11176,6 @@ snapshots: '@protobufjs/eventemitter': 1.1.1 '@protobufjs/fetch': 1.1.1 '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.2 '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.1 @@ -8453,19 +11189,22 @@ snapshots: proxy-from-env@2.1.0: {} - qs@6.15.2: + punycode@2.3.1: {} + + qs@6.15.3: dependencies: - side-channel: 1.1.0 + es-define-property: 1.0.1 + side-channel: 1.1.1 queue-microtask@1.2.3: {} - range-parser@1.2.1: {} + range-parser@1.3.0: {} raw-body@3.0.2: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 unpipe: 1.0.0 rc@1.2.8: @@ -8475,76 +11214,76 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-day-picker@9.13.2(react@19.2.4): + react-day-picker@9.13.2(react@19.2.8): dependencies: '@date-fns/tz': 1.5.0 date-fns: 4.1.0 date-fns-jalali: 4.1.0-0 - react: 19.2.4 + react: 19.2.8 - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.8(react@19.2.8): dependencies: - react: 19.2.4 + react: 19.2.8 scheduler: 0.27.0 - react-hook-form@7.76.1(react@19.2.4): + react-hook-form@7.76.1(react@19.2.8): dependencies: - react: 19.2.4 + react: 19.2.8 react-is@16.13.1: {} react-is@18.3.1: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.8): dependencies: - react: 19.2.4 - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.8 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.8) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.4): + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.8): dependencies: - react: 19.2.4 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.8 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.8) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) - use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.8) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.8) optionalDependencies: '@types/react': 19.2.14 - react-resizable-panels@2.1.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-resizable-panels@2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) - react-smooth@4.0.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-smooth@4.0.4(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: fast-equals: 5.4.0 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-transition-group: 4.4.5(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.8): dependencies: get-nonce: 1.0.1 - react: 19.2.4 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - react-transition-group@4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-transition-group@4.4.5(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@babel/runtime': 7.29.7 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) - react@19.2.4: {} + react@19.2.8: {} readable-stream@2.3.8: dependencies: @@ -8568,15 +11307,15 @@ snapshots: dependencies: decimal.js-light: 2.5.1 - recharts@2.15.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + recharts@2.15.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: clsx: 2.1.1 eventemitter3: 4.0.7 lodash: 4.18.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) react-is: 18.3.1 - react-smooth: 4.0.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-smooth: 4.0.4(react-dom@19.2.8(react@19.2.8))(react@19.2.8) recharts-scale: 0.4.5 tiny-invariant: 1.3.3 victory-vendor: 36.9.2 @@ -8592,6 +11331,17 @@ snapshots: - '@node-rs/xxhash' - '@opentelemetry/api' + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + regex-recursion@6.0.2: dependencies: regex-utilities: 2.3.0 @@ -8602,6 +11352,15 @@ snapshots: dependencies: regex-utilities: 2.3.0 + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + remark-frontmatter@5.0.0: dependencies: '@types/mdast': 4.0.4 @@ -8641,6 +11400,19 @@ snapshots: require-from-string@2.0.2: {} + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@2.0.0-next.7: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + node-exports-info: 1.6.2 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + reusify@1.1.0: {} roarr@2.15.4: @@ -8697,10 +11469,29 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + safer-buffer@2.1.2: {} scheduler@0.27.0: {} @@ -8712,8 +11503,12 @@ snapshots: semver-compare@1.0.0: {} + semver@6.3.1: {} + semver@7.8.1: {} + semver@7.8.5: {} + send@1.2.1: dependencies: debug: 4.4.3 @@ -8725,7 +11520,7 @@ snapshots: mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 - range-parser: 1.2.1 + range-parser: 1.3.0 statuses: 2.0.2 transitivePeerDependencies: - supports-color @@ -8745,40 +11540,97 @@ snapshots: set-blocking@2.0.0: {} + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} - sharp@0.34.5: + sharp@0.35.0: dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.8.1 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.0 + '@img/sharp-darwin-x64': 0.35.0 + '@img/sharp-freebsd-wasm32': 0.35.0 + '@img/sharp-libvips-darwin-arm64': 1.3.0 + '@img/sharp-libvips-darwin-x64': 1.3.0 + '@img/sharp-libvips-linux-arm': 1.3.0 + '@img/sharp-libvips-linux-arm64': 1.3.0 + '@img/sharp-libvips-linux-ppc64': 1.3.0 + '@img/sharp-libvips-linux-riscv64': 1.3.0 + '@img/sharp-libvips-linux-s390x': 1.3.0 + '@img/sharp-libvips-linux-x64': 1.3.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 + '@img/sharp-linux-arm': 0.35.0 + '@img/sharp-linux-arm64': 0.35.0 + '@img/sharp-linux-ppc64': 0.35.0 + '@img/sharp-linux-riscv64': 0.35.0 + '@img/sharp-linux-s390x': 0.35.0 + '@img/sharp-linux-x64': 0.35.0 + '@img/sharp-linuxmusl-arm64': 0.35.0 + '@img/sharp-linuxmusl-x64': 0.35.0 + '@img/sharp-webcontainers-wasm32': 0.35.0 + '@img/sharp-win32-arm64': 0.35.0 + '@img/sharp-win32-ia32': 0.35.0 + '@img/sharp-win32-x64': 0.35.0 + + sharp@0.35.3(@types/node@22.19.19): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 22.19.19 + optional: true shebang-command@2.0.0: dependencies: @@ -8817,7 +11669,7 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -8841,10 +11693,10 @@ snapshots: transitivePeerDependencies: - supports-color - sonner@1.7.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + sonner@1.7.4(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) source-map-js@1.2.1: {} @@ -8854,13 +11706,18 @@ snapshots: sprintf-js@1.1.3: {} + stable-hash@0.0.5: {} + stackback@0.0.2: {} statuses@2.0.2: {} std-env@3.10.0: {} - std-env@4.1.0: {} + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 string-width@4.2.3: dependencies: @@ -8874,6 +11731,57 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.2.0 + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.1 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.11: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -8897,16 +11805,28 @@ snapshots: strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} + strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 - styled-jsx@5.1.6(react@19.2.4): + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.8): dependencies: client-only: 0.0.1 - react: 19.2.4 + react: 19.2.8 + optionalDependencies: + '@babel/core': 7.29.7 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} tailwind-merge@3.6.0: {} @@ -8914,16 +11834,7 @@ snapshots: tapable@2.3.3: {} - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - - tar@7.5.15: + tar@7.5.21: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -8937,8 +11848,6 @@ snapshots: tinyexec@0.3.2: {} - tinyexec@1.2.3: {} - tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -8948,10 +11857,12 @@ snapshots: tinyrainbow@2.0.0: {} - tinyrainbow@3.1.0: {} - tinyspy@4.0.4: {} + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -8964,16 +11875,10 @@ snapshots: node-gyp-build: 4.8.4 optional: true - tree-sitter-c-sharp@0.21.3: - dependencies: - node-addon-api: 8.8.0 - node-gyp-build: 4.8.4 - - tree-sitter-c-sharp@0.23.5(tree-sitter@0.22.4): + tree-sitter-c-sharp@0.21.3(tree-sitter@0.22.4): dependencies: node-addon-api: 8.8.0 node-gyp-build: 4.8.4 - optionalDependencies: tree-sitter: 0.22.4 tree-sitter-c@0.23.6: @@ -9184,6 +12089,17 @@ snapshots: trough@2.2.0: {} + ts-api-utils@2.5.0(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + tslib@2.8.1: {} tsx@4.22.3: @@ -9203,23 +12119,80 @@ snapshots: tw-animate-css@1.3.3: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + type-fest@0.13.1: {} + type-fest@0.21.3: {} + type-is@2.1.0: dependencies: - content-type: 2.0.0 - media-typer: 1.1.0 + content-type: 2.1.0 + media-typer: 1.1.1 mime-types: 3.0.2 + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.8: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.7.3) + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + typescript@5.7.3: {} typescript@5.9.3: {} + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + underscore@1.13.8: {} undici-types@6.21.0: {} - undici@7.26.0: {} + undici@7.29.0: {} unified@11.0.5: dependencies: @@ -9258,42 +12231,73 @@ snapshots: unpipe@1.0.0: {} + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + url-join@4.0.1: {} - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.8): dependencies: - react: 19.2.4 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.8): dependencies: detect-node-es: 1.1.0 - react: 19.2.4 + react: 19.2.8 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - use-sync-external-store@1.6.0(react@19.2.4): + use-sync-external-store@1.6.0(react@19.2.8): dependencies: - react: 19.2.4 + react: 19.2.8 util-deprecate@1.0.2: {} vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -9351,7 +12355,7 @@ snapshots: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.15 + postcss: 8.5.23 rollup: 4.60.4 tinyglobby: 0.2.16 optionalDependencies: @@ -9403,40 +12407,53 @@ snapshots: - tsx - yaml - vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(vite@7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)): - dependencies: - '@vitest/expect': 4.1.7 - '@vitest/mocker': 4.1.7(vite@7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)) - '@vitest/pretty-format': 4.1.7 - '@vitest/runner': 4.1.7 - '@vitest/snapshot': 4.1.7 - '@vitest/spy': 4.1.7 - '@vitest/utils': 4.1.7 - es-module-lexer: 2.1.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.2.3 - tinyglobby: 0.2.16 - tinyrainbow: 3.1.0 - vite: 7.3.3(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@types/node': 22.19.19 - transitivePeerDependencies: - - msw - whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 whatwg-mimetype@4.0.0: {} + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.2.0 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.22 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.22: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -9450,6 +12467,14 @@ snapshots: dependencies: string-width: 4.2.3 + word-wrap@1.2.5: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -9468,7 +12493,7 @@ snapshots: y18n@5.0.8: {} - yallist@4.0.0: {} + yallist@3.1.1: {} yallist@5.0.0: {} @@ -9484,6 +12509,10 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} + + yoctocolors-cjs@2.1.3: {} + zod-to-json-schema@3.25.2(zod@3.25.76): dependencies: zod: 3.25.76 @@ -9492,6 +12521,10 @@ snapshots: dependencies: zod: 4.3.5 + zod-validation-error@4.0.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod@3.25.76: {} zod@4.3.5: {} diff --git a/scripts/release/__tests__/smoke-package.test.ts b/scripts/release/__tests__/smoke-package.test.ts new file mode 100644 index 00000000..95b96b06 --- /dev/null +++ b/scripts/release/__tests__/smoke-package.test.ts @@ -0,0 +1,246 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import type { SpawnSyncReturns } from 'node:child_process'; +import { + resolveNpmInvocation, + resolveSmokeInput, + resolveValidatedPackageInput, + smokePackage, +} from '../smoke-package.mjs'; + +const temporaryDirectories: string[] = []; + +afterEach(() => { + for (const directory of temporaryDirectories.splice(0)) { + rmSync(directory, { recursive: true, force: true }); + } +}); + +function processResult( + status: number, + stdout = '', + stderr = '', +): SpawnSyncReturns { + return { + pid: 123, + output: [null, stdout, stderr], + stdout, + stderr, + status, + signal: null, + error: undefined, + }; +} + +function createTarball(): string { + const directory = mkdtempSync(join(tmpdir(), 'codegraph-smoke-test-')); + temporaryDirectories.push(directory); + const tarballPath = join(directory, 'codegraph-mcp-0.1.0.tgz'); + writeFileSync(tarballPath, 'fixture'); + return tarballPath; +} + +function successfulRunner() { + return { + run: vi.fn() + .mockReturnValueOnce(processResult(0)) + .mockReturnValueOnce(processResult(0, '0.1.0\n')) + .mockReturnValueOnce(processResult(0, JSON.stringify({ + tools: ['search', 'knowledge', 'codebase', 'query'], + databaseVerified: true, + }))), + }; +} + +describe('smokePackage', () => { + it('launches npm through cmd.exe on Windows', () => { + expect(resolveNpmInvocation('win32', 'C:\\Windows\\System32\\cmd.exe')).toEqual({ + command: 'C:\\Windows\\System32\\cmd.exe', + args: ['/d', '/s', '/c', 'npm.cmd'], + }); + expect(resolveNpmInvocation('linux')).toEqual({ command: 'npm', args: [] }); + expect(resolveNpmInvocation('darwin')).toEqual({ command: 'npm', args: [] }); + }); + + it('rejects a missing tarball before running commands', async () => { + const runner = successfulRunner(); + + await expect(smokePackage({ + tarballPath: '/tmp/codegraph-missing-package.tgz', + expectedVersion: '0.1.0', + runner, + })).rejects.toThrow('does not exist'); + expect(runner.run).not.toHaveBeenCalled(); + }); + + it('rejects a failed npm install', async () => { + const runner = { run: vi.fn().mockReturnValue(processResult(1, '', 'install failed')) }; + + await expect(smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + })).rejects.toThrow('install failed'); + }); + + it('reports a spawn error when stderr is unavailable', async () => { + const runner = { + run: vi.fn().mockReturnValue({ + pid: 0, + output: null, + stdout: undefined, + stderr: undefined, + status: null, + signal: null, + error: new Error('spawn EINVAL'), + }), + }; + + await expect(smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + })).rejects.toThrow('spawn EINVAL'); + }); + + it('rejects a CLI version mismatch', async () => { + const runner = { + run: vi.fn() + .mockReturnValueOnce(processResult(0)) + .mockReturnValueOnce(processResult(0, '9.9.9\n')), + }; + + await expect(smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + })).rejects.toThrow(/9\.9\.9[\s\S]*0\.1\.0/); + }); + + it('rejects non-JSON handshake output', async () => { + const runner = successfulRunner(); + runner.run.mockReset() + .mockReturnValueOnce(processResult(0)) + .mockReturnValueOnce(processResult(0, '0.1.0\n')) + .mockReturnValueOnce(processResult(0, 'server log on stdout')); + + await expect(smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + })).rejects.toThrow('non-JSON'); + }); + + it('requires all four public MCP tools', async () => { + const runner = successfulRunner(); + runner.run.mockReset() + .mockReturnValueOnce(processResult(0)) + .mockReturnValueOnce(processResult(0, '0.1.0\n')) + .mockReturnValueOnce(processResult(0, JSON.stringify({ + tools: ['search'], + databaseVerified: true, + }))); + + await expect(smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + })).rejects.toThrow('knowledge'); + }); + + it('returns the installed version and tool names after a valid smoke run', async () => { + await expect(smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner: successfulRunner(), + })).resolves.toEqual({ + version: '0.1.0', + tools: ['search', 'knowledge', 'codebase', 'query'], + databaseVerified: true, + }); + }); + + it('bounds every external command', async () => { + const runner = successfulRunner(); + + await smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + }); + + expect(runner.run.mock.calls.map((call) => call[2].timeout)).toEqual([ + 300_000, + 30_000, + 60_000, + ]); + }); + + it('isolates package state and uses a short embedded database path', async () => { + const runner = successfulRunner(); + + await smokePackage({ + tarballPath: createTarball(), + expectedVersion: '0.1.0', + runner, + }); + + const handshakeOptions = runner.run.mock.calls[2][2]; + expect(handshakeOptions.env).toEqual(expect.objectContaining({ + CODEGRAPH_DATA_DIR: expect.stringMatching(/\/data$/), + CODEGRAPH_DB_PATH: expect.stringMatching(/\/db$/), + })); + expect(String(handshakeOptions.env?.CODEGRAPH_DB_PATH).length).toBeLessThan(90); + }); +}); + +describe('resolveSmokeInput', () => { + it('uses a validation result when no CLI arguments are provided', () => { + expect(resolveSmokeInput([], '/repo/tmp/release/package-result.json')).toEqual({ + kind: 'result', + resultPath: '/repo/tmp/release/package-result.json', + }); + }); + + it('accepts an exact tarball and version for downloaded CI artifacts', () => { + expect(resolveSmokeInput([ + '--tarball', + '/repo/tmp/release/codegraph-mcp-0.1.0.tgz', + '--version', + '0.1.0', + ], '/repo/tmp/release/package-result.json')).toEqual({ + kind: 'tarball', + tarballPath: '/repo/tmp/release/codegraph-mcp-0.1.0.tgz', + expectedVersion: '0.1.0', + }); + }); + + it('rejects incomplete direct tarball input', () => { + expect(() => resolveSmokeInput([ + '--tarball', + '/repo/tmp/release/codegraph-mcp-0.1.0.tgz', + ], '/repo/tmp/release/package-result.json')).toThrow('--version'); + }); +}); + +describe('resolveValidatedPackageInput', () => { + it('relocates a downloaded artifact beside its validation result', () => { + expect(resolveValidatedPackageInput({ + tarballPath: '/home/runner/work/repo/tmp/release/codegraph-mcp-0.1.0.tgz', + filename: 'codegraph-mcp-0.1.0.tgz', + version: '0.1.0', + }, '/different-runner/tmp/release/package-result.json')).toEqual({ + tarballPath: '/different-runner/tmp/release/codegraph-mcp-0.1.0.tgz', + expectedVersion: '0.1.0', + }); + }); + + it('rejects an unsafe artifact filename', () => { + expect(() => resolveValidatedPackageInput({ + filename: '../codegraph-mcp.tgz', + version: '0.1.0', + }, '/repo/tmp/release/package-result.json')).toThrow('filename'); + }); +}); diff --git a/scripts/release/__tests__/validate-package.test.ts b/scripts/release/__tests__/validate-package.test.ts new file mode 100644 index 00000000..56c03bea --- /dev/null +++ b/scripts/release/__tests__/validate-package.test.ts @@ -0,0 +1,151 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { + validatePackageDirectory, + validatePackReport, +} from '../validate-package.mjs'; + +const temporaryDirectories: string[] = []; + +afterEach(() => { + for (const directory of temporaryDirectories.splice(0)) { + rmSync(directory, { recursive: true, force: true }); + } +}); + +function createValidFixture(): string { + const directory = mkdtempSync(join(tmpdir(), 'codegraph-package-')); + temporaryDirectories.push(directory); + mkdirSync(join(directory, 'bin')); + mkdirSync(join(directory, 'server')); + writeFileSync(join(directory, 'bin', 'codegraph-mcp.mjs'), '#!/usr/bin/env node\n'); + chmodSync(join(directory, 'bin', 'codegraph-mcp.mjs'), 0o755); + writeFileSync(join(directory, 'server', 'index.mjs'), 'export {};\n'); + writeFileSync(join(directory, 'LICENSE'), 'MIT License\n'); + writeFileSync(join(directory, 'README.md'), '# CodeGraph\n'); + writeFileSync(join(directory, 'package.json'), JSON.stringify({ + name: 'codegraph-mcp', + version: '0.1.0', + license: 'MIT', + repository: { + type: 'git', + url: 'git+https://github.com/Phoenixrr2113/codebase-graph.git', + }, + homepage: 'https://v0-landing-page-build-kappa-virid.vercel.app', + bugs: { url: 'https://github.com/Phoenixrr2113/codebase-graph/issues' }, + engines: { node: '>=20.0.0' }, + publishConfig: { access: 'public' }, + bin: { 'codegraph-mcp': 'bin/codegraph-mcp.mjs' }, + dependencies: { 'tree-sitter': '^0.22.4' }, + })); + return directory; +} + +describe('validatePackageDirectory', () => { + it('accepts a valid staged package', async () => { + const directory = createValidFixture(); + + await expect(validatePackageDirectory(pathToFileURL(directory))).resolves.toMatchObject({ + name: 'codegraph-mcp', + version: '0.1.0', + fileCount: 5, + }); + }); + + it('reports workspace ranges', async () => { + const directory = createValidFixture(); + const manifestPath = join(directory, 'package.json'); + const manifest = JSON.parse(await import('node:fs/promises').then((fs) => fs.readFile(manifestPath, 'utf8'))); + manifest.dependencies.internal = 'workspace:*'; + writeFileSync(manifestPath, JSON.stringify(manifest)); + + await expect(validatePackageDirectory(pathToFileURL(directory))).rejects.toThrow('workspace:'); + }); + + it('reports node_modules directories and native binaries', async () => { + const directory = createValidFixture(); + mkdirSync(join(directory, 'node_modules')); + writeFileSync(join(directory, 'server', 'binding.node'), 'binary'); + + await expect(validatePackageDirectory(pathToFileURL(directory))).rejects.toThrow(/node_modules[\s\S]*\.node/); + }); + + it('reports source maps containing absolute repository paths', async () => { + const directory = createValidFixture(); + writeFileSync( + join(directory, 'server', 'index.mjs.map'), + JSON.stringify({ sources: [join(process.cwd(), 'packages/mcp-server/src/index.ts')] }), + ); + + await expect(validatePackageDirectory(pathToFileURL(directory))).rejects.toThrow(/source map|absolute/i); + }); + + it('reports a missing executable bit on the CLI', async () => { + const directory = createValidFixture(); + chmodSync(join(directory, 'bin', 'codegraph-mcp.mjs'), 0o644); + + await expect(validatePackageDirectory(pathToFileURL(directory))).rejects.toThrow('executable'); + }); + + it('reports incorrect license and repository metadata together', async () => { + const directory = createValidFixture(); + const manifestPath = join(directory, 'package.json'); + const manifest = JSON.parse(await import('node:fs/promises').then((fs) => fs.readFile(manifestPath, 'utf8'))); + manifest.license = 'UNLICENSED'; + manifest.repository.url = 'https://example.com/wrong.git'; + writeFileSync(manifestPath, JSON.stringify(manifest)); + + await expect(validatePackageDirectory(pathToFileURL(directory))).rejects.toThrow(/MIT[\s\S]*repository/); + }); + + it('reports incorrect public package endpoints and constraints', async () => { + const directory = createValidFixture(); + const manifestPath = join(directory, 'package.json'); + const manifest = JSON.parse(await import('node:fs/promises').then((fs) => fs.readFile(manifestPath, 'utf8'))); + manifest.homepage = 'https://example.com'; + manifest.bugs.url = 'https://example.com/issues'; + manifest.engines.node = '>=18'; + manifest.publishConfig.access = 'restricted'; + writeFileSync(manifestPath, JSON.stringify(manifest)); + + await expect(validatePackageDirectory(pathToFileURL(directory))).rejects.toThrow( + /homepage[\s\S]*bugs[\s\S]*engines[\s\S]*publishConfig/, + ); + }); +}); + +describe('validatePackReport', () => { + it('returns package and size metadata for a valid npm report', () => { + expect(validatePackReport([{ + name: 'codegraph-mcp', + version: '0.1.0', + filename: 'codegraph-mcp-0.1.0.tgz', + size: 1024, + unpackedSize: 4096, + entryCount: 5, + files: [{ path: 'package/bin/codegraph-mcp.mjs', size: 20, mode: 493 }], + }])).toEqual({ + name: 'codegraph-mcp', + version: '0.1.0', + filename: 'codegraph-mcp-0.1.0.tgz', + fileCount: 5, + packedSize: 1024, + unpackedSize: 4096, + }); + }); + + it('rejects packed artifacts over 15 MB', () => { + expect(() => validatePackReport([{ + name: 'codegraph-mcp', + version: '0.1.0', + filename: 'codegraph-mcp-0.1.0.tgz', + size: (15 * 1024 * 1024) + 1, + unpackedSize: 20 * 1024 * 1024, + entryCount: 5, + files: [], + }])).toThrow('15 MB'); + }); +}); diff --git a/scripts/release/__tests__/verify-release-tag.test.ts b/scripts/release/__tests__/verify-release-tag.test.ts new file mode 100644 index 00000000..16462c8f --- /dev/null +++ b/scripts/release/__tests__/verify-release-tag.test.ts @@ -0,0 +1,172 @@ +import { describe, expect, it } from 'vitest'; +import { + verifyBootstrapRelease, + verifyReleaseTag, + verifyVersionIsPublished, + verifyVersionIsUnpublished, +} from '../verify-release-tag.mjs'; + +describe('verifyReleaseTag', () => { + it('accepts the exact stable package tag', () => { + expect(verifyReleaseTag('refs/tags/v0.1.0', 'codegraph-mcp', '0.1.0')).toEqual({ + packageName: 'codegraph-mcp', + version: '0.1.0', + }); + }); + + it('rejects prerelease versions until a non-latest dist-tag policy exists', () => { + expect(() => verifyReleaseTag( + 'refs/tags/v1.2.3-rc.1', + 'codegraph-mcp', + '1.2.3-rc.1', + )).toThrow('stable'); + }); + + it('rejects a tag without the v prefix', () => { + expect(() => verifyReleaseTag( + 'refs/tags/0.1.0', + 'codegraph-mcp', + '0.1.0', + )).toThrow('refs/tags/v0.1.0'); + }); + + it('rejects a tag that does not match the package version', () => { + expect(() => verifyReleaseTag( + 'refs/tags/v0.2.0', + 'codegraph-mcp', + '0.1.0', + )).toThrow(/v0\.1\.0/); + }); + + it('rejects the wrong package name', () => { + expect(() => verifyReleaseTag( + 'refs/tags/v0.1.0', + '@codegraph/mcp', + '0.1.0', + )).toThrow('codegraph-mcp'); + }); + + it.each([ + '1.0', + 'v1.0.0', + '01.0.0', + '1.0.0-', + '1.0.0+bad metadata', + ])('rejects invalid semantic version %s', (version) => { + expect(() => verifyReleaseTag( + `refs/tags/v${version}`, + 'codegraph-mcp', + version, + )).toThrow('valid semantic version'); + }); +}); + +describe('verifyBootstrapRelease', () => { + const reviewedCommit = '0123456789abcdef0123456789abcdef01234567'; + + it('accepts the one-time 0.1.0 bootstrap from main', () => { + expect(verifyBootstrapRelease( + 'refs/heads/main', + '0.1.0', + reviewedCommit, + 'codegraph-mcp', + '0.1.0', + )).toEqual({ + packageName: 'codegraph-mcp', + version: '0.1.0', + reviewedCommit, + }); + }); + + it('rejects a bootstrap from a branch other than main', () => { + expect(() => verifyBootstrapRelease( + 'refs/heads/release', + '0.1.0', + reviewedCommit, + 'codegraph-mcp', + '0.1.0', + )).toThrow('main'); + }); + + it('rejects a bootstrap version other than 0.1.0', () => { + expect(() => verifyBootstrapRelease( + 'refs/heads/main', + '0.2.0', + reviewedCommit, + 'codegraph-mcp', + '0.2.0', + )).toThrow('0.1.0'); + }); + + it('rejects input that does not match the package version', () => { + expect(() => verifyBootstrapRelease( + 'refs/heads/main', + '0.1.0', + reviewedCommit, + 'codegraph-mcp', + '0.1.1', + )).toThrow('match'); + }); + + it('rejects a missing or abbreviated reviewed commit', () => { + expect(() => verifyBootstrapRelease( + 'refs/heads/main', + '0.1.0', + '0123456', + 'codegraph-mcp', + '0.1.0', + )).toThrow('40-character'); + }); +}); + +describe('verifyVersionIsUnpublished', () => { + it('accepts npm E404 as an unpublished version', () => { + expect(() => verifyVersionIsUnpublished({ + status: 1, + stderr: 'npm error code E404\nnpm error 404 Not Found', + stdout: '', + }, 'codegraph-mcp', '0.1.0')).not.toThrow(); + }); + + it('rejects a version that already exists', () => { + expect(() => verifyVersionIsUnpublished({ + status: 0, + stderr: '', + stdout: '"0.1.0"\n', + }, 'codegraph-mcp', '0.1.0')).toThrow('already exists'); + }); + + it('does not treat authentication or network failures as availability', () => { + expect(() => verifyVersionIsUnpublished({ + status: 1, + stderr: 'npm error code E401', + stdout: '', + }, 'codegraph-mcp', '0.1.0')).toThrow('Unable to verify'); + }); +}); + +describe('verifyVersionIsPublished', () => { + it('accepts an exact published version', () => { + expect(() => verifyVersionIsPublished({ + status: 0, + stderr: '', + stdout: '"0.1.0"\n', + }, 'codegraph-mcp', '0.1.0')).not.toThrow(); + }); + + it('rejects a missing package version', () => { + expect(() => verifyVersionIsPublished({ + status: 1, + stderr: 'npm error code E404', + stdout: '', + }, 'codegraph-mcp', '0.1.0')).toThrow('must already exist'); + }); + + it('rejects an unexpected published version response', () => { + expect(() => verifyVersionIsPublished({ + status: 0, + stderr: '', + stdout: '"0.1.1"\n', + }, 'codegraph-mcp', '0.1.0')).toThrow('expected 0.1.0'); + }); +}); diff --git a/scripts/release/smoke-package.mjs b/scripts/release/smoke-package.mjs new file mode 100644 index 00000000..09c94466 --- /dev/null +++ b/scripts/release/smoke-package.mjs @@ -0,0 +1,313 @@ +#!/usr/bin/env node + +import { spawnSync } from 'node:child_process'; +import { access, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { basename, dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +/** + * @typedef {{ + * run(command: string, args: string[], options: import('node:child_process').SpawnSyncOptionsWithStringEncoding): import('node:child_process').SpawnSyncReturns + * }} CommandRunner + */ + +const requiredTools = ['search', 'knowledge', 'codebase', 'query']; +const releaseDirectory = dirname(fileURLToPath(import.meta.url)); +const rootDirectory = resolve(releaseDirectory, '../..'); + +const defaultRunner = { + run(command, args, options) { + return spawnSync(command, args, options); + }, +}; + +function commandFailure(label, result) { + const stderr = typeof result.stderr === 'string' ? result.stderr.trim() : ''; + const detail = stderr || result.error?.message || `exit status ${result.status}`; + return new Error(`${label} failed: ${detail}`); +} + +export function resolveNpmInvocation( + platform = process.platform, + windowsCommand = process.env.ComSpec || 'cmd.exe', +) { + if (platform === 'win32') { + return { + command: windowsCommand, + args: ['/d', '/s', '/c', 'npm.cmd'], + }; + } + return { command: 'npm', args: [] }; +} + +function parseHandshake(stdout) { + let parsed; + try { + parsed = JSON.parse(stdout); + } catch { + throw new Error('MCP handshake emitted non-JSON data on stdout'); + } + if (typeof parsed !== 'object' || parsed === null || !Array.isArray(parsed.tools)) { + throw new Error('MCP handshake result must contain a tools array'); + } + if (!parsed.tools.every((toolName) => typeof toolName === 'string')) { + throw new Error('MCP handshake returned an invalid tool name'); + } + if (typeof parsed.databaseVerified !== 'boolean') { + throw new Error('MCP handshake result must report database verification'); + } + for (const toolName of requiredTools) { + if (!parsed.tools.includes(toolName)) { + throw new Error(`MCP handshake did not expose required tool: ${toolName}`); + } + } + return { + tools: parsed.tools, + databaseVerified: parsed.databaseVerified, + }; +} + +const handshakeSource = ` +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; + +const binPath = process.argv[2]; +const environment = Object.fromEntries( + Object.entries(process.env).filter((entry) => typeof entry[1] === 'string'), +); +environment.CODEGRAPH_EMBEDDING_PROVIDER = 'none'; +environment.CODEGRAPH_LOG_STDERR = 'true'; + +const transport = new StdioClientTransport({ + command: process.execPath, + args: [binPath], + env: environment, + stderr: 'pipe', +}); +const client = new Client( + { name: 'codegraph-package-smoke', version: '1.0.0' }, + { capabilities: {} }, +); +let serverStderr = ''; +transport.stderr?.on('data', (chunk) => { + serverStderr = (serverStderr + chunk.toString()).slice(-4000); +}); + +try { + await client.connect(transport); + const result = await client.listTools(); + const supportsEmbeddedDatabase = + (process.platform === 'darwin' && process.arch === 'arm64') || + (process.platform === 'linux' && process.arch === 'x64'); + let databaseVerified = false; + if (supportsEmbeddedDatabase) { + const storeResult = await client.callTool({ + name: 'knowledge', + arguments: { + action: 'store', + text: 'codegraph package smoke', + type: 'Verification', + }, + }); + const storeText = storeResult.content.find((item) => item.type === 'text')?.text; + if (storeResult.isError || typeof storeText !== 'string') { + throw new Error( + 'Database-backed knowledge store call failed: ' + JSON.stringify(storeResult.content), + ); + } + const stored = JSON.parse(storeText); + if (typeof stored !== 'object' || stored === null || stored.stored !== true) { + throw new Error( + 'Database-backed knowledge store returned an error: ' + JSON.stringify(stored), + ); + } + const queryResult = await client.callTool({ + name: 'query', + arguments: { + cypher: 'MATCH (n:Entity {text: $text}) RETURN count(n) AS count', + params: { text: 'codegraph package smoke' }, + }, + }); + const queryText = queryResult.content.find((item) => item.type === 'text')?.text; + if (queryResult.isError || typeof queryText !== 'string') { + throw new Error('Database-backed verification query failed'); + } + const verification = JSON.parse(queryText); + if ( + typeof verification !== 'object' + || verification === null + || verification.success !== true + || !Array.isArray(verification.data) + || verification.data[0]?.count !== 1 + ) { + throw new Error( + 'Database-backed verification query returned an error: ' + JSON.stringify(verification), + ); + } + databaseVerified = true; + } + await client.close(); + process.stdout.write(JSON.stringify({ + tools: result.tools.map((tool) => tool.name), + databaseVerified, + }) + '\\n'); +} catch (error) { + await client.close().catch(() => {}); + const message = error instanceof Error ? error.message : String(error); + process.stderr.write(message + (serverStderr ? '\\n' + serverStderr : '') + '\\n'); + process.exitCode = 1; +} +`; + +export async function smokePackage({ tarballPath, expectedVersion, runner = defaultRunner }) { + const absoluteTarball = resolve(tarballPath); + try { + await access(absoluteTarball); + } catch { + throw new Error(`Package tarball does not exist: ${absoluteTarball}`); + } + if (typeof expectedVersion !== 'string' || expectedVersion.length === 0) { + throw new TypeError('expectedVersion must be a non-empty string'); + } + + const consumerDirectory = await mkdtemp(join(tmpdir(), 'cg-')); + try { + await writeFile( + join(consumerDirectory, 'package.json'), + '{"name":"codegraph-package-smoke","version":"1.0.0","private":true,"type":"module"}\n', + ); + const npmInvocation = resolveNpmInvocation(); + const installResult = runner.run( + npmInvocation.command, + [...npmInvocation.args, 'install', absoluteTarball, '--ignore-scripts', '--no-audit', '--no-fund'], + { cwd: consumerDirectory, encoding: 'utf8', timeout: 300_000 }, + ); + if (installResult.status !== 0) { + throw commandFailure('npm install', installResult); + } + + const binPath = join( + consumerDirectory, + 'node_modules', + 'codegraph-mcp', + 'bin', + 'codegraph-mcp.mjs', + ); + const versionResult = runner.run( + process.execPath, + [binPath, '--version'], + { cwd: consumerDirectory, encoding: 'utf8', timeout: 30_000 }, + ); + if (versionResult.status !== 0) { + throw commandFailure('codegraph-mcp --version', versionResult); + } + const installedVersion = versionResult.stdout.trim(); + if (installedVersion !== expectedVersion) { + throw new Error( + `Installed CLI version ${installedVersion || ''} does not match expected ${expectedVersion}`, + ); + } + + const handshakePath = join(consumerDirectory, 'mcp-handshake.mjs'); + await writeFile(handshakePath, handshakeSource); + const smokeEnvironment = { + ...process.env, + CODEGRAPH_DATA_DIR: join(consumerDirectory, 'data'), + CODEGRAPH_DB_PATH: join(consumerDirectory, 'db'), + }; + const handshakeResult = runner.run( + process.execPath, + [handshakePath, binPath], + { + cwd: consumerDirectory, + encoding: 'utf8', + env: smokeEnvironment, + timeout: 60_000, + }, + ); + if (handshakeResult.status !== 0) { + throw commandFailure('MCP handshake', handshakeResult); + } + const handshake = parseHandshake(handshakeResult.stdout); + return { version: installedVersion, ...handshake }; + } finally { + await rm(consumerDirectory, { recursive: true, force: true }); + } +} + +export function resolveSmokeInput(argumentsList, defaultResultPath) { + if (argumentsList.length === 0) { + return { kind: 'result', resultPath: resolve(defaultResultPath) }; + } + if (argumentsList.length === 1 && !argumentsList[0].startsWith('--')) { + return { kind: 'result', resultPath: resolve(argumentsList[0]) }; + } + const values = new Map(); + for (let index = 0; index < argumentsList.length; index += 2) { + const flag = argumentsList[index]; + const value = argumentsList[index + 1]; + if (!['--tarball', '--version'].includes(flag) || !value) { + throw new Error('Usage: smoke-package.mjs [result.json] or --tarball --version '); + } + values.set(flag, value); + } + const tarballPath = values.get('--tarball'); + const expectedVersion = values.get('--version'); + if (!tarballPath || !expectedVersion) { + throw new Error('Direct smoke input requires both --tarball and --version'); + } + return { + kind: 'tarball', + tarballPath: resolve(tarballPath), + expectedVersion, + }; +} + +export function resolveValidatedPackageInput(packageResult, resultPath) { + if ( + typeof packageResult !== 'object' || + packageResult === null || + typeof packageResult.filename !== 'string' || + basename(packageResult.filename) !== packageResult.filename || + !packageResult.filename.endsWith('.tgz') + ) { + throw new Error('Package validation result has an invalid artifact filename'); + } + if (typeof packageResult.version !== 'string' || packageResult.version.length === 0) { + throw new Error('Package validation result is missing a version'); + } + return { + tarballPath: resolve(dirname(resultPath), packageResult.filename), + expectedVersion: packageResult.version, + }; +} + +async function runCli() { + const input = resolveSmokeInput( + process.argv.slice(2), + join(rootDirectory, 'tmp/release/package-result.json'), + ); + if (input.kind === 'tarball') { + const result = await smokePackage(input); + process.stdout.write(`${JSON.stringify(result)}\n`); + return; + } + let packageResult; + try { + packageResult = JSON.parse(await readFile(input.resultPath, 'utf8')); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Unable to read package validation result: ${message}`); + } + const result = await smokePackage(resolveValidatedPackageInput(packageResult, input.resultPath)); + process.stdout.write(`${JSON.stringify(result)}\n`); +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + runCli().catch((error) => { + const message = error instanceof Error ? error.message : String(error); + process.stderr.write(`${message}\n`); + process.exitCode = 1; + }); +} diff --git a/scripts/release/validate-package.mjs b/scripts/release/validate-package.mjs new file mode 100644 index 00000000..1ebf65c5 --- /dev/null +++ b/scripts/release/validate-package.mjs @@ -0,0 +1,303 @@ +#!/usr/bin/env node + +import { spawnSync } from 'node:child_process'; +import { + chmod, + lstat, + mkdir, + readFile, + readdir, + rm, + writeFile, +} from 'node:fs/promises'; +import { dirname, extname, isAbsolute, join, relative, resolve, sep } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const canonicalRepository = 'git+https://github.com/Phoenixrr2113/codebase-graph.git'; +const canonicalHomepage = 'https://v0-landing-page-build-kappa-virid.vercel.app'; +const canonicalIssues = 'https://github.com/Phoenixrr2113/codebase-graph/issues'; +const maximumPackedBytes = 15 * 1024 * 1024; +const releaseDirectory = dirname(fileURLToPath(import.meta.url)); +const rootDirectory = resolve(releaseDirectory, '../..'); + +function requireRecord(value, label, violations) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + violations.push(`${label} must be an object`); + return {}; + } + return value; +} + +function readRepositoryUrl(manifest, violations) { + const repository = requireRecord(manifest.repository, 'package.json repository', violations); + return typeof repository.url === 'string' ? repository.url : undefined; +} + +async function collectEntries(root, current, entries, violations) { + for (const entry of await readdir(current, { withFileTypes: true })) { + const path = join(current, entry.name); + const relativePath = relative(root, path); + if (entry.isSymbolicLink()) { + violations.push(`symbolic links are not allowed: ${relativePath}`); + continue; + } + if (entry.isDirectory()) { + if (entry.name === 'node_modules') { + violations.push(`node_modules directory is not allowed: ${relativePath}`); + } + await collectEntries(root, path, entries, violations); + continue; + } + entries.push({ path, relativePath, stats: await lstat(path) }); + } +} + +function findWorkspaceRange(value, location = 'package.json') { + if (typeof value === 'string') { + return value.startsWith('workspace:') ? location : undefined; + } + if (Array.isArray(value)) { + for (const [index, item] of value.entries()) { + const found = findWorkspaceRange(item, `${location}[${index}]`); + if (found) return found; + } + return undefined; + } + if (typeof value === 'object' && value !== null) { + for (const [key, item] of Object.entries(value)) { + const found = findWorkspaceRange(item, `${location}.${key}`); + if (found) return found; + } + } + return undefined; +} + +export async function validatePackageDirectory(directoryUrl) { + const directory = directoryUrl instanceof URL ? fileURLToPath(directoryUrl) : resolve(directoryUrl); + const violations = []; + const entries = []; + + try { + const directoryStats = await lstat(directory); + if (!directoryStats.isDirectory()) { + throw new Error('path is not a directory'); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Package staging directory is unavailable: ${message}`); + } + + await collectEntries(directory, directory, entries, violations); + const paths = new Set(entries.map((entry) => entry.relativePath)); + for (const requiredPath of [ + 'package.json', + 'LICENSE', + 'README.md', + join('bin', 'codegraph-mcp.mjs'), + join('server', 'index.mjs'), + ]) { + if (!paths.has(requiredPath)) { + violations.push(`required file is missing: ${requiredPath}`); + } + } + + let manifest = {}; + try { + manifest = requireRecord( + JSON.parse(await readFile(join(directory, 'package.json'), 'utf8')), + 'package.json', + violations, + ); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + violations.push(`package.json is invalid: ${message}`); + } + + const workspaceLocation = findWorkspaceRange(manifest); + if (workspaceLocation) { + violations.push(`workspace: range found at ${workspaceLocation}`); + } + if (manifest.name !== 'codegraph-mcp') { + violations.push('package.json name must be codegraph-mcp'); + } + if (typeof manifest.version !== 'string' || manifest.version.length === 0) { + violations.push('package.json version must be a non-empty string'); + } + if (manifest.license !== 'MIT') { + violations.push('package.json license must be MIT'); + } + if (readRepositoryUrl(manifest, violations) !== canonicalRepository) { + violations.push(`package.json repository must be ${canonicalRepository}`); + } + if (manifest.homepage !== canonicalHomepage) { + violations.push(`package.json homepage must be ${canonicalHomepage}`); + } + const bugs = requireRecord(manifest.bugs, 'package.json bugs', violations); + if (bugs.url !== canonicalIssues) { + violations.push(`package.json bugs.url must be ${canonicalIssues}`); + } + const engines = requireRecord(manifest.engines, 'package.json engines', violations); + if (engines.node !== '>=20.0.0') { + violations.push('package.json engines.node must be >=20.0.0'); + } + const publishConfig = requireRecord( + manifest.publishConfig, + 'package.json publishConfig', + violations, + ); + if (publishConfig.access !== 'public') { + violations.push('package.json publishConfig.access must be public'); + } + if (manifest.scripts !== undefined) { + violations.push('published package must not contain lifecycle scripts'); + } + + const bin = requireRecord(manifest.bin, 'package.json bin', violations); + const binRelativePath = bin['codegraph-mcp']; + if (binRelativePath !== 'bin/codegraph-mcp.mjs') { + violations.push('package.json bin must map codegraph-mcp to bin/codegraph-mcp.mjs'); + } else { + try { + const binStats = await lstat(join(directory, binRelativePath)); + if ((binStats.mode & 0o111) === 0) { + violations.push('codegraph-mcp bin file must be executable'); + } + } catch { + violations.push('codegraph-mcp bin file is missing'); + } + } + + try { + const license = await readFile(join(directory, 'LICENSE'), 'utf8'); + if (!license.startsWith('MIT License')) { + violations.push('LICENSE must contain the MIT license text'); + } + } catch { + // Missing LICENSE is already reported above. + } + + for (const entry of entries) { + if (entry.relativePath.split(sep).includes('node_modules')) continue; + if (extname(entry.relativePath) === '.node') { + violations.push(`native .node file is not allowed: ${entry.relativePath}`); + } + if (extname(entry.relativePath) === '.map') { + violations.push(`source map is not allowed: ${entry.relativePath}`); + } + if (entry.relativePath === '.env' || entry.relativePath === '.npmrc') { + violations.push(`credential-bearing file is not allowed: ${entry.relativePath}`); + } + if (/\.(?:mjs|js|json|md|txt|map)$/i.test(entry.relativePath)) { + const content = await readFile(entry.path, 'utf8'); + if (content.includes(rootDirectory)) { + violations.push(`absolute repository path found in ${entry.relativePath}`); + } + } + } + + if (violations.length > 0) { + throw new Error(`Package validation failed:\n- ${violations.join('\n- ')}`); + } + + return { + name: manifest.name, + version: manifest.version, + fileCount: entries.length, + }; +} + +export function validatePackReport(report) { + const violations = []; + if (!Array.isArray(report) || report.length !== 1) { + throw new Error('npm pack report must contain exactly one package'); + } + const item = requireRecord(report[0], 'npm pack report item', violations); + const files = Array.isArray(item.files) ? item.files : []; + if (item.name !== 'codegraph-mcp') { + violations.push('packed package name must be codegraph-mcp'); + } + if (typeof item.version !== 'string' || item.version.length === 0) { + violations.push('packed package version is missing'); + } + if (typeof item.filename !== 'string' || item.filename.length === 0) { + violations.push('packed package filename is missing'); + } + if (typeof item.size !== 'number' || !Number.isFinite(item.size)) { + violations.push('packed package size is invalid'); + } else if (item.size > maximumPackedBytes) { + violations.push('packed package exceeds the 15 MB compressed size budget'); + } + if (typeof item.unpackedSize !== 'number' || !Number.isFinite(item.unpackedSize)) { + violations.push('packed package unpacked size is invalid'); + } + if (typeof item.entryCount !== 'number' || !Number.isInteger(item.entryCount)) { + violations.push('packed package entry count is invalid'); + } + for (const file of files) { + const fileRecord = requireRecord(file, 'npm pack file', violations); + const path = typeof fileRecord.path === 'string' ? fileRecord.path : ''; + if (path.split('/').includes('node_modules')) violations.push(`packed node_modules path: ${path}`); + if (path.endsWith('.node')) violations.push(`packed native binary: ${path}`); + if (path.endsWith('.map')) violations.push(`packed source map: ${path}`); + } + if (violations.length > 0) { + throw new Error(`npm pack validation failed:\n- ${violations.join('\n- ')}`); + } + return { + name: item.name, + version: item.version, + filename: item.filename, + fileCount: item.entryCount, + packedSize: item.size, + unpackedSize: item.unpackedSize, + }; +} + +async function runCli() { + const stagingArgument = process.argv[2]; + if (!stagingArgument) { + throw new Error('Usage: node scripts/release/validate-package.mjs '); + } + const stagingDirectory = resolve(stagingArgument); + const directoryResult = await validatePackageDirectory(pathToFileURL(stagingDirectory)); + const artifactDirectory = resolve(rootDirectory, 'tmp/release'); + await rm(artifactDirectory, { recursive: true, force: true }); + await mkdir(artifactDirectory, { recursive: true }); + + const pack = spawnSync( + 'npm', + ['pack', '--json', '--pack-destination', artifactDirectory, stagingDirectory], + { encoding: 'utf8', cwd: rootDirectory }, + ); + if (pack.status !== 0) { + throw new Error(`npm pack failed: ${pack.stderr.trim() || 'unknown error'}`); + } + let report; + try { + report = JSON.parse(pack.stdout); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`npm pack returned invalid JSON: ${message}`); + } + const packResult = validatePackReport(report); + if (packResult.version !== directoryResult.version) { + throw new Error('staged and packed package versions do not match'); + } + const tarballPath = resolve(artifactDirectory, packResult.filename); + const resultPath = resolve(artifactDirectory, 'package-result.json'); + await writeFile( + resultPath, + `${JSON.stringify({ ...packResult, tarballPath }, null, 2)}\n`, + { mode: 0o600 }, + ); + await chmod(tarballPath, 0o644); + process.stdout.write(`${JSON.stringify({ ...packResult, tarballPath, resultPath })}\n`); +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + runCli().catch((error) => { + const message = error instanceof Error ? error.message : String(error); + process.stderr.write(`${message}\n`); + process.exitCode = 1; + }); +} diff --git a/scripts/release/verify-release-tag.mjs b/scripts/release/verify-release-tag.mjs new file mode 100644 index 00000000..51eef964 --- /dev/null +++ b/scripts/release/verify-release-tag.mjs @@ -0,0 +1,129 @@ +#!/usr/bin/env node + +import { spawnSync } from 'node:child_process'; +import { readFile } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const packageName = 'codegraph-mcp'; +const semanticVersionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/; +const releaseDirectory = dirname(fileURLToPath(import.meta.url)); +const rootDirectory = resolve(releaseDirectory, '../..'); + +export function verifyReleaseTag(tag, manifestPackageName, packageVersion) { + if (manifestPackageName !== packageName) { + throw new Error(`Release manifest name must be ${packageName}, received ${manifestPackageName}`); + } + const semanticVersion = packageVersion.match(semanticVersionPattern); + if (!semanticVersion) { + throw new Error(`Package version must be a valid semantic version, received ${packageVersion}`); + } + if (semanticVersion[4]) { + throw new Error('Release package version must be stable until prerelease dist-tags are supported'); + } + const expectedTag = `refs/tags/v${packageVersion}`; + if (tag !== expectedTag) { + throw new Error(`Release tag must be ${expectedTag}, received ${tag || ''}`); + } + return { packageName: manifestPackageName, version: packageVersion }; +} + +export function verifyBootstrapRelease( + ref, + requestedVersion, + reviewedCommit, + manifestPackageName, + packageVersion, +) { + if (ref !== 'refs/heads/main') { + throw new Error(`Bootstrap release must run from refs/heads/main, received ${ref || ''}`); + } + if (requestedVersion !== packageVersion) { + throw new Error(`Bootstrap version ${requestedVersion || ''} must match package version ${packageVersion}`); + } + if (packageVersion !== '0.1.0') { + throw new Error(`Bootstrap release is restricted to 0.1.0, received ${packageVersion}`); + } + if (!/^[0-9a-f]{40}$/i.test(reviewedCommit)) { + throw new Error('Bootstrap reviewed commit must be a full 40-character Git SHA'); + } + const release = verifyReleaseTag( + `refs/tags/v${packageVersion}`, + manifestPackageName, + packageVersion, + ); + return { ...release, reviewedCommit }; +} + +export function verifyVersionIsUnpublished(result, name, version) { + if (result.status === 0) { + throw new Error(`${name}@${version} already exists on npm`); + } + const errorText = `${result.stderr ?? ''}\n${result.stdout ?? ''}`; + if (result.error) { + throw new Error(`Unable to query npm: ${result.error.message}`); + } + if (!/(?:E404|404 Not Found)/i.test(errorText)) { + const detail = String(result.stderr ?? '').trim() || `exit status ${result.status}`; + throw new Error(`Unable to verify npm package availability: ${detail}`); + } +} + +export function verifyVersionIsPublished(result, name, version) { + if (result.error) { + throw new Error(`Unable to query npm: ${result.error.message}`); + } + if (result.status !== 0) { + const detail = String(result.stderr ?? '').trim() || `exit status ${result.status}`; + throw new Error(`${name}@${version} must already exist on npm before bootstrap finalization: ${detail}`); + } + + let publishedVersion; + try { + publishedVersion = JSON.parse(String(result.stdout ?? '')); + } catch { + throw new Error(`npm returned an invalid version response for ${name}@${version}`); + } + if (publishedVersion !== version) { + throw new Error(`npm returned ${String(publishedVersion)}, expected ${version}`); + } +} + +async function runCli() { + const manifestPath = resolve(rootDirectory, 'packages/npm-package/package.json'); + const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); + const isBootstrap = process.env.GITHUB_EVENT_NAME === 'workflow_dispatch'; + const release = isBootstrap + ? verifyBootstrapRelease( + process.env.GITHUB_REF ?? '', + process.env.BOOTSTRAP_VERSION ?? '', + process.env.BOOTSTRAP_COMMIT ?? '', + manifest.name, + manifest.version, + ) + : verifyReleaseTag( + process.env.GITHUB_REF ?? '', + manifest.name, + manifest.version, + ); + const result = spawnSync( + 'npm', + ['view', `${release.packageName}@${release.version}`, 'version', '--json'], + { cwd: rootDirectory, encoding: 'utf8' }, + ); + if (isBootstrap) { + verifyVersionIsPublished(result, release.packageName, release.version); + process.stdout.write(`${release.packageName}@${release.version} is published and ready for bootstrap finalization\n`); + } else { + verifyVersionIsUnpublished(result, release.packageName, release.version); + process.stdout.write(`${release.packageName}@${release.version} is available for publication\n`); + } +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + runCli().catch((error) => { + const message = error instanceof Error ? error.message : String(error); + process.stderr.write(`${message}\n`); + process.exitCode = 1; + }); +} diff --git a/turbo.json b/turbo.json index 37431d0c..eca7530f 100644 --- a/turbo.json +++ b/turbo.json @@ -13,8 +13,12 @@ "lint": { "dependsOn": ["^build"] }, + "typecheck": { + "dependsOn": ["^typecheck"], + "outputs": [] + }, "test": { - "dependsOn": ["build"], + "dependsOn": ["^build"], "outputs": ["coverage/**"] }, "clean": { diff --git a/vitest.config.ts b/vitest.config.ts index cc063b6b..340378c8 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { - include: ['scripts/__tests__/**/*.test.ts'], + include: ['scripts/**/__tests__/**/*.test.ts'], testTimeout: 30000, // FalkorDB connect can be slow on first call hookTimeout: 30000, pool: 'forks', diff --git a/vitest.package.config.ts b/vitest.package.config.ts new file mode 100644 index 00000000..57c65991 --- /dev/null +++ b/vitest.package.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts', 'src/__tests__/**/*.test.ts', '__tests__/**/*.test.ts'], + passWithNoTests: false, + }, +})