From b49e519952ef5d159904ced21eceb82c54f803f3 Mon Sep 17 00:00:00 2001 From: reaatech <138725666+reaatech@users.noreply.github.com> Date: Sat, 2 May 2026 11:08:39 -0700 Subject: [PATCH 1/5] chore: migrate to pnpm+turbo+biome monorepo with 10 packages - Split monolithic src/ into 10 workspace packages under packages/ - Switch package manager from npm to pnpm 10.22 with workspace support - Add turbo.json for build orchestration - Replace eslint+prettier with biome 1.9 for lint and format - Build per-package with tsup (cjs+esm+dts) - Add changesets for versioning and changelog generation - Move Docker setup to docker/ subdirectory - Remove old tooling (husky, lint-staged, eslint, prettier, vitest root) --- .changeset/config.json | 11 + .lintstagedrc.json | 13 - .npmrc | 2 + .prettierrc | 11 - Dockerfile | 30 - biome.json | 33 + docker-compose.yml | 58 - docker/Dockerfile | 27 + docker/docker-compose.yml | 11 + eslint.config.mjs | 51 - package-lock.json | 6289 ----------------- package.json | 92 +- packages/cli/LICENSE | 21 + packages/cli/README.md | 253 + packages/cli/package.json | 58 + {src => packages/cli/src}/cli.ts | 8 +- .../cli/src}/commands/compare.command.ts | 7 +- .../cli/src}/commands/cost.command.ts | 3 +- .../cli/src}/commands/evaluate.command.ts | 21 +- .../cli/src}/commands/gate.command.ts | 7 +- .../cli/src}/commands/index.ts | 0 .../cli/src}/commands/judge.command.ts | 7 +- .../cli/src}/commands/mcp-server.command.ts | 2 +- .../cli/src}/commands/report.command.ts | 19 +- packages/cli/src/index.ts | 12 + .../cli/tests}/cli-commands.test.ts | 32 +- packages/cli/tsconfig.json | 8 + packages/cli/vitest.config.ts | 11 + packages/core/LICENSE | 21 + packages/core/README.md | 115 + packages/core/package.json | 45 + {src/types => packages/core/src}/domain.ts | 0 {src/types => packages/core/src}/index.ts | 0 {src/types => packages/core/src}/schemas.ts | 4 +- .../core/tests}/schemas.test.ts | 4 +- packages/core/tsconfig.json | 8 + packages/core/vitest.config.ts | 11 + packages/cost/LICENSE | 21 + packages/cost/README.md | 225 + packages/cost/package.json | 47 + .../cost/src}/budget-manager.ts | 9 +- {src/cost => packages/cost/src}/index.ts | 0 {src/cost => packages/cost/src}/pricing.ts | 6 +- {src/cost => packages/cost/src}/reporter.ts | 10 +- {src/cost => packages/cost/src}/tracker.ts | 14 +- .../unit => packages/cost/tests}/cost.test.ts | 14 +- packages/cost/tsconfig.json | 8 + packages/cost/vitest.config.ts | 11 + packages/dataset/LICENSE | 21 + packages/dataset/README.md | 239 + packages/dataset/package.json | 48 + .../dataset/src}/generator.ts | 22 +- .../dataset => packages/dataset/src}/index.ts | 0 .../dataset/src}/loader.ts | 30 +- .../dataset/src}/validator.ts | 7 +- .../dataset/src}/versioning.ts | 4 +- .../dataset/tests}/dataset.test.ts | 16 +- packages/dataset/tsconfig.json | 8 + packages/dataset/vitest.config.ts | 11 + packages/gate/LICENSE | 21 + packages/gate/README.md | 221 + packages/gate/package.json | 46 + .../gate/src}/baseline-gates.ts | 6 +- .../gate/src}/ci-integration.ts | 12 +- {src/gate => packages/gate/src}/engine.ts | 12 +- {src/gate => packages/gate/src}/index.ts | 0 .../gate/src}/threshold-gates.ts | 4 +- .../gate/tests}/baseline-gates.test.ts | 9 +- .../gate/tests}/ci-integration.test.ts | 6 +- .../unit => packages/gate/tests}/gate.test.ts | 32 +- .../gate/tests}/threshold-gates.test.ts | 10 +- packages/gate/tsconfig.json | 8 + packages/gate/vitest.config.ts | 11 + packages/judge/LICENSE | 21 + packages/judge/README.md | 264 + packages/judge/package.json | 50 + .../judge/src}/calibration.ts | 24 +- .../judge/src}/cost-tracker.ts | 16 +- {src/judge => packages/judge/src}/engine.ts | 67 +- {src/judge => packages/judge/src}/index.ts | 0 {src/judge => packages/judge/src}/prompts.ts | 6 +- .../judge/tests}/judge.test.ts | 16 +- packages/judge/tsconfig.json | 8 + packages/judge/vitest.config.ts | 11 + packages/mcp-server/LICENSE | 21 + packages/mcp-server/README.md | 233 + packages/mcp-server/package.json | 50 + packages/mcp-server/src/index.ts | 4 + .../mcp-server/src}/mcp-server.ts | 4 +- .../mcp-server/src}/tools/gate/index.ts | 8 +- .../mcp-server/src}/tools/judge/index.ts | 16 +- .../mcp-server/src}/tools/suite/index.ts | 8 +- .../mcp-server/tests}/mcp-suite-tools.test.ts | 10 +- packages/mcp-server/tsconfig.json | 8 + packages/mcp-server/vitest.config.ts | 11 + packages/metrics/LICENSE | 21 + packages/metrics/README.md | 207 + packages/metrics/package.json | 49 + .../metrics/src}/context-precision.ts | 12 +- .../metrics/src}/context-recall.ts | 6 +- .../metrics/src}/engine.ts | 68 +- .../metrics/src}/faithfulness.ts | 10 +- .../metrics => packages/metrics/src}/index.ts | 0 .../metrics/src}/relevance.ts | 4 +- .../metrics/tests}/metrics.test.ts | 17 +- packages/metrics/tsconfig.json | 8 + packages/metrics/vitest.config.ts | 11 + packages/observability/LICENSE | 21 + packages/observability/README.md | 273 + packages/observability/package.json | 51 + .../observability/src}/dashboard.ts | 4 +- .../observability/src}/index.ts | 0 .../observability/src}/logger.ts | 14 +- .../observability/src}/metrics.ts | 5 +- .../observability/src}/tracing.ts | 9 +- .../observability/tests}/dashboard.test.ts | 14 +- .../tests}/observability-metrics.test.ts | 10 +- .../observability/tests}/tracing.test.ts | 14 +- packages/observability/tsconfig.json | 8 + packages/observability/vitest.config.ts | 11 + packages/suite/LICENSE | 21 + packages/suite/README.md | 200 + packages/suite/package.json | 52 + .../suite/src}/evaluation-suite.ts | 43 +- packages/suite/src/index.ts | 1 + .../suite/tests}/evaluation-suite.test.ts | 6 +- packages/suite/tsconfig.json | 8 + packages/suite/vitest.config.ts | 11 + pnpm-lock.yaml | 4576 ++++++++++++ pnpm-workspace.yaml | 4 + src/index.ts | 24 - tsconfig.eslint.json | 5 - tsconfig.typecheck.json | 18 + turbo.json | 23 + vitest.config.ts | 36 - 135 files changed, 8271 insertions(+), 6934 deletions(-) create mode 100644 .changeset/config.json delete mode 100644 .lintstagedrc.json create mode 100644 .npmrc delete mode 100644 .prettierrc delete mode 100644 Dockerfile create mode 100644 biome.json delete mode 100644 docker-compose.yml create mode 100644 docker/Dockerfile create mode 100644 docker/docker-compose.yml delete mode 100644 eslint.config.mjs delete mode 100644 package-lock.json create mode 100644 packages/cli/LICENSE create mode 100644 packages/cli/README.md create mode 100644 packages/cli/package.json rename {src => packages/cli/src}/cli.ts (95%) rename {src/cli => packages/cli/src}/commands/compare.command.ts (89%) rename {src/cli => packages/cli/src}/commands/cost.command.ts (94%) rename {src/cli => packages/cli/src}/commands/evaluate.command.ts (88%) rename {src/cli => packages/cli/src}/commands/gate.command.ts (89%) rename {src/cli => packages/cli/src}/commands/index.ts (100%) rename {src/cli => packages/cli/src}/commands/judge.command.ts (89%) rename {src/cli => packages/cli/src}/commands/mcp-server.command.ts (81%) rename {src/cli => packages/cli/src}/commands/report.command.ts (81%) create mode 100644 packages/cli/src/index.ts rename {tests/unit => packages/cli/tests}/cli-commands.test.ts (86%) create mode 100644 packages/cli/tsconfig.json create mode 100644 packages/cli/vitest.config.ts create mode 100644 packages/core/LICENSE create mode 100644 packages/core/README.md create mode 100644 packages/core/package.json rename {src/types => packages/core/src}/domain.ts (100%) rename {src/types => packages/core/src}/index.ts (100%) rename {src/types => packages/core/src}/schemas.ts (99%) rename {tests/unit => packages/core/tests}/schemas.test.ts (86%) create mode 100644 packages/core/tsconfig.json create mode 100644 packages/core/vitest.config.ts create mode 100644 packages/cost/LICENSE create mode 100644 packages/cost/README.md create mode 100644 packages/cost/package.json rename {src/cost => packages/cost/src}/budget-manager.ts (90%) rename {src/cost => packages/cost/src}/index.ts (100%) rename {src/cost => packages/cost/src}/pricing.ts (97%) rename {src/cost => packages/cost/src}/reporter.ts (92%) rename {src/cost => packages/cost/src}/tracker.ts (92%) rename {tests/unit => packages/cost/tests}/cost.test.ts (94%) create mode 100644 packages/cost/tsconfig.json create mode 100644 packages/cost/vitest.config.ts create mode 100644 packages/dataset/LICENSE create mode 100644 packages/dataset/README.md create mode 100644 packages/dataset/package.json rename {src/dataset => packages/dataset/src}/generator.ts (86%) rename {src/dataset => packages/dataset/src}/index.ts (100%) rename {src/dataset => packages/dataset/src}/loader.ts (88%) rename {src/dataset => packages/dataset/src}/validator.ts (94%) rename {src/dataset => packages/dataset/src}/versioning.ts (96%) rename {tests/unit => packages/dataset/tests}/dataset.test.ts (91%) create mode 100644 packages/dataset/tsconfig.json create mode 100644 packages/dataset/vitest.config.ts create mode 100644 packages/gate/LICENSE create mode 100644 packages/gate/README.md create mode 100644 packages/gate/package.json rename {src/gate => packages/gate/src}/baseline-gates.ts (94%) rename {src/gate => packages/gate/src}/ci-integration.ts (96%) rename {src/gate => packages/gate/src}/engine.ts (97%) rename {src/gate => packages/gate/src}/index.ts (100%) rename {src/gate => packages/gate/src}/threshold-gates.ts (94%) rename {tests/unit => packages/gate/tests}/baseline-gates.test.ts (91%) rename {tests/unit => packages/gate/tests}/ci-integration.test.ts (95%) rename {tests/unit => packages/gate/tests}/gate.test.ts (85%) rename {tests/unit => packages/gate/tests}/threshold-gates.test.ts (93%) create mode 100644 packages/gate/tsconfig.json create mode 100644 packages/gate/vitest.config.ts create mode 100644 packages/judge/LICENSE create mode 100644 packages/judge/README.md create mode 100644 packages/judge/package.json rename {src/judge => packages/judge/src}/calibration.ts (88%) rename {src/judge => packages/judge/src}/cost-tracker.ts (92%) rename {src/judge => packages/judge/src}/engine.ts (92%) rename {src/judge => packages/judge/src}/index.ts (100%) rename {src/judge => packages/judge/src}/prompts.ts (97%) rename {tests/unit => packages/judge/tests}/judge.test.ts (96%) create mode 100644 packages/judge/tsconfig.json create mode 100644 packages/judge/vitest.config.ts create mode 100644 packages/mcp-server/LICENSE create mode 100644 packages/mcp-server/README.md create mode 100644 packages/mcp-server/package.json create mode 100644 packages/mcp-server/src/index.ts rename {src/mcp-server => packages/mcp-server/src}/mcp-server.ts (99%) rename {src/mcp-server => packages/mcp-server/src}/tools/gate/index.ts (94%) rename {src/mcp-server => packages/mcp-server/src}/tools/judge/index.ts (92%) rename {src/mcp-server => packages/mcp-server/src}/tools/suite/index.ts (96%) rename {tests/unit => packages/mcp-server/tests}/mcp-suite-tools.test.ts (78%) create mode 100644 packages/mcp-server/tsconfig.json create mode 100644 packages/mcp-server/vitest.config.ts create mode 100644 packages/metrics/LICENSE create mode 100644 packages/metrics/README.md create mode 100644 packages/metrics/package.json rename {src/metrics => packages/metrics/src}/context-precision.ts (96%) rename {src/metrics => packages/metrics/src}/context-recall.ts (98%) rename {src/metrics => packages/metrics/src}/engine.ts (81%) rename {src/metrics => packages/metrics/src}/faithfulness.ts (97%) rename {src/metrics => packages/metrics/src}/index.ts (100%) rename {src/metrics => packages/metrics/src}/relevance.ts (98%) rename {tests/unit => packages/metrics/tests}/metrics.test.ts (90%) create mode 100644 packages/metrics/tsconfig.json create mode 100644 packages/metrics/vitest.config.ts create mode 100644 packages/observability/LICENSE create mode 100644 packages/observability/README.md create mode 100644 packages/observability/package.json rename {src/observability => packages/observability/src}/dashboard.ts (97%) rename {src/observability => packages/observability/src}/index.ts (100%) rename {src/observability => packages/observability/src}/logger.ts (90%) rename {src/observability => packages/observability/src}/metrics.ts (94%) rename {src/observability => packages/observability/src}/tracing.ts (89%) rename {tests/unit => packages/observability/tests}/dashboard.test.ts (95%) rename {tests/unit => packages/observability/tests}/observability-metrics.test.ts (94%) rename {tests/unit => packages/observability/tests}/tracing.test.ts (94%) create mode 100644 packages/observability/tsconfig.json create mode 100644 packages/observability/vitest.config.ts create mode 100644 packages/suite/LICENSE create mode 100644 packages/suite/README.md create mode 100644 packages/suite/package.json rename {src => packages/suite/src}/evaluation-suite.ts (91%) create mode 100644 packages/suite/src/index.ts rename {tests/unit => packages/suite/tests}/evaluation-suite.test.ts (86%) create mode 100644 packages/suite/tsconfig.json create mode 100644 packages/suite/vitest.config.ts create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml delete mode 100644 src/index.ts delete mode 100644 tsconfig.eslint.json create mode 100644 tsconfig.typecheck.json create mode 100644 turbo.json delete mode 100644 vitest.config.ts diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000..68f74be --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json", + "changelog": ["@changesets/changelog-github", { "repo": "reaatech/rag-eval-pack" }], + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.lintstagedrc.json b/.lintstagedrc.json deleted file mode 100644 index 3446772..0000000 --- a/.lintstagedrc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "src/**/*.ts": [ - "eslint --fix", - "prettier --write" - ], - "tests/**/*.ts": [ - "eslint --fix", - "prettier --write" - ], - "*.{json,md,yaml,yml}": [ - "prettier --write" - ] -} diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..f7bafc7 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +shamefully-hoist=false +strict-peer-dependencies=true diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 57fd5da..0000000 --- a/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "semi": true, - "trailingComma": "es5", - "singleQuote": true, - "printWidth": 100, - "tabWidth": 2, - "useTabs": false, - "bracketSpacing": true, - "arrowParens": "always", - "endOfLine": "lf" -} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 2fa9fe1..0000000 --- a/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -# Stage 1: Build -FROM node:22-alpine AS builder - -WORKDIR /app - -COPY package*.json ./ -COPY tsconfig.json ./ - -ENV HUSKY=0 -RUN npm ci - -COPY src/ ./src/ - -RUN npm run build && npm prune --omit=dev && npm cache clean --force - -# Stage 2: Production -FROM node:22-alpine AS production - -WORKDIR /app - -RUN addgroup -g 1001 -S nodejs && \ - adduser -S nodejs -u 1001 - -COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist -COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules -COPY --chown=nodejs:nodejs package.json ./ - -USER nodejs - -CMD ["node", "dist/cli.js"] diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..d7cd1be --- /dev/null +++ b/biome.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "files": { + "ignore": ["dist", ".turbo", "node_modules", "coverage"] + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "noNonNullAssertion": "error" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "all" + } + } +} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index fad3e56..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,58 +0,0 @@ -version: '3.8' - -services: - # Main application - rag-eval-pack: - build: - context: . - dockerfile: Dockerfile - ports: - - "3000:3000" - environment: - - NODE_ENV=production - - LOG_LEVEL=info - # LLM API keys (set via .env or secrets) - - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - - OPENAI_API_KEY=${OPENAI_API_KEY:-} - - GOOGLE_API_KEY=${GOOGLE_API_KEY:-} - volumes: - - ./datasets:/app/datasets - - ./results:/app/results - command: ["node", "dist/cli.js", "mcp-server"] - - # Jaeger for tracing (development) - jaeger: - image: jaegertracing/all-in-one:latest - ports: - - "16686:16686" # Jaeger UI - - "4317:4317" # OTLP gRPC - - "4318:4318" # OTLP HTTP - environment: - - COLLECTOR_OTLP_ENABLED=true - profiles: - - observability - - # Prometheus for metrics (development) - prometheus: - image: prom/prometheus:latest - ports: - - "9090:9090" - volumes: - - ./infra/prometheus.yml:/etc/prometheus/prometheus.yml - profiles: - - observability - - # Grafana for dashboards (development) - grafana: - image: grafana/grafana:latest - ports: - - "3001:3000" - environment: - - GF_SECURITY_ADMIN_PASSWORD=admin - volumes: - - grafana-data:/var/lib/grafana - profiles: - - observability - -volumes: - grafana-data: diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..8957fca --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,27 @@ +FROM node:22-alpine AS base +RUN npm install -g pnpm@10 + +FROM base AS deps +WORKDIR /app +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json tsconfig.json biome.json ./ +COPY packages/ ./packages/ +RUN pnpm install --frozen-lockfile + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app ./ +RUN pnpm build + +FROM base AS runner +WORKDIR /app +ENV NODE_ENV=production +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=builder /app/pnpm-workspace.yaml ./pnpm-workspace.yaml +COPY --from=builder /app/turbo.json ./turbo.json +COPY --from=builder /app/tsconfig.json ./tsconfig.json +COPY --from=builder /app/biome.json ./biome.json +COPY --from=builder /app/packages ./packages +RUN pnpm install --prod --frozen-lockfile + +ENTRYPOINT ["node", "packages/cli/dist/cli.js"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..11248b5 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,11 @@ +services: + eval: + build: + context: .. + dockerfile: docker/Dockerfile + environment: + - NODE_ENV=production + - LOG_LEVEL=info + volumes: + - ../datasets:/app/datasets:ro + - ./results:/app/results diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 817f5b3..0000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import eslint from '@eslint/js'; -import tseslint from 'typescript-eslint'; -import prettier from 'eslint-config-prettier'; -import prettierPlugin from 'eslint-plugin-prettier'; - -export default tseslint.config( - { - ignores: ['dist/**', 'node_modules/**', 'coverage/**', '*.js'], - }, - eslint.configs.recommended, - ...tseslint.configs.recommended, - { - languageOptions: { - parserOptions: { - project: './tsconfig.eslint.json', - tsconfigRootDir: import.meta.dirname, - }, - }, - plugins: { - prettier: prettierPlugin, - }, - rules: { - ...prettier.rules, - '@typescript-eslint/no-unused-vars': [ - 'error', - { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }, - ], - '@typescript-eslint/explicit-function-return-type': [ - 'warn', - { - allowExpressions: true, - allowTypedFunctionExpressions: true, - }, - ], - '@typescript-eslint/no-explicit-any': 'error', - '@typescript-eslint/prefer-nullish-coalescing': 'warn', - '@typescript-eslint/prefer-optional-chain': 'warn', - 'no-console': ['warn', { allow: ['warn', 'error'] }], - 'prefer-const': 'error', - 'no-var': 'error', - }, - }, - { - files: ['tests/**/*.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': 'off', - 'no-console': 'off', - }, - } -); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 67092a9..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6289 +0,0 @@ -{ - "name": "rag-eval-pack", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "rag-eval-pack", - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@anthropic-ai/sdk": "^0.32.0", - "@google/generative-ai": "^0.21.0", - "@modelcontextprotocol/sdk": "^1.9.0", - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/sdk-metrics": "^1.28.0", - "@opentelemetry/sdk-trace-base": "^1.28.0", - "chalk": "^5.3.0", - "cli-progress": "^3.12.0", - "commander": "^14.0.3", - "compromise": "^14.15.0", - "js-tiktoken": "^1.0.15", - "natural": "^8.1.1", - "openai": "^6.35.0", - "p-limit": "^7.3.0", - "pino": "^9.5.0", - "pino-pretty": "^13.1.3", - "yaml": "^2.6.1", - "zod": "^3.23.8" - }, - "bin": { - "rag-eval-pack": "dist/cli.js" - }, - "devDependencies": { - "@types/cli-progress": "^3.11.6", - "@types/node": "^20.17.0", - "@types/pino": "^7.0.5", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "@typescript-eslint/parser": "^7.18.0", - "@vitest/coverage-v8": "^4.1.4", - "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "husky": "^9.1.7", - "lint-staged": "^16.4.0", - "prettier": "^3.4.2", - "typescript": "^6.0.3", - "typescript-eslint": "^7.18.0", - "vitest": "^4.1.5" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.32.1", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.32.1.tgz", - "integrity": "sha512-U9JwTrDvdQ9iWuABVsMLj8nJVwAyQz6QXvgLsVhryhCEPkLsbcP/MXxm+jYcAwLoV8ESbaTTjnD4kuAFa+Hyjg==", - "license": "MIT", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - } - }, - "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { - "version": "18.19.130", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", - "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@anthropic-ai/sdk/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@google/generative-ai": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.21.0.tgz", - "integrity": "sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.8.tgz", - "integrity": "sha512-kpjr2jy2w71w0oqAMI8oibBmiF9lXxWkEQs5gMkW4hVE48bsqINGLxnCSYW62ck/NHXJQpQEfA9WlJ1sY0eqBg==", - "license": "MIT", - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", - "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", - "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.30.1.tgz", - "integrity": "sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", - "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", - "license": "MIT" - }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@redis/bloom": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.12.1.tgz", - "integrity": "sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@redis/client": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.12.1.tgz", - "integrity": "sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==", - "license": "MIT", - "dependencies": { - "cluster-key-slot": "1.1.2" - }, - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@node-rs/xxhash": "^1.1.0", - "@opentelemetry/api": ">=1 <2" - }, - "peerDependenciesMeta": { - "@node-rs/xxhash": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - } - } - }, - "node_modules/@redis/json": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.12.1.tgz", - "integrity": "sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@redis/search": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.12.1.tgz", - "integrity": "sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@redis/time-series": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.12.1.tgz", - "integrity": "sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", - "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/cli-progress": { - "version": "3.11.6", - "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz", - "integrity": "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", - "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.13", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", - "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.4" - } - }, - "node_modules/@types/pino": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@types/pino/-/pino-7.0.5.tgz", - "integrity": "sha512-wKoab31pknvILkxAF8ss+v9iNyhw5Iu/0jLtRkUD74cNfOOLJNnqfFKAv0r7wVaTQxRZtWrMpGfShwwBjOcgcg==", - "deprecated": "This is a stub types definition. pino provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "pino": "*" - } - }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "license": "MIT" - }, - "node_modules/@types/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", - "license": "MIT", - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.5.tgz", - "integrity": "sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.5", - "ast-v8-to-istanbul": "^1.0.0", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.2", - "obug": "^2.1.1", - "std-env": "^4.0.0-rc.1", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.1.5", - "vitest": "4.1.5" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", - "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.5", - "@vitest/utils": "4.1.5", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", - "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.5", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", - "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", - "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.5", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", - "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.5", - "@vitest/utils": "4.1.5", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", - "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", - "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.5", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/afinn-165": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/afinn-165/-/afinn-165-2.0.2.tgz", - "integrity": "sha512-mJ/RLUfpXfQA6bzugv+bBsc/QYkVrKaLYeS8fWBpKbTCsonv4iuV9ET0fgReEunm9vKLkaNgnekuSNlTC3WQ1Q==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/afinn-165-financialmarketnews": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/afinn-165-financialmarketnews/-/afinn-165-financialmarketnews-3.0.0.tgz", - "integrity": "sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/apparatus": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/apparatus/-/apparatus-0.0.10.tgz", - "integrity": "sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==", - "license": "MIT", - "dependencies": { - "sylvester": ">= 0.0.8" - }, - "engines": { - "node": ">=0.2.6" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-v8-to-istanbul": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", - "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bson": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", - "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-progress": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", - "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", - "license": "MIT", - "dependencies": { - "string-width": "^4.2.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-truncate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^8.0.0", - "string-width": "^8.2.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", - "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/compromise": { - "version": "14.15.0", - "resolved": "https://registry.npmjs.org/compromise/-/compromise-14.15.0.tgz", - "integrity": "sha512-YEMv5JGWyqRJw5hdZqDVQF3MMlHA6TRiXreR8IYffk6xB7GA5p/8DeDzvg0Jy2tHNGpD+qJGl0+oJwA+5R/sVA==", - "license": "MIT", - "dependencies": { - "efrt": "2.7.0", - "grad-school": "0.0.5", - "suffix-thumb": "5.0.2" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/efrt": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/efrt/-/efrt-2.7.0.tgz", - "integrity": "sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", - "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.12" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", - "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", - "license": "MIT", - "dependencies": { - "ip-address": "10.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/fast-copy": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", - "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", - "license": "MIT" - }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "license": "MIT", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/grad-school": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/grad-school/-/grad-school-0.0.5.tgz", - "integrity": "sha512-rXunEHF9M9EkMydTBux7+IryYXEZinRk6g8OBOGDBzo/qWJjhTxy86i5q7lQYpCLHN8Sqv1XX3OIOc7ka2gtvQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", - "license": "MIT" - }, - "node_modules/hono": { - "version": "4.12.14", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz", - "integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jose": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", - "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/js-tiktoken": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz", - "integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.5.1" - } - }, - "node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/kareem": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.2.0.tgz", - "integrity": "sha512-VS8MWZz/cT+SqBCpVfNN4zoVz5VskR3N4+sTmUXme55e9avQHntpwpNq0yjnosISXqwJ3AQVjlbI4Dyzv//JtA==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lint-staged": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", - "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^14.0.3", - "listr2": "^9.0.5", - "picomatch": "^4.0.3", - "string-argv": "^0.3.2", - "tinyexec": "^1.0.4", - "yaml": "^2.8.2" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/lint-staged/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "source-map-js": "^1.2.1" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/memjs": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/memjs/-/memjs-1.3.2.tgz", - "integrity": "sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "license": "MIT" - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mongodb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.1.tgz", - "integrity": "sha512-067DXiMjcpYQl6bGjWQoTUEE9UoRViTtKFcoqX7z08I+iDZv/emH1g8XEFiO3qiDfXAheT5ozl1VffDTKhIW/w==", - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/saslprep": "^1.3.0", - "bson": "^7.1.1", - "mongodb-connection-string-url": "^7.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.806.0", - "@mongodb-js/zstd": "^7.0.0", - "gcp-metadata": "^7.0.1", - "kerberos": "^7.0.0", - "mongodb-client-encryption": ">=7.0.0 <7.1.0", - "snappy": "^7.3.2", - "socks": "^2.8.6" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz", - "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==", - "license": "Apache-2.0", - "dependencies": { - "@types/whatwg-url": "^13.0.0", - "whatwg-url": "^14.1.0" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/mongoose": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.4.1.tgz", - "integrity": "sha512-4rFBWa+/wdBQSfvnOPJBpiSG6UCEbhSQh865dEdaH9Y8WfHBUC+I2XT28dp0IBIGrEwmh+gzrgZgea5PbmrHWA==", - "license": "MIT", - "dependencies": { - "kareem": "3.2.0", - "mongodb": "~7.1", - "mpath": "0.9.0", - "mquery": "6.0.0", - "ms": "2.1.3", - "sift": "17.1.3" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mquery": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz", - "integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==", - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/natural/-/natural-8.1.1.tgz", - "integrity": "sha512-Ucb+lsUcGxUqu3rn8cwHjT6gJQosO63nIX/aBQXB3+IDkNbFV7PuviysO+Rzz3aKn7PZhPj3bNF4PS9gDVjYCQ==", - "license": "MIT", - "dependencies": { - "afinn-165": "^2.0.2", - "afinn-165-financialmarketnews": "^3.0.0", - "apparatus": "^0.0.10", - "dotenv": "^17.3.1", - "memjs": "^1.3.2", - "mongoose": "^9.2.1", - "pg": "^8.18.0", - "redis": "^5.11.0", - "safe-stable-stringify": "^2.5.0", - "stopwords-iso": "^1.1.0", - "sylvester": "^0.0.21", - "underscore": "^1.13.0", - "uuid": "^13.0.0", - "wordnet-db": "^3.1.14" - }, - "engines": { - "node": ">=0.4.10" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openai": { - "version": "6.35.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.35.0.tgz", - "integrity": "sha512-L/skwIGnt5xQZHb0UfTu9uAUKbis3ehKypOuJKi20QvG7UStV6C8IC3myGYHcdiF4kms/bAvOJ9UqqNWqi8x/Q==", - "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.0.tgz", - "integrity": "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.2.1" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pg": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", - "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", - "license": "MIT", - "dependencies": { - "pg-connection-string": "^2.12.0", - "pg-pool": "^3.13.0", - "pg-protocol": "^1.13.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.3.0" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", - "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", - "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", - "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", - "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", - "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "license": "MIT", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pino": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", - "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^2.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^3.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", - "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-pretty": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", - "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", - "license": "MIT", - "dependencies": { - "colorette": "^2.0.7", - "dateformat": "^4.6.3", - "fast-copy": "^4.0.0", - "fast-safe-stringify": "^2.1.1", - "help-me": "^5.0.0", - "joycon": "^3.1.1", - "minimist": "^1.2.6", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pump": "^3.0.0", - "secure-json-parse": "^4.0.0", - "sonic-boom": "^4.0.1", - "strip-json-comments": "^5.0.2" - }, - "bin": { - "pino-pretty": "bin.js" - } - }, - "node_modules/pino-pretty/node_modules/pino-abstract-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-pretty/node_modules/strip-json-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", - "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", - "license": "MIT" - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/postcss": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", - "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/redis": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-5.12.1.tgz", - "integrity": "sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==", - "license": "MIT", - "dependencies": { - "@redis/bloom": "5.12.1", - "@redis/client": "5.12.1", - "@redis/json": "5.12.1", - "@redis/search": "5.12.1", - "@redis/time-series": "5.12.1" - }, - "engines": { - "node": ">= 18.19.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rolldown": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", - "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.127.0", - "@rolldown/pluginutils": "1.0.0-rc.17" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-x64": "1.0.0-rc.17", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/secure-json-parse": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", - "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sift": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", - "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", - "license": "MIT" - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.3", - "is-fullwidth-code-point": "^5.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/sonic-boom": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "license": "MIT", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/stopwords-iso": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stopwords-iso/-/stopwords-iso-1.1.0.tgz", - "integrity": "sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/suffix-thumb": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/suffix-thumb/-/suffix-thumb-5.0.2.tgz", - "integrity": "sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==", - "license": "MIT" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sylvester": { - "version": "0.0.21", - "resolved": "https://registry.npmjs.org/sylvester/-/sylvester-0.0.21.tgz", - "integrity": "sha512-yUT0ukFkFEt4nb+NY+n2ag51aS/u9UHXoZw+A4jgD77/jzZsBoSDHuqysrVCBC4CYR4TYvUJq54ONpXgDBH8tA==", - "engines": { - "node": ">=0.2.6" - } - }, - "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/thread-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", - "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", - "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", - "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.18.0", - "@typescript-eslint/parser": "7.18.0", - "@typescript-eslint/utils": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/underscore": { - "version": "1.13.8", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", - "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", - "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vite": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", - "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.10", - "rolldown": "1.0.0-rc.17", - "tinyglobby": "^0.2.16" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", - "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.1.5", - "@vitest/mocker": "4.1.5", - "@vitest/pretty-format": "4.1.5", - "@vitest/runner": "4.1.5", - "@vitest/snapshot": "4.1.5", - "@vitest/spy": "4.1.5", - "@vitest/utils": "4.1.5", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "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.5", - "@vitest/browser-preview": "4.1.5", - "@vitest/browser-webdriverio": "4.1.5", - "@vitest/coverage-istanbul": "4.1.5", - "@vitest/coverage-v8": "4.1.5", - "@vitest/ui": "4.1.5", - "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 - }, - "vite": { - "optional": false - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "license": "MIT", - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordnet-db": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/wordnet-db/-/wordnet-db-3.1.14.tgz", - "integrity": "sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==", - "license": "MIT", - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } - } - } -} diff --git a/package.json b/package.json index bc86d0f..5829b0a 100644 --- a/package.json +++ b/package.json @@ -1,73 +1,21 @@ { "name": "rag-eval-pack", "version": "0.1.0", - "description": "RAG evaluation metrics with LLM-as-judge, cost accounting, and CI gates", - "author": "Rick Somers (https://reaatech.com)", - "license": "MIT", + "private": true, + "description": "Evaluation toolkit for RAG (Retrieval-Augmented Generation) systems β€” monorepo of composable metrics, judges, gates, and CLI tools", "type": "module", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "bin": { - "rag-eval-pack": "dist/cli.js" - }, - "files": [ - "dist", - "src" - ], "scripts": { - "build": "tsc", - "clean": "rm -rf dist", - "dev": "tsc --watch", - "lint": "eslint src/ tests/", - "lint:fix": "eslint src/ tests/ --fix", - "prettier": "prettier --check src/ tests/", - "prettier:fix": "prettier --write src/ tests/", - "prepublishOnly": "npm run build", - "test": "vitest run", - "test:coverage": "vitest run --coverage", - "test:watch": "vitest", - "typecheck": "tsc --noEmit", - "prepare": "husky || true" - }, - "dependencies": { - "@anthropic-ai/sdk": "^0.32.0", - "@google/generative-ai": "^0.21.0", - "@modelcontextprotocol/sdk": "^1.9.0", - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/sdk-metrics": "^1.28.0", - "@opentelemetry/sdk-trace-base": "^1.28.0", - "chalk": "^5.3.0", - "cli-progress": "^3.12.0", - "commander": "^14.0.3", - "compromise": "^14.15.0", - "js-tiktoken": "^1.0.15", - "natural": "^8.1.1", - "openai": "^6.35.0", - "p-limit": "^7.3.0", - "pino": "^9.5.0", - "pino-pretty": "^13.1.3", - "yaml": "^2.6.1", - "zod": "^3.23.8" - }, - "devDependencies": { - "@types/cli-progress": "^3.11.6", - "@types/node": "^20.17.0", - "@types/pino": "^7.0.5", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "@typescript-eslint/parser": "^7.18.0", - "@vitest/coverage-v8": "^4.1.4", - "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "husky": "^9.1.7", - "lint-staged": "^16.4.0", - "prettier": "^3.4.2", - "typescript": "^6.0.3", - "typescript-eslint": "^7.18.0", - "vitest": "^4.1.5" - }, - "engines": { - "node": ">=22.0.0" + "build": "turbo run build", + "test": "turbo run test", + "test:coverage": "turbo run test:coverage", + "lint": "biome check .", + "lint:fix": "biome check --write .", + "format": "biome format --write .", + "typecheck": "tsc --noEmit -p tsconfig.typecheck.json", + "clean": "turbo run clean && rm -rf node_modules", + "changeset": "changeset", + "version-packages": "changeset version", + "release": "turbo run build && changeset publish" }, "keywords": [ "rag", @@ -81,12 +29,24 @@ "ci-cd", "mcp" ], + "author": "Rick Somers (https://reaatech.com)", + "license": "MIT", + "packageManager": "pnpm@10.22.0", "repository": { "type": "git", "url": "https://github.com/reaatech/rag-eval-pack.git" }, - "homepage": "https://github.com/reaatech/rag-eval-pack#readme", "bugs": { "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack#readme", + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@changesets/changelog-github": "^0.6.0", + "@changesets/cli": "^2.28.1", + "@vitest/coverage-v8": "3.2.4", + "turbo": "^2.5.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" } } diff --git a/packages/cli/LICENSE b/packages/cli/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/cli/README.md b/packages/cli/README.md new file mode 100644 index 0000000..4d7ec55 --- /dev/null +++ b/packages/cli/README.md @@ -0,0 +1,253 @@ +# @reaatech/rag-eval-cli + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-cli.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-cli) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +CLI entry point and commands for the RAG evaluation toolkit. Also serves as the master barrel package, re-exporting the full API surface of all `@reaatech/rag-eval-*` packages for programmatic consumers. + +## Installation + +```bash +npm install @reaatech/rag-eval-cli +# or +pnpm add @reaatech/rag-eval-cli +``` + +## Feature Overview + +- **Seven CLI commands** β€” evaluate, gate, compare, cost, report, judge, and mcp-server +- **Multi-format output** β€” write results as JSON, Markdown, or both simultaneously +- **Config-driven evaluation** β€” load suite configuration from YAML or JSON files +- **Master barrel export** β€” re-exports all types, scorers, judges, trackers, gates, and tools from sibling packages +- **Dual ESM/CJS** β€” works as both a CLI tool and an importable library + +## Quick Start + +### CLI Usage + +```bash +# Run evaluation suite on a dataset +rag-eval-pack evaluate --dataset dataset.jsonl --output results.json + +# Run quality gates against results +rag-eval-pack gate --results results.json --gates gates.yaml + +# Compare two evaluation runs +rag-eval-pack compare --baseline baseline.json --candidate candidate.json + +# View cost breakdown +rag-eval-pack cost --results results.json + +# Generate markdown report +rag-eval-pack report --results results.json --output report.md + +# Run LLM judge on a dataset +rag-eval-pack judge --dataset dataset.jsonl --metric faithfulness + +# Start MCP server +rag-eval-pack mcp-server +``` + +### Programmatic Usage + +```typescript +import { + EvaluationSuite, + FaithfulnessScorer, + GateEngine, + JudgeEngine, +} from "@reaatech/rag-eval-cli"; + +// The CLI package re-exports everything from all @reaatech/rag-eval-* packages +// Use it as a single dependency if you need the full toolkit + +const suite = new EvaluationSuite({ + metrics: ["faithfulness", "relevance"], +}); +const result = await suite.runFromFile("dataset.jsonl"); +``` + +## Commands + +### `evaluate` + +Run the evaluation suite on a dataset. + +```bash +rag-eval-pack evaluate \ + --dataset datasets/samples.jsonl \ + --config eval-config.yaml \ + --output results/results.json \ + --format json,markdown \ + --no-judge +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--dataset` | `string` | (required) | Path to evaluation dataset (JSONL, JSON, YAML) | +| `--config` | `string` | β€” | Path to evaluation config (YAML or JSON) | +| `--output` | `string` | β€” | Output file path for results | +| `--format` | `string` | `"json"` | Output formats: `json`, `markdown`, or `json,markdown` | +| `--no-judge` | `boolean` | `false` | Skip LLM judge evaluation | + +### `gate` + +Run CI gates against evaluation results. + +```bash +rag-eval-pack gate \ + --results results/results.json \ + --gates gates.yaml \ + --baseline results/baseline.json +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--results` | `string` | (required) | Path to evaluation results JSON | +| `--gates` | `string` | (required) | Path to gate config (YAML or JSON) | +| `--baseline` | `string` | β€” | Path to baseline results for comparison gates | + +### `compare` + +Compare two evaluation runs. + +```bash +rag-eval-pack compare \ + --baseline results/v1.json \ + --candidate results/v2.json \ + --output diff.json +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--baseline` | `string` | (required) | Path to baseline evaluation results | +| `--candidate` | `string` | (required) | Path to candidate evaluation results | +| `--output` | `string` | β€” | Output file for diff | + +### `cost` + +Display cost breakdown for an evaluation run. + +```bash +rag-eval-pack cost --results results/results.json +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--results` | `string` | (required) | Path to evaluation results JSON | + +### `report` + +Generate a formatted report from evaluation results. + +```bash +rag-eval-pack report \ + --results results/results.json \ + --gates gates.yaml \ + --output report.md +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--results` | `string` | (required) | Path to evaluation results JSON | +| `--gates` | `string` | β€” | Path to gate config for gate status in report | +| `--output` | `string` | (required) | Output file path for report | + +### `judge` + +Run LLM judge evaluation on a dataset. + +```bash +rag-eval-pack judge \ + --dataset dataset.jsonl \ + --metric faithfulness \ + --model claude-opus \ + --output judge-results.json +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--dataset` | `string` | (required) | Path to dataset (JSONL, JSON, YAML) | +| `--metric` | `string` | `"faithfulness"` | Metric to evaluate | +| `--model` | `string` | `"claude-opus"` | LLM model to use | +| `--output` | `string` | β€” | Output file for judge results | +| `--consensus` | `boolean` | `false` | Enable consensus voting | + +### `mcp-server` + +Start the MCP server for agent integration. + +```bash +rag-eval-pack mcp-server +``` + +The server uses stdio transport. Configure in MCP client settings (e.g., `claude_desktop_config.json`) to expose evaluation tools. + +## Configuration + +### Suite Config (YAML) + +```yaml +# eval-config.yaml +metrics: + - faithfulness + - relevance + - context_precision + - context_recall + +judge: + model: claude-opus + enabled: true + consensus: + enabled: false + +cost: + budget_limit: 10.00 + hard_limit: true + alert_thresholds: [0.5, 0.75, 0.9] + +execution: + parallel_jobs: 5 +``` + +### Gate Config (YAML) + +```yaml +# gates.yaml +gates: + - name: min-faithfulness + type: threshold + metric: avg_faithfulness + operator: ">=" + threshold: 0.85 + + - name: max-cost-per-sample + type: threshold + metric: cost_per_sample + operator: "<=" + threshold: 0.05 + + - name: no-regression + type: baseline-comparison + metric: overall_score + allow_regression: false +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-metrics`](https://www.npmjs.com/package/@reaatech/rag-eval-metrics) β€” Metric scorers +- [`@reaatech/rag-eval-judge`](https://www.npmjs.com/package/@reaatech/rag-eval-judge) β€” LLM judge +- [`@reaatech/rag-eval-cost`](https://www.npmjs.com/package/@reaatech/rag-eval-cost) β€” Cost tracking +- [`@reaatech/rag-eval-gate`](https://www.npmjs.com/package/@reaatech/rag-eval-gate) β€” Quality gates +- [`@reaatech/rag-eval-dataset`](https://www.npmjs.com/package/@reaatech/rag-eval-dataset) β€” Dataset management +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Orchestrator +- [`@reaatech/rag-eval-observability`](https://www.npmjs.com/package/@reaatech/rag-eval-observability) β€” Observability +- [`@reaatech/rag-eval-mcp-server`](https://www.npmjs.com/package/@reaatech/rag-eval-mcp-server) β€” MCP server + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 0000000..10e09a8 --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,58 @@ +{ + "name": "@reaatech/rag-eval-cli", + "version": "0.1.0", + "description": "CLI entry point and commands for the RAG evaluation toolkit", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/cli" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/cli#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/cli.ts src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@reaatech/rag-eval-core": "workspace:*", + "@reaatech/rag-eval-cost": "workspace:*", + "@reaatech/rag-eval-dataset": "workspace:*", + "@reaatech/rag-eval-gate": "workspace:*", + "@reaatech/rag-eval-judge": "workspace:*", + "@reaatech/rag-eval-mcp-server": "workspace:*", + "@reaatech/rag-eval-metrics": "workspace:*", + "@reaatech/rag-eval-observability": "workspace:*", + "@reaatech/rag-eval-suite": "workspace:*", + "chalk": "^5.3.0", + "cli-progress": "^3.12.0", + "commander": "^14.0.3", + "yaml": "^2.6.1" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/cli.ts b/packages/cli/src/cli.ts similarity index 95% rename from src/cli.ts rename to packages/cli/src/cli.ts index d6f5ed0..b2404be 100644 --- a/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -2,14 +2,14 @@ import { Command } from 'commander'; import { - createEvaluateCommand, - createGateCommand, createCompareCommand, createCostCommand, - createReportCommand, + createEvaluateCommand, + createGateCommand, createJudgeCommand, createMcpServerCommand, -} from './cli/commands/index.js'; + createReportCommand, +} from './commands/index.js'; const program = new Command(); diff --git a/src/cli/commands/compare.command.ts b/packages/cli/src/commands/compare.command.ts similarity index 89% rename from src/cli/commands/compare.command.ts rename to packages/cli/src/commands/compare.command.ts index 86ec282..e057d1a 100644 --- a/src/cli/commands/compare.command.ts +++ b/packages/cli/src/commands/compare.command.ts @@ -1,7 +1,6 @@ -/* eslint-disable no-console */ +import { readFileSync } from 'node:fs'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; import { Command } from 'commander'; -import { readFileSync } from 'fs'; -import { EvaluationSuite } from '../../evaluation-suite.js'; export function createCompareCommand(): Command { const command = new Command('compare'); @@ -20,7 +19,7 @@ export function createCompareCommand(): Command { const suite = new EvaluationSuite({ metrics: [] }); const diff = suite.compareRuns(baseline, candidate); - const { writeFileSync } = await import('fs'); + const { writeFileSync } = await import('node:fs'); writeFileSync(options.output, JSON.stringify(diff, null, 2)); console.log('Comparison Results:'); diff --git a/src/cli/commands/cost.command.ts b/packages/cli/src/commands/cost.command.ts similarity index 94% rename from src/cli/commands/cost.command.ts rename to packages/cli/src/commands/cost.command.ts index adcfba3..25569c8 100644 --- a/src/cli/commands/cost.command.ts +++ b/packages/cli/src/commands/cost.command.ts @@ -1,6 +1,5 @@ -/* eslint-disable no-console */ +import { readFileSync } from 'node:fs'; import { Command } from 'commander'; -import { readFileSync } from 'fs'; export function createCostCommand(): Command { const command = new Command('cost'); diff --git a/src/cli/commands/evaluate.command.ts b/packages/cli/src/commands/evaluate.command.ts similarity index 88% rename from src/cli/commands/evaluate.command.ts rename to packages/cli/src/commands/evaluate.command.ts index 0f42cc7..5820508 100644 --- a/src/cli/commands/evaluate.command.ts +++ b/packages/cli/src/commands/evaluate.command.ts @@ -1,16 +1,15 @@ -/* eslint-disable no-console */ +import { existsSync } from 'node:fs'; +import type { EvalSuiteConfig } from '@reaatech/rag-eval-core'; +import { loadEvalConfig } from '@reaatech/rag-eval-dataset'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; import { Command } from 'commander'; -import { existsSync } from 'fs'; -import { EvaluationSuite } from '../../evaluation-suite.js'; -import { loadEvalConfig } from '../../dataset/loader.js'; -import type { EvalSuiteConfig } from '../../types/domain.js'; export function createEvaluateCommand(): Command { const command = new Command('evaluate'); command.description('Run evaluation suite on a dataset'); command.requiredOption( '-d, --dataset ', - 'Path to evaluation dataset (JSONL, JSON, or YAML)' + 'Path to evaluation dataset (JSONL, JSON, or YAML)', ); command.option('-c, --config ', 'Path to evaluation config file (YAML or JSON)'); command.option('-o, --output ', 'Path to output results file', 'results.json'); @@ -33,7 +32,7 @@ export function createEvaluateCommand(): Command { const suite = new EvaluationSuite(config); const result = await suite.runFromFile(options.dataset); - const { writeFileSync } = await import('fs'); + const { writeFileSync } = await import('node:fs'); const formats = parseFormats(options.format); const payload = { ...result.results, gate_result: result.gate_result }; @@ -79,7 +78,7 @@ function parseFormats(input: string): Array<'json' | 'markdown'> { function getOutputPath( requestedPath: string, format: 'json' | 'markdown', - multipleFormats: boolean + multipleFormats: boolean, ): string { if (!multipleFormats) { return requestedPath; @@ -93,7 +92,7 @@ function getOutputPath( return `${requestedPath}${extension}`; } -function generateMarkdownReport(results: import('../../types/domain.js').EvalResults): string { +function generateMarkdownReport(results: import('@reaatech/rag-eval-core').EvalResults): string { const metrics = results.metrics; const lines: string[] = []; @@ -104,8 +103,8 @@ function generateMarkdownReport(results: import('../../types/domain.js').EvalRes lines.push(''); lines.push('## Overall Results'); lines.push(''); - lines.push(`| Metric | Score |`); - lines.push(`|--------|-------|`); + lines.push('| Metric | Score |'); + lines.push('|--------|-------|'); lines.push(`| Overall | ${metrics.overall_score?.toFixed(3) || 'N/A'} |`); lines.push(`| Faithfulness | ${metrics.avg_faithfulness?.toFixed(3) || 'N/A'} |`); lines.push(`| Relevance | ${metrics.avg_relevance?.toFixed(3) || 'N/A'} |`); diff --git a/src/cli/commands/gate.command.ts b/packages/cli/src/commands/gate.command.ts similarity index 89% rename from src/cli/commands/gate.command.ts rename to packages/cli/src/commands/gate.command.ts index 3c0f074..7c98754 100644 --- a/src/cli/commands/gate.command.ts +++ b/packages/cli/src/commands/gate.command.ts @@ -1,9 +1,8 @@ -/* eslint-disable no-console */ +import { existsSync, readFileSync } from 'node:fs'; +import type { GateConfig } from '@reaatech/rag-eval-core'; +import { GateEngine } from '@reaatech/rag-eval-gate'; import { Command } from 'commander'; -import { readFileSync, existsSync } from 'fs'; import { parse as parseYaml } from 'yaml'; -import { GateEngine } from '../../gate/engine.js'; -import type { GateConfig } from '../../types/domain.js'; export function createGateCommand(): Command { const command = new Command('gate'); diff --git a/src/cli/commands/index.ts b/packages/cli/src/commands/index.ts similarity index 100% rename from src/cli/commands/index.ts rename to packages/cli/src/commands/index.ts diff --git a/src/cli/commands/judge.command.ts b/packages/cli/src/commands/judge.command.ts similarity index 89% rename from src/cli/commands/judge.command.ts rename to packages/cli/src/commands/judge.command.ts index 9dde8a0..848d8a7 100644 --- a/src/cli/commands/judge.command.ts +++ b/packages/cli/src/commands/judge.command.ts @@ -1,8 +1,7 @@ -/* eslint-disable no-console */ +import { writeFileSync } from 'node:fs'; +import { DatasetLoader } from '@reaatech/rag-eval-dataset'; +import { JudgeEngine, type JudgeMetric } from '@reaatech/rag-eval-judge'; import { Command } from 'commander'; -import { writeFileSync } from 'fs'; -import { DatasetLoader } from '../../dataset/loader.js'; -import { JudgeEngine, type JudgeMetric } from '../../judge/engine.js'; const VALID_METRICS: JudgeMetric[] = [ 'faithfulness', diff --git a/src/cli/commands/mcp-server.command.ts b/packages/cli/src/commands/mcp-server.command.ts similarity index 81% rename from src/cli/commands/mcp-server.command.ts rename to packages/cli/src/commands/mcp-server.command.ts index d0c3500..5857c68 100644 --- a/src/cli/commands/mcp-server.command.ts +++ b/packages/cli/src/commands/mcp-server.command.ts @@ -1,5 +1,5 @@ +import { startMcpServer } from '@reaatech/rag-eval-mcp-server'; import { Command } from 'commander'; -import { startMcpServer } from '../../mcp-server/mcp-server.js'; export function createMcpServerCommand(): Command { const command = new Command('mcp-server'); diff --git a/src/cli/commands/report.command.ts b/packages/cli/src/commands/report.command.ts similarity index 81% rename from src/cli/commands/report.command.ts rename to packages/cli/src/commands/report.command.ts index 160dfa2..25a0f62 100644 --- a/src/cli/commands/report.command.ts +++ b/packages/cli/src/commands/report.command.ts @@ -1,9 +1,8 @@ -/* eslint-disable no-console */ +import { readFileSync } from 'node:fs'; +import { CIIntegration } from '@reaatech/rag-eval-gate'; +import { GateEngine } from '@reaatech/rag-eval-gate'; import { Command } from 'commander'; -import { readFileSync } from 'fs'; import { parse as parseYaml } from 'yaml'; -import { CIIntegration } from '../../gate/ci-integration.js'; -import { GateEngine } from '../../gate/engine.js'; export function createReportCommand(): Command { const command = new Command('report'); @@ -40,7 +39,7 @@ export function createReportCommand(): Command { } if (options.output) { - const { writeFileSync } = await import('fs'); + const { writeFileSync } = await import('node:fs'); writeFileSync(options.output, report); console.log(`Report saved to: ${options.output}`); } else { @@ -51,17 +50,19 @@ export function createReportCommand(): Command { return command; } -function parseGateConfig(content: string): import('../../types/domain.js').GateConfig[] { +function parseGateConfig(content: string): import('@reaatech/rag-eval-core').GateConfig[] { try { const parsed = JSON.parse(content); return parsed.gates ?? parsed; } catch { - const parsed = parseYaml(content) as { gates?: import('../../types/domain.js').GateConfig[] }; - return parsed.gates ?? (parsed as import('../../types/domain.js').GateConfig[]); + const parsed = parseYaml(content) as { gates?: import('@reaatech/rag-eval-core').GateConfig[] }; + return parsed.gates ?? (parsed as import('@reaatech/rag-eval-core').GateConfig[]); } } -function generateBasicMarkdownReport(results: import('../../types/domain.js').EvalResults): string { +function generateBasicMarkdownReport( + results: import('@reaatech/rag-eval-core').EvalResults, +): string { const metrics = results.metrics; return `# RAG Evaluation Report diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts new file mode 100644 index 0000000..dc41743 --- /dev/null +++ b/packages/cli/src/index.ts @@ -0,0 +1,12 @@ +/** + * rag-eval-pack β€” RAG evaluation metrics with LLM-as-judge, cost accounting, and CI gates + */ + +export * from '@reaatech/rag-eval-core'; +export * from '@reaatech/rag-eval-metrics'; +export * from '@reaatech/rag-eval-judge'; +export * from '@reaatech/rag-eval-cost'; +export * from '@reaatech/rag-eval-gate'; +export * from '@reaatech/rag-eval-dataset'; +export * from '@reaatech/rag-eval-observability'; +export { EvaluationSuite, type SuiteRunResult } from '@reaatech/rag-eval-suite'; diff --git a/tests/unit/cli-commands.test.ts b/packages/cli/tests/cli-commands.test.ts similarity index 86% rename from tests/unit/cli-commands.test.ts rename to packages/cli/tests/cli-commands.test.ts index c4922e9..e67bed3 100644 --- a/tests/unit/cli-commands.test.ts +++ b/packages/cli/tests/cli-commands.test.ts @@ -1,13 +1,13 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs'; -import { tmpdir } from 'os'; -import { join } from 'path'; -import { createEvaluateCommand } from '../../src/cli/commands/evaluate.command.js'; -import { createGateCommand } from '../../src/cli/commands/gate.command.js'; -import { createCompareCommand } from '../../src/cli/commands/compare.command.js'; -import { createCostCommand } from '../../src/cli/commands/cost.command.js'; -import { createReportCommand } from '../../src/cli/commands/report.command.js'; -import { createJudgeCommand } from '../../src/cli/commands/judge.command.js'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { createCompareCommand } from '../src/commands/compare.command.js'; +import { createCostCommand } from '../src/commands/cost.command.js'; +import { createEvaluateCommand } from '../src/commands/evaluate.command.js'; +import { createGateCommand } from '../src/commands/gate.command.js'; +import { createJudgeCommand } from '../src/commands/judge.command.js'; +import { createReportCommand } from '../src/commands/report.command.js'; describe('CLI Commands', () => { let tempDir: string; @@ -38,7 +38,7 @@ describe('CLI Commands', () => { context: ['Refunds are processed within 14 days of purchase.'], ground_truth: 'Refunds are processed within 14 days of purchase.', generated_answer: 'Refunds are processed within 14 days of purchase.', - }) + }), ); const command = createEvaluateCommand(); @@ -56,12 +56,12 @@ describe('CLI Commands', () => { 'json,markdown', '--no-judge', ], - { from: 'node' } + { from: 'node' }, ); expect(JSON.parse(readFileSync(outputPath, 'utf-8')).run_id).toBeDefined(); expect(readFileSync(join(tempDir, 'results.md'), 'utf-8')).toContain( - '# RAG Evaluation Report' + '# RAG Evaluation Report', ); expect(consoleSpy).toHaveBeenCalled(); }); @@ -123,11 +123,11 @@ describe('CLI Commands', () => { cost_breakdown: { total: 0.01, by_metric: {}, by_provider: {}, per_sample: [] }, duration_ms: 5, completed_at: '2026-04-20T00:00:00.000Z', - }) + }), ); writeFileSync( gatesPath, - `gates:\n - name: min-faithfulness\n type: threshold\n metric: avg_faithfulness\n operator: ">="\n threshold: 0.85\n` + `gates:\n - name: min-faithfulness\n type: threshold\n metric: avg_faithfulness\n operator: ">="\n threshold: 0.85\n`, ); const command = createReportCommand(); @@ -135,7 +135,7 @@ describe('CLI Commands', () => { await command.parseAsync( ['node', 'report', '--results', resultsPath, '--gates', gatesPath, '--output', outputPath], - { from: 'node' } + { from: 'node' }, ); expect(readFileSync(outputPath, 'utf-8')).toContain('| min-faithfulness | βœ… Pass |'); diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/cli/vitest.config.ts b/packages/cli/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/cli/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/core/LICENSE b/packages/core/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/core/README.md b/packages/core/README.md new file mode 100644 index 0000000..c99de6e --- /dev/null +++ b/packages/core/README.md @@ -0,0 +1,115 @@ +# @reaatech/rag-eval-core + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-core.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-core) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Canonical TypeScript types and Zod schemas for RAG (Retrieval-Augmented Generation) evaluation. This package is the single source of truth for all evaluation shapes used throughout the `@reaatech/rag-eval-*` ecosystem. + +## Installation + +```bash +npm install @reaatech/rag-eval-core +# or +pnpm add @reaatech/rag-eval-core +``` + +## Feature Overview + +- **18+ exported types** β€” `EvaluationSample`, `EvalSuiteConfig`, `SampleEvalResult`, `EvalResults`, `GateConfig`, `JudgeConfig`, and more +- **2 Zod schemas** β€” `EvaluationSampleSchema` and `EvalSuiteConfigSchema` for runtime validation +- **Full cost accounting types** β€” `CostBreakdown`, `TokenUsage`, `PricingConfig` for per-evaluation cost tracking +- **Gate configuration types** β€” `ThresholdGateConfig`, `BaselineGateConfig` with full operator support +- **Zero runtime dependencies** beyond `zod` β€” lightweight and tree-shakeable +- **Dual ESM/CJS output** β€” works with `import` and `require` + +## Quick Start + +```typescript +import { + EvaluationSampleSchema, + EvalSuiteConfigSchema, + type EvaluationSample, + type EvalSuiteConfig, +} from "@reaatech/rag-eval-core"; + +// Validate an evaluation sample at the boundary +const rawSample = JSON.parse(incomingJson); +const sample: EvaluationSample = EvaluationSampleSchema.parse(rawSample); + +// Validate a suite configuration +const rawConfig = JSON.parse(configJson); +const config: EvalSuiteConfig = EvalSuiteConfigSchema.parse(rawConfig); +``` + +## Exports + +### Core Types + +| Export | Description | +|--------|-------------| +| `EvaluationSample` | Input sample: `query`, `context`, `ground_truth`, `generated_answer`, optional `retrieved_chunk_ids` and `metadata` | +| `EvalSuiteConfig` | Full evaluation suite configuration: metrics, judge, cost, execution, gates | +| `SampleEvalResult` | Per-sample result with heuristic and judge scores for each metric | +| `EvalResults` | Aggregated results: `run_id`, `metrics`, `samples`, `total_cost`, `cost_breakdown`, `duration_ms` | +| `AggregatedMetrics` | Aggregated metric scores: `overall_score`, `avg_faithfulness`, `avg_relevance`, mean + std dev per metric | + +### Judge Types + +| Export | Description | +|--------|-------------| +| `JudgeConfig` | Judge configuration: `model`, `enabled`, `consensus`, `calibration`, `cost` | +| `ConsensusConfig` | Multi-model consensus: `enabled`, `models` with weights, `voting_strategy`, `tie_breaker` | +| `CalibrationConfig` | Calibration settings: `enabled`, `human_labels` path, `calibration_method` | +| `JudgeMetric` | Metric union: `faithfulness \| relevance \| context_precision \| context_recall \| overall` | + +### Gate Types + +| Export | Description | +|--------|-------------| +| `GateConfig` | Union of `ThresholdGateConfig \| BaselineGateConfig` | +| `ThresholdGateConfig` | `{ name, type: "threshold", metric, operator, threshold }` | +| `BaselineGateConfig` | `{ name, type: "baseline-comparison", metric, allow_regression }` | +| `GateResult` | Gate evaluation result: `passed`, `gates[]`, `failures[]` | +| `GateEvalResult` | Per-gate result: `passed`, `gate_name`, `actual_value`, `message` | + +### Cost Types + +| Export | Description | +|--------|-------------| +| `CostBreakdown` | `{ total, by_metric, by_provider, per_sample }` | +| `TokenUsage` | `{ input, output, total }` | +| `PricingConfig` | Per-model pricing: `{ model, provider, inputCostPerMillion, outputCostPerMillion }` | + +### Schemas + +| Export | Description | +|--------|-------------| +| `EvaluationSampleSchema` | Zod schema for validating evaluation samples (query, context, ground_truth, generated_answer) | +| `EvalSuiteConfigSchema` | Zod schema for validating suite configuration (metrics, judge, cost, gates, execution) | + +## Usage Pattern + +Every schema export has a matching type export. Use the schema for runtime validation and the type for compile-time checking: + +```typescript +import { EvaluationSampleSchema, type EvaluationSample } from "@reaatech/rag-eval-core"; + +function processSample(raw: unknown): EvaluationSample { + // Parse at the boundary β€” throws ZodError on invalid data + return EvaluationSampleSchema.parse(raw); +} +``` + +## Related Packages + +- [`@reaatech/rag-eval-metrics`](https://www.npmjs.com/package/@reaatech/rag-eval-metrics) β€” Faithfulness, relevance, context precision/recall scorers +- [`@reaatech/rag-eval-judge`](https://www.npmjs.com/package/@reaatech/rag-eval-judge) β€” LLM-as-judge with calibration and consensus +- [`@reaatech/rag-eval-cost`](https://www.npmjs.com/package/@reaatech/rag-eval-cost) β€” Pricing, budgeting, and cost reporting +- [`@reaatech/rag-eval-gate`](https://www.npmjs.com/package/@reaatech/rag-eval-gate) β€” Quality gates and CI regression checks + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 0000000..fba5113 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,45 @@ +{ + "name": "@reaatech/rag-eval-core", + "version": "0.1.0", + "description": "Core types, schemas, and domain models for RAG evaluation", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/core" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/core#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "zod": "^3.24.2" + }, + "devDependencies": { + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/types/domain.ts b/packages/core/src/domain.ts similarity index 100% rename from src/types/domain.ts rename to packages/core/src/domain.ts diff --git a/src/types/index.ts b/packages/core/src/index.ts similarity index 100% rename from src/types/index.ts rename to packages/core/src/index.ts diff --git a/src/types/schemas.ts b/packages/core/src/schemas.ts similarity index 99% rename from src/types/schemas.ts rename to packages/core/src/schemas.ts index ccbbb4a..e0a8360 100644 --- a/src/types/schemas.ts +++ b/packages/core/src/schemas.ts @@ -28,7 +28,7 @@ export const FaithfulnessResultSchema = z.object({ statement: z.string(), supported: z.boolean(), reasoning: z.string().optional(), - }) + }), ) .optional(), }); @@ -61,7 +61,7 @@ export const ContextRecallResultSchema = z.object({ fact: z.string(), covered: z.boolean(), matching_context: z.string().optional(), - }) + }), ) .optional(), explanation: z.string().optional(), diff --git a/tests/unit/schemas.test.ts b/packages/core/tests/schemas.test.ts similarity index 86% rename from tests/unit/schemas.test.ts rename to packages/core/tests/schemas.test.ts index 01db40b..dce57f3 100644 --- a/tests/unit/schemas.test.ts +++ b/packages/core/tests/schemas.test.ts @@ -1,5 +1,5 @@ -import { describe, it, expect } from 'vitest'; -import { EvalSuiteConfigSchema } from '../../src/types/schemas.js'; +import { EvalSuiteConfigSchema } from '@reaatech/rag-eval-core'; +import { describe, expect, it } from 'vitest'; describe('Schemas', () => { it('should retain supported judge and gate configuration fields', () => { diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/core/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/cost/LICENSE b/packages/cost/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/cost/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/cost/README.md b/packages/cost/README.md new file mode 100644 index 0000000..4dd2664 --- /dev/null +++ b/packages/cost/README.md @@ -0,0 +1,225 @@ +# @reaatech/rag-eval-cost + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-cost.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-cost) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Cost tracking, pricing, budgeting, and reporting infrastructure for RAG evaluations. Tracks per-sample token consumption, enforces budget limits with configurable alert thresholds, and generates cost reports in JSON and JUnit XML formats. + +## Installation + +```bash +npm install @reaatech/rag-eval-cost +# or +pnpm add @reaatech/rag-eval-cost +``` + +## Feature Overview + +- **Multi-provider pricing** β€” built-in pricing for Anthropic (Claude), OpenAI (GPT), and Google (Gemini) models +- **Per-sample cost tracking** β€” record costs by sample ID, metric, and provider with token-level detail +- **Budget enforcement** β€” configurable per-run budget limits with hard/soft stop modes +- **Alert thresholds** β€” trigger actions at 50%, 75%, and 90% of budget with configurable callbacks +- **Report generation** β€” JSON cost reports and JUnit XML for CI integration +- **Extensible pricing** β€” add custom model pricing for any provider + +## Quick Start + +```typescript +import { CostTracker, Pricing, BudgetManager, CostReporter } from "@reaatech/rag-eval-cost"; + +// Track costs with budget limits +const tracker = new CostTracker({ budgetLimit: 10.00, hardLimit: false }); + +const result = tracker.recordCost( + "sample-1", + 0.025, + { input: 500, output: 75, total: 575 }, + "faithfulness", + "anthropic" +); + +console.log(result.withinBudget); // true +console.log(tracker.getTotalCost()); // 0.025 + +// Generate report for CI +const reporter = new CostReporter(); +const report = reporter.generateReport(tracker.getBreakdown()); +console.log(report.totalCost); // 0.025 +console.log(report.costPerSample); // 0.025 +``` + +## API Reference + +### `CostTracker` + +Per-evaluation cost accounting with budget limits. + +```typescript +import { CostTracker, type CostTrackerOptions } from "@reaatech/rag-eval-cost"; + +const tracker = new CostTracker({ + budgetLimit: 50.00, + hardLimit: true, + alertThresholds: [0.5, 0.75, 0.9], +}); +``` + +#### `CostTrackerOptions` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `budgetLimit` | `number` | `Infinity` | Maximum total cost before stopping | +| `hardLimit` | `boolean` | `false` | If `true`, `shouldStop` returns `true` when budget exceeded | +| `alertThresholds` | `number[]` | `[0.5, 0.75, 0.9]` | Budget usage percentages that trigger alerts | + +#### Instance Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `recordCost(id, cost, tokens?, metric?, provider?)` | `{ cost, withinBudget, shouldStop }` | Record a cost entry and check budget | +| `getTotalCost()` | `number` | Total accumulated cost | +| `getCount()` | `number` | Number of recorded samples | +| `getAverageCost()` | `number` | Mean cost per sample | +| `getBreakdown()` | `CostBreakdown` | Cost breakdown by metric, provider, and per-sample | +| `isWithinBudget()` | `boolean` | Whether total cost is within budget | +| `reset()` | `void` | Clear all recorded costs | + +### `Pricing` + +Provider model pricing lookup and cost calculation. + +```typescript +import { Pricing, type ModelPricing } from "@reaatech/rag-eval-cost"; + +const pricing = new Pricing(); + +// Look up pricing for a model +const config = pricing.getPricing("claude-opus", "anthropic"); +console.log(config.input); // 15.00 (per million tokens) +console.log(config.output); // 75.00 (per million tokens) + +// Calculate cost from token counts +const cost = pricing.calculateCost("gpt-4", "openai", 1000000, 500000); +console.log(cost); // 25.00 +``` + +#### Built-in Pricing + +| Model | Provider | Input $/1M | Output $/1M | +|-------|----------|------------|-------------| +| `claude-opus` | anthropic | 15.00 | 75.00 | +| `claude-sonnet-4-6` | anthropic | 3.00 | 15.00 | +| `claude-haiku-4-5` | anthropic | 0.80 | 4.00 | +| `gpt-4` | openai | 30.00 | 60.00 | +| `gpt-4-turbo` | openai | 10.00 | 30.00 | +| `gpt-4o` | openai | 5.00 | 15.00 | +| `gemini-pro` | google | 2.50 | 7.50 | +| `gemini-flash` | google | 0.075 | 0.30 | + +#### Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `getPricing(model, provider)` | `ModelPricing` | Get pricing config for a model | +| `calculateCost(model, provider, inputTokens, outputTokens)` | `number` | Calculate cost from token counts | +| `addModelPricing(pricing)` | `void` | Register custom model pricing | + +### `BudgetManager` + +Budget enforcement with alert thresholds. + +```typescript +import { BudgetManager } from "@reaatech/rag-eval-cost"; + +const manager = new BudgetManager({ + budgetLimit: 10.00, + hardLimit: true, + alertThresholds: [0.5, 0.75, 0.9], +}); + +const result = manager.recordSpend(7.00); +console.log(result.withinBudget); // true +console.log(manager.getBudgetUsage()); // 0.7 + +const alerts = manager.getActiveAlerts(); +// β†’ [{ threshold: 0.5, message: "Budget 50% used", level: "warn" }] +``` + +#### `BudgetManagerOptions` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `budgetLimit` | `number` | (required) | Maximum budget | +| `hardLimit` | `boolean` | `false` | Stop execution when budget exceeded | +| `alertThresholds` | `number[]` | `[0.5, 0.75, 0.9]` | Usage thresholds for alerts | + +### `CostReporter` + +Report generation in multiple formats. + +```typescript +import { CostReporter } from "@reaatech/rag-eval-cost"; + +const reporter = new CostReporter(); + +const report = reporter.generateReport(breakdown); +// β†’ { totalCost: 1.50, costPerSample: 0.075, trend: "stable", ... } + +const xml = reporter.generateJUnitXml(breakdown); +// β†’ +``` + +| Method | Returns | Description | +|--------|---------|-------------| +| `generateReport(breakdown)` | `CostReport` | Generate JSON cost report with trends | +| `generateJUnitXml(breakdown)` | `string` | Generate JUnit XML for CI reporting | +| `addHistoricalCost(date, cost)` | `void` | Add historical data for trend calculation | + +## Usage Patterns + +### Budget Enforcement in Pipelines + +```typescript +const tracker = new CostTracker({ budgetLimit: 10.00, hardLimit: true }); + +for (const sample of samples) { + const { shouldStop } = tracker.recordCost(sample.id, sample.cost, sample.tokens, sample.metric); + if (shouldStop) { + console.warn("Budget exceeded β€” stopping evaluation"); + break; + } + await evaluateSample(sample); +} +``` + +### CI Cost Gate + +```typescript +import { CostReporter, CostTracker } from "@reaatech/rag-eval-cost"; + +const tracker = new CostTracker({ budgetLimit: 50.00 }); +// ... run evaluations ... + +const reporter = new CostReporter(); +const xml = reporter.generateJUnitXml(tracker.getBreakdown()); +writeFileSync("reports/cost-report.xml", xml); + +// Fail CI if over budget +if (!tracker.isWithinBudget()) { + console.error(`Budget exceeded: $${tracker.getTotalCost()}`); + process.exit(1); +} +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-judge`](https://www.npmjs.com/package/@reaatech/rag-eval-judge) β€” LLM judge (uses pricing for cost estimation) +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Central orchestrator (uses tracker for budget enforcement) + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/cost/package.json b/packages/cost/package.json new file mode 100644 index 0000000..a52b70f --- /dev/null +++ b/packages/cost/package.json @@ -0,0 +1,47 @@ +{ + "name": "@reaatech/rag-eval-cost", + "version": "0.1.0", + "description": "Cost tracking, pricing, budgeting, and reporting for RAG evaluations", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/cost" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/cost#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@reaatech/rag-eval-core": "workspace:*", + "js-tiktoken": "^1.0.15" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/cost/budget-manager.ts b/packages/cost/src/budget-manager.ts similarity index 90% rename from src/cost/budget-manager.ts rename to packages/cost/src/budget-manager.ts index b69dc01..ace1d3b 100644 --- a/src/cost/budget-manager.ts +++ b/packages/cost/src/budget-manager.ts @@ -16,10 +16,10 @@ export class BudgetManager { private hardLimit: boolean; private alertThresholds: number[]; private alerts: BudgetAlert[]; - private totalSpent: number = 0; + private totalSpent = 0; constructor(config?: BudgetConfig) { - this.budgetLimit = config?.budgetLimit ?? Infinity; + this.budgetLimit = config?.budgetLimit ?? Number.POSITIVE_INFINITY; this.hardLimit = config?.hardLimit ?? false; this.alertThresholds = config?.alertThresholds ?? [0.5, 0.75, 0.9]; this.alerts = this.alertThresholds.map((threshold) => ({ @@ -35,7 +35,8 @@ export class BudgetManager { newAlerts: BudgetAlert[]; } { this.totalSpent += amount; - const usageRatio = this.budgetLimit === Infinity ? 0 : this.totalSpent / this.budgetLimit; + const usageRatio = + this.budgetLimit === Number.POSITIVE_INFINITY ? 0 : this.totalSpent / this.budgetLimit; const newAlerts: BudgetAlert[] = []; for (const alert of this.alerts) { @@ -57,7 +58,7 @@ export class BudgetManager { } getBudgetUsage(): number { - if (this.budgetLimit === Infinity) return 0; + if (this.budgetLimit === Number.POSITIVE_INFINITY) return 0; return this.totalSpent / this.budgetLimit; } diff --git a/src/cost/index.ts b/packages/cost/src/index.ts similarity index 100% rename from src/cost/index.ts rename to packages/cost/src/index.ts diff --git a/src/cost/pricing.ts b/packages/cost/src/pricing.ts similarity index 97% rename from src/cost/pricing.ts rename to packages/cost/src/pricing.ts index 93bf5bf..4536edb 100644 --- a/src/cost/pricing.ts +++ b/packages/cost/src/pricing.ts @@ -1,4 +1,4 @@ -import type { LLMProvider } from '../types/domain.js'; +import type { LLMProvider } from '@reaatech/rag-eval-core'; /** * Pricing configuration for a provider/model @@ -123,7 +123,7 @@ function normalize(model: string): string { export class Pricing { // Preserve insertion order; earlier entries win substring ties. private pricingTable: Map = new Map(); - private version: string = '1.0.0'; + private version = '1.0.0'; constructor(customPricing?: ModelPricing[]) { for (const p of DEFAULT_PRICING) { @@ -170,7 +170,7 @@ export class Pricing { model: string, provider: LLMProvider, inputTokens: number, - outputTokens: number + outputTokens: number, ): number { const pricing = this.getPricing(model, provider); const inputCost = (inputTokens / 1_000_000) * pricing.input; diff --git a/src/cost/reporter.ts b/packages/cost/src/reporter.ts similarity index 92% rename from src/cost/reporter.ts rename to packages/cost/src/reporter.ts index 889501e..67b4784 100644 --- a/src/cost/reporter.ts +++ b/packages/cost/src/reporter.ts @@ -1,4 +1,4 @@ -import type { CostBreakdown, EvalResults } from '../types/domain.js'; +import type { CostBreakdown, EvalResults } from '@reaatech/rag-eval-core'; export interface CostReport { totalCost: number; @@ -47,12 +47,12 @@ export class CostReporter { '', '### By Metric', ...Object.entries(report.byMetric).map( - ([metric, cost]) => `- ${metric}: $${cost.toFixed(4)}` + ([metric, cost]) => `- ${metric}: $${cost.toFixed(4)}`, ), '', '### By Provider', ...Object.entries(report.byProvider).map( - ([provider, cost]) => `- ${provider}: $${cost.toFixed(4)}` + ([provider, cost]) => `- ${provider}: $${cost.toFixed(4)}`, ), ]; return lines.join('\n'); @@ -76,8 +76,8 @@ export class CostReporter { private calculateTrend(): 'increasing' | 'decreasing' | 'stable' { if (this.historicalCosts.length < 2) return 'stable'; const recent = this.historicalCosts.slice(-5); - const first = recent[0]!.cost; - const last = recent[recent.length - 1]!.cost; + const first = recent[0]?.cost; + const last = recent[recent.length - 1]?.cost; const diff = last - first; if (Math.abs(diff) < 0.01) return 'stable'; return diff > 0 ? 'increasing' : 'decreasing'; diff --git a/src/cost/tracker.ts b/packages/cost/src/tracker.ts similarity index 92% rename from src/cost/tracker.ts rename to packages/cost/src/tracker.ts index 5c836fd..c710c8e 100644 --- a/src/cost/tracker.ts +++ b/packages/cost/src/tracker.ts @@ -1,4 +1,4 @@ -import type { CostBreakdown, SampleCost, TokenCount, LLMProvider } from '../types/domain.js'; +import type { CostBreakdown, LLMProvider, SampleCost, TokenCount } from '@reaatech/rag-eval-core'; import { Pricing, type PricingConfig } from './pricing.js'; export type { PricingConfig }; @@ -11,11 +11,11 @@ export type { PricingConfig }; */ export class CostTracker { private costs: SampleCost[] = []; - private totalCost: number = 0; + private totalCost = 0; private costByMetric: Record = {}; private costByProvider: Record = {}; - private budgetLimit: number = Infinity; - private hardLimit: boolean = false; + private budgetLimit: number = Number.POSITIVE_INFINITY; + private hardLimit = false; private alertThresholds: number[] = [0.5, 0.75, 0.9]; private alertsTriggered: number[] = []; private pricing: Pricing; @@ -59,7 +59,7 @@ export class CostTracker { model: string, provider: LLMProvider, inputTokens: number, - outputTokens: number + outputTokens: number, ): number { return this.pricing.calculateCost(model, provider, inputTokens, outputTokens); } @@ -72,7 +72,7 @@ export class CostTracker { cost: number, tokens?: TokenCount, metric?: string, - provider?: string + provider?: string, ): { cost: number; withinBudget: boolean; shouldStop: boolean } { const sampleCost: SampleCost = { sample_id: sampleId, @@ -134,7 +134,7 @@ export class CostTracker { * Get budget usage ratio */ getBudgetUsage(): number { - if (this.budgetLimit === Infinity) return 0; + if (this.budgetLimit === Number.POSITIVE_INFINITY) return 0; return Math.round((this.totalCost / this.budgetLimit) * 1000) / 1000; } diff --git a/tests/unit/cost.test.ts b/packages/cost/tests/cost.test.ts similarity index 94% rename from tests/unit/cost.test.ts rename to packages/cost/tests/cost.test.ts index 9a85e95..c72c678 100644 --- a/tests/unit/cost.test.ts +++ b/packages/cost/tests/cost.test.ts @@ -1,8 +1,8 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { CostTracker } from '../../src/cost/tracker.js'; -import { Pricing } from '../../src/cost/pricing.js'; -import { BudgetManager } from '../../src/cost/budget-manager.js'; -import { CostReporter } from '../../src/cost/reporter.js'; +import { CostTracker } from '@reaatech/rag-eval-cost'; +import { Pricing } from '@reaatech/rag-eval-cost'; +import { BudgetManager } from '@reaatech/rag-eval-cost'; +import { CostReporter } from '@reaatech/rag-eval-cost'; +import { beforeEach, describe, expect, it } from 'vitest'; describe('Cost', () => { describe('CostTracker', () => { @@ -39,14 +39,14 @@ describe('Cost', () => { 0.1, { input: 100, output: 50, total: 150 }, 'faithfulness', - 'anthropic' + 'anthropic', ); tracker.recordCost( 'sample-2', 0.05, { input: 50, output: 25, total: 75 }, 'relevance', - 'openai' + 'openai', ); const breakdown = tracker.getBreakdown(); expect(breakdown.total).toBe(0.15); diff --git a/packages/cost/tsconfig.json b/packages/cost/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/cost/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/cost/vitest.config.ts b/packages/cost/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/cost/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/dataset/LICENSE b/packages/dataset/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/dataset/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/dataset/README.md b/packages/dataset/README.md new file mode 100644 index 0000000..7c4a367 --- /dev/null +++ b/packages/dataset/README.md @@ -0,0 +1,239 @@ +# @reaatech/rag-eval-dataset + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-dataset.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-dataset) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Dataset management utilities for RAG evaluation. Loads evaluation samples from JSONL, JSON, and YAML files; validates samples against Zod schemas; generates synthetic datasets from templates; and tracks dataset versioning. + +## Installation + +```bash +npm install @reaatech/rag-eval-dataset +# or +pnpm add @reaatech/rag-eval-dataset +``` + +## Feature Overview + +- **Multi-format loading** β€” read evaluation samples from JSONL, JSON array, and YAML files +- **Schema validation** β€” validate every sample against `EvaluationSampleSchema` with detailed error reporting +- **Duplicate detection** β€” identify duplicate queries and context sets across samples +- **Synthetic generation** β€” generate evaluation datasets from templates with configurable difficulty +- **Version tracking** β€” maintain dataset changelogs and version identifiers +- **Config loading** β€” load evaluation suite configurations from YAML or JSON files + +## Quick Start + +```typescript +import { DatasetLoader, DatasetValidator } from "@reaatech/rag-eval-dataset"; + +const loader = new DatasetLoader(); + +// Load samples from any supported format +const samples = await loader.load("datasets/eval-samples.jsonl"); +console.log(`Loaded ${samples.length} samples`); + +// Validate the dataset +const validator = new DatasetValidator(); +const result = validator.validate(samples); + +if (!result.valid) { + for (const error of result.errors) { + console.error(`[${error.field}] ${error.message}`); + } +} +``` + +## API Reference + +### `DatasetLoader` + +Loads evaluation datasets from files or strings. + +```typescript +import { DatasetLoader } from "@reaatech/rag-eval-dataset"; + +const loader = new DatasetLoader(); +``` + +#### Loading Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `load(path: string)` | `Promise` | Auto-detect format from file extension and load | +| `loadFromString(content, format)` | `Promise` | Parse content string in specified format (`"jsonl" \| "json"`) | + +#### Supported Formats + +| Format | Extension | Structure | +|--------|-----------|-----------| +| JSONL | `.jsonl` | One JSON object per line | +| JSON | `.json` | Array of sample objects | +| YAML | `.yaml`, `.yml` | Array of sample objects | + +Each sample is validated against `EvaluationSampleSchema` from `@reaatech/rag-eval-core`. Invalid lines in JSONL files are skipped with a warning. + +#### Config Loading + +```typescript +import { loadEvalConfig } from "@reaatech/rag-eval-dataset"; + +const config = await loadEvalConfig("eval-config.yaml"); +// β†’ EvalSuiteConfig with metrics, judge, cost, gates, execution +``` + +| Export | Description | +|--------|-------------| +| `loadEvalConfig(path)` | Load and validate an `EvalSuiteConfig` from YAML or JSON | + +### `DatasetValidator` + +Validates datasets for structural correctness and quality issues. + +```typescript +import { DatasetValidator } from "@reaatech/rag-eval-dataset"; + +const validator = new DatasetValidator(); +const result = validator.validate(samples); +``` + +#### `ValidationResult` + +| Property | Type | Description | +|----------|------|-------------| +| `valid` | `boolean` | Whether the dataset passed all checks | +| `errors` | `ValidationError[]` | Errors found (empty if valid) | +| `warnings` | `ValidationWarning[]` | Non-blocking warnings | + +#### `ValidationError` + +| Property | Type | Description | +|----------|------|-------------| +| `field` | `string` | Field name or sample index | +| `message` | `string` | Human-readable error description | + +#### Validations Performed + +- **Schema compliance** β€” every sample matches `EvaluationSampleSchema` +- **Required fields** β€” `query`, `context`, `ground_truth`, `generated_answer` +- **Non-empty context** β€” context arrays must contain at least one chunk +- **Non-empty dataset** β€” dataset must contain at least one sample +- **Duplicate detection** β€” identical queries with matching context triggers a warning + +### `DatasetGenerator` + +Generates synthetic evaluation datasets from templates. + +```typescript +import { DatasetGenerator } from "@reaatech/rag-eval-dataset"; + +const generator = new DatasetGenerator(); +const samples = generator.generate({ + templates: myTemplates, + count: 100, + difficulty: "medium", + domain: "customer-support", +}); +``` + +#### `GeneratorConfig` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `templates` | `DatasetTemplate[]` | (required) | Templates for sample generation | +| `count` | `number` | `10` | Number of samples to generate | +| `difficulty` | `"easy" \| "medium" \| "hard"` | `"medium"` | Difficulty level | +| `domain` | `string` | β€” | Domain label for metadata | + +### `DatasetVersioning` + +Tracks dataset version history and changelogs. + +```typescript +import { DatasetVersioning } from "@reaatech/rag-eval-dataset"; + +const versioning = new DatasetVersioning(); + +// Record a new version +versioning.addVersion({ + version: "v1.1.0", + description: "Added 50 new e-commerce samples", + timestamp: new Date().toISOString(), +}); + +// Get version history +const history = versioning.getHistory(); +``` + +## Usage Patterns + +### Loading and Validating a Dataset + +```typescript +import { DatasetLoader, DatasetValidator } from "@reaatech/rag-eval-dataset"; + +const loader = new DatasetLoader(); +const validator = new DatasetValidator(); + +try { + const samples = await loader.load("eval-dataset.jsonl"); + const result = validator.validate(samples); + + if (!result.valid) { + console.error("Dataset validation failed:"); + for (const error of result.errors) { + console.error(` - ${error.message}`); + } + process.exit(1); + } + + console.log(`Ready to evaluate ${samples.length} samples`); +} catch (err) { + console.error("Failed to load dataset:", err); + process.exit(1); +} +``` + +### Loading Config from YAML + +```yaml +# eval-config.yaml +metrics: + - faithfulness + - relevance + - context_precision + - context_recall + +judge: + model: claude-opus + enabled: true + +cost: + budget_limit: 10.00 + +gates: + - name: min-faithfulness + type: threshold + metric: avg_faithfulness + operator: ">=" + threshold: 0.85 +``` + +```typescript +import { loadEvalConfig } from "@reaatech/rag-eval-dataset"; + +const config = await loadEvalConfig("eval-config.yaml"); +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Central orchestrator +- [`@reaatech/rag-eval-cli`](https://www.npmjs.com/package/@reaatech/rag-eval-cli) β€” CLI with `evaluate` command + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/dataset/package.json b/packages/dataset/package.json new file mode 100644 index 0000000..f7e8387 --- /dev/null +++ b/packages/dataset/package.json @@ -0,0 +1,48 @@ +{ + "name": "@reaatech/rag-eval-dataset", + "version": "0.1.0", + "description": "Dataset loading, validation, generation, and versioning for RAG evals", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/dataset" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/dataset#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@reaatech/rag-eval-core": "workspace:*", + "yaml": "^2.6.1", + "zod": "^3.24.2" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/dataset/generator.ts b/packages/dataset/src/generator.ts similarity index 86% rename from src/dataset/generator.ts rename to packages/dataset/src/generator.ts index 0791275..e659850 100644 --- a/src/dataset/generator.ts +++ b/packages/dataset/src/generator.ts @@ -1,4 +1,4 @@ -import type { EvaluationSample } from '../types/domain.js'; +import type { EvaluationSample } from '@reaatech/rag-eval-core'; export type DifficultyLevel = 'easy' | 'medium' | 'hard'; @@ -64,7 +64,7 @@ const DOMAIN_TEMPLATES: Record< export class DatasetGenerator { generate(config: GeneratorConfig): EvaluationSample[] { - const template = DOMAIN_TEMPLATES[config.domain] || DOMAIN_TEMPLATES['general']; + const template = DOMAIN_TEMPLATES[config.domain] || DOMAIN_TEMPLATES.general; const samples: EvaluationSample[] = []; for (let i = 0; i < config.numSamples; i++) { @@ -72,11 +72,16 @@ export class DatasetGenerator { const contextIdx = i % template.contexts.length; const answerIdx = i % template.answers.length; + const query = template.queries[queryIdx]; + const contextTemplate = template.contexts[contextIdx]; + const answer = template.answers[answerIdx]; + if (!query || !contextTemplate || !answer) continue; + const sample: EvaluationSample = { - query: template.queries[queryIdx]!, - context: this.generateContext(template.contexts[contextIdx]!, config.difficulty), - ground_truth: template.answers[answerIdx]!, - generated_answer: template.answers[answerIdx]!, + query, + context: this.generateContext(contextTemplate, config.difficulty), + ground_truth: answer, + generated_answer: answer, metadata: { difficulty: config.difficulty, domain: config.domain, @@ -110,7 +115,8 @@ export class DatasetGenerator { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); - [shuffled[i], shuffled[j]] = [shuffled[j]!, shuffled[i]!]; + const temp = shuffled[i] as T; + [shuffled[i], shuffled[j]] = [shuffled[j] as T, temp]; } return shuffled; } @@ -118,7 +124,7 @@ export class DatasetGenerator { generateDomainSpecific( domain: string, numSamples: number, - difficulty: DifficultyLevel = 'medium' + difficulty: DifficultyLevel = 'medium', ): EvaluationSample[] { return this.generate({ domain, difficulty, numSamples }); } diff --git a/src/dataset/index.ts b/packages/dataset/src/index.ts similarity index 100% rename from src/dataset/index.ts rename to packages/dataset/src/index.ts diff --git a/src/dataset/loader.ts b/packages/dataset/src/loader.ts similarity index 88% rename from src/dataset/loader.ts rename to packages/dataset/src/loader.ts index 113e037..f091282 100644 --- a/src/dataset/loader.ts +++ b/packages/dataset/src/loader.ts @@ -1,7 +1,7 @@ -import { readFileSync, existsSync } from 'fs'; +import { existsSync, readFileSync } from 'node:fs'; +import type { EvalSuiteConfig, EvaluationSample } from '@reaatech/rag-eval-core'; +import { EvaluationSampleSchema } from '@reaatech/rag-eval-core'; import { parse as parseYaml } from 'yaml'; -import type { EvaluationSample, EvalSuiteConfig } from '../types/domain.js'; -import { EvaluationSampleSchema } from '../types/schemas.js'; /** * Dataset Loader @@ -42,13 +42,15 @@ export class DatasetLoader { const samples: EvaluationSample[] = []; for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!line) continue; try { - const parsed = JSON.parse(lines[i]!); + const parsed = JSON.parse(line); const validated = EvaluationSampleSchema.parse(parsed); samples.push(validated); } catch (error) { throw new Error( - `Error parsing line ${i + 1}: ${error instanceof Error ? error.message : 'Invalid JSON'}` + `Error parsing line ${i + 1}: ${error instanceof Error ? error.message : 'Invalid JSON'}`, ); } } @@ -68,7 +70,7 @@ export class DatasetLoader { if (!Array.isArray(samplesArray)) { throw new Error( - 'JSON file must contain an array of samples or an object with a "samples" or "data" property' + 'JSON file must contain an array of samples or an object with a "samples" or "data" property', ); } @@ -79,7 +81,7 @@ export class DatasetLoader { samples.push(validated); } catch (error) { throw new Error( - `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}` + `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}`, ); } } @@ -99,7 +101,7 @@ export class DatasetLoader { if (!Array.isArray(samplesArray)) { throw new Error( - 'YAML file must contain an array of samples or an object with a "samples" or "data" property' + 'YAML file must contain an array of samples or an object with a "samples" or "data" property', ); } @@ -110,7 +112,7 @@ export class DatasetLoader { samples.push(validated); } catch (error) { throw new Error( - `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}` + `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}`, ); } } @@ -127,13 +129,15 @@ export class DatasetLoader { const lines = content.split('\n').filter((line) => line.trim()); const samples: EvaluationSample[] = []; for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!line) continue; try { - const parsed = JSON.parse(lines[i]!); + const parsed = JSON.parse(line); const validated = EvaluationSampleSchema.parse(parsed); samples.push(validated); } catch (error) { throw new Error( - `Error parsing line ${i + 1}: ${error instanceof Error ? error.message : 'Invalid JSON'}` + `Error parsing line ${i + 1}: ${error instanceof Error ? error.message : 'Invalid JSON'}`, ); } } @@ -149,7 +153,7 @@ export class DatasetLoader { samples.push(validated); } catch (error) { throw new Error( - `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}` + `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}`, ); } } @@ -165,7 +169,7 @@ export class DatasetLoader { samples.push(validated); } catch (error) { throw new Error( - `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}` + `Error validating sample ${i + 1}: ${error instanceof Error ? error.message : 'Invalid sample format'}`, ); } } diff --git a/src/dataset/validator.ts b/packages/dataset/src/validator.ts similarity index 94% rename from src/dataset/validator.ts rename to packages/dataset/src/validator.ts index b6365a8..344a0e8 100644 --- a/src/dataset/validator.ts +++ b/packages/dataset/src/validator.ts @@ -1,5 +1,5 @@ -import type { EvaluationSample } from '../types/domain.js'; -import { EvaluationSampleSchema } from '../types/schemas.js'; +import type { EvaluationSample } from '@reaatech/rag-eval-core'; +import { EvaluationSampleSchema } from '@reaatech/rag-eval-core'; import { z } from 'zod'; export interface ValidationResult { @@ -33,7 +33,8 @@ export class DatasetValidator { const seenContexts = new Set(); for (let i = 0; i < samples.length; i++) { - const sample = samples[i]!; + const sample = samples[i]; + if (!sample) continue; try { EvaluationSampleSchema.parse(sample); diff --git a/src/dataset/versioning.ts b/packages/dataset/src/versioning.ts similarity index 96% rename from src/dataset/versioning.ts rename to packages/dataset/src/versioning.ts index d3b1c3c..b0f0deb 100644 --- a/src/dataset/versioning.ts +++ b/packages/dataset/src/versioning.ts @@ -1,4 +1,4 @@ -import type { DatasetVersion, DatasetSampleStats, EvaluationSample } from '../types/domain.js'; +import type { DatasetSampleStats, DatasetVersion, EvaluationSample } from '@reaatech/rag-eval-core'; export interface VersionedDataset { version: string; @@ -62,7 +62,7 @@ export class DatasetVersioning { compareVersions( version1: string, - version2: string + version2: string, ): { version1Newer: boolean; sampleCountDiff: number; diff --git a/tests/unit/dataset.test.ts b/packages/dataset/tests/dataset.test.ts similarity index 91% rename from tests/unit/dataset.test.ts rename to packages/dataset/tests/dataset.test.ts index 968cd56..6a81069 100644 --- a/tests/unit/dataset.test.ts +++ b/packages/dataset/tests/dataset.test.ts @@ -1,9 +1,9 @@ -import { describe, it, expect } from 'vitest'; -import { DatasetLoader } from '../../src/dataset/loader.js'; -import { DatasetValidator } from '../../src/dataset/validator.js'; -import { DatasetGenerator } from '../../src/dataset/generator.js'; -import { DatasetVersioning } from '../../src/dataset/versioning.js'; -import type { EvaluationSample } from '../../src/types/domain.js'; +import type { EvaluationSample } from '@reaatech/rag-eval-core'; +import { DatasetLoader } from '@reaatech/rag-eval-dataset'; +import { DatasetValidator } from '@reaatech/rag-eval-dataset'; +import { DatasetGenerator } from '@reaatech/rag-eval-dataset'; +import { DatasetVersioning } from '@reaatech/rag-eval-dataset'; +import { describe, expect, it } from 'vitest'; describe('Dataset', () => { describe('DatasetLoader', () => { @@ -96,7 +96,7 @@ describe('Dataset', () => { const generator = new DatasetGenerator(); const easy = generator.generate({ domain: 'general', difficulty: 'easy', numSamples: 3 }); const hard = generator.generate({ domain: 'general', difficulty: 'hard', numSamples: 3 }); - expect(easy[0]!.context.length).toBeLessThanOrEqual(hard[0]!.context.length); + expect(easy[0]?.context.length).toBeLessThanOrEqual(hard[0]?.context.length); }); it('should include metadata', () => { @@ -142,7 +142,7 @@ describe('Dataset', () => { const versioning = new DatasetVersioning(); versioning.createVersion( [{ query: 'test', context: [], ground_truth: 't', generated_answer: 'a' }], - { changes: ['initial'] } + { changes: ['initial'] }, ); const changelog = versioning.getChangelog(); expect(changelog.length).toBe(1); diff --git a/packages/dataset/tsconfig.json b/packages/dataset/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/dataset/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/dataset/vitest.config.ts b/packages/dataset/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/dataset/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/gate/LICENSE b/packages/gate/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/gate/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/gate/README.md b/packages/gate/README.md new file mode 100644 index 0000000..ae1e16e --- /dev/null +++ b/packages/gate/README.md @@ -0,0 +1,221 @@ +# @reaatech/rag-eval-gate + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-gate.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-gate) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Quality gates and CI/CD regression checks for RAG evaluations. Provides threshold gates (metric value comparisons) and baseline-comparison gates (regression detection), with formatted CI output and configurable exit codes. + +## Installation + +```bash +npm install @reaatech/rag-eval-gate +# or +pnpm add @reaatech/rag-eval-gate +``` + +## Feature Overview + +- **Threshold gates** β€” compare any metric against a fixed threshold with `>=`, `<=`, `>`, `<`, `==` operators +- **Baseline-comparison gates** β€” detect regressions by comparing candidate results against a stored baseline +- **Multi-gate evaluation** β€” load and evaluate multiple gates in a single pass +- **CI integration** β€” formatted output suitable for GitHub Actions annotations and exit code control +- **Dynamic gate management** β€” add, remove, and clear gates at runtime + +## Quick Start + +```typescript +import { GateEngine } from "@reaatech/rag-eval-gate"; +import type { EvalResults } from "@reaatech/rag-eval-core"; + +const engine = new GateEngine(); + +engine.loadGates([ + { + name: "min-faithfulness", + type: "threshold", + metric: "avg_faithfulness", + operator: ">=", + threshold: 0.85, + }, + { + name: "max-cost-per-sample", + type: "threshold", + metric: "cost_per_sample", + operator: "<=", + threshold: 0.05, + }, + { + name: "no-regression", + type: "baseline-comparison", + metric: "overall_score", + allow_regression: false, + }, +]); + +const result = engine.evaluate(evalResults, baselineResults); + +if (!result.passed) { + console.error("Gates failed:"); + for (const failure of result.failures) { + console.error(` - ${failure.gate_name}: ${failure.message}`); + } + process.exit(1); +} +``` + +## API Reference + +### `GateEngine` + +Manages and evaluates quality gates against evaluation results. + +```typescript +import { GateEngine } from "@reaatech/rag-eval-gate"; + +const engine = new GateEngine(); +``` + +#### Gate Management + +| Method | Description | +|--------|-------------| +| `loadGates(gates: GateConfig[])` | Replace all gates with a new set | +| `addGate(gate: GateConfig)` | Add a single gate | +| `removeGate(name: string)` | Remove a gate by name | +| `clearGates()` | Remove all gates | +| `getGates()` | Get the current gate list | + +#### Gate Evaluation + +| Method | Returns | Description | +|--------|---------|-------------| +| `evaluate(results, baseline?)` | `GateResult` | Evaluate all gates against results | +| `setBaseline(baseline)` | `void` | Store a baseline for comparison gates | + +### `ThresholdGates` + +Evaluates threshold-based gates against metric values. + +```typescript +import { ThresholdGates } from "@reaatech/rag-eval-gate"; + +const gates = new ThresholdGates(); + +const result = gates.evaluate( + { name: "min-faithfulness", type: "threshold", metric: "avg_faithfulness", operator: ">=", threshold: 0.85 }, + 0.90 +); +console.log(result.passed); // true +``` + +#### Supported Operators + +| Operator | Description | Example | +|----------|-------------|---------| +| `>=` | Greater than or equal | `avg_faithfulness >= 0.85` | +| `<=` | Less than or equal | `cost_per_sample <= 0.05` | +| `>` | Strictly greater than | `overall_score > 0.5` | +| `<` | Strictly less than | `error_rate < 0.1` | +| `==` | Exactly equal | `total_samples == 100` | + +### `BaselineGates` + +Detects regressions between a candidate and baseline evaluation run. + +```typescript +import { BaselineGates } from "@reaatech/rag-eval-gate"; + +const gates = new BaselineGates(); + +const result = gates.evaluate( + { name: "no-regression", type: "baseline-comparison", metric: "overall_score", allow_regression: false }, + baselineResults, + candidateResults +); +``` + +| Parameter | Description | +|-----------|-------------| +| `allow_regression: true` | Gate always passes; regression reported but not blocking | +| `allow_regression: false` | Gate fails if candidate score is more than 0.01 worse than baseline | + +### `CIIntegration` + +Formats gate results for CI environments. + +```typescript +import { CIIntegration } from "@reaatech/rag-eval-gate"; + +const ci = new CIIntegration(); + +const output = ci.formatGateResult(gateResult); +// β†’ Formatted lines suitable for GitHub Actions annotations + +const exitCode = ci.getExitCode(gateResult); +// β†’ 0 on pass, 1 on fail +``` + +| Method | Returns | Description | +|--------|---------|-------------| +| `formatGateResult(result)` | `string` | Format gate results for CI output | +| `getExitCode(result)` | `number` | Get appropriate exit code (0 or 1) | + +## Usage Patterns + +### CI Regression Gate + +```yaml +# .github/workflows/eval.yml +- name: Run regression gates + run: | + node packages/cli/dist/cli.js gate \ + --results results/eval-results.json \ + --gates gates.yaml \ + --baseline results/baseline.json + id: gate-check + +- name: Fail if gates failed + if: steps.gate-check.outcome == 'failure' + run: exit 1 +``` + +### Programmatic Gate Pipeline + +```typescript +import { GateEngine } from "@reaatech/rag-eval-gate"; +import { readFileSync } from "node:fs"; + +const engine = new GateEngine(); + +// Load gate config from YAML +engine.loadGates([ + { name: "min-faithfulness", type: "threshold", metric: "avg_faithfulness", operator: ">=", threshold: 0.85 }, + { name: "min-relevance", type: "threshold", metric: "avg_relevance", operator: ">=", threshold: 0.80 }, + { name: "min-context-recall", type: "threshold", metric: "avg_context_recall", operator: ">=", threshold: 0.90 }, + { name: "no-regression", type: "baseline-comparison", metric: "overall_score", allow_regression: false }, +]); + +const baseline = JSON.parse(readFileSync("results/baseline.json", "utf-8")); +engine.setBaseline(baseline); + +const candidate = JSON.parse(readFileSync("results/candidate.json", "utf-8")); +const result = engine.evaluate(candidate, baseline); + +for (const gate of result.gates) { + const icon = gate.passed ? "βœ…" : "❌"; + console.log(`${icon} ${gate.name}: ${gate.actual_value}`); +} +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Gate type definitions +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Central orchestrator +- [`@reaatech/rag-eval-cli`](https://www.npmjs.com/package/@reaatech/rag-eval-cli) β€” CLI with `gate` command + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/gate/package.json b/packages/gate/package.json new file mode 100644 index 0000000..f48e2ac --- /dev/null +++ b/packages/gate/package.json @@ -0,0 +1,46 @@ +{ + "name": "@reaatech/rag-eval-gate", + "version": "0.1.0", + "description": "Quality gates and CI/CD regression checks for RAG evaluations", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/gate" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/gate#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@reaatech/rag-eval-core": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/gate/baseline-gates.ts b/packages/gate/src/baseline-gates.ts similarity index 94% rename from src/gate/baseline-gates.ts rename to packages/gate/src/baseline-gates.ts index 24c2b9f..17c5706 100644 --- a/src/gate/baseline-gates.ts +++ b/packages/gate/src/baseline-gates.ts @@ -1,4 +1,4 @@ -import type { GateConfig, EvalResults, IndividualGateResult } from '../types/domain.js'; +import type { EvalResults, GateConfig, IndividualGateResult } from '@reaatech/rag-eval-core'; export interface BaselineGateConfig extends GateConfig { type: 'baseline-comparison'; @@ -11,7 +11,7 @@ export class BaselineGates { evaluate( gate: BaselineGateConfig, candidateValue: number, - baseline: EvalResults + baseline: EvalResults, ): IndividualGateResult { const baselineValue = this.getMetricValue(gate.metric, baseline); const diff = candidateValue - baselineValue; @@ -45,7 +45,7 @@ export class BaselineGates { evaluateAll( gates: BaselineGateConfig[], candidateResults: EvalResults, - baseline: EvalResults + baseline: EvalResults, ): IndividualGateResult[] { return gates.map((gate) => { const candidateValue = this.getMetricValue(gate.metric, candidateResults); diff --git a/src/gate/ci-integration.ts b/packages/gate/src/ci-integration.ts similarity index 96% rename from src/gate/ci-integration.ts rename to packages/gate/src/ci-integration.ts index 22302b3..9ff8c2b 100644 --- a/src/gate/ci-integration.ts +++ b/packages/gate/src/ci-integration.ts @@ -1,4 +1,4 @@ -import type { GateResult, EvalResults } from '../types/domain.js'; +import type { EvalResults, GateResult } from '@reaatech/rag-eval-core'; export interface GitHubActionsOutput { passed: boolean; @@ -29,7 +29,7 @@ export interface PRCommentData { export class CIIntegration { generateGitHubActionsOutput( gateResult: GateResult, - _evalResults?: EvalResults + _evalResults?: EvalResults, ): GitHubActionsOutput { return { passed: gateResult.passed, @@ -47,10 +47,10 @@ export class CIIntegration { const testCases = gateResult.gates .map( ( - gate + gate, ) => ` ${!gate.passed ? `${this.escapeXml(gate.message)}` : ''} - ` + `, ) .join('\n'); @@ -65,7 +65,7 @@ ${testCases} const gatesStatus = data.gatesPassed ? 'βœ… Passed' : '❌ Failed'; const lines = [ - `## RAG Evaluation Results`, + '## RAG Evaluation Results', '', `**Overall Score:** ${data.overallScore.toFixed(3)}`, `**Faithfulness:** ${data.avgFaithfulness.toFixed(3)}`, @@ -110,7 +110,7 @@ ${testCases} '| Gate | Result | Details |', '|------|--------|---------|', ...gateResult.gates.map( - (g) => `| ${g.name} | ${g.passed ? 'βœ… Pass' : '❌ Fail'} | ${g.message} |` + (g) => `| ${g.name} | ${g.passed ? 'βœ… Pass' : '❌ Fail'} | ${g.message} |`, ), '', ]; diff --git a/src/gate/engine.ts b/packages/gate/src/engine.ts similarity index 97% rename from src/gate/engine.ts rename to packages/gate/src/engine.ts index c66d4f5..4f891f4 100644 --- a/src/gate/engine.ts +++ b/packages/gate/src/engine.ts @@ -1,10 +1,10 @@ import type { + EvalResults, GateConfig, + GateFailure, GateResult, - EvalResults, IndividualGateResult, - GateFailure, -} from '../types/domain.js'; +} from '@reaatech/rag-eval-core'; /** * Gate Engine @@ -73,7 +73,7 @@ export class GateEngine { private evaluateGate( gate: GateConfig, results: EvalResults, - baseline?: EvalResults | null + baseline?: EvalResults | null, ): IndividualGateResult { const actualValue = this.getMetricValue(gate.metric, results); @@ -151,7 +151,7 @@ export class GateEngine { private evaluateBaselineGate( gate: GateConfig, candidateValue: number, - baseline: EvalResults + baseline: EvalResults, ): IndividualGateResult { const baselineValue = this.getMetricValue(gate.metric, baseline); const diff = candidateValue - baselineValue; @@ -214,7 +214,7 @@ export class GateEngine { return metrics.std_dev[metric as keyof typeof metrics.std_dev] || 0; } throw new Error( - `Unknown metric: '${metric}'. Valid metrics: avg_faithfulness, avg_relevance, avg_context_precision, avg_context_recall, overall_score, cost_per_sample, cost_per_eval, total_cost` + `Unknown metric: '${metric}'. Valid metrics: avg_faithfulness, avg_relevance, avg_context_precision, avg_context_recall, overall_score, cost_per_sample, cost_per_eval, total_cost`, ); } } diff --git a/src/gate/index.ts b/packages/gate/src/index.ts similarity index 100% rename from src/gate/index.ts rename to packages/gate/src/index.ts diff --git a/src/gate/threshold-gates.ts b/packages/gate/src/threshold-gates.ts similarity index 94% rename from src/gate/threshold-gates.ts rename to packages/gate/src/threshold-gates.ts index 32f096f..975f9df 100644 --- a/src/gate/threshold-gates.ts +++ b/packages/gate/src/threshold-gates.ts @@ -1,4 +1,4 @@ -import type { GateConfig, IndividualGateResult } from '../types/domain.js'; +import type { GateConfig, IndividualGateResult } from '@reaatech/rag-eval-core'; export interface ThresholdGateConfig extends GateConfig { type: 'threshold'; @@ -58,7 +58,7 @@ export class ThresholdGates { evaluateAll( gates: ThresholdGateConfig[], - getMetricValue: (metric: string) => number + getMetricValue: (metric: string) => number, ): IndividualGateResult[] { return gates.map((gate) => this.evaluate(gate, getMetricValue(gate.metric))); } diff --git a/tests/unit/baseline-gates.test.ts b/packages/gate/tests/baseline-gates.test.ts similarity index 91% rename from tests/unit/baseline-gates.test.ts rename to packages/gate/tests/baseline-gates.test.ts index 5615a30..c1754bc 100644 --- a/tests/unit/baseline-gates.test.ts +++ b/packages/gate/tests/baseline-gates.test.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { BaselineGates } from '../../src/gate/baseline-gates.js'; -import type { BaselineGateConfig, EvalResults } from '../../src/gate/index.js'; +import type { EvalResults } from '@reaatech/rag-eval-core'; +import { BaselineGates } from '@reaatech/rag-eval-gate'; +import type { BaselineGateConfig } from '@reaatech/rag-eval-gate'; +import { beforeEach, describe, expect, it } from 'vitest'; describe('BaselineGates', () => { let gates: BaselineGates; @@ -106,7 +107,7 @@ describe('BaselineGates', () => { const results = gates.evaluateAll(testGates, candidateResults, mockBaselineResults); expect(results).toHaveLength(1); - expect(results[0]!.passed).toBe(true); + expect(results[0]?.passed).toBe(true); }); }); }); diff --git a/tests/unit/ci-integration.test.ts b/packages/gate/tests/ci-integration.test.ts similarity index 95% rename from tests/unit/ci-integration.test.ts rename to packages/gate/tests/ci-integration.test.ts index 983effa..da48713 100644 --- a/tests/unit/ci-integration.test.ts +++ b/packages/gate/tests/ci-integration.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect } from 'vitest'; -import { CIIntegration } from '../../src/gate/ci-integration.js'; -import type { GateResult, EvalResults } from '../../src/types/domain.js'; +import type { EvalResults, GateResult } from '@reaatech/rag-eval-core'; +import { CIIntegration } from '@reaatech/rag-eval-gate'; +import { beforeEach, describe, expect, it } from 'vitest'; describe('CIIntegration', () => { let ci: CIIntegration; diff --git a/tests/unit/gate.test.ts b/packages/gate/tests/gate.test.ts similarity index 85% rename from tests/unit/gate.test.ts rename to packages/gate/tests/gate.test.ts index 3b96986..32c4d24 100644 --- a/tests/unit/gate.test.ts +++ b/packages/gate/tests/gate.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { GateEngine } from '../../src/gate/engine.js'; -import type { GateConfig, EvalResults } from '../../src/types/domain.js'; +import type { EvalResults } from '@reaatech/rag-eval-core'; +import { GateEngine } from '@reaatech/rag-eval-gate'; +import { beforeEach, describe, expect, it } from 'vitest'; describe('GateEngine', () => { let engine: GateEngine; @@ -9,9 +9,11 @@ describe('GateEngine', () => { engine = new GateEngine(); }); - const createMockResults = (overrides = {}): EvalResults => ({ + const createMockResults = (overrides: Partial = {}): EvalResults => ({ run_id: 'test-run', evaluated_at: new Date().toISOString(), + dataset: 'test-dataset', + config: { metrics: ['faithfulness'] }, metrics: { avg_faithfulness: 0.87, avg_relevance: 0.82, @@ -23,6 +25,9 @@ describe('GateEngine', () => { }, samples: [], total_cost: 0.15, + cost_breakdown: { total: 0.15, by_metric: {}, by_provider: {}, per_sample: [] }, + duration_ms: 100, + completed_at: new Date().toISOString(), ...overrides, }); @@ -93,8 +98,10 @@ describe('GateEngine', () => { }, ]); - const baseline = createMockResults({ metrics: { overall_score: 0.8 } as any }); - const candidate = createMockResults({ metrics: { overall_score: 0.85 } as any }); + const baseline = createMockResults(); + baseline.metrics.overall_score = 0.8; + const candidate = createMockResults(); + candidate.metrics.overall_score = 0.85; const gateResult = engine.evaluate(candidate, baseline); @@ -111,8 +118,10 @@ describe('GateEngine', () => { }, ]); - const baseline = createMockResults({ metrics: { overall_score: 0.9 } as any }); - const candidate = createMockResults({ metrics: { overall_score: 0.8 } as any }); + const baseline = createMockResults(); + baseline.metrics.overall_score = 0.9; + const candidate = createMockResults(); + candidate.metrics.overall_score = 0.8; const gateResult = engine.evaluate(candidate, baseline); @@ -126,12 +135,15 @@ describe('GateEngine', () => { name: 'allow-regression', type: 'baseline-comparison', metric: 'overall_score', + allow_regression: true, }, ]); - const baseline = createMockResults({ metrics: { overall_score: 0.9 } as any }); - const candidate = createMockResults({ metrics: { overall_score: 0.8 } as any }); + const baseline = createMockResults(); + baseline.metrics.overall_score = 0.9; + const candidate = createMockResults(); + candidate.metrics.overall_score = 0.8; const gateResult = engine.evaluate(candidate, baseline); diff --git a/tests/unit/threshold-gates.test.ts b/packages/gate/tests/threshold-gates.test.ts similarity index 93% rename from tests/unit/threshold-gates.test.ts rename to packages/gate/tests/threshold-gates.test.ts index 6ef2669..6d56859 100644 --- a/tests/unit/threshold-gates.test.ts +++ b/packages/gate/tests/threshold-gates.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { ThresholdGates } from '../../src/gate/threshold-gates.js'; -import type { ThresholdGateConfig } from '../../src/gate/threshold-gates.js'; +import { ThresholdGates } from '@reaatech/rag-eval-gate'; +import type { ThresholdGateConfig } from '@reaatech/rag-eval-gate'; +import { beforeEach, describe, expect, it } from 'vitest'; describe('ThresholdGates', () => { let gates: ThresholdGates; @@ -130,8 +130,8 @@ describe('ThresholdGates', () => { const getMetric = (metric: string): number => (metric === 'score1' ? 0.7 : 0.8); const results = gates.evaluateAll(testGates, getMetric); expect(results).toHaveLength(2); - expect(results[0]!.passed).toBe(true); - expect(results[1]!.passed).toBe(true); + expect(results[0]?.passed).toBe(true); + expect(results[1]?.passed).toBe(true); }); }); }); diff --git a/packages/gate/tsconfig.json b/packages/gate/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/gate/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/gate/vitest.config.ts b/packages/gate/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/gate/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/judge/LICENSE b/packages/judge/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/judge/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/judge/README.md b/packages/judge/README.md new file mode 100644 index 0000000..a2f9bd9 --- /dev/null +++ b/packages/judge/README.md @@ -0,0 +1,264 @@ +# @reaatech/rag-eval-judge + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-judge.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-judge) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +LLM-as-judge for RAG evaluation with multi-provider support, calibration against human labels, and consensus voting across models. Provides prompt templates for faithfulness, relevance, context precision, context recall, and overall quality scoring. + +## Installation + +```bash +npm install @reaatech/rag-eval-judge +# or +pnpm add @reaatech/rag-eval-judge +``` + +## Feature Overview + +- **Multi-provider support** β€” Anthropic (Claude), OpenAI (GPT), and Google (Gemini) with automatic provider selection +- **Provider fallback** β€” configure backup models that activate when primary provider credentials are unavailable +- **Consensus voting** β€” weighted, majority, or unanimous voting across multiple judge models for higher accuracy +- **Calibration** β€” temperature scaling or isotonic regression against human-labeled data +- **Cost tracking** β€” per-judgment token counting and cost estimation via `@reaatech/rag-eval-cost` +- **Prompt templates** β€” curated prompts for each metric with structured score/explanation output parsing + +## Quick Start + +```typescript +import { JudgeEngine } from "@reaatech/rag-eval-judge"; + +const engine = new JudgeEngine({ + model: "claude-opus", +}); + +const result = await engine.evaluate( + { + query: "What is the refund policy?", + context: [ + "Refunds are processed within 14 days of purchase.", + "Contact support@example.com for refund requests.", + ], + ground_truth: "Refunds must be requested within 14 days by contacting support.", + generated_answer: "You can request a refund within 14 days by emailing support.", + }, + "faithfulness" +); + +console.log(result.score); // 0.85–0.95 +console.log(result.provider); // "anthropic" +console.log(result.model); // "claude-opus" +``` + +## API Reference + +### `JudgeEngine` + +The primary class for LLM-based evaluation. + +```typescript +import { JudgeEngine, type JudgeConfig, type JudgeMetric, type JudgeResult } from "@reaatech/rag-eval-judge"; + +const engine = new JudgeEngine(config: JudgeConfig); +``` + +#### `JudgeConfig` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `model` | `string` | β€” | Primary judge model ID | +| `enabled` | `boolean` | `true` | Enable/disable LLM judging | +| `fallback_models` | `string[]` | `[]` | Backup model IDs for provider fallback | +| `consensus` | `ConsensusConfig` | β€” | Multi-model consensus configuration | +| `calibration` | `CalibrationConfig` | β€” | Human-label calibration configuration | +| `cost` | `JudgeCostConfig` | β€” | Per-judgment cost limits | + +#### Instance Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `evaluate(sample, metric, model?)` | `Promise` | Run single-metric judge evaluation | +| `evaluateWithConsensus(sample, metric)` | `Promise` | Run consensus-based evaluation with multiple models | +| `evaluateBatch(samples, metric, useConsensus?)` | `Promise` | Evaluate multiple samples for a single metric | + +#### `JudgeResult` + +| Property | Type | Description | +|----------|------|-------------| +| `score` | `number` | Judged score (0–1) | +| `metric` | `string` | Evaluated metric name | +| `provider` | `string` | LLM provider used | +| `model` | `string` | LLM model used | +| `explanation` | `string` | Judge's reasoning | +| `raw_response` | `string` | Raw LLM response | + +### `JudgeCalibrator` + +Calibrates judge scores against human-labeled data. + +```typescript +import { JudgeCalibrator } from "@reaatech/rag-eval-judge"; + +const calibrator = new JudgeCalibrator({ + method: "temperature_scaling", +}); + +// Load human-labeled data +calibrator.loadData([ + { rawScore: 0.7, humanScore: 0.75 }, + { rawScore: 0.5, humanScore: 0.55 }, + { rawScore: 0.3, humanScore: 0.35 }, +]); + +// Train the calibration model +await calibrator.train(); + +// Apply calibration to new scores +const calibratedScore = calibrator.apply(0.7); +console.log(calibratedScore); // Adjusted based on training data +``` + +#### `CalibrationConfig` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `enabled` | `boolean` | `false` | Enable calibration | +| `method` | `"temperature_scaling" \| "isotonic_regression"` | `"temperature_scaling"` | Calibration algorithm | +| `human_labels` | `string` | β€” | Path to human labels JSONL file | + +#### Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `addDataPoint(rawScore, humanScore)` | `void` | Add a single calibration datapoint | +| `loadData(points)` | `void` | Load calibration data from array | +| `train()` | `Promise` | Train the calibration model | +| `apply(rawScore)` | `number` | Apply calibration to a raw score | +| `isTrained()` | `boolean` | Whether the model has been trained | +| `getMetrics()` | `CalibrationMetrics` | Get MAE and RMSE after training | +| `getMethod()` | `string` | Get the current calibration method | + +### `JudgeCostTracker` + +Tracks per-judgment costs with budget enforcement. + +```typescript +import { JudgeCostTracker } from "@reaatech/rag-eval-judge"; + +const tracker = new JudgeCostTracker({ + budgetLimit: 10.00, + alertThresholds: [0.5, 0.75, 0.9], +}); + +// Estimate cost before making a call +const estimate = tracker.estimateCost("claude-opus", "anthropic", inputText); +console.log(estimate.cost); // estimated cost +console.log(estimate.tokens.input); // estimated input tokens + +// Record cost after a judgment +tracker.recordCost( + sampleIndex, + "claude-opus", + "anthropic", + inputTokens, + outputTokens, + "faithfulness" +); +``` + +### Prompt Templates + +Pre-built prompts for each metric, with structured output formatting: + +| Export | Metric | +|--------|--------| +| `FAITHFULNESS_PROMPT` | Verify if answer is faithful to context | +| `RELEVANCE_PROMPT` | Check if answer addresses the query | +| `CONTEXT_PRECISION_PROMPT` | Evaluate context ranking quality | +| `CONTEXT_RECALL_PROMPT` | Evaluate ground truth coverage in context | +| `OVERALL_QUALITY_PROMPT` | Holistic answer quality assessment | + +```typescript +import { applyPromptTemplate, parseJudgeResponse, FAITHFULNESS_PROMPT } from "@reaatech/rag-eval-judge"; + +const prompt = applyPromptTemplate(FAITHFULNESS_PROMPT, { + query: sample.query, + context: sample.context.join("\n"), + answer: sample.generated_answer, +}); + +// Send to LLM, then parse the response +const result = parseJudgeResponse(llmResponse); +// β†’ { score: 0.90, explanation: "The answer accurately reflects..." } +``` + +## Usage Patterns + +### Consensus Voting + +```typescript +import { JudgeEngine } from "@reaatech/rag-eval-judge"; + +const engine = new JudgeEngine({ + model: "claude-opus", + consensus: { + enabled: true, + models: [ + { id: "claude-opus", weight: 0.5 }, + { id: "gpt-4-turbo", weight: 0.3 }, + { id: "gemini-pro", weight: 0.2 }, + ], + voting_strategy: "weighted", + tie_breaker: "highest_confidence", + min_agreement: 0.7, + }, +}); + +const result = await engine.evaluateWithConsensus(sample, "faithfulness"); +// Weighted average across all 3 models +``` + +### Calibrated Evaluation Pipeline + +```typescript +import { JudgeEngine, JudgeCalibrator } from "@reaatech/rag-eval-judge"; + +const calibrator = new JudgeCalibrator({ method: "temperature_scaling" }); +calibrator.loadData(humanLabels); +await calibrator.train(); + +const engine = new JudgeEngine({ + model: "claude-opus", + calibration: { enabled: true }, +}); + +const rawResult = await engine.evaluate(sample, "faithfulness"); +const calibratedScore = calibrator.apply(rawResult.score); +console.log(`Raw: ${rawResult.score} β†’ Calibrated: ${calibratedScore}`); +``` + +### Provider Fallback + +```typescript +const engine = new JudgeEngine({ + model: "claude-opus", + fallback_models: ["gpt-4-turbo", "gemini-pro"], +}); + +// If ANTHROPIC_API_KEY is missing, falls back to OpenAI, then Google +const result = await engine.evaluate(sample, "faithfulness"); +console.log(`Used: ${result.provider} / ${result.model}`); +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-cost`](https://www.npmjs.com/package/@reaatech/rag-eval-cost) β€” Pricing and budget infrastructure +- [`@reaatech/rag-eval-metrics`](https://www.npmjs.com/package/@reaatech/rag-eval-metrics) β€” Heuristic metrics (lower cost alternative) +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Central orchestrator + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/judge/package.json b/packages/judge/package.json new file mode 100644 index 0000000..6442881 --- /dev/null +++ b/packages/judge/package.json @@ -0,0 +1,50 @@ +{ + "name": "@reaatech/rag-eval-judge", + "version": "0.1.0", + "description": "LLM-as-judge with calibration, consensus voting, and cost tracking", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/judge" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/judge#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.32.0", + "@google/generative-ai": "^0.21.0", + "@reaatech/rag-eval-core": "workspace:*", + "@reaatech/rag-eval-cost": "workspace:*", + "openai": "^6.35.0" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/judge/calibration.ts b/packages/judge/src/calibration.ts similarity index 88% rename from src/judge/calibration.ts rename to packages/judge/src/calibration.ts index c452612..3dbeb58 100644 --- a/src/judge/calibration.ts +++ b/packages/judge/src/calibration.ts @@ -19,8 +19,8 @@ export type CalibrationMethod = 'temperature_scaling' | 'isotonic_regression'; */ export class JudgeCalibrator { private method: CalibrationMethod; - private temperature: number = 1.0; - private trained: boolean = false; + private temperature = 1.0; + private trained = false; private calibrationData: CalibrationDataPoint[] = []; constructor(config?: { method?: CalibrationMethod }) { @@ -70,13 +70,13 @@ export class JudgeCalibrator { // Find optimal temperature using gradient descent // Temperature scaling: calibrated = sigmoid(logit(raw) / T) let bestTemp = 1.0; - let bestLoss = Infinity; + let bestLoss = Number.POSITIVE_INFINITY; for (let temp = 0.1; temp <= 5.0; temp += 0.1) { let loss = 0; for (const point of this.calibrationData) { const calibrated = this.applyTemperatureScaling(point.rawScore, temp); - loss += Math.pow(calibrated - point.humanScore, 2); + loss += (calibrated - point.humanScore) ** 2; } if (loss < bestLoss) { @@ -164,22 +164,22 @@ export class JudgeCalibrator { const mapping = this.mappingData; if (mapping.length === 1) { - return mapping[0]!.calibrated; + return mapping[0]?.calibrated; } - if (rawScore <= mapping[0]!.raw) { - return mapping[0]!.calibrated; + if (rawScore <= mapping[0]?.raw) { + return mapping[0]?.calibrated; } - if (rawScore >= mapping[mapping.length - 1]!.raw) { - return mapping[mapping.length - 1]!.calibrated; + if (rawScore >= mapping[mapping.length - 1]?.raw) { + return mapping[mapping.length - 1]?.calibrated; } for (let i = 0; i < mapping.length - 1; i++) { - if (rawScore >= mapping[i]!.raw && rawScore <= mapping[i + 1]!.raw) { - const ratio = (rawScore - mapping[i]!.raw) / (mapping[i + 1]!.raw - mapping[i]!.raw); + if (rawScore >= mapping[i]?.raw && rawScore <= mapping[i + 1]?.raw) { + const ratio = (rawScore - mapping[i]?.raw) / (mapping[i + 1]?.raw - mapping[i]?.raw); return ( - mapping[i]!.calibrated + ratio * (mapping[i + 1]!.calibrated - mapping[i]!.calibrated) + mapping[i]?.calibrated + ratio * (mapping[i + 1]?.calibrated - mapping[i]?.calibrated) ); } } diff --git a/src/judge/cost-tracker.ts b/packages/judge/src/cost-tracker.ts similarity index 92% rename from src/judge/cost-tracker.ts rename to packages/judge/src/cost-tracker.ts index 7203058..a5e1c12 100644 --- a/src/judge/cost-tracker.ts +++ b/packages/judge/src/cost-tracker.ts @@ -1,5 +1,5 @@ -import type { LLMProvider, CostBreakdown, SampleCost, TokenCount } from '../types/domain.js'; -import { Pricing, type PricingConfig } from '../cost/pricing.js'; +import type { CostBreakdown, LLMProvider, SampleCost, TokenCount } from '@reaatech/rag-eval-core'; +import { Pricing, type PricingConfig } from '@reaatech/rag-eval-cost'; /** * Pricing information for a model @@ -14,10 +14,10 @@ export type ModelPricing = PricingConfig; */ export class JudgeCostTracker { private costs: SampleCost[] = []; - private totalCost: number = 0; + private totalCost = 0; private costByMetric: Record = {}; private costByProvider: Record = {}; - private budgetLimit: number = Infinity; + private budgetLimit: number = Number.POSITIVE_INFINITY; private alertThresholds: number[] = [0.5, 0.75, 0.9]; private alertsTriggered: number[] = []; private pricing: Pricing; @@ -54,7 +54,7 @@ export class JudgeCostTracker { model: string, provider: LLMProvider, inputTokens: number, - outputTokens: number + outputTokens: number, ): number { return this.pricing.calculateCost(model, provider, inputTokens, outputTokens); } @@ -68,7 +68,7 @@ export class JudgeCostTracker { provider: LLMProvider, inputTokens: number, outputTokens: number, - metric?: string + metric?: string, ): { cost: number; withinBudget: boolean; alertTriggered: boolean } { const cost = this.calculateCost(model, provider, inputTokens, outputTokens); @@ -117,7 +117,7 @@ export class JudgeCostTracker { model: string, provider: LLMProvider, inputText: string, - outputEstimate?: number + outputEstimate?: number, ): { cost: number; tokens: TokenCount } { const inputTokens = this.estimateTokens(inputText); const outputTokens = outputEstimate ?? Math.ceil(inputTokens * 0.3); // Estimate 30% of input @@ -159,7 +159,7 @@ export class JudgeCostTracker { * Get budget usage ratio */ getBudgetUsage(): number { - if (this.budgetLimit === Infinity) return 0; + if (this.budgetLimit === Number.POSITIVE_INFINITY) return 0; return Math.round((this.totalCost / this.budgetLimit) * 1000) / 1000; } diff --git a/src/judge/engine.ts b/packages/judge/src/engine.ts similarity index 92% rename from src/judge/engine.ts rename to packages/judge/src/engine.ts index 9586e62..576930a 100644 --- a/src/judge/engine.ts +++ b/packages/judge/src/engine.ts @@ -1,21 +1,21 @@ import type { + ConsensusConfig, EvaluationSample, + JudgeConfig, JudgeScore, LLMProvider, - JudgeConfig, - ConsensusConfig, -} from '../types/domain.js'; +} from '@reaatech/rag-eval-core'; +import { type CalibrationDataPoint, JudgeCalibrator } from './calibration.js'; import { - FAITHFULNESS_PROMPT, - RELEVANCE_PROMPT, CONTEXT_PRECISION_PROMPT, CONTEXT_RECALL_PROMPT, + FAITHFULNESS_PROMPT, OVERALL_QUALITY_PROMPT, + type PromptTemplate, + RELEVANCE_PROMPT, applyPromptTemplate, parseJudgeResponse, - type PromptTemplate, } from './prompts.js'; -import { JudgeCalibrator, type CalibrationDataPoint } from './calibration.js'; /** Judge metric type */ export type JudgeMetric = @@ -46,7 +46,7 @@ export class JudgeEngine { constructor(config: JudgeConfig) { this.config = config; this.calibrator = new JudgeCalibrator( - config.calibration?.method ? { method: config.calibration.method } : undefined + config.calibration?.method ? { method: config.calibration.method } : undefined, ); } @@ -98,7 +98,7 @@ export class JudgeEngine { async evaluate( sample: EvaluationSample, metric: JudgeMetric, - model?: string + model?: string, ): Promise { const targetModel = model ?? this.config.model ?? JudgeEngine.DEFAULT_MODEL; const provider = this.getProvider(targetModel); @@ -130,7 +130,7 @@ export class JudgeEngine { model: targetModel, provider, metric, - sample_id: sample.metadata?.['sample_id'] as string | number, + sample_id: sample.metadata?.sample_id as string | number, }; } catch (error) { // Try fallback models @@ -139,9 +139,7 @@ export class JudgeEngine { if (!fallback) continue; try { return await this.evaluate(sample, metric, fallback); - } catch { - continue; - } + } catch {} } } @@ -154,7 +152,7 @@ export class JudgeEngine { model: targetModel, provider, metric, - sample_id: sample.metadata?.['sample_id'] as string | number, + sample_id: sample.metadata?.sample_id as string | number, }; } } @@ -187,10 +185,10 @@ export class JudgeEngine { results: JudgeResult[], config: ConsensusConfig, metric: JudgeMetric, - sample: EvaluationSample + sample: EvaluationSample, ): JudgeResult { const provider = this.getProvider( - config.models[0]?.id ?? this.config.model ?? JudgeEngine.DEFAULT_MODEL + config.models[0]?.id ?? this.config.model ?? JudgeEngine.DEFAULT_MODEL, ); switch (config.voting_strategy) { @@ -214,7 +212,7 @@ export class JudgeEngine { model: config.models.map((m) => m.id).join(', '), provider, metric, - sample_id: sample.metadata?.['sample_id'] as string | number, + sample_id: sample.metadata?.sample_id as string | number, }; } @@ -235,13 +233,13 @@ export class JudgeEngine { model: config.models.map((m) => m.id).join(', '), provider, metric, - sample_id: sample.metadata?.['sample_id'] as string | number, + sample_id: sample.metadata?.sample_id as string | number, }; } case 'unanimous': { const allSame = results.every( - (r) => Math.round(r.score * 10) === Math.round(results[0]!.score * 10) + (r) => Math.round(r.score * 10) === Math.round(results[0]?.score * 10), ); const avgScore = results.reduce((sum, r) => sum + r.score, 0) / results.length; @@ -255,12 +253,25 @@ export class JudgeEngine { model: config.models.map((m) => m.id).join(', '), provider, metric, - sample_id: sample.metadata?.['sample_id'] as string | number, + sample_id: sample.metadata?.sample_id as string | number, }; } - default: - return results[0]!; + default: { + const first = results[0]; + if (!first) + return { + score: 0.5, + explanation: 'No results available', + confidence: 0, + calibrated: false, + model: config.models.map((m) => m.id).join(', '), + provider, + metric, + sample_id: sample.metadata?.sample_id as string | number, + }; + return first; + } } } @@ -316,7 +327,7 @@ export class JudgeEngine { model: string, provider: LLMProvider, system: string, - user: string + user: string, ): Promise { const apiKey = this.getApiKeyForModel(model); @@ -343,7 +354,7 @@ export class JudgeEngine { lastError = error instanceof Error ? error : new Error(String(error)); if (this.isRateLimitError(error) && attempt < maxRetries - 1) { - const delay = Math.pow(2, attempt) * 1000; + const delay = 2 ** attempt * 1000; await this.sleep(delay); continue; } @@ -379,7 +390,7 @@ export class JudgeEngine { model: string, apiKey: string, system: string, - user: string + user: string, ): Promise { // Dynamic import to avoid requiring the package at runtime if not used const { Anthropic } = await import('@anthropic-ai/sdk'); @@ -402,7 +413,7 @@ export class JudgeEngine { model: string, apiKey: string, system: string, - user: string + user: string, ): Promise { const { OpenAI } = await import('openai'); const client = new OpenAI({ apiKey }); @@ -426,7 +437,7 @@ export class JudgeEngine { model: string, apiKey: string, system: string, - user: string + user: string, ): Promise { const { GoogleGenerativeAI } = await import('@google/generative-ai'); const genAI = new GoogleGenerativeAI(apiKey); @@ -479,7 +490,7 @@ Explanation: Mock evaluation - in production, this would be evaluated by an LLM async evaluateBatch( samples: EvaluationSample[], metric: JudgeMetric, - useConsensus: boolean = false + useConsensus = false, ): Promise { const results: JudgeResult[] = []; diff --git a/src/judge/index.ts b/packages/judge/src/index.ts similarity index 100% rename from src/judge/index.ts rename to packages/judge/src/index.ts diff --git a/src/judge/prompts.ts b/packages/judge/src/prompts.ts similarity index 97% rename from src/judge/prompts.ts rename to packages/judge/src/prompts.ts index e0fca7a..06f0208 100644 --- a/src/judge/prompts.ts +++ b/packages/judge/src/prompts.ts @@ -196,7 +196,7 @@ Explanation: [your explanation]`, */ export function applyPromptTemplate( template: PromptTemplate, - variables: PromptVariables + variables: PromptVariables, ): { system: string; user: string } { const applyVariables = (text: string): string => { let result = text; @@ -223,8 +223,8 @@ export function parseJudgeResponse(response: string): { score: number; explanati const scoreMatch = response.match(/Score:\s*([0-9]*\.?[0-9]+)/i); const explanationMatch = response.match(/Explanation:\s*(.*)/is); - const score = scoreMatch ? parseFloat(scoreMatch[1]!) : 0.5; - const explanation = explanationMatch ? explanationMatch[1]!.trim() : response; + const score = scoreMatch ? Number.parseFloat(scoreMatch[1] ?? '0.5') : 0.5; + const explanation = explanationMatch ? explanationMatch[1]?.trim() : response; // Clamp score to [0, 1] const clampedScore = Math.max(0, Math.min(1, score)); diff --git a/tests/unit/judge.test.ts b/packages/judge/tests/judge.test.ts similarity index 96% rename from tests/unit/judge.test.ts rename to packages/judge/tests/judge.test.ts index a26a0fe..298d7ea 100644 --- a/tests/unit/judge.test.ts +++ b/packages/judge/tests/judge.test.ts @@ -1,8 +1,8 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { JudgeEngine } from '../../src/judge/engine.js'; -import { JudgeCalibrator } from '../../src/judge/calibration.js'; -import { JudgeCostTracker } from '../../src/judge/cost-tracker.js'; -import type { EvaluationSample, JudgeConfig } from '../../src/types/domain.js'; +import type { EvaluationSample, JudgeConfig } from '@reaatech/rag-eval-core'; +import { JudgeEngine } from '@reaatech/rag-eval-judge'; +import { JudgeCalibrator } from '@reaatech/rag-eval-judge'; +import { JudgeCostTracker } from '@reaatech/rag-eval-judge'; +import { describe, expect, it, vi } from 'vitest'; describe('JudgeEngine', () => { const sampleData: EvaluationSample = { @@ -92,7 +92,7 @@ describe('JudgeEngine', () => { const previousAnthropicKey = process.env.ANTHROPIC_API_KEY; const previousOpenAIKey = process.env.OPENAI_API_KEY; - delete process.env.ANTHROPIC_API_KEY; + process.env.ANTHROPIC_API_KEY = undefined; process.env.OPENAI_API_KEY = 'openai-test-key'; try { @@ -109,13 +109,13 @@ describe('JudgeEngine', () => { expect(result.score).toBe(0.9); } finally { if (previousAnthropicKey === undefined) { - delete process.env.ANTHROPIC_API_KEY; + process.env.ANTHROPIC_API_KEY = undefined; } else { process.env.ANTHROPIC_API_KEY = previousAnthropicKey; } if (previousOpenAIKey === undefined) { - delete process.env.OPENAI_API_KEY; + process.env.OPENAI_API_KEY = undefined; } else { process.env.OPENAI_API_KEY = previousOpenAIKey; } diff --git a/packages/judge/tsconfig.json b/packages/judge/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/judge/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/judge/vitest.config.ts b/packages/judge/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/judge/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/mcp-server/LICENSE b/packages/mcp-server/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/mcp-server/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md new file mode 100644 index 0000000..80bd37b --- /dev/null +++ b/packages/mcp-server/README.md @@ -0,0 +1,233 @@ +# @reaatech/rag-eval-mcp-server + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-mcp-server.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-mcp-server) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +MCP (Model Context Protocol) server exposing RAG evaluation tools as a three-layer API: atomic judge operations, orchestrated suite runs, and CI-style regression gates. Connect from MCP clients like Claude Desktop or Cursor to evaluate RAG systems in real time. + +## Installation + +```bash +npm install @reaatech/rag-eval-mcp-server @modelcontextprotocol/sdk +# or +pnpm add @reaatech/rag-eval-mcp-server @modelcontextprotocol/sdk +``` + +## Feature Overview + +- **Three-layer tool architecture** β€” `rag_eval.judge.*` (atomic), `rag_eval.suite.*` (orchestrated), `rag_eval.gate.*` (CI gates) +- **Judge tools** β€” faithfulness, relevance, context precision, context recall, and cost check +- **Suite tools** β€” run, status, results, compare, and baseline management +- **Gate tools** β€” run gates, get/set config, and diff from baseline +- **Stdio transport** β€” standard MCP transport for local agent integration +- **Programmatic and standalone modes** β€” embed as a library or run as a standalone server + +## Quick Start + +### Standalone Server + +```bash +# Start the MCP server via CLI +npx rag-eval-pack mcp-server +``` + +### Programmatic Usage + +```typescript +import { createMcpServer, startMcpServer } from "@reaatech/rag-eval-mcp-server"; + +// Create a server instance +const server = createMcpServer(); + +// Start via stdio (for MCP client integration) +await startMcpServer(); +``` + +## API Reference + +### Server Functions + +```typescript +import { createMcpServer, startMcpServer } from "@reaatech/rag-eval-mcp-server"; + +const server = createMcpServer(); +await startMcpServer(); +``` + +| Function | Returns | Description | +|----------|---------|-------------| +| `createMcpServer()` | `Server` | Create an MCP server with all tools registered | +| `startMcpServer()` | `Promise` | Start the server via stdio transport | + +### Tool Handler Functions + +For programmatic invocation outside the MCP protocol: + +```typescript +import { handleJudgeTool, handleSuiteTool, handleGateTool } from "@reaatech/rag-eval-mcp-server"; +``` + +| Function | Description | +|----------|-------------| +| `handleJudgeTool(name, input)` | Invoke a judge tool programmatically | +| `handleSuiteTool(name, input)` | Invoke a suite tool programmatically | +| `handleGateTool(name, input)` | Invoke a gate tool programmatically | + +Each returns an MCP-compatible `CallToolResult`. + +## Tool Reference + +### Layer 1: `rag_eval.judge.*` (Atomic Operations) + +Fast, stateless, composable operations for mid-task self-evaluation. + +#### `rag_eval.judge.faithfulness` + +Check if a generated answer is faithful to the provided context. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `context` | `string[]` | Yes | Retrieved context chunks | +| `generated_answer` | `string` | Yes | RAG system's generated answer | + +**Returns:** `{ score, statements, supported_count }` + +#### `rag_eval.judge.relevance` + +Check if an answer is relevant to the query. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `query` | `string` | Yes | User query | +| `generated_answer` | `string` | Yes | RAG system's generated answer | + +**Returns:** `{ score, semantic_similarity, intent_score }` + +#### `rag_eval.judge.context_precision` + +Check context ranking quality against a ground truth. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `query` | `string` | Yes | User query | +| `context` | `string[]` | Yes | Retrieved context chunks | +| `ground_truth` | `string` | Yes | Expected answer | + +**Returns:** `{ score, map, ndcg }` + +#### `rag_eval.judge.context_recall` + +Check ground truth coverage in retrieved context. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `query` | `string` | Yes | User query | +| `context` | `string[]` | Yes | Retrieved context chunks | +| `ground_truth` | `string` | Yes | Expected answer | + +**Returns:** `{ score, total_facts, covered_facts }` + +#### `rag_eval.judge.cost_check` + +Verify evaluation cost is within budget. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `eval_result` | `object` | Yes | Partial evaluation result | +| `budget` | `number` | Yes | Budget limit | + +**Returns:** `{ within_budget, cost }` + +### Layer 2: `rag_eval.suite.*` (Orchestrated Runs) + +Stateful, longer-running operations for eval-driven development. + +| Tool | Description | +|------|-------------| +| `rag_eval.suite.run` | Execute a full evaluation suite with dataset and config | +| `rag_eval.suite.status` | Get the status of a running evaluation | +| `rag_eval.suite.results` | Retrieve results for a completed evaluation | +| `rag_eval.suite.compare` | Compare two evaluation runs | +| `rag_eval.suite.baseline` | Set a baseline for regression comparison | + +#### `rag_eval.suite.run` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `dataset` | `string \| EvaluationSample[]` | Yes | Path to dataset or in-memory samples | +| `config` | `EvalSuiteConfig` | Yes | Evaluation configuration | + +**Returns:** `{ run_id, status }` + +### Layer 3: `rag_eval.gate.*` (CI Gates) + +Opinionated, blocking operations for CI/CD integration. + +| Tool | Description | +|------|-------------| +| `rag_eval.gate.run` | Run CI-style pass/fail gate evaluation | +| `rag_eval.gate.config` | Get or set gate configuration | +| `rag_eval.gate.diff` | Get detailed diff from baseline | + +#### `rag_eval.gate.run` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `results` | `EvalResults` | Yes | Evaluation results to gate | +| `gate_config` | `GateConfig[]` | Yes | Gate configuration | + +**Returns:** `{ passed, failures[] }` + +## Usage Patterns + +### Agent Self-Evaluation Mid-Task + +```typescript +import { handleJudgeTool } from "@reaatech/rag-eval-mcp-server"; + +const response = await handleJudgeTool("rag_eval.judge.faithfulness", { + context: [ + "Refunds are processed within 14 days of purchase.", + "Contact support@example.com for refund requests.", + ], + generated_answer: "You can request a refund within 14 days by emailing support.", +}); + +const result = JSON.parse(response.content[0].text); +if (result.score < 0.85) { + // Trigger fallback: retrieve more context +} +``` + +### CI Pipeline Gate + +```typescript +const gateResponse = await handleGateTool("rag_eval.gate.run", { + results: latestEvalResults, + gate_config: [ + { name: "min-faithfulness", type: "threshold", metric: "avg_faithfulness", operator: ">=", threshold: 0.85 }, + { name: "no-regression", type: "baseline-comparison", metric: "overall_score", allow_regression: false }, + ], +}); + +const gateResult = JSON.parse(gateResponse.content[0].text); +if (!gateResult.passed) { + console.error("Gates failed:", gateResult.failures); + process.exit(1); +} +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-metrics`](https://www.npmjs.com/package/@reaatech/rag-eval-metrics) β€” Metric scorers used by judge tools +- [`@reaatech/rag-eval-gate`](https://www.npmjs.com/package/@reaatech/rag-eval-gate) β€” Gate engine used by gate tools +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Suite engine used by suite tools +- [`@reaatech/rag-eval-cli`](https://www.npmjs.com/package/@reaatech/rag-eval-cli) β€” CLI with `mcp-server` command + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json new file mode 100644 index 0000000..09e8d99 --- /dev/null +++ b/packages/mcp-server/package.json @@ -0,0 +1,50 @@ +{ + "name": "@reaatech/rag-eval-mcp-server", + "version": "0.1.0", + "description": "MCP server exposing RAG evaluation tools (judge, suite, gate)", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/mcp-server" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/mcp-server#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.9.0", + "@reaatech/rag-eval-core": "workspace:*", + "@reaatech/rag-eval-gate": "workspace:*", + "@reaatech/rag-eval-metrics": "workspace:*", + "@reaatech/rag-eval-suite": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts new file mode 100644 index 0000000..e1c4525 --- /dev/null +++ b/packages/mcp-server/src/index.ts @@ -0,0 +1,4 @@ +export { createMcpServer, startMcpServer } from './mcp-server.js'; +export { handleSuiteTool } from './tools/suite/index.js'; +export { handleJudgeTool } from './tools/judge/index.js'; +export { handleGateTool } from './tools/gate/index.js'; diff --git a/src/mcp-server/mcp-server.ts b/packages/mcp-server/src/mcp-server.ts similarity index 99% rename from src/mcp-server/mcp-server.ts rename to packages/mcp-server/src/mcp-server.ts index fb219b4..6ac68ca 100644 --- a/src/mcp-server/mcp-server.ts +++ b/packages/mcp-server/src/mcp-server.ts @@ -16,9 +16,9 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; +import { createGateTools, handleGateTool } from './tools/gate/index.js'; import { createJudgeTools, handleJudgeTool } from './tools/judge/index.js'; import { createSuiteTools, handleSuiteTool } from './tools/suite/index.js'; -import { createGateTools, handleGateTool } from './tools/gate/index.js'; export function createMcpServer(): Server { const server = new Server( @@ -30,7 +30,7 @@ export function createMcpServer(): Server { capabilities: { tools: {}, }, - } + }, ); server.setRequestHandler(ListToolsRequestSchema, async () => { diff --git a/src/mcp-server/tools/gate/index.ts b/packages/mcp-server/src/tools/gate/index.ts similarity index 94% rename from src/mcp-server/tools/gate/index.ts rename to packages/mcp-server/src/tools/gate/index.ts index 083848e..12dd57c 100644 --- a/src/mcp-server/tools/gate/index.ts +++ b/packages/mcp-server/src/tools/gate/index.ts @@ -1,6 +1,6 @@ -import type { EvalResults, GateConfig } from '../../../types/domain.js'; -import { GateEngine } from '../../../gate/engine.js'; -import { EvaluationSuite } from '../../../evaluation-suite.js'; +import type { EvalResults, GateConfig } from '@reaatech/rag-eval-core'; +import { GateEngine } from '@reaatech/rag-eval-gate'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; export interface GateRunInput { results: EvalResults; @@ -85,7 +85,7 @@ let storedConfig: GateConfig[] = []; export async function handleGateTool( name: string, - args: Record + args: Record, ): Promise<{ content: { type: string; text: string }[] }> { switch (name) { case 'rag_eval.gate.run': { diff --git a/src/mcp-server/tools/judge/index.ts b/packages/mcp-server/src/tools/judge/index.ts similarity index 92% rename from src/mcp-server/tools/judge/index.ts rename to packages/mcp-server/src/tools/judge/index.ts index d268067..4613af5 100644 --- a/src/mcp-server/tools/judge/index.ts +++ b/packages/mcp-server/src/tools/judge/index.ts @@ -1,8 +1,8 @@ -import type { EvaluationSample } from '../../../types/domain.js'; -import { FaithfulnessScorer } from '../../../metrics/faithfulness.js'; -import { RelevanceScorer } from '../../../metrics/relevance.js'; -import { ContextPrecisionScorer } from '../../../metrics/context-precision.js'; -import { ContextRecallScorer } from '../../../metrics/context-recall.js'; +import type { EvaluationSample } from '@reaatech/rag-eval-core'; +import { FaithfulnessScorer } from '@reaatech/rag-eval-metrics'; +import { RelevanceScorer } from '@reaatech/rag-eval-metrics'; +import { ContextPrecisionScorer } from '@reaatech/rag-eval-metrics'; +import { ContextRecallScorer } from '@reaatech/rag-eval-metrics'; export interface FaithfulnessInput { context: string[]; @@ -115,7 +115,7 @@ export function createJudgeTools(): Array<{ export async function handleJudgeTool( name: string, - args: Record + args: Record, ): Promise<{ content: { type: string; text: string }[] }> { switch (name) { case 'rag_eval.judge.faithfulness': { @@ -173,7 +173,7 @@ export async function handleJudgeTool( case 'rag_eval.judge.cost_check': { const input = args as unknown as CostCheckInput; const totalCost = input.total_cost || 0; - const budgetLimit = input.budget_limit || Infinity; + const budgetLimit = input.budget_limit || Number.POSITIVE_INFINITY; const withinBudget = totalCost <= budgetLimit; return { content: [ @@ -188,7 +188,7 @@ export async function handleJudgeTool( usage_ratio: budgetLimit > 0 ? totalCost / budgetLimit : 0, }, null, - 2 + 2, ), }, ], diff --git a/src/mcp-server/tools/suite/index.ts b/packages/mcp-server/src/tools/suite/index.ts similarity index 96% rename from src/mcp-server/tools/suite/index.ts rename to packages/mcp-server/src/tools/suite/index.ts index fc3c340..dc8fc15 100644 --- a/src/mcp-server/tools/suite/index.ts +++ b/packages/mcp-server/src/tools/suite/index.ts @@ -1,5 +1,5 @@ -import type { EvaluationSample, EvalSuiteConfig, EvalResults } from '../../../types/domain.js'; -import { EvaluationSuite } from '../../../evaluation-suite.js'; +import type { EvalResults, EvalSuiteConfig, EvaluationSample } from '@reaatech/rag-eval-core'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; export interface SuiteRunInput { samples: EvaluationSample[]; @@ -98,7 +98,7 @@ export function createSuiteTools(): Array<{ export async function handleSuiteTool( name: string, - args: Record + args: Record, ): Promise<{ content: { type: string; text: string }[] }> { switch (name) { case 'rag_eval.suite.run': { @@ -195,7 +195,7 @@ export async function handleSuiteTool( text: JSON.stringify( { baseline_id: input.run_id, name: input.name ?? input.run_id }, null, - 2 + 2, ), }, ], diff --git a/tests/unit/mcp-suite-tools.test.ts b/packages/mcp-server/tests/mcp-suite-tools.test.ts similarity index 78% rename from tests/unit/mcp-suite-tools.test.ts rename to packages/mcp-server/tests/mcp-suite-tools.test.ts index 88603b5..f440767 100644 --- a/tests/unit/mcp-suite-tools.test.ts +++ b/packages/mcp-server/tests/mcp-suite-tools.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect } from 'vitest'; -import { handleSuiteTool } from '../../src/mcp-server/tools/suite/index.js'; -import type { EvaluationSample, EvalSuiteConfig } from '../../src/types/domain.js'; +import type { EvalSuiteConfig, EvaluationSample } from '@reaatech/rag-eval-core'; +import { handleSuiteTool } from '@reaatech/rag-eval-mcp-server'; +import { describe, expect, it } from 'vitest'; describe('MCP Suite Tools', () => { const samples: EvaluationSample[] = [ @@ -19,14 +19,14 @@ describe('MCP Suite Tools', () => { it('should return results with the same run id reported at start', async () => { const runResponse = await handleSuiteTool('rag_eval.suite.run', { samples, config }); - const runData = JSON.parse(runResponse.content[0]!.text) as { run_id: string }; + const runData = JSON.parse(runResponse.content[0]?.text) as { run_id: string }; let resultsPayload: Record | null = null; for (let attempt = 0; attempt < 20; attempt++) { const resultsResponse = await handleSuiteTool('rag_eval.suite.results', { run_id: runData.run_id, }); - const payload = JSON.parse(resultsResponse.content[0]!.text) as Record; + const payload = JSON.parse(resultsResponse.content[0]?.text) as Record; if (!('error' in payload)) { resultsPayload = payload; break; diff --git a/packages/mcp-server/tsconfig.json b/packages/mcp-server/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/mcp-server/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/mcp-server/vitest.config.ts b/packages/mcp-server/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/mcp-server/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/metrics/LICENSE b/packages/metrics/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/metrics/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/metrics/README.md b/packages/metrics/README.md new file mode 100644 index 0000000..7955f0c --- /dev/null +++ b/packages/metrics/README.md @@ -0,0 +1,207 @@ +# @reaatech/rag-eval-metrics + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-metrics.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-metrics) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Heuristic metric scorers for RAG evaluation. Provides four independent scorers β€” faithfulness, relevance, context precision, and context recall β€” plus a `MetricsEngine` orchestrator that runs them in parallel with configurable concurrency. + +## Installation + +```bash +npm install @reaatech/rag-eval-metrics +# or +pnpm add @reaatech/rag-eval-metrics +``` + +## Feature Overview + +- **Faithfulness** β€” measures factual grounding of the answer in retrieved context (statement-level decomposition) +- **Relevance** β€” measures semantic alignment between query and answer (intent decomposition + cosine similarity) +- **Context Precision** β€” measures retrieval ranking quality via MAP (Mean Average Precision) and NDCG +- **Context Recall** β€” measures ground truth coverage by decomposing facts and checking context overlap +- **Parallel execution** β€” `MetricsEngine` runs all configured scorers concurrently with configurable `parallelJobs` +- **Heuristic-first** β€” no LLM calls required; all scorers use NLP libraries (`compromise`, `natural`) + +## Quick Start + +```typescript +import { + FaithfulnessScorer, + RelevanceScorer, + ContextPrecisionScorer, + ContextRecallScorer, + MetricsEngine, +} from "@reaatech/rag-eval-metrics"; + +const engine = new MetricsEngine({ parallelJobs: 4 }); + +const result = await engine.evaluateSample( + { + query: "What is the refund policy?", + context: [ + "Refunds are processed within 14 days of purchase.", + "Contact support@example.com for refund requests.", + ], + ground_truth: "Refunds must be requested within 14 days by contacting support.", + generated_answer: "You can request a refund within 14 days by emailing support.", + }, + { metrics: ["faithfulness", "relevance", "context_precision", "context_recall"] }, + 0 +); + +console.log(result.faithfulness?.score); // ~0.95 +console.log(result.relevance?.score); // ~0.88 +``` + +## API Reference + +### `FaithfulnessScorer` + +Decomposes the generated answer into atomic statements and verifies each against the provided context. + +```typescript +import { FaithfulnessScorer } from "@reaatech/rag-eval-metrics"; + +const scorer = new FaithfulnessScorer(); +const result = await scorer.score(sample); +// β†’ { score: 0.90, statements: [...], supported_count: 8, total_count: 9 } +``` + +| Property | Type | Description | +|----------|------|-------------| +| `score` | `number` | Ratio of supported statements to total (0–1) | +| `statements` | `string[]` | Decomposed atomic statements from the answer | +| `supported_count` | `number` | Number of statements supported by context | +| `total_count` | `number` | Total number of extracted statements | + +### `RelevanceScorer` + +Decomposes the query into intents and checks how well the answer addresses each intent using semantic similarity. + +```typescript +import { RelevanceScorer } from "@reaatech/rag-eval-metrics"; + +const scorer = new RelevanceScorer(); +const result = await scorer.score(sample); +// β†’ { score: 0.88, intents: [...], similarity: 0.82 } +``` + +| Property | Type | Description | +|----------|------|-------------| +| `score` | `number` | Composite relevance score (0–1) | +| `intents` | `string[]` | Decomposed query intents | +| `similarity` | `number` | Cosine similarity between intent and answer embeddings | + +### `ContextPrecisionScorer` + +Evaluates how well the retrieval system ranks relevant context chunks. Computes MAP and NDCG against the ground truth. + +```typescript +import { ContextPrecisionScorer } from "@reaatech/rag-eval-metrics"; + +const scorer = new ContextPrecisionScorer(); +const result = await scorer.score(sample); +// β†’ { score: 0.75, map: 0.72, ndcg: 0.78, relevant_ranks: [1, 3] } +``` + +| Property | Type | Description | +|----------|------|-------------| +| `score` | `number` | Average of MAP and NDCG | +| `map` | `number` | Mean Average Precision | +| `ndcg` | `number` | Normalized Discounted Cumulative Gain | +| `relevant_ranks` | `number[]` | Rank positions of relevant chunks (1-indexed) | + +### `ContextRecallScorer` + +Decomposes the ground truth into individual facts and measures how many are covered by the retrieved context. + +```typescript +import { ContextRecallScorer } from "@reaatech/rag-eval-metrics"; + +const scorer = new ContextRecallScorer(); +const result = await scorer.score(sample); +// β†’ { score: 0.90, total_facts: 5, covered_facts: 4 } +``` + +| Property | Type | Description | +|----------|------|-------------| +| `score` | `number` | Ratio of covered facts to total (0–1) | +| `total_facts` | `number` | Number of facts extracted from ground truth | +| `covered_facts` | `number` | Number of facts found in retrieved context | + +### `MetricsEngine` + +Orchestrates parallel metric computation. + +```typescript +import { MetricsEngine } from "@reaatech/rag-eval-metrics"; + +const engine = new MetricsEngine({ parallelJobs: 5 }); + +// Evaluate a single sample +const result = await engine.evaluateSample(sample, config, index); + +// Aggregate results across all samples +const aggregated = engine.aggregateResults(sampleResults); +// β†’ { overall_score, avg_faithfulness, avg_relevance, ..., std_dev: { ... } } +``` + +#### Constructor Options + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `parallelJobs` | `number` | `5` | Maximum concurrent metric evaluations | + +## Usage Patterns + +### Individual Scorer + +```typescript +import { FaithfulnessScorer } from "@reaatech/rag-eval-metrics"; + +const scorer = new FaithfulnessScorer(); + +const result = await scorer.score({ + query: "What is the refund policy?", + context: ["Refunds are processed within 14 days."], + ground_truth: "Refunds within 14 days.", + generated_answer: "You have 14 days to request a refund.", +}); + +if (result.score < 0.85) { + console.warn("Answer may contain hallucinations"); +} +``` + +### Batch Evaluation with Aggregation + +```typescript +import { MetricsEngine } from "@reaatech/rag-eval-metrics"; +import type { EvaluationSample, EvalSuiteConfig } from "@reaatech/rag-eval-core"; + +const engine = new MetricsEngine({ parallelJobs: 8 }); +const config: EvalSuiteConfig = { + metrics: ["faithfulness", "relevance", "context_precision", "context_recall"], +}; + +const results = await Promise.all( + samples.map((sample, i) => engine.evaluateSample(sample, config, i)) +); + +const aggregated = engine.aggregateResults(results); +console.log("Overall score:", aggregated.overall_score); +console.log("Faithfulness:", aggregated.avg_faithfulness); +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-judge`](https://www.npmjs.com/package/@reaatech/rag-eval-judge) β€” LLM-based evaluation (higher accuracy, higher cost) +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Central orchestrator + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/metrics/package.json b/packages/metrics/package.json new file mode 100644 index 0000000..0172a14 --- /dev/null +++ b/packages/metrics/package.json @@ -0,0 +1,49 @@ +{ + "name": "@reaatech/rag-eval-metrics", + "version": "0.1.0", + "description": "RAG evaluation metric scorers: faithfulness, relevance, context precision/recall", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/metrics" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/metrics#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@reaatech/rag-eval-core": "workspace:*", + "compromise": "^14.15.0", + "natural": "^8.1.1", + "p-limit": "^7.3.0" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/metrics/context-precision.ts b/packages/metrics/src/context-precision.ts similarity index 96% rename from src/metrics/context-precision.ts rename to packages/metrics/src/context-precision.ts index 7f668be..a60f607 100644 --- a/src/metrics/context-precision.ts +++ b/packages/metrics/src/context-precision.ts @@ -1,4 +1,4 @@ -import type { EvaluationSample, ContextPrecisionResult } from '../types/domain.js'; +import type { ContextPrecisionResult, EvaluationSample } from '@reaatech/rag-eval-core'; /** * Context Precision Scorer @@ -16,7 +16,7 @@ export class ContextPrecisionScorer { // Assess relevance of each context chunk const chunkRelevanceScores = await Promise.all( - context.map((chunk) => this.assessChunkRelevance(query, chunk, ground_truth)) + context.map((chunk) => this.assessChunkRelevance(query, chunk, ground_truth)), ); // Calculate MAP (Mean Average Precision) @@ -50,7 +50,7 @@ export class ContextPrecisionScorer { private async assessChunkRelevance( query: string, chunk: string, - groundTruth: string + groundTruth: string, ): Promise { const chunkLower = chunk.toLowerCase(); const groundTruthLower = groundTruth.toLowerCase(); @@ -118,7 +118,7 @@ export class ContextPrecisionScorer { for (let i = 0; i < relevanceScores.length; i++) { // Using gain = 2^rel - 1 for graded relevance const score = relevanceScores[i] ?? 0; - const gain = Math.pow(2, score) - 1; + const gain = 2 ** score - 1; const discount = Math.log2(i + 2); // i+2 because positions are 1-indexed dcg += gain / discount; } @@ -128,7 +128,7 @@ export class ContextPrecisionScorer { let idcg = 0; for (let i = 0; i < idealScores.length; i++) { const score = idealScores[i] ?? 0; - const gain = Math.pow(2, score) - 1; + const gain = 2 ** score - 1; const discount = Math.log2(i + 2); idcg += gain / discount; } @@ -286,7 +286,7 @@ export class ContextPrecisionScorer { score: number, map: number, ndcg: number, - relevanceScores: number[] + relevanceScores: number[], ): string { const relevantChunks = relevanceScores.filter((s) => s >= 0.5).length; const totalChunks = relevanceScores.length; diff --git a/src/metrics/context-recall.ts b/packages/metrics/src/context-recall.ts similarity index 98% rename from src/metrics/context-recall.ts rename to packages/metrics/src/context-recall.ts index 68a618f..968dfd6 100644 --- a/src/metrics/context-recall.ts +++ b/packages/metrics/src/context-recall.ts @@ -1,4 +1,4 @@ -import type { EvaluationSample, ContextRecallResult, FactCoverage } from '../types/domain.js'; +import type { ContextRecallResult, EvaluationSample, FactCoverage } from '@reaatech/rag-eval-core'; /** * Context Recall Scorer @@ -20,7 +20,7 @@ export class ContextRecallScorer { // Check coverage of each fact in the context const factCoverage: FactCoverage[] = await Promise.all( - facts.map((fact) => this.checkFactCoverage(fact, contextText)) + facts.map((fact) => this.checkFactCoverage(fact, contextText)), ); const coveredFacts = factCoverage.filter((f) => f.covered).length; @@ -343,7 +343,7 @@ export class ContextRecallScorer { score: number, coveredFacts: number, totalFacts: number, - factCoverage: FactCoverage[] + factCoverage: FactCoverage[], ): string { if (totalFacts === 0) { return 'No facts to evaluate in ground truth'; diff --git a/src/metrics/engine.ts b/packages/metrics/src/engine.ts similarity index 81% rename from src/metrics/engine.ts rename to packages/metrics/src/engine.ts index 8cd2e73..e29df1c 100644 --- a/src/metrics/engine.ts +++ b/packages/metrics/src/engine.ts @@ -1,14 +1,14 @@ -import pLimit from 'p-limit'; import type { + AggregatedMetrics, + EvalSuiteConfig, EvaluationSample, SampleEvalResult, - EvalSuiteConfig, - AggregatedMetrics, -} from '../types/domain.js'; -import { FaithfulnessScorer } from './faithfulness.js'; -import { RelevanceScorer } from './relevance.js'; +} from '@reaatech/rag-eval-core'; +import pLimit from 'p-limit'; import { ContextPrecisionScorer } from './context-precision.js'; import { ContextRecallScorer } from './context-recall.js'; +import { FaithfulnessScorer } from './faithfulness.js'; +import { RelevanceScorer } from './relevance.js'; /** * Metrics Engine @@ -37,7 +37,7 @@ export class MetricsEngine { async evaluateSample( sample: EvaluationSample, config: EvalSuiteConfig, - sampleId?: string | number + sampleId?: string | number, ): Promise { const result: SampleEvalResult = { sample_id: sampleId ?? crypto.randomUUID(), @@ -51,7 +51,7 @@ export class MetricsEngine { metricPromises.push( this.limit(async () => { result.faithfulness = await this.faithfulnessScorer.score(sample); - }) + }), ); } @@ -59,7 +59,7 @@ export class MetricsEngine { metricPromises.push( this.limit(async () => { result.relevance = await this.relevanceScorer.score(sample); - }) + }), ); } @@ -67,7 +67,7 @@ export class MetricsEngine { metricPromises.push( this.limit(async () => { result.context_precision = await this.contextPrecisionScorer.score(sample); - }) + }), ); } @@ -75,7 +75,7 @@ export class MetricsEngine { metricPromises.push( this.limit(async () => { result.context_recall = await this.contextRecallScorer.score(sample); - }) + }), ); } @@ -92,10 +92,10 @@ export class MetricsEngine { */ async evaluateBatch( samples: EvaluationSample[], - config: EvalSuiteConfig + config: EvalSuiteConfig, ): Promise { const promises = samples.map((sample, i) => - this.limit(() => this.evaluateSample(sample, config, i)) + this.limit(() => this.evaluateSample(sample, config, i)), ); return Promise.all(promises); } @@ -123,24 +123,24 @@ export class MetricsEngine { }; if (result.faithfulness) { - scores.push(result.faithfulness!.score); + scores.push(result.faithfulness?.score); weights.push(config.metrics.includes('faithfulness') ? effectiveWeights.faithfulness : 0); } if (result.relevance) { - scores.push(result.relevance!.score); + scores.push(result.relevance?.score); weights.push(config.metrics.includes('relevance') ? effectiveWeights.relevance : 0); } if (result.context_precision) { - scores.push(result.context_precision!.score); + scores.push(result.context_precision?.score); weights.push( - config.metrics.includes('context_precision') ? effectiveWeights.context_precision : 0 + config.metrics.includes('context_precision') ? effectiveWeights.context_precision : 0, ); } if (result.context_recall) { - scores.push(result.context_recall!.score); + scores.push(result.context_recall?.score); weights.push(config.metrics.includes('context_recall') ? effectiveWeights.context_recall : 0); } @@ -161,17 +161,17 @@ export class MetricsEngine { const faithfulnessScores = results .filter((r) => r.faithfulness) - .map((r) => r.faithfulness!.score); - const relevanceScores = results.filter((r) => r.relevance).map((r) => r.relevance!.score); + .map((r) => r.faithfulness?.score); + const relevanceScores = results.filter((r) => r.relevance).map((r) => r.relevance?.score); const contextPrecisionScores = results .filter((r) => r.context_precision) - .map((r) => r.context_precision!.score); + .map((r) => r.context_precision?.score); const contextRecallScores = results .filter((r) => r.context_recall) - .map((r) => r.context_recall!.score); + .map((r) => r.context_recall?.score); const overallScores = results - .filter((r) => r.overall_score !== undefined) - .map((r) => r.overall_score!); + .filter((r): r is typeof r & { overall_score: number } => r.overall_score !== undefined) + .map((r) => r.overall_score); return { overall_score: this.mean(overallScores), @@ -194,20 +194,22 @@ export class MetricsEngine { /** * Calculate mean of an array of numbers */ - private mean(values: number[]): number { - if (values.length === 0) return 0; - const sum = values.reduce((a, b) => a + b, 0); - return Math.round((sum / values.length) * 1000) / 1000; + private mean(values: (number | undefined)[]): number { + const filtered = values.filter((v): v is number => v !== undefined); + if (filtered.length === 0) return 0; + const sum = filtered.reduce((a, b) => a + b, 0); + return Math.round((sum / filtered.length) * 1000) / 1000; } /** * Calculate standard deviation */ - private stdDev(values: number[]): number { - if (values.length === 0) return 0; - const mean = this.mean(values); - const squareDiffs = values.map((value) => Math.pow(value - mean, 2)); - const variance = squareDiffs.reduce((a, b) => a + b, 0) / values.length; + private stdDev(values: (number | undefined)[]): number { + const filtered = values.filter((v): v is number => v !== undefined); + if (filtered.length === 0) return 0; + const mean = this.mean(filtered); + const squareDiffs = filtered.map((value) => (value - mean) ** 2); + const variance = squareDiffs.reduce((a, b) => a + b, 0) / filtered.length; return Math.round(Math.sqrt(variance) * 1000) / 1000; } } diff --git a/src/metrics/faithfulness.ts b/packages/metrics/src/faithfulness.ts similarity index 97% rename from src/metrics/faithfulness.ts rename to packages/metrics/src/faithfulness.ts index 153b189..6b8e2ad 100644 --- a/src/metrics/faithfulness.ts +++ b/packages/metrics/src/faithfulness.ts @@ -1,4 +1,8 @@ -import type { EvaluationSample, FaithfulnessResult, StatementSupport } from '../types/domain.js'; +import type { + EvaluationSample, + FaithfulnessResult, + StatementSupport, +} from '@reaatech/rag-eval-core'; /** * Faithfulness Scorer @@ -20,7 +24,7 @@ export class FaithfulnessScorer { // Check each statement against the context const statementSupport: StatementSupport[] = await Promise.all( - statements.map((statement) => this.checkStatementSupport(statement, contextText)) + statements.map((statement) => this.checkStatementSupport(statement, contextText)), ); const supportedCount = statementSupport.filter((s) => s.supported).length; @@ -68,7 +72,7 @@ export class FaithfulnessScorer { */ private async checkStatementSupport( statement: string, - context: string + context: string, ): Promise { const statementLower = statement.toLowerCase(); const contextLower = context.toLowerCase(); diff --git a/src/metrics/index.ts b/packages/metrics/src/index.ts similarity index 100% rename from src/metrics/index.ts rename to packages/metrics/src/index.ts diff --git a/src/metrics/relevance.ts b/packages/metrics/src/relevance.ts similarity index 98% rename from src/metrics/relevance.ts rename to packages/metrics/src/relevance.ts index dae2f55..48c37c8 100644 --- a/src/metrics/relevance.ts +++ b/packages/metrics/src/relevance.ts @@ -1,4 +1,4 @@ -import type { EvaluationSample, RelevanceResult } from '../types/domain.js'; +import type { EvaluationSample, RelevanceResult } from '@reaatech/rag-eval-core'; /** * Relevance Scorer @@ -329,7 +329,7 @@ export class RelevanceScorer { private generateExplanation( score: number, semanticSimilarity: number, - intentScore: number + intentScore: number, ): string { if (score >= 0.8) { return `Answer is highly relevant (semantic: ${semanticSimilarity.toFixed(2)}, intent: ${intentScore.toFixed(2)})`; diff --git a/tests/unit/metrics.test.ts b/packages/metrics/tests/metrics.test.ts similarity index 90% rename from tests/unit/metrics.test.ts rename to packages/metrics/tests/metrics.test.ts index 3557578..96ab58e 100644 --- a/tests/unit/metrics.test.ts +++ b/packages/metrics/tests/metrics.test.ts @@ -1,9 +1,9 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { FaithfulnessScorer } from '../../src/metrics/faithfulness.js'; -import { RelevanceScorer } from '../../src/metrics/relevance.js'; -import { ContextPrecisionScorer } from '../../src/metrics/context-precision.js'; -import { ContextRecallScorer } from '../../src/metrics/context-recall.js'; -import type { EvaluationSample } from '../../src/types/domain.js'; +import type { EvaluationSample } from '@reaatech/rag-eval-core'; +import { FaithfulnessScorer } from '@reaatech/rag-eval-metrics'; +import { RelevanceScorer } from '@reaatech/rag-eval-metrics'; +import { ContextPrecisionScorer } from '@reaatech/rag-eval-metrics'; +import { ContextRecallScorer } from '@reaatech/rag-eval-metrics'; +import { beforeEach, describe, expect, it } from 'vitest'; describe('Metrics', () => { describe('FaithfulnessScorer', () => { @@ -94,6 +94,7 @@ describe('Metrics', () => { 'Shipping takes 5-7 days.', ], ground_truth: 'Refunds must be requested within 14 days.', + generated_answer: '', }; const result = await scorer.score(sample); @@ -108,6 +109,7 @@ describe('Metrics', () => { query: 'Test query', context: [], ground_truth: 'Test answer', + generated_answer: '', }; const result = await scorer.score(sample); @@ -130,6 +132,7 @@ describe('Metrics', () => { 'Contact support@example.com for refund requests.', ], ground_truth: 'Refunds must be requested within 14 days by contacting support.', + generated_answer: '', }; const result = await scorer.score(sample); @@ -144,6 +147,7 @@ describe('Metrics', () => { query: 'What is the refund policy?', context: ['Shipping takes 5-7 days.'], ground_truth: 'Refunds within 14 days by contacting support.', + generated_answer: '', }; const result = await scorer.score(sample); @@ -156,6 +160,7 @@ describe('Metrics', () => { query: 'Test query', context: [], ground_truth: 'Test answer', + generated_answer: '', }; const result = await scorer.score(sample); diff --git a/packages/metrics/tsconfig.json b/packages/metrics/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/metrics/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/metrics/vitest.config.ts b/packages/metrics/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/metrics/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/observability/LICENSE b/packages/observability/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/observability/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/observability/README.md b/packages/observability/README.md new file mode 100644 index 0000000..2edda31 --- /dev/null +++ b/packages/observability/README.md @@ -0,0 +1,273 @@ +# @reaatech/rag-eval-observability + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-observability.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-observability) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Structured logging, OpenTelemetry tracing, and metrics for RAG evaluations. Built on [Pino](https://github.com/pinojs/pino) (v9) for logging and OpenTelemetry for distributed tracing and metrics collection. + +## Installation + +```bash +npm install @reaatech/rag-eval-observability +# or +pnpm add @reaatech/rag-eval-observability +``` + +## Feature Overview + +- **Structured JSON logging** β€” Pino-powered, fast and low-overhead +- **Automatic pretty-printing** β€” human-readable output in development, raw JSON in production +- **OpenTelemetry tracing** β€” span creation for eval runs, metric calculations, judge calls, and gate evaluations +- **OpenTelemetry metrics** β€” counters, histograms, and gauges for run counts, judge costs, gate results, and metric scores +- **Dashboard output** β€” text and JSON dashboard formats for evaluation run summaries + +## Quick Start + +```typescript +import { + createLogger, + traceEvalRun, + traceJudgeCall, + recordEvalRun, +} from "@reaatech/rag-eval-observability"; + +// Structured logging +const logger = createLogger("rag-eval"); +logger.info({ run_id: "eval-123", samples: 100 }, "Evaluation completed"); + +// Distributed tracing +await traceEvalRun("run-456", async (span) => { + // Your evaluation logic here + span.end(); +}); + +// OpenTelemetry metrics +recordEvalRun("run-789", 100); +``` + +## API Reference + +### Logging + +#### `createLogger(name: string, options?: LoggerOptions): Logger` + +Creates a configured Pino logger instance. + +```typescript +import { createLogger } from "@reaatech/rag-eval-observability"; + +const logger = createLogger("rag-eval"); +logger.info("Evaluation started"); +``` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `name` parameter | `string` | (required) | Logger name, included in every log line | + +**Transport behavior:** +- **Development** (`NODE_ENV !== "production"`): enables `pino-pretty` with colorized output +- **Production** (`NODE_ENV === "production"`): raw JSON output for log aggregators + +### Tracing (OpenTelemetry) + +#### `traceEvalRun(runId: string, fn: (span: Span) => Promise): Promise` + +Wraps a full evaluation run in a trace span. + +```typescript +import { traceEvalRun } from "@reaatech/rag-eval-observability"; + +const result = await traceEvalRun("run-123", async (span) => { + // Run evaluation... + span.end(); + return evalResults; +}); +``` + +#### `traceMetricCalculation(runId, sampleId, metric, fn): Promise` + +Traces an individual metric computation. + +```typescript +const score = await traceMetricCalculation("run-123", "sample-1", "faithfulness", async (span) => { + span.end(); + return 0.95; +}); +``` + +#### `traceJudgeCall(runId, sampleId, model, fn): Promise` + +Traces an LLM judge API call with provider and model attributes. + +```typescript +const result = await traceJudgeCall("run-123", "sample-1", "claude-opus", async (span) => { + span.end(); + return { score: 0.9 }; +}); +``` + +#### `traceGateEvaluation(runId, fn): Promise` + +Traces a gate evaluation run. + +```typescript +const result = await traceGateEvaluation("run-123", async (span) => { + span.end(); + return { passed: true }; +}); +``` + +#### `createSpan(name, attributes?): Span` + +Creates a standalone span with custom attributes. + +```typescript +import { createSpan } from "@reaatech/rag-eval-observability"; + +const span = createSpan("eval.judge.call", { + run_id: "run-123", + sample_id: "sample-1", + metric: "faithfulness", + model: "claude-opus", +}); +// ... work ... +span.end(); +``` + +#### `withSpan(name: string, fn: (span: Span) => Promise): Promise` + +Executes an async function within a span context. + +```typescript +const result = await withSpan("eval.process", async (span) => { + span.end(); + return processedData; +}); +``` + +### Metrics (OpenTelemetry) + +#### Metric Recording Functions + +| Function | Description | +|----------|-------------| +| `recordEvalRun(runId, sampleCount)` | Record an evaluation run counter | +| `recordJudgeCall(model, provider, cost)` | Record judge call histogram with cost | +| `recordGateResult(runId, passed)` | Record gate result gauge (1/0) | +| `recordCost(runId, cost)` | Record evaluation cost histogram | +| `recordMetricScore(runId, metric, score)` | Record metric score gauge | +| `recordEvalComplete(runId, metrics, cost, durationMs)` | Record comprehensive run completion metrics | + +```typescript +import { recordEvalComplete } from "@reaatech/rag-eval-observability"; + +recordEvalComplete("run-123", { + avg_faithfulness: 0.85, + avg_relevance: 0.82, + avg_context_precision: 0.78, + avg_context_recall: 0.91, + overall_score: 0.84, +}, 1.25, 5000); +``` + +### Dashboard + +#### `Dashboard` + +Generates formatted evaluation dashboards. + +```typescript +import { Dashboard } from "@reaatech/rag-eval-observability"; +import type { EvalResults } from "@reaatech/rag-eval-core"; + +const dashboard = new Dashboard(); + +const text = dashboard.generateText(results); +console.log(text); +// β†’ RAG Evaluation Dashboard +// β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β” +// β”‚ Metric β”‚ Score β”‚ +// β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€ +// β”‚ Faithfulness β”‚ 0.850 β”‚ +// β”‚ ... + +const json = dashboard.generateJson(results); +writeFileSync("dashboard.json", JSON.stringify(json, null, 2)); +``` + +| Method | Returns | Description | +|--------|---------|-------------| +| `generateText(results)` | `string` | Formatted text dashboard | +| `generateJson(results)` | `string` | JSON dashboard output | + +## Usage Patterns + +### Structured Context Logging + +```typescript +import { createLogger } from "@reaatech/rag-eval-observability"; + +const logger = createLogger("rag-eval"); + +logger.info({ run_id: "eval-123", samples: 100 }, "Evaluation started"); +// β†’ {"name":"rag-eval","level":"INFO","run_id":"eval-123","samples":100,"msg":"Evaluation started"} + +logger.warn({ cost: 8.50, budgetLimit: 10.00 }, "Approaching budget limit"); +``` + +### Error Logging + +```typescript +try { + await evaluateSample(sample); +} catch (err) { + logger.error({ err, sample_id: sample.id }, "Sample evaluation failed"); +} +``` + +### Full Observability Pipeline + +```typescript +import { + createLogger, + traceEvalRun, + traceMetricCalculation, + recordEvalRun, + recordEvalComplete, +} from "@reaatech/rag-eval-observability"; + +const logger = createLogger("eval-pipeline"); + +async function runEvaluation(samples) { + return traceEvalRun("eval-456", async () => { + recordEvalRun("eval-456", samples.length); + + const results = []; + for (const sample of samples) { + const score = await traceMetricCalculation("eval-456", sample.id, "faithfulness", async (span) => { + const s = await computeMetric(sample); + span.end(); + return s; + }); + results.push(score); + } + + recordEvalComplete("eval-456", aggregateMetrics, totalCost, durationMs); + logger.info("Evaluation complete"); + return results; + }); +} +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-suite`](https://www.npmjs.com/package/@reaatech/rag-eval-suite) β€” Central orchestrator +- [`@reaatech/rag-eval-mcp-server`](https://www.npmjs.com/package/@reaatech/rag-eval-mcp-server) β€” MCP server + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/observability/package.json b/packages/observability/package.json new file mode 100644 index 0000000..65901f8 --- /dev/null +++ b/packages/observability/package.json @@ -0,0 +1,51 @@ +{ + "name": "@reaatech/rag-eval-observability", + "version": "0.1.0", + "description": "Structured logging, OpenTelemetry tracing, and metrics for RAG evaluations", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/observability" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/observability#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/sdk-metrics": "^1.28.0", + "@opentelemetry/sdk-trace-base": "^1.28.0", + "@reaatech/rag-eval-core": "workspace:*", + "pino": "^9.5.0", + "pino-pretty": "^13.1.3" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/observability/dashboard.ts b/packages/observability/src/dashboard.ts similarity index 97% rename from src/observability/dashboard.ts rename to packages/observability/src/dashboard.ts index 52f7f75..2768d19 100644 --- a/src/observability/dashboard.ts +++ b/packages/observability/src/dashboard.ts @@ -1,4 +1,4 @@ -import type { EvalResults } from '../types/domain.js'; +import type { EvalResults } from '@reaatech/rag-eval-core'; export interface EvalRunSummary { runId: string; @@ -78,7 +78,7 @@ export class Dashboard { }; } - getRecentRuns(count: number = 10): EvalRunSummary[] { + getRecentRuns(count = 10): EvalRunSummary[] { return this.runHistory.slice(-count); } diff --git a/src/observability/index.ts b/packages/observability/src/index.ts similarity index 100% rename from src/observability/index.ts rename to packages/observability/src/index.ts diff --git a/src/observability/logger.ts b/packages/observability/src/logger.ts similarity index 90% rename from src/observability/logger.ts rename to packages/observability/src/logger.ts index 483dbbc..ec256bf 100644 --- a/src/observability/logger.ts +++ b/packages/observability/src/logger.ts @@ -55,7 +55,7 @@ export function logEvalStart(runId: string, sampleCount: number): void { event: 'eval_start', sample_count: sampleCount, }, - 'Evaluation started' + 'Evaluation started', ); } @@ -72,7 +72,7 @@ export function logEvalComplete( overall_score: number; }, cost: number, - durationMs: number + durationMs: number, ): void { logger.info( { @@ -83,7 +83,7 @@ export function logEvalComplete( cost, duration_ms: durationMs, }, - 'Evaluation completed' + 'Evaluation completed', ); } @@ -93,7 +93,7 @@ export function logEvalComplete( export function logGateResult( runId: string, passed: boolean, - failures: Array<{ gate_name: string; metric: string }> + failures: Array<{ gate_name: string; metric: string }>, ): void { logger.info( { @@ -103,7 +103,7 @@ export function logGateResult( passed, failures, }, - `Gates ${passed ? 'passed' : 'failed'}` + `Gates ${passed ? 'passed' : 'failed'}`, ); } @@ -113,7 +113,7 @@ export function logGateResult( export function logError( runId: string | undefined, error: Error, - context?: Record + context?: Record, ): void { logger.error( { @@ -124,6 +124,6 @@ export function logError( stack: error.stack, ...context, }, - 'Error occurred' + 'Error occurred', ); } diff --git a/src/observability/metrics.ts b/packages/observability/src/metrics.ts similarity index 94% rename from src/observability/metrics.ts rename to packages/observability/src/metrics.ts index e6e9313..cb4f136 100644 --- a/src/observability/metrics.ts +++ b/packages/observability/src/metrics.ts @@ -1,4 +1,5 @@ -import { metrics, Counter, Histogram, Gauge, Meter } from '@opentelemetry/api'; +import { metrics } from '@opentelemetry/api'; +import type { Counter, Gauge, Histogram, Meter } from '@opentelemetry/api'; const meter: Meter = metrics.getMeter('rag-eval-pack', '0.1.0'); @@ -64,7 +65,7 @@ export function recordEvalComplete( overall_score: number; }, cost: number, - _durationMs: number + _durationMs: number, ): void { recordMetricScore(runId, 'avg_faithfulness', metrics.avg_faithfulness); recordMetricScore(runId, 'avg_relevance', metrics.avg_relevance); diff --git a/src/observability/tracing.ts b/packages/observability/src/tracing.ts similarity index 89% rename from src/observability/tracing.ts rename to packages/observability/src/tracing.ts index efec65c..0afd2c7 100644 --- a/src/observability/tracing.ts +++ b/packages/observability/src/tracing.ts @@ -1,4 +1,5 @@ -import { trace, context, Span, SpanStatusCode, Tracer, SpanKind } from '@opentelemetry/api'; +import { SpanKind, SpanStatusCode, context, trace } from '@opentelemetry/api'; +import type { Span, Tracer } from '@opentelemetry/api'; const tracer: Tracer = trace.getTracer('rag-eval-pack', '0.1.0'); @@ -19,7 +20,7 @@ export function createSpan(name: string, attributes?: SpanAttributes): Span { export function withSpan( name: string, fn: (span: Span) => Promise, - attributes?: SpanAttributes + attributes?: SpanAttributes, ): Promise { const span = createSpan(name, attributes); return context.with(trace.setSpan(context.active(), span), async () => { @@ -47,7 +48,7 @@ export function traceMetricCalculation( runId: string, sampleId: string | number, metric: string, - fn: (span: Span) => Promise + fn: (span: Span) => Promise, ): Promise { return withSpan(`metric.${metric}`, fn, { run_id: runId, sample_id: sampleId, metric }); } @@ -56,7 +57,7 @@ export function traceJudgeCall( runId: string, sampleId: string | number, model: string, - fn: (span: Span) => Promise + fn: (span: Span) => Promise, ): Promise { return withSpan('judge.call', fn, { run_id: runId, sample_id: sampleId, model }); } diff --git a/tests/unit/dashboard.test.ts b/packages/observability/tests/dashboard.test.ts similarity index 95% rename from tests/unit/dashboard.test.ts rename to packages/observability/tests/dashboard.test.ts index 38f8980..b5f9d1d 100644 --- a/tests/unit/dashboard.test.ts +++ b/packages/observability/tests/dashboard.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect } from 'vitest'; -import { Dashboard } from '../../src/observability/dashboard.js'; -import type { EvalResults } from '../../src/types/domain.js'; +import type { EvalResults } from '@reaatech/rag-eval-core'; +import { Dashboard } from '@reaatech/rag-eval-observability'; +import { beforeEach, describe, expect, it } from 'vitest'; function createMockEvalResults(override: Partial = {}): EvalResults { return { @@ -61,7 +61,7 @@ describe('Dashboard', () => { cost_per_sample: 0.03, total_samples: 10, }, - }) + }), ); dashboard.addRun( createMockEvalResults({ @@ -75,7 +75,7 @@ describe('Dashboard', () => { cost_per_sample: 0.03, total_samples: 10, }, - }) + }), ); const metrics = dashboard.getMetrics(); expect(metrics.averageScore).toBe(0.85); @@ -119,7 +119,7 @@ describe('Dashboard', () => { cost_per_sample: 0.03, total_samples: 10, }, - }) + }), ); } expect(dashboard.getQualityTrend()).toBe('improving'); @@ -140,7 +140,7 @@ describe('Dashboard', () => { cost_per_sample: 0.03, total_samples: 10, }, - }) + }), ); } expect(dashboard.getQualityTrend()).toBe('declining'); diff --git a/tests/unit/observability-metrics.test.ts b/packages/observability/tests/observability-metrics.test.ts similarity index 94% rename from tests/unit/observability-metrics.test.ts rename to packages/observability/tests/observability-metrics.test.ts index 83c0307..696d7ca 100644 --- a/tests/unit/observability-metrics.test.ts +++ b/packages/observability/tests/observability-metrics.test.ts @@ -1,12 +1,12 @@ -import { describe, it, expect } from 'vitest'; import { + recordCost, + recordEvalComplete, recordEvalRun, - recordJudgeCall, recordGateResult, - recordCost, + recordJudgeCall, recordMetricScore, - recordEvalComplete, -} from '../../src/observability/metrics.js'; +} from '@reaatech/rag-eval-observability'; +import { describe, expect, it } from 'vitest'; describe('Observability Metrics', () => { describe('recordEvalRun', () => { diff --git a/tests/unit/tracing.test.ts b/packages/observability/tests/tracing.test.ts similarity index 94% rename from tests/unit/tracing.test.ts rename to packages/observability/tests/tracing.test.ts index fca61f9..5f0cddd 100644 --- a/tests/unit/tracing.test.ts +++ b/packages/observability/tests/tracing.test.ts @@ -1,12 +1,12 @@ -import { describe, it, expect } from 'vitest'; import { createSpan, - withSpan, traceEvalRun, - traceMetricCalculation, - traceJudgeCall, traceGateEvaluation, -} from '../../src/observability/tracing.js'; + traceJudgeCall, + traceMetricCalculation, + withSpan, +} from '@reaatech/rag-eval-observability'; +import { describe, expect, it } from 'vitest'; describe('Tracing', () => { describe('createSpan', () => { @@ -31,7 +31,7 @@ describe('Tracing', () => { withSpan('test.operation', async (span) => { span.end(); throw new Error('test error'); - }) + }), ).rejects.toThrow('test error'); }); }); @@ -55,7 +55,7 @@ describe('Tracing', () => { async (span) => { span.end(); return 0.95; - } + }, ); expect(result).toBe(0.95); }); diff --git a/packages/observability/tsconfig.json b/packages/observability/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/observability/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/observability/vitest.config.ts b/packages/observability/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/observability/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/packages/suite/LICENSE b/packages/suite/LICENSE new file mode 100644 index 0000000..9f30114 --- /dev/null +++ b/packages/suite/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rick Somers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/suite/README.md b/packages/suite/README.md new file mode 100644 index 0000000..d2d042a --- /dev/null +++ b/packages/suite/README.md @@ -0,0 +1,200 @@ +# @reaatech/rag-eval-suite + +[![npm version](https://img.shields.io/npm/v/@reaatech/rag-eval-suite.svg)](https://www.npmjs.com/package/@reaatech/rag-eval-suite) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/reaatech/rag-eval-pack/ci.yml?branch=main&label=CI)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) + +> **Status:** Pre-1.0 β€” APIs may change in minor versions. Pin to a specific version in production. + +Central evaluation orchestrator that ties metrics, judge, cost tracking, quality gates, and dataset loading into a single `EvaluationSuite` class. The primary entry point for running comprehensive RAG evaluations. + +## Installation + +```bash +npm install @reaatech/rag-eval-suite +# or +pnpm add @reaatech/rag-eval-suite +``` + +## Feature Overview + +- **End-to-end orchestration** β€” run metrics, LLM judge, cost tracking, and gate evaluation in a single call +- **Parallel metric execution** β€” configurable concurrency for heuristic metric computation +- **Judge integration** β€” optional LLM-based scoring for faithfulness, relevance, and overall quality +- **Budget enforcement** β€” per-run and per-sample cost tracking with automatic stopping +- **Gate evaluation** β€” threshold and baseline-comparison gates evaluated against aggregated results +- **Run comparison** β€” diff two evaluation runs to identify regressions and improvements +- **Baseline management** β€” set and compare against stored baselines for CI regression detection + +## Quick Start + +```typescript +import { EvaluationSuite } from "@reaatech/rag-eval-suite"; + +const suite = new EvaluationSuite({ + metrics: ["faithfulness", "relevance", "context_precision", "context_recall"], + judge: { model: "claude-opus" }, + gates: [ + { name: "min-faithfulness", type: "threshold", metric: "avg_faithfulness", operator: ">=", threshold: 0.85 }, + ], + cost: { budget_limit: 10.00, hard_limit: true }, +}); + +const result = await suite.runFromFile("datasets/eval-samples.jsonl"); + +console.log("Overall score:", result.results.metrics.overall_score); +console.log("Faithfulness:", result.results.metrics.avg_faithfulness); +console.log("Total cost:", result.results.total_cost); +console.log("Gates passed:", result.gate_result?.passed); +``` + +## API Reference + +### `EvaluationSuite` + +The main class for running evaluations. + +```typescript +import { EvaluationSuite, type SuiteRunResult } from "@reaatech/rag-eval-suite"; +import type { EvalSuiteConfig, EvaluationSample, EvalResults } from "@reaatech/rag-eval-core"; + +const suite = new EvaluationSuite(config: EvalSuiteConfig); +``` + +#### `EvalSuiteConfig` + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `metrics` | `MetricName[]` | (required) | Metrics to evaluate: `"faithfulness"`, `"relevance"`, `"context_precision"`, `"context_recall"` | +| `judge` | `JudgeConfig` | β€” | Optional LLM judge configuration | +| `cost` | `CostConfig` | β€” | Budget limits and alert thresholds | +| `gates` | `GateConfig[]` | β€” | Quality gates to evaluate | +| `execution` | `ExecutionConfig` | `{ parallel_jobs: 5 }` | Execution configuration | + +#### Run Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `run(samples, runId?)` | `Promise` | Run evaluation on in-memory samples | +| `runFromFile(datasetPath)` | `Promise` | Load samples from file and evaluate | + +#### `SuiteRunResult` + +| Property | Type | Description | +|----------|------|-------------| +| `run_id` | `string` | Unique run identifier | +| `status` | `"completed" \| "partial" \| "failed"` | Run completion status | +| `results` | `EvalResults` | Full evaluation results | +| `gate_result` | `GateResult?` | Gate evaluation result (if gates configured) | + +#### Comparison Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `compareRuns(baseline, candidate)` | `{ diff, regressions, improvements }` | Compare two evaluation runs | +| `setBaseline(baseline)` | `void` | Store a baseline for gate comparison | + +#### Cost Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `getCostBreakdown()` | `{ judge: CostBreakdown, total: CostBreakdown }` | Get detailed cost breakdown | + +### How It Works + +1. **Dataset loading** β€” loads and validates samples from JSONL/JSON/YAML +2. **Heuristic metrics** β€” runs `MetricsEngine` in parallel for all configured metrics +3. **LLM judging** (optional) β€” evaluates faithfulness, relevance, and overall quality via LLM +4. **Cost tracking** β€” records token usage and cost at both the sample and run level +5. **Aggregation** β€” computes mean, standard deviation, and overall score across all samples +6. **Gate evaluation** β€” runs threshold and baseline-comparison gates against aggregated results + +## Usage Patterns + +### Without Judge (Heuristic-Only) + +```typescript +const suite = new EvaluationSuite({ + metrics: ["faithfulness", "relevance"], +}); + +const result = await suite.run(samples); +// No LLM costs, fast evaluation using NLP heuristics only +``` + +### With Judge and Budget + +```typescript +const suite = new EvaluationSuite({ + metrics: ["faithfulness", "relevance", "context_precision", "context_recall"], + judge: { + model: "claude-opus", + consensus: { + enabled: true, + models: [ + { id: "claude-opus", weight: 0.5 }, + { id: "gpt-4-turbo", weight: 0.5 }, + ], + voting_strategy: "weighted", + }, + }, + cost: { budget_limit: 50.00, hard_limit: true }, +}); + +const result = await suite.runFromFile("datasets/large-eval.jsonl"); +console.log(`Cost: $${result.results.total_cost}`); +``` + +### CI Regression Detection + +```typescript +import { EvaluationSuite } from "@reaatech/rag-eval-suite"; +import { readFileSync, existsSync } from "node:fs"; + +const suite = new EvaluationSuite({ + metrics: ["faithfulness", "relevance"], + gates: [ + { name: "no-regression", type: "baseline-comparison", metric: "overall_score", allow_regression: false }, + ], +}); + +// Load baseline if it exists +const baselinePath = "results/baseline.json"; +if (existsSync(baselinePath)) { + const baseline = JSON.parse(readFileSync(baselinePath, "utf-8")); + suite.setBaseline(baseline); +} + +const result = await suite.runFromFile("datasets/eval.jsonl"); + +if (result.gate_result && !result.gate_result.passed) { + console.error("Regression detected!"); + process.exit(1); +} +``` + +### Run Comparison + +```typescript +const suite = new EvaluationSuite({ metrics: ["faithfulness"] }); + +const diff = suite.compareRuns(v10Results, v11Results); + +console.log("Diffs:", diff.diff); +console.log("Regressions:", diff.regressions); +console.log("Improvements:", diff.improvements); +``` + +## Related Packages + +- [`@reaatech/rag-eval-core`](https://www.npmjs.com/package/@reaatech/rag-eval-core) β€” Types and schemas +- [`@reaatech/rag-eval-metrics`](https://www.npmjs.com/package/@reaatech/rag-eval-metrics) β€” Heuristic metric scorers +- [`@reaatech/rag-eval-judge`](https://www.npmjs.com/package/@reaatech/rag-eval-judge) β€” LLM judge with calibration +- [`@reaatech/rag-eval-cost`](https://www.npmjs.com/package/@reaatech/rag-eval-cost) β€” Cost tracking and budgeting +- [`@reaatech/rag-eval-gate`](https://www.npmjs.com/package/@reaatech/rag-eval-gate) β€” Quality gates +- [`@reaatech/rag-eval-dataset`](https://www.npmjs.com/package/@reaatech/rag-eval-dataset) β€” Dataset loading and validation +- [`@reaatech/rag-eval-cli`](https://www.npmjs.com/package/@reaatech/rag-eval-cli) β€” CLI tool + +## License + +[MIT](https://github.com/reaatech/rag-eval-pack/blob/main/LICENSE) diff --git a/packages/suite/package.json b/packages/suite/package.json new file mode 100644 index 0000000..e39964d --- /dev/null +++ b/packages/suite/package.json @@ -0,0 +1,52 @@ +{ + "name": "@reaatech/rag-eval-suite", + "version": "0.1.0", + "description": "Central evaluation orchestrator that ties metrics, judge, cost, gate, and dataset together", + "license": "MIT", + "author": "Rick Somers (https://reaatech.com)", + "repository": { + "type": "git", + "url": "https://github.com/reaatech/rag-eval-pack.git", + "directory": "packages/suite" + }, + "homepage": "https://github.com/reaatech/rag-eval-pack/tree/main/packages/suite#readme", + "bugs": { + "url": "https://github.com/reaatech/rag-eval-pack/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": ["dist"], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts --clean", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "clean": "rm -rf dist" + }, + "dependencies": { + "@reaatech/rag-eval-core": "workspace:*", + "@reaatech/rag-eval-cost": "workspace:*", + "@reaatech/rag-eval-dataset": "workspace:*", + "@reaatech/rag-eval-gate": "workspace:*", + "@reaatech/rag-eval-judge": "workspace:*", + "@reaatech/rag-eval-metrics": "workspace:*", + "p-limit": "^7.3.0" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "tsup": "^8.4.0", + "typescript": "^5.8.3", + "vitest": "^3.1.1" + } +} diff --git a/src/evaluation-suite.ts b/packages/suite/src/evaluation-suite.ts similarity index 91% rename from src/evaluation-suite.ts rename to packages/suite/src/evaluation-suite.ts index 5367f50..20b0ade 100644 --- a/src/evaluation-suite.ts +++ b/packages/suite/src/evaluation-suite.ts @@ -1,17 +1,17 @@ import type { - EvaluationSample, - EvalSuiteConfig, - SampleEvalResult, + CostBreakdown, EvalResults, + EvalSuiteConfig, + EvaluationSample, GateResult, - CostBreakdown, -} from './types/domain.js'; -import { MetricsEngine } from './metrics/engine.js'; -import { JudgeEngine, type JudgeMetric } from './judge/engine.js'; -import { JudgeCostTracker } from './judge/cost-tracker.js'; -import { CostTracker } from './cost/tracker.js'; -import { GateEngine } from './gate/engine.js'; -import { DatasetLoader } from './dataset/loader.js'; + SampleEvalResult, +} from '@reaatech/rag-eval-core'; +import { CostTracker } from '@reaatech/rag-eval-cost'; +import { DatasetLoader } from '@reaatech/rag-eval-dataset'; +import { GateEngine } from '@reaatech/rag-eval-gate'; +import { JudgeEngine, type JudgeMetric } from '@reaatech/rag-eval-judge'; +import { JudgeCostTracker } from '@reaatech/rag-eval-judge'; +import { MetricsEngine } from '@reaatech/rag-eval-metrics'; /** * Evaluation Suite Run result @@ -37,8 +37,8 @@ export class EvaluationSuite { private costTracker: CostTracker; private gateEngine?: GateEngine; private datasetLoader: DatasetLoader; - private runId: string = ''; - private datasetPath: string = ''; + private runId = ''; + private datasetPath = ''; constructor(config: EvalSuiteConfig) { this.config = config; @@ -86,7 +86,8 @@ export class EvaluationSuite { // Run metrics evaluation for (let i = 0; i < samples.length; i++) { - const sample = samples[i]!; + const sample = samples[i]; + if (!sample) continue; try { // Run heuristic metrics @@ -151,7 +152,7 @@ export class EvaluationSuite { private async runJudgeEvaluation( sample: EvaluationSample, result: SampleEvalResult, - index: number + index: number, ): Promise { if (!this.judgeEngine) return; @@ -166,7 +167,7 @@ export class EvaluationSuite { const costEstimate = this.judgeCostTracker.estimateCost( this.config.judge?.model ?? 'claude-sonnet-4-6', judgeResult.provider, - inputText + inputText, ); this.judgeCostTracker.recordCost( @@ -175,7 +176,7 @@ export class EvaluationSuite { judgeResult.provider, costEstimate.tokens.input, costEstimate.tokens.output, - metric + metric, ); this.costTracker.recordCost( @@ -183,7 +184,7 @@ export class EvaluationSuite { costEstimate.cost, costEstimate.tokens, `judge_${metric}`, - judgeResult.provider + judgeResult.provider, ); // Store judge result in sample result @@ -216,7 +217,7 @@ export class EvaluationSuite { */ compareRuns( baseline: EvalResults, - candidate: EvalResults + candidate: EvalResults, ): { diff: Record; regressions: string[]; @@ -244,11 +245,11 @@ export class EvaluationSuite { if (difference < -0.01) { regressions.push( - `${metric}: ${baselineValue.toFixed(3)} -> ${candidateValue.toFixed(3)} (${difference.toFixed(3)})` + `${metric}: ${baselineValue.toFixed(3)} -> ${candidateValue.toFixed(3)} (${difference.toFixed(3)})`, ); } else if (difference > 0.01) { improvements.push( - `${metric}: ${baselineValue.toFixed(3)} -> ${candidateValue.toFixed(3)} (${difference.toFixed(3)})` + `${metric}: ${baselineValue.toFixed(3)} -> ${candidateValue.toFixed(3)} (${difference.toFixed(3)})`, ); } } diff --git a/packages/suite/src/index.ts b/packages/suite/src/index.ts new file mode 100644 index 0000000..d3845e8 --- /dev/null +++ b/packages/suite/src/index.ts @@ -0,0 +1 @@ +export { EvaluationSuite, type SuiteRunResult } from './evaluation-suite.js'; diff --git a/tests/unit/evaluation-suite.test.ts b/packages/suite/tests/evaluation-suite.test.ts similarity index 86% rename from tests/unit/evaluation-suite.test.ts rename to packages/suite/tests/evaluation-suite.test.ts index bad62d6..ede44ec 100644 --- a/tests/unit/evaluation-suite.test.ts +++ b/packages/suite/tests/evaluation-suite.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect } from 'vitest'; -import { EvaluationSuite } from '../../src/evaluation-suite.js'; -import type { EvalSuiteConfig, EvaluationSample } from '../../src/types/domain.js'; +import type { EvaluationSample } from '@reaatech/rag-eval-core'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; +import { describe, expect, it } from 'vitest'; describe('EvaluationSuite', () => { const sample: EvaluationSample = { diff --git a/packages/suite/tsconfig.json b/packages/suite/tsconfig.json new file mode 100644 index 0000000..90d76d7 --- /dev/null +++ b/packages/suite/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/suite/vitest.config.ts b/packages/suite/vitest.config.ts new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/packages/suite/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: false, + environment: 'node', + coverage: { + reporter: ['text', 'json-summary'], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..9997580 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4576 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@biomejs/biome': + specifier: ^1.9.4 + version: 1.9.4 + '@changesets/changelog-github': + specifier: ^0.6.0 + version: 0.6.0 + '@changesets/cli': + specifier: ^2.28.1 + version: 2.31.0(@types/node@25.6.0) + '@vitest/coverage-v8': + specifier: 3.2.4 + version: 3.2.4(vitest@3.2.4(@types/node@25.6.0)(yaml@2.8.4)) + turbo: + specifier: ^2.5.0 + version: 2.9.7 + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/cli: + dependencies: + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + '@reaatech/rag-eval-cost': + specifier: workspace:* + version: link:../cost + '@reaatech/rag-eval-dataset': + specifier: workspace:* + version: link:../dataset + '@reaatech/rag-eval-gate': + specifier: workspace:* + version: link:../gate + '@reaatech/rag-eval-judge': + specifier: workspace:* + version: link:../judge + '@reaatech/rag-eval-mcp-server': + specifier: workspace:* + version: link:../mcp-server + '@reaatech/rag-eval-metrics': + specifier: workspace:* + version: link:../metrics + '@reaatech/rag-eval-observability': + specifier: workspace:* + version: link:../observability + '@reaatech/rag-eval-suite': + specifier: workspace:* + version: link:../suite + chalk: + specifier: ^5.3.0 + version: 5.6.2 + cli-progress: + specifier: ^3.12.0 + version: 3.12.0 + commander: + specifier: ^14.0.3 + version: 14.0.3 + yaml: + specifier: ^2.6.1 + version: 2.8.4 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/core: + dependencies: + zod: + specifier: ^3.24.2 + version: 3.25.76 + devDependencies: + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/cost: + dependencies: + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + js-tiktoken: + specifier: ^1.0.15 + version: 1.0.21 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/dataset: + dependencies: + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + yaml: + specifier: ^2.6.1 + version: 2.8.4 + zod: + specifier: ^3.24.2 + version: 3.25.76 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/gate: + dependencies: + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/judge: + dependencies: + '@anthropic-ai/sdk': + specifier: ^0.32.0 + version: 0.32.1 + '@google/generative-ai': + specifier: ^0.21.0 + version: 0.21.0 + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + '@reaatech/rag-eval-cost': + specifier: workspace:* + version: link:../cost + openai: + specifier: ^6.35.0 + version: 6.35.0(zod@3.25.76) + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/mcp-server: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.9.0 + version: 1.29.0(zod@3.25.76) + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + '@reaatech/rag-eval-gate': + specifier: workspace:* + version: link:../gate + '@reaatech/rag-eval-metrics': + specifier: workspace:* + version: link:../metrics + '@reaatech/rag-eval-suite': + specifier: workspace:* + version: link:../suite + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/metrics: + dependencies: + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + compromise: + specifier: ^14.15.0 + version: 14.15.0 + natural: + specifier: ^8.1.1 + version: 8.1.1(@opentelemetry/api@1.9.1) + p-limit: + specifier: ^7.3.0 + version: 7.3.0 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/observability: + dependencies: + '@opentelemetry/api': + specifier: ^1.9.0 + version: 1.9.1 + '@opentelemetry/sdk-metrics': + specifier: ^1.28.0 + version: 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': + specifier: ^1.28.0 + version: 1.30.1(@opentelemetry/api@1.9.1) + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + pino: + specifier: ^9.5.0 + version: 9.14.0 + pino-pretty: + specifier: ^13.1.3 + version: 13.1.3 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + + packages/suite: + dependencies: + '@reaatech/rag-eval-core': + specifier: workspace:* + version: link:../core + '@reaatech/rag-eval-cost': + specifier: workspace:* + version: link:../cost + '@reaatech/rag-eval-dataset': + specifier: workspace:* + version: link:../dataset + '@reaatech/rag-eval-gate': + specifier: workspace:* + version: link:../gate + '@reaatech/rag-eval-judge': + specifier: workspace:* + version: link:../judge + '@reaatech/rag-eval-metrics': + specifier: workspace:* + version: link:../metrics + p-limit: + specifier: ^7.3.0 + version: 7.3.0 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + tsup: + specifier: ^8.4.0 + version: 8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + vitest: + specifier: ^3.1.1 + version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@anthropic-ai/sdk@0.32.1': + resolution: {integrity: sha512-U9JwTrDvdQ9iWuABVsMLj8nJVwAyQz6QXvgLsVhryhCEPkLsbcP/MXxm+jYcAwLoV8ESbaTTjnD4kuAFa+Hyjg==} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + + '@biomejs/biome@1.9.4': + resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.9.4': + resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.9.4': + resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.9.4': + resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.9.4': + resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.9.4': + resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.9.4': + resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.9.4': + resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.9.4': + resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@changesets/apply-release-plan@7.1.1': + resolution: {integrity: sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==} + + '@changesets/assemble-release-plan@6.0.10': + resolution: {integrity: sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A==} + + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/changelog-github@0.6.0': + resolution: {integrity: sha512-wA2/y4hR/A1K411cCT75rz0d46Iezxp1WYRFoFJDIUpkQ6oDBAIUiU7BZkDCmYgz0NBl94X1lgcZO+mHoiHnFg==} + + '@changesets/cli@2.31.0': + resolution: {integrity: sha512-AhI4enNTgHu2IZr6K4WZyf0EPch4XVMn1yOMFmCD9gsfBGqMYaHXls5HyDv6/CL5axVQABz68eG30eCtbr2wFg==} + hasBin: true + + '@changesets/config@3.1.4': + resolution: {integrity: sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.4': + resolution: {integrity: sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg==} + + '@changesets/get-github-info@0.8.0': + resolution: {integrity: sha512-cRnC+xdF0JIik7coko3iUP9qbnfi1iJQ3sAa6dE+Tx3+ET8bjFEm63PA4WEohgjYcmsOikPHWzPsMWWiZmntOQ==} + + '@changesets/get-release-plan@4.0.16': + resolution: {integrity: sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.3': + resolution: {integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==} + + '@changesets/pre@2.0.2': + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + + '@changesets/read@0.6.7': + resolution: {integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==} + + '@changesets/should-skip-package@0.1.2': + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.1.0': + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@google/generative-ai@0.21.0': + resolution: {integrity: sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==} + engines: {node: '>=18.0.0'} + + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@mongodb-js/saslprep@1.4.10': + resolution: {integrity: sha512-DDb3OAw8ezai9p2i1F7R5wMVmyrMIuT8ixjV56R4Hl4cazCo2tOMTDyPR5rrCUcHiMbWHzCXOdife5OD6H1C8w==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/core@1.30.1': + resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/resources@1.30.1': + resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-metrics@1.30.1': + resolution: {integrity: sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@1.30.1': + resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.28.0': + resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} + engines: {node: '>=14'} + + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@redis/bloom@5.12.1': + resolution: {integrity: sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@redis/client@5.12.1': + resolution: {integrity: sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@node-rs/xxhash': ^1.1.0 + '@opentelemetry/api': '>=1 <2' + peerDependenciesMeta: + '@node-rs/xxhash': + optional: true + '@opentelemetry/api': + optional: true + + '@redis/json@5.12.1': + resolution: {integrity: sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@redis/search@5.12.1': + resolution: {integrity: sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@redis/time-series@5.12.1': + resolution: {integrity: sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@rollup/rollup-android-arm-eabi@4.60.2': + resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.2': + resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.2': + resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.2': + resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.2': + resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.2': + resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.2': + resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.60.2': + resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.60.2': + resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.2': + resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.60.2': + resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.2': + resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.2': + resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.60.2': + resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.60.2': + resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.60.2': + resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.2': + resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.2': + resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.2': + resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.2': + resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.2': + resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} + cpu: [x64] + os: [win32] + + '@turbo/darwin-64@2.9.7': + resolution: {integrity: sha512-wnvOWuVWJ5EUHNKxExEWiGlTeVpLG1L0PCu5MUozyC1P2SHGiWsmpW6/yAuShH91Fa2TAHOvdCRBzriZh4j4Eg==} + cpu: [x64] + os: [darwin] + + '@turbo/darwin-arm64@2.9.7': + resolution: {integrity: sha512-mA0FIPMwwN3lodDkQYaGxj6PeT7ZaN5aCEbkKn/WB+ZB9yJdVWA4J83GH7t43jqDc5dcnVluVN5UFx3plRiXhA==} + cpu: [arm64] + os: [darwin] + + '@turbo/linux-64@2.9.7': + resolution: {integrity: sha512-fEbUYpgb5l7P+q+5tsWF2gw+/GSjUsuUTcnfm+f0lozUjgcjLKyOat6PgtAChmIFcTPchCL/8rJ3TvkBy01gfA==} + cpu: [x64] + os: [linux] + + '@turbo/linux-arm64@2.9.7': + resolution: {integrity: sha512-VkUjulo9ytfHKUHOS5gy0XPoh4CTKPXWCL8nLdrlHVi9fSut31ECeUqnm/dAbETP5D4xo9mH9XkJ+qMzGe/zmg==} + cpu: [arm64] + os: [linux] + + '@turbo/windows-64@2.9.7': + resolution: {integrity: sha512-/GWdY6/x4aIHqkYJq596Rpdk1x0MkpRPkJcLAoB3yGRwyUms0+u2F1GnV54IbyAZTeKLRWSJKzNC+QwVGdYchA==} + cpu: [x64] + os: [win32] + + '@turbo/windows-arm64@2.9.7': + resolution: {integrity: sha512-xBBgxCC5PK2+WZ1PPRZdp+aJ0bMBcEbweXWux3RUHJvX9ZodcoQySkrW6qt+ahb+uk8ZjyQodLfDwtVSoYds1w==} + cpu: [arm64] + os: [win32] + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@13.0.0': + resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==} + + '@vitest/coverage-v8@3.2.4': + resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} + peerDependencies: + '@vitest/browser': 3.2.4 + vitest: 3.2.4 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + afinn-165-financialmarketnews@3.0.0: + resolution: {integrity: sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw==} + + afinn-165@2.0.2: + resolution: {integrity: sha512-mJ/RLUfpXfQA6bzugv+bBsc/QYkVrKaLYeS8fWBpKbTCsonv4iuV9ET0fgReEunm9vKLkaNgnekuSNlTC3WQ1Q==} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + apparatus@0.0.10: + resolution: {integrity: sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==} + engines: {node: '>=0.2.6'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-v8-to-istanbul@0.3.12: + resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + 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==} + + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + bson@7.2.0: + resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} + engines: {node: '>=20.19.0'} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + cli-progress@3.12.0: + resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==} + engines: {node: '>=4'} + + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + compromise@14.15.0: + resolution: {integrity: sha512-YEMv5JGWyqRJw5hdZqDVQF3MMlHA6TRiXreR8IYffk6xB7GA5p/8DeDzvg0Jy2tHNGpD+qJGl0+oJwA+5R/sVA==} + engines: {node: '>=12.0.0'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + dataloader@1.4.0: + resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + + dotenv@8.6.0: + resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} + engines: {node: '>=10'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + efrt@2.7.0: + resolution: {integrity: sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==} + engines: {node: '>=12.0.0'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventsource-parser@3.0.8: + resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + express-rate-limit@8.4.1: + resolution: {integrity: sha512-NGVYwQSAyEQgzxX1iCM978PP9AdO/hW93gMcF6ZwQCm+rFvLsBH6w4xcXWTcliS8La5EPRN3p9wzItqBwJrfNw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + fast-copy@4.0.3: + resolution: {integrity: sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + 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 + hasBin: true + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grad-school@0.0.5: + resolution: {integrity: sha512-rXunEHF9M9EkMydTBux7+IryYXEZinRk6g8OBOGDBzo/qWJjhTxy86i5q7lQYpCLHN8Sqv1XX3OIOc7ka2gtvQ==} + engines: {node: '>=8.0.0'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hono@4.12.16: + resolution: {integrity: sha512-jN0ZewiNAWSe5khM3EyCmBb250+b40wWbwNILNfEvq84VREWwOIkuUsFONk/3i3nqkz7Oe1PcpM2mwQEK2L9Kg==} + engines: {node: '>=16.9.0'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tiktoken@1.0.21: + resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} + + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + + 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==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + kareem@3.3.0: + resolution: {integrity: sha512-kpSuLD3/7RenBnjnJdOHXCKC8dTd1JzeOiJhN0necWWci6cC+qX+VuwPnMVgb+a4+KNJSfgqahpnfWaeDXCimw==} + engines: {node: '>=18.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + memjs@1.3.2: + resolution: {integrity: sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg==} + engines: {node: '>=0.10.0'} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mongodb-connection-string-url@7.0.1: + resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==} + engines: {node: '>=20.19.0'} + + mongodb@7.2.0: + resolution: {integrity: sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.806.0 + '@mongodb-js/zstd': ^7.0.0 + gcp-metadata: ^7.0.1 + kerberos: ^7.0.0 + mongodb-client-encryption: '>=7.0.0 <7.1.0' + snappy: ^7.3.2 + socks: ^2.8.6 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose@9.6.1: + resolution: {integrity: sha512-3T8/b0plM3ZJPW3WjlzVMIGJEYYTjgDPQ05Qzru3xu3/wOPSFKWYxdwUF2dl8h3NG5dVkzIuOkZdLacnlLf/sA==} + engines: {node: '>=20.19.0'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@6.0.0: + resolution: {integrity: sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==} + engines: {node: '>=20.19.0'} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural@8.1.1: + resolution: {integrity: sha512-Ucb+lsUcGxUqu3rn8cwHjT6gJQosO63nIX/aBQXB3+IDkNbFV7PuviysO+Rzz3aKn7PZhPj3bNF4PS9gDVjYCQ==} + engines: {node: '>=0.4.10'} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + openai@6.35.0: + resolution: {integrity: sha512-L/skwIGnt5xQZHb0UfTu9uAUKbis3ehKypOuJKi20QvG7UStV6C8IC3myGYHcdiF4kms/bAvOJ9UqqNWqi8x/Q==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@7.3.0: + resolution: {integrity: sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==} + engines: {node: '>=20'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + + parseurl@1.3.3: + 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-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + pg-cloudflare@1.3.0: + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} + + pg-connection-string@2.12.0: + resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.13.0: + resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.13.0: + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-pretty@13.1.3: + resolution: {integrity: sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==} + hasBin: true + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} + hasBin: true + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss@8.5.13: + resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} + engines: {node: ^10 || ^12 || >=14} + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.15.1: + resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} + engines: {node: '>=0.6'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + redis@5.12.1: + resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==} + engines: {node: '>= 18.19.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.60.2: + resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + stopwords-iso@1.1.0: + resolution: {integrity: sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + suffix-thumb@5.0.2: + resolution: {integrity: sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + sylvester@0.0.21: + resolution: {integrity: sha512-yUT0ukFkFEt4nb+NY+n2ag51aS/u9UHXoZw+A4jgD77/jzZsBoSDHuqysrVCBC4CYR4TYvUJq54ONpXgDBH8tA==} + engines: {node: '>=0.2.6'} + + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + turbo@2.9.7: + resolution: {integrity: sha512-epxzqVO2s0IxcSWcgb+qKrtco8isfe7g3VtiS6hkYnEK4A9XQDZbrtavQ6MtWR1KoQn+1fUomaQth2rfRHlUlg==} + hasBin: true + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + underscore@1.13.8: + resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + uuid@13.0.1: + resolution: {integrity: sha512-9ezox2roIft6ExBVTVqibSd5dc5/47Sw/uY6b4SjQUT2TzQ0tltNquWA46y4xPQmdZYqvnio22SgWd41M86+jw==} + hasBin: true + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.3.2: + resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wordnet-db@3.1.14: + resolution: {integrity: sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==} + engines: {node: '>=0.6.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yaml@2.8.4: + resolution: {integrity: sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==} + engines: {node: '>= 14.6'} + hasBin: true + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@anthropic-ai/sdk@0.32.1': + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/runtime@7.29.2': {} + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@1.0.2': {} + + '@biomejs/biome@1.9.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.9.4 + '@biomejs/cli-darwin-x64': 1.9.4 + '@biomejs/cli-linux-arm64': 1.9.4 + '@biomejs/cli-linux-arm64-musl': 1.9.4 + '@biomejs/cli-linux-x64': 1.9.4 + '@biomejs/cli-linux-x64-musl': 1.9.4 + '@biomejs/cli-win32-arm64': 1.9.4 + '@biomejs/cli-win32-x64': 1.9.4 + + '@biomejs/cli-darwin-arm64@1.9.4': + optional: true + + '@biomejs/cli-darwin-x64@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64@1.9.4': + optional: true + + '@biomejs/cli-linux-x64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-x64@1.9.4': + optional: true + + '@biomejs/cli-win32-arm64@1.9.4': + optional: true + + '@biomejs/cli-win32-x64@1.9.4': + optional: true + + '@changesets/apply-release-plan@7.1.1': + dependencies: + '@changesets/config': 3.1.4 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.4 + + '@changesets/assemble-release-plan@6.0.10': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.4 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/changelog-github@0.6.0': + dependencies: + '@changesets/get-github-info': 0.8.0 + '@changesets/types': 6.1.0 + dotenv: 8.6.0 + transitivePeerDependencies: + - encoding + + '@changesets/cli@2.31.0(@types/node@25.6.0)': + dependencies: + '@changesets/apply-release-plan': 7.1.1 + '@changesets/assemble-release-plan': 6.0.10 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.4 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/get-release-plan': 4.0.16 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@25.6.0) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.4 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.4': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/logger': 0.1.1 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.4': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.4 + + '@changesets/get-github-info@0.8.0': + dependencies: + dataloader: 1.4.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + '@changesets/get-release-plan@4.0.16': + dependencies: + '@changesets/assemble-release-plan': 6.0.10 + '@changesets/config': 3.1.4 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.3': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 4.1.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.7': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.3 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.3 + prettier: 2.8.8 + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@google/generative-ai@0.21.0': {} + + '@hono/node-server@1.19.14(hono@4.12.16)': + dependencies: + hono: 4.12.16 + + '@inquirer/external-editor@1.0.3(@types/node@25.6.0)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 25.6.0 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.6': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.29.2 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.29.2 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.16) + 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.0.8 + express: 5.2.1 + express-rate-limit: 8.4.1(express@5.2.1) + hono: 4.12.16 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@mongodb-js/saslprep@1.4.10': + dependencies: + sparse-bitfield: 3.0.3 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@opentelemetry/api@1.9.1': {} + + '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/sdk-metrics@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/semantic-conventions@1.28.0': {} + + '@pinojs/redact@0.4.0': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@redis/bloom@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + dependencies: + '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + + '@redis/client@5.12.1(@opentelemetry/api@1.9.1)': + dependencies: + cluster-key-slot: 1.1.2 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + + '@redis/json@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + dependencies: + '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + + '@redis/search@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + dependencies: + '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + + '@redis/time-series@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + dependencies: + '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + + '@rollup/rollup-android-arm-eabi@4.60.2': + optional: true + + '@rollup/rollup-android-arm64@4.60.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.2': + optional: true + + '@rollup/rollup-darwin-x64@4.60.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.2': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.2': + optional: true + + '@turbo/darwin-64@2.9.7': + optional: true + + '@turbo/darwin-arm64@2.9.7': + optional: true + + '@turbo/linux-64@2.9.7': + optional: true + + '@turbo/linux-arm64@2.9.7': + optional: true + + '@turbo/windows-64@2.9.7': + optional: true + + '@turbo/windows-arm64@2.9.7': + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 25.6.0 + form-data: 4.0.5 + + '@types/node@12.20.55': {} + + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + + '@types/node@25.6.0': + dependencies: + undici-types: 7.19.2 + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@13.0.0': + dependencies: + '@types/webidl-conversions': 7.0.3 + + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@25.6.0)(yaml@2.8.4))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.12 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.2 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.3.2(@types/node@25.6.0)(yaml@2.8.4))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.2(@types/node@25.6.0)(yaml@2.8.4) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn@8.16.0: {} + + afinn-165-financialmarketnews@3.0.0: {} + + afinn-165@2.0.2: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + any-promise@1.3.0: {} + + apparatus@0.0.10: + dependencies: + sylvester: 0.0.21 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + assertion-error@2.0.1: {} + + ast-v8-to-istanbul@0.3.12: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + + asynckit@0.4.0: {} + + atomic-sleep@1.0.0: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.1 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bson@7.2.0: {} + + bundle-require@5.1.0(esbuild@0.27.7): + dependencies: + esbuild: 0.27.7 + load-tsconfig: 0.2.5 + + bytes@3.1.2: {} + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@5.6.2: {} + + chardet@2.1.1: {} + + check-error@2.1.3: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + cli-progress@3.12.0: + dependencies: + string-width: 4.2.3 + + cluster-key-slot@1.1.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@14.0.3: {} + + commander@4.1.1: {} + + compromise@14.15.0: + dependencies: + efrt: 2.7.0 + grad-school: 0.0.5 + suffix-thumb: 5.0.2 + + confbox@0.1.8: {} + + consola@3.4.2: {} + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + dataloader@1.4.0: {} + + dateformat@4.6.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + detect-indent@6.1.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dotenv@17.4.2: {} + + dotenv@8.6.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + efrt@2.7.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.3 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escape-html@1.0.3: {} + + esprima@4.0.1: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + eventsource-parser@3.0.8: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.8 + + expect-type@1.3.0: {} + + express-rate-limit@8.4.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.1 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extendable-error@0.1.7: {} + + fast-copy@4.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + 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-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.60.2 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data-encoder@1.7.2: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.3 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.3 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + grad-school@0.0.5: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + + help-me@5.0.0: {} + + hono@4.12.16: {} + + html-escaper@2.0.2: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + human-id@4.1.3: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + inherits@2.0.4: {} + + ip-address@10.1.0: {} + + ipaddr.js@1.9.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-promise@4.0.0: {} + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-windows@1.0.2: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jose@6.2.3: {} + + joycon@3.1.1: {} + + js-tiktoken@1.0.21: + dependencies: + base64-js: 1.5.1 + + js-tokens@10.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + kareem@3.3.0: {} + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + load-tsconfig@0.2.5: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.startcase@4.4.0: {} + + loupe@3.2.1: {} + + lru-cache@10.4.3: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.4 + + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + memjs@1.3.2: {} + + memory-pager@1.5.0: {} + + merge-descriptors@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + mongodb-connection-string-url@7.0.1: + dependencies: + '@types/whatwg-url': 13.0.0 + whatwg-url: 14.2.0 + + mongodb@7.2.0: + dependencies: + '@mongodb-js/saslprep': 1.4.10 + bson: 7.2.0 + mongodb-connection-string-url: 7.0.1 + + mongoose@9.6.1: + dependencies: + kareem: 3.3.0 + mongodb: 7.2.0 + mpath: 0.9.0 + mquery: 6.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + + mpath@0.9.0: {} + + mquery@6.0.0: {} + + mri@1.2.0: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.12: {} + + natural@8.1.1(@opentelemetry/api@1.9.1): + dependencies: + afinn-165: 2.0.2 + afinn-165-financialmarketnews: 3.0.0 + apparatus: 0.0.10 + dotenv: 17.4.2 + memjs: 1.3.2 + mongoose: 9.6.1 + pg: 8.20.0 + redis: 5.12.1(@opentelemetry/api@1.9.1) + safe-stable-stringify: 2.5.0 + stopwords-iso: 1.1.0 + sylvester: 0.0.21 + underscore: 1.13.8 + uuid: 13.0.1 + wordnet-db: 3.1.14 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - '@node-rs/xxhash' + - '@opentelemetry/api' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - pg-native + - snappy + - socks + + negotiator@1.0.0: {} + + node-domexception@1.0.0: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-exit-leak-free@2.1.2: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + openai@6.35.0(zod@3.25.76): + optionalDependencies: + zod: 3.25.76 + + outdent@0.5.0: {} + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@7.3.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-map@2.1.0: {} + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-to-regexp@8.4.2: {} + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + pg-cloudflare@1.3.0: + optional: true + + pg-connection-string@2.12.0: {} + + pg-int8@1.0.1: {} + + pg-pool@3.13.0(pg@8.20.0): + dependencies: + pg: 8.20.0 + + pg-protocol@1.13.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.20.0: + dependencies: + pg-connection-string: 2.12.0 + pg-pool: 3.13.0(pg@8.20.0) + pg-protocol: 1.13.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.3.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pify@4.0.1: {} + + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.1.3: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 4.0.3 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pump: 3.0.4 + secure-json-parse: 4.1.0 + sonic-boom: 4.2.1 + strip-json-comments: 5.0.3 + + pino-std-serializers@7.1.0: {} + + pino@9.14.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + + pirates@4.0.7: {} + + pkce-challenge@5.0.1: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + postcss-load-config@6.0.1(postcss@8.5.13)(yaml@2.8.4): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + postcss: 8.5.13 + yaml: 2.8.4 + + postcss@8.5.13: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postgres-array@2.0.0: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + prettier@2.8.8: {} + + process-warning@5.0.0: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + qs@6.15.1: + dependencies: + side-channel: 1.1.0 + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + quick-format-unescaped@4.0.4: {} + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.2 + pify: 4.0.1 + strip-bom: 3.0.0 + + readdirp@4.1.2: {} + + real-require@0.2.0: {} + + redis@5.12.1(@opentelemetry/api@1.9.1): + dependencies: + '@redis/bloom': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) + '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + '@redis/json': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) + '@redis/search': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) + '@redis/time-series': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) + transitivePeerDependencies: + - '@node-rs/xxhash' + - '@opentelemetry/api' + + require-from-string@2.0.2: {} + + resolve-from@5.0.0: {} + + reusify@1.1.0: {} + + rollup@4.60.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.2 + '@rollup/rollup-android-arm64': 4.60.2 + '@rollup/rollup-darwin-arm64': 4.60.2 + '@rollup/rollup-darwin-x64': 4.60.2 + '@rollup/rollup-freebsd-arm64': 4.60.2 + '@rollup/rollup-freebsd-x64': 4.60.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 + '@rollup/rollup-linux-arm-musleabihf': 4.60.2 + '@rollup/rollup-linux-arm64-gnu': 4.60.2 + '@rollup/rollup-linux-arm64-musl': 4.60.2 + '@rollup/rollup-linux-loong64-gnu': 4.60.2 + '@rollup/rollup-linux-loong64-musl': 4.60.2 + '@rollup/rollup-linux-ppc64-gnu': 4.60.2 + '@rollup/rollup-linux-ppc64-musl': 4.60.2 + '@rollup/rollup-linux-riscv64-gnu': 4.60.2 + '@rollup/rollup-linux-riscv64-musl': 4.60.2 + '@rollup/rollup-linux-s390x-gnu': 4.60.2 + '@rollup/rollup-linux-x64-gnu': 4.60.2 + '@rollup/rollup-linux-x64-musl': 4.60.2 + '@rollup/rollup-openbsd-x64': 4.60.2 + '@rollup/rollup-openharmony-arm64': 4.60.2 + '@rollup/rollup-win32-arm64-msvc': 4.60.2 + '@rollup/rollup-win32-ia32-msvc': 4.60.2 + '@rollup/rollup-win32-x64-gnu': 4.60.2 + '@rollup/rollup-win32-x64-msvc': 4.60.2 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-stable-stringify@2.5.0: {} + + safer-buffer@2.1.2: {} + + secure-json-parse@4.1.0: {} + + semver@7.7.4: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sift@17.1.3: {} + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + split2@4.2.0: {} + + sprintf-js@1.0.3: {} + + stackback@0.0.2: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + stopwords-iso@1.1.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-json-comments@5.0.3: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.16 + ts-interface-checker: 0.1.13 + + suffix-thumb@5.0.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + sylvester@0.0.21: {} + + term-size@2.2.1: {} + + test-exclude@7.0.2: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 10.5.0 + minimatch: 10.2.5 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tr46@0.0.3: {} + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + + tsup@8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.7) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.5.13)(yaml@2.8.4) + resolve-from: 5.0.0 + rollup: 4.60.2 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.16 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.13 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + turbo@2.9.7: + optionalDependencies: + '@turbo/darwin-64': 2.9.7 + '@turbo/darwin-arm64': 2.9.7 + '@turbo/linux-64': 2.9.7 + '@turbo/linux-arm64': 2.9.7 + '@turbo/windows-64': 2.9.7 + '@turbo/windows-arm64': 2.9.7 + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + underscore@1.13.8: {} + + undici-types@5.26.5: {} + + undici-types@7.19.2: {} + + universalify@0.1.2: {} + + unpipe@1.0.0: {} + + uuid@13.0.1: {} + + vary@1.1.2: {} + + vite-node@3.2.4(@types/node@25.6.0)(yaml@2.8.4): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.2(@types/node@25.6.0)(yaml@2.8.4) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.3.2(@types/node@25.6.0)(yaml@2.8.4): + dependencies: + esbuild: 0.27.7 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.13 + rollup: 4.60.2 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.6.0 + fsevents: 2.3.3 + yaml: 2.8.4 + + vitest@3.2.4(@types/node@25.6.0)(yaml@2.8.4): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.3.2(@types/node@25.6.0)(yaml@2.8.4)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.16 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.2(@types/node@25.6.0)(yaml@2.8.4) + vite-node: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.6.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wordnet-db@3.1.14: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + xtend@4.0.2: {} + + yaml@2.8.4: {} + + yocto-queue@1.2.2: {} + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..fa48ea2 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +packages: + - 'packages/*' + - 'examples/*' + - 'e2e' diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index dd7bc48..0000000 --- a/src/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * rag-eval-pack β€” RAG evaluation metrics with LLM-as-judge, cost accounting, and CI gates - */ - -// Types -export * from './types/index.js'; - -// Metrics -export * from './metrics/index.js'; - -// Judge -export * from './judge/index.js'; - -// Cost -export * from './cost/index.js'; - -// Gates -export * from './gate/index.js'; - -// Dataset -export * from './dataset/index.js'; - -// Core -export { EvaluationSuite, type SuiteRunResult } from './evaluation-suite.js'; diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json deleted file mode 100644 index 40d215b..0000000 --- a/tsconfig.eslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["src/**/*", "tests/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/tsconfig.typecheck.json b/tsconfig.typecheck.json new file mode 100644 index 0000000..99d4230 --- /dev/null +++ b/tsconfig.typecheck.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@reaatech/rag-eval-core": ["./packages/core/src/index.ts"], + "@reaatech/rag-eval-metrics": ["./packages/metrics/src/index.ts"], + "@reaatech/rag-eval-cost": ["./packages/cost/src/index.ts"], + "@reaatech/rag-eval-judge": ["./packages/judge/src/index.ts"], + "@reaatech/rag-eval-gate": ["./packages/gate/src/index.ts"], + "@reaatech/rag-eval-dataset": ["./packages/dataset/src/index.ts"], + "@reaatech/rag-eval-observability": ["./packages/observability/src/index.ts"], + "@reaatech/rag-eval-suite": ["./packages/suite/src/index.ts"], + "@reaatech/rag-eval-mcp-server": ["./packages/mcp-server/src/index.ts"], + "@reaatech/rag-eval-cli": ["./packages/cli/src/index.ts"] + } + } +} diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..cd83e4f --- /dev/null +++ b/turbo.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": ["**/.env.*local"], + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "test": { + "dependsOn": ["build"] + }, + "test:coverage": { + "dependsOn": ["build"] + }, + "lint": {}, + "typecheck": { + "dependsOn": ["^build"] + }, + "clean": { + "cache": false + } + } +} diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index 2403a7a..0000000 --- a/vitest.config.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import path from 'path'; - -export default defineConfig({ - test: { - globals: true, - environment: 'node', - include: ['tests/**/*.test.ts'], - exclude: ['node_modules', 'dist', 'coverage'], - coverage: { - provider: 'v8', - reporter: ['text', 'json', 'html'], - include: ['src/**/*'], - exclude: ['src/index.ts', 'src/cli.ts', 'src/mcp-server/**', 'src/observability/**'], - thresholds: { - global: { - statements: 80, - branches: 75, - functions: 80, - lines: 80, - }, - }, - }, - testTimeout: 30000, - hookTimeout: 10000, - setupFiles: ['tests/setup.ts'], - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, -}); From 9bf272b24ec86d32986a4875a54999192e9dc1d4 Mon Sep 17 00:00:00 2001 From: reaatech <138725666+reaatech@users.noreply.github.com> Date: Sat, 2 May 2026 11:08:53 -0700 Subject: [PATCH 2/5] refactor: update CI, skills, docs and configs for monorepo structure - Rewrite CI workflow with A2A-matched job separation (install, audit, format, lint, typecheck, build, test matrix, coverage, docker, all-checks) - Update release workflow to changesets-based publish with npm + GitHub Packages mirror - Rewrite AGENTS.md with 10-package monorepo structure, tooling table, and updated imports - Rewrite ARCHITECTURE.md with package dependency graph, build system diagram, and package-annotated components - Update root README with A2A-matched format: badges, features, package table, documentation links - Fix all 9 skill files to use @reaatech/rag-eval-* package imports instead of monolithic import - Update CI examples in eval workflow for pnpm monorepo - Remove all references to removed GITHUB_TO_NPM.md and ABC_REMEDIATION.md --- .dockerignore | 20 +- .env.example | 18 +- .github/workflows/ci.yml | 326 +++++++++++++++--- .github/workflows/eval.yml | 29 +- .github/workflows/release.yml | 72 ++-- .gitignore | 43 +-- .nvmrc | 2 +- AGENTS.md | 288 +++++++++------- ARCHITECTURE.md | 419 ++++++++++++------------ README.md | 340 +++++-------------- skills/context-precision/skill.md | 2 +- skills/context-recall/skill.md | 2 +- skills/cost-accounting/skill.md | 2 +- skills/dataset-management/skill.md | 2 +- skills/eval-gating/skill.md | 2 +- skills/faithfulness-eval/skill.md | 2 +- skills/llm-judge-rag/skill.md | 2 +- skills/rag-eval-suite/skill.md | 2 +- skills/relevance-eval/skill.md | 2 +- tests/integration/eval-pipeline.test.ts | 19 +- tsconfig.json | 27 +- 21 files changed, 891 insertions(+), 730 deletions(-) diff --git a/.dockerignore b/.dockerignore index d7db622..74e6b88 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,17 +1,15 @@ node_modules -npm-debug.log +.pnpm-store +dist +build +*.tsbuildinfo .git -.gitignore -README.md -.nvmrc -.env -.env.* -.nyc_output +.github coverage -dist -docs -tests .vscode .idea *.log -*.tsbuildinfo +.env +.env.* +.DS_Store +Thumbs.db diff --git a/.env.example b/.env.example index 9ff294d..ca8ffa8 100644 --- a/.env.example +++ b/.env.example @@ -1,12 +1,10 @@ -# LLM API Keys (at least one required for LLM-as-judge) -ANTHROPIC_API_KEY=sk-ant-your-key-here -OPENAI_API_KEY=sk-your-key-here -GOOGLE_API_KEY=your-key-here +# Runtime environment +NODE_ENV=development -# Observability (optional) -OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 -OTEL_SERVICE_NAME=rag-eval-pack +# Pino log level (trace, debug, info, warn, error, fatal) +LOG_LEVEL=info -# Evaluation Settings (optional) -RAG_EVAL_DEFAULT_MODEL=claude-sonnet-4-6 -RAG_EVAL_DEFAULT_BUDGET=10.00 +# LLM Provider API Keys (for judge evaluation) +ANTHROPIC_API_KEY=sk-ant-xxx +OPENAI_API_KEY=sk-xxx +GOOGLE_API_KEY=xxx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae43c79..5a541d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,108 +6,340 @@ on: pull_request: branches: [main] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + NODE_VERSION: 22 + jobs: - # ─────────────────────────────────────────────── - # Stage 1 β€” Build & Code Quality (parallel) - # ─────────────────────────────────────────────── - build: - name: Build + install: + name: Install Dependencies runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version-file: '.nvmrc' - cache: 'npm' + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' - name: Install dependencies - run: npm ci - - - name: Build - run: npm run build + run: pnpm install --frozen-lockfile - - name: Upload build artifacts - uses: actions/upload-artifact@v4 + - name: Save pnpm store + uses: actions/cache@v4 with: - name: dist - path: dist/ + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} - code-quality: - name: Code Quality + audit: + name: Security Audit runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version-file: '.nvmrc' - cache: 'npm' + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' - name: Install dependencies - run: npm ci + run: pnpm install --frozen-lockfile + + - name: Audit dependencies + run: pnpm audit --audit-level moderate + + format: + name: Code Format + runs-on: ubuntu-latest + needs: install + steps: + - name: Checkout + uses: actions/checkout@v4 - - name: Audit - run: npm audit --audit-level=high + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' + + - name: Restore dependencies + uses: actions/cache@v4 + with: + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} + + - name: Check formatting + run: pnpm biome format --write . && git diff --exit-code + + lint: + name: Lint + runs-on: ubuntu-latest + needs: install + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' + + - name: Restore dependencies + uses: actions/cache@v4 + with: + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} - name: Lint - run: npm run lint + run: pnpm lint + + typecheck: + name: Type Check + runs-on: ubuntu-latest + needs: install + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' + + - name: Restore dependencies + uses: actions/cache@v4 + with: + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} - name: Type check - run: npm run typecheck + run: pnpm typecheck - - name: Check formatting - run: npm run prettier + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, typecheck] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' + + - name: Restore dependencies + uses: actions/cache@v4 + with: + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} + + - name: Re-link workspace packages + run: pnpm install --frozen-lockfile --prefer-offline + + - name: Build packages + run: pnpm build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-dist + path: packages/*/dist + retention-days: 1 - # ─────────────────────────────────────────────── - # Stage 2 β€” Tests & Docker (depend on Stage 1) - # ─────────────────────────────────────────────── test: - name: Tests - needs: [build, code-quality] + name: Test runs-on: ubuntu-latest + needs: build + strategy: + fail-fast: false + matrix: + node-version: [20, 22] steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: - node-version-file: '.nvmrc' - cache: 'npm' + node-version: ${{ matrix.node-version }} + cache: 'pnpm' - - name: Install dependencies - run: npm ci + - name: Restore dependencies + uses: actions/cache@v4 + with: + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} + + - name: Re-link workspace packages + run: pnpm install --frozen-lockfile --prefer-offline - name: Download build artifacts uses: actions/download-artifact@v4 with: - name: dist - path: dist/ + name: build-dist - name: Run tests - run: npm test + run: pnpm test + + coverage: + name: Coverage + runs-on: ubuntu-latest + needs: build + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' + + - name: Restore dependencies + uses: actions/cache@v4 + with: + path: | + ~/.local/share/pnpm/store + node_modules + */*/node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} + + - name: Re-link workspace packages + run: pnpm install --frozen-lockfile --prefer-offline + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-dist - name: Run tests with coverage - run: npm run test:coverage + run: pnpm test:coverage - - name: Upload coverage - uses: codecov/codecov-action@v4 + - name: Upload coverage reports + uses: actions/upload-artifact@v4 with: - files: ./coverage/coverage-final.json - fail_ci_if_error: false + name: coverage-reports + path: packages/*/coverage + retention-days: 7 - docker: + - name: Post coverage summary + run: | + echo '## Test Coverage Summary' >> $GITHUB_STEP_SUMMARY + for pkg in packages/*/coverage/coverage-summary.json; do + if [ -f "$pkg" ]; then + name=$(basename $(dirname $(dirname "$pkg"))) + lines=$(jq -r '.total.lines.pct // "N/A"' "$pkg") + funcs=$(jq -r '.total.functions.pct // "N/A"' "$pkg") + branches=$(jq -r '.total.branches.pct // "N/A"' "$pkg") + echo "| $name | $lines% | $funcs% | $branches% |" >> $GITHUB_STEP_SUMMARY + fi + done + + docker-build: name: Docker Build - needs: [build, code-quality] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build Docker image - run: docker build -t rag-eval-pack:ci . + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/Dockerfile + push: false + tags: rag-eval-pack:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + docker-compose: + name: Docker Compose + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Validate Docker Compose + working-directory: ./docker + run: docker compose config + + all-checks: + name: All Checks Passed + runs-on: ubuntu-latest + needs: [audit, format, lint, typecheck, build, test, coverage, docker-build, docker-compose] + if: always() + steps: + - name: Check all jobs passed + run: | + check() { + if [ "$1" != "success" ]; then + echo "$2 did not succeed: $1" + exit 1 + fi + } + check '${{ needs.audit.result }}' 'Security Audit' + check '${{ needs.format.result }}' 'Code Format' + check '${{ needs.lint.result }}' 'Lint' + check '${{ needs.typecheck.result }}' 'Type Check' + check '${{ needs.build.result }}' 'Build' + check '${{ needs.test.result }}' 'Test' + check '${{ needs.coverage.result }}' 'Coverage' + check '${{ needs.docker-build.result }}' 'Docker Build' + check '${{ needs.docker-compose.result }}' 'Docker Compose' + echo "All checks passed!" diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index 41b5576..7d5966e 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -12,30 +12,33 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' - cache: 'npm' + cache: 'pnpm' - name: Install dependencies - run: npm ci + run: pnpm install --frozen-lockfile - name: Build - run: npm run build + run: pnpm build - name: Run evaluation env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | - npx rag-eval-pack evaluate \ + node packages/cli/dist/cli.js evaluate \ --dataset datasets/examples/samples.jsonl \ --config datasets/examples/config.yaml \ --output results/eval-results.json - name: Run regression gates run: | - npx rag-eval-pack gate \ + node packages/cli/dist/cli.js gate \ --results results/eval-results.json \ --gates datasets/examples/gates.yaml \ --baseline results/baseline.json @@ -55,13 +58,13 @@ jobs: with: script: | const fs = require('fs'); - + try { const results = JSON.parse(fs.readFileSync('results/eval-results.json', 'utf8')); const metrics = results.metrics; - - const comment = `## πŸ“Š RAG Evaluation Results - + + const comment = `## RAG Evaluation Results + | Metric | Score | |--------|-------| | Faithfulness | ${metrics.avg_faithfulness?.toFixed(3) || 'N/A'} | @@ -70,12 +73,12 @@ jobs: | Context Recall | ${metrics.avg_context_recall?.toFixed(3) || 'N/A'} | | Overall Score | ${metrics.overall_score?.toFixed(3) || 'N/A'} | | Cost per Sample | $${metrics.cost_per_sample?.toFixed(4) || 'N/A'} | - + **Samples:** ${metrics.total_samples || 0} **Total Cost:** $${results.total_cost?.toFixed(2) || '0.00'} - - ${process.exitCode === 0 ? 'βœ… **All gates passed!**' : '❌ **Some gates failed.** Check the artifacts for details.'}`; - + + ${process.exitCode === 0 ? 'All gates passed!' : 'Some gates failed. Check the artifacts for details.'}`; + github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d87213a..67b2c80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,48 +1,72 @@ name: Release on: - push: - tags: - - 'v*' + workflow_dispatch: + # Add `push: branches: [main]` AFTER the first manual publish succeeds. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +env: + NODE_VERSION: 22 jobs: release: - name: Publish Release + name: Release runs-on: ubuntu-latest permissions: contents: write + pull-requests: write + id-token: write packages: write steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version-file: '.nvmrc' + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' registry-url: 'https://registry.npmjs.org' - cache: 'npm' - name: Install dependencies - run: npm ci - - - name: Run tests - run: npm test + run: pnpm install --frozen-lockfile - - name: Build - run: npm run build + - name: Build packages + run: pnpm build - - name: Publish to npm - run: npm publish --access public + - name: Create release PR or publish to npm + id: changesets + uses: changesets/action@v1 + with: + publish: pnpm release + version: pnpm version-packages + commit: 'chore(release): version packages' + title: 'chore(release): version packages' env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Build Docker image - run: docker build -t rag-eval-pack:${{ github.ref_name }} . + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: 'true' - - name: Create GitHub Release - uses: softprops/action-gh-release@v1 - with: - generate_release_notes: true - files: | - dist/*.js + - name: Mirror published packages to GitHub Packages + if: steps.changesets.outputs.published == 'true' + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} + run: | + cat > .npmrc < $dir" + (cd "$dir" && npm publish --registry=https://npm.pkg.github.com) + done diff --git a/.gitignore b/.gitignore index 9db95c9..0cc939e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,40 +1,45 @@ # Dependencies node_modules/ +.pnpm-store/ -# Build output +# Build outputs dist/ +build/ +*.tsbuildinfo -# Test coverage -coverage/ +# Stray build artifacts inside src/ (tsup output belongs in dist/ only) +packages/*/src/**/*.js +packages/*/src/**/*.js.map +packages/*/src/**/*.d.ts +packages/*/src/**/*.d.ts.map -# Environment files +# Logs +logs/ +*.log +npm-debug.log* +pnpm-debug.log* + +# Environment .env .env.local .env.*.local # IDE -.claude/ -.idea/ .vscode/ +.idea/ +.claude/ *.swp *.swo -# OS files +# OS .DS_Store Thumbs.db -# Logs -*.log -logs/ - -# Temp files -tmp/ -temp/ -*.tmp +# Test +coverage/ -# Test outputs -results.json -*.results.json +# Turborepo +.turbo/ -# Project-specific +# Development DEV_PLAN.md diff --git a/.nvmrc b/.nvmrc index 7d41c73..2bd5a0a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.14.0 +22 diff --git a/AGENTS.md b/AGENTS.md index 65736f4..812f6c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,12 +11,87 @@ confidence_threshold: 0.9 ## What this is -This document defines how to use `rag-eval-pack` to evaluate RAG (Retrieval-Augmented Generation) systems through comprehensive metrics including faithfulness, answer relevance, context precision/recall, with cost accounting and CI gates. It covers the three-layer MCP tool architecture (judge/suite/gate), LLM-as-judge with calibration, and CI integration patterns. +This document defines how to use `rag-eval-pack` to evaluate RAG (Retrieval-Augmented Generation) systems through comprehensive metrics including faithfulness, answer relevance, context precision/recall, with cost accounting and CI gates. It covers the 10-package monorepo structure, three-layer MCP tool architecture (judge/suite/gate), LLM-as-judge with calibration, and CI integration patterns. **Target audience:** Engineers building production RAG systems who need to evaluate retrieval and generation quality, optimize costs, ensure quality, and prevent regressions in CI/CD pipelines. --- +## Monorepo Structure + +``` +rag-eval-pack/ +β”œβ”€β”€ packages/ +β”‚ β”œβ”€β”€ core/ # @reaatech/rag-eval-core +β”‚ β”œβ”€β”€ metrics/ # @reaatech/rag-eval-metrics +β”‚ β”œβ”€β”€ cost/ # @reaatech/rag-eval-cost +β”‚ β”œβ”€β”€ judge/ # @reaatech/rag-eval-judge +β”‚ β”œβ”€β”€ gate/ # @reaatech/rag-eval-gate +β”‚ β”œβ”€β”€ dataset/ # @reaatech/rag-eval-dataset +β”‚ β”œβ”€β”€ observability/ # @reaatech/rag-eval-observability +β”‚ β”œβ”€β”€ suite/ # @reaatech/rag-eval-suite +β”‚ β”œβ”€β”€ mcp-server/ # @reaatech/rag-eval-mcp-server +β”‚ └── cli/ # @reaatech/rag-eval-cli +β”œβ”€β”€ pnpm-workspace.yaml +β”œβ”€β”€ turbo.json +β”œβ”€β”€ biome.json +β”œβ”€β”€ tsconfig.json +└── .github/workflows/ +``` + +### Package Dependency Graph + +``` +core ← metrics ← suite ← mcp-server, cli + ↑ ↑ + β”œβ”€β”€ cost ← judge ← suite, cli + β”œβ”€β”€ gate ← suite, mcp-server, cli + β”œβ”€β”€ dataset ← suite, cli + └── observability (standalone) +``` + +### Key Components + +| Component | Package | Purpose | +|-----------|---------|---------| +| **Types & Schemas** | `@reaatech/rag-eval-core` | Domain types, Zod schemas | +| **Faithfulness Scorer** | `@reaatech/rag-eval-metrics` | Measure answer grounding in context | +| **Relevance Scorer** | `@reaatech/rag-eval-metrics` | Measure answer relevance to query | +| **Context Precision** | `@reaatech/rag-eval-metrics` | Measure retrieval ranking quality | +| **Context Recall** | `@reaatech/rag-eval-metrics` | Measure ground truth coverage | +| **LLM Judge** | `@reaatech/rag-eval-judge` | Calibrated quality scoring with multi-provider support | +| **Cost Tracker** | `@reaatech/rag-eval-cost` | Per-evaluation cost calculation and budget enforcement | +| **Gate Engine** | `@reaatech/rag-eval-gate` | CI regression gates and threshold checks | +| **Dataset Manager** | `@reaatech/rag-eval-dataset` | Dataset loading, validation, generation | +| **Observability** | `@reaatech/rag-eval-observability` | Structured logging, OTel tracing, metrics | +| **Evaluation Suite** | `@reaatech/rag-eval-suite` | Central orchestrator tying all modules together | +| **MCP Server** | `@reaatech/rag-eval-mcp-server` | Three-layer MCP tool exposure | +| **CLI** | `@reaatech/rag-eval-cli` | CLI commands and master barrel re-export | + +### Tooling + +| Tool | Purpose | +|------|---------| +| **pnpm** (10.22) | Package manager with workspace support | +| **turbo** (2.5) | Monorepo build orchestration | +| **biome** (1.9) | Linting and formatting (replaces eslint + prettier) | +| **tsup** (8.4) | Per-package build (cjs + esm + dts) | +| **changesets** (2.28) | Versioning and changelog generation | +| **vitest** (3.2) | Test runner | +| **TypeScript** (5.8) | Type checking | + +### Dev Commands + +```bash +pnpm build # Build all packages (turbo) +pnpm test # Run all tests (turbo) +pnpm lint # Lint all files (biome) +pnpm typecheck # Type-check cross-package imports +pnpm changeset # Create a changeset for versioning +``` + +--- + ## Architecture Overview ``` @@ -38,19 +113,6 @@ This document defines how to use `rag-eval-pack` to evaluate RAG (Retrieval-Augm β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -### Key Components - -| Component | Location | Purpose | -|-----------|----------|---------| -| **Faithfulness Scorer** | `src/metrics/faithfulness.ts` | Measure answer grounding in context | -| **Relevance Scorer** | `src/metrics/relevance.ts` | Measure answer relevance to query | -| **Context Precision** | `src/metrics/context-precision.ts` | Measure retrieval ranking quality | -| **Context Recall** | `src/metrics/context-recall.ts` | Measure ground truth coverage | -| **LLM Judge** | `src/judge/` | Calibrated quality scoring | -| **Cost Tracker** | `src/cost/` | Per-evaluation cost calculation | -| **Gate Engine** | `src/gate/` | CI regression gates | -| **MCP Server** | `src/mcp-server/` | Three-layer tool exposure | - --- ## Three-Layer MCP Tool Architecture @@ -167,25 +229,31 @@ Opinionated, blocking operations for CI/CD: judge: # Primary judge model (any provider) model: claude-opus - + # Fallback models for resilience fallback_models: - gpt-4-turbo - gemini-pro - + # Calibration settings calibration: enabled: true human_labels: 'calibration/human-labels.jsonl' calibration_method: 'temperature_scaling' - + # Consensus settings consensus: enabled: true - models: [claude-opus, gpt-4-turbo] + models: + - id: claude-opus + weight: 0.5 + - id: gpt-4-turbo + weight: 0.3 + - id: gemini-pro + weight: 0.2 voting_strategy: weighted tie_breaker: highest_confidence - + # Cost controls cost: budget_limit: 50.00 @@ -201,14 +269,14 @@ judge: 4. **Apply calibration** to future judge scores ```typescript -import { JudgeCalibrator } from 'rag-eval-pack'; +import { JudgeCalibrator } from '@reaatech/rag-eval-judge'; const calibrator = new JudgeCalibrator({ humanLabelsPath: 'calibration/human-labels.jsonl', method: 'temperature_scaling', }); -await calibrator.calibrate(); +await calibrator.train(); // Apply calibration to new scores const calibratedScore = calibrator.apply(rawScore); @@ -252,13 +320,13 @@ cost: gemini-pro: input: 2.50 output: 7.50 - + # Budget settings budgets: per_sample: 0.05 per_run: 10.00 daily: 100.00 - + # Alert thresholds alerts: - threshold: 0.5 @@ -278,15 +346,18 @@ The pack tracks costs at multiple levels: "run_id": "eval-123", "total_cost": 1.234, "breakdown": { - "faithfulness_judge": 0.500, - "relevance_judge": 0.250, - "context_precision": 0.000, - "context_recall": 0.000 - }, - "per_sample": [ - { "sample_id": 1, "cost": 0.012, "tokens": { "input": 500, "output": 50 } }, - { "sample_id": 2, "cost": 0.011, "tokens": { "input": 450, "output": 45 } } - ] + "total": 1.234, + "by_metric": { + "faithfulness_judge": 0.500, + "relevance_judge": 0.250 + }, + "by_provider": { + "anthropic": 0.750 + }, + "per_sample": [ + { "sample_id": "sample-1", "cost": 0.012, "tokens": { "input": 500, "output": 50 } } + ] + } } ``` @@ -309,51 +380,46 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - name: Run evaluation suite + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - name: Run evaluation + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | - npx rag-eval-pack evaluate \ - --dataset datasets/eval-samples.jsonl \ - --config eval-config.yaml \ - --output results.json - + node packages/cli/dist/cli.js evaluate \ + --dataset datasets/examples/samples.jsonl \ + --config datasets/examples/config.yaml \ + --output results/eval-results.json + - name: Run regression gates run: | - npx rag-eval-pack gate \ - --results results.json \ - --gates gates.yaml \ + node packages/cli/dist/cli.js gate \ + --results results/eval-results.json \ + --gates datasets/examples/gates.yaml \ --baseline results/baseline.json - - - name: Upload results + continue-on-error: true + id: gate-check + + - name: Upload evaluation results if: always() uses: actions/upload-artifact@v4 with: name: eval-results path: results/ - - - name: Comment on PR - if: always() - uses: actions/github-script@v7 - with: - script: | - const results = require('./results.json'); - const comment = `## Evaluation Results - - **Overall Score:** ${results.overall_score} - **Faithfulness:** ${results.avg_faithfulness} - **Relevance:** ${results.avg_relevance} - **Context Precision:** ${results.avg_context_precision} - **Context Recall:** ${results.avg_context_recall} - **Gates:** ${results.gates_passed ? 'βœ… Passed' : '❌ Failed'} - - ${results.regressions.length > 0 ? '**Regressions:**\n' + results.regressions.map(r => `- ${r.metric}: ${r.baseline} β†’ ${r.current}`).join('\n') : ''}`; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); + + - name: Fail if gates failed + if: steps.gate-check.outcome == 'failure' + run: exit 1 ``` ### Gate Configuration @@ -363,13 +429,13 @@ jobs: gates: - name: min-faithfulness type: threshold - metric: avg_faithfulness_score + metric: avg_faithfulness operator: ">=" threshold: 0.85 - name: min-relevance type: threshold - metric: avg_relevance_score + metric: avg_relevance operator: ">=" threshold: 0.80 @@ -393,7 +459,6 @@ gates: - name: no-regression type: baseline-comparison - baseline: results/baseline.json metric: overall_score allow_regression: false ``` @@ -402,36 +467,27 @@ gates: ## Using with RAG Systems -### Integration with hybrid-rag-qdrant - -Use rag-eval-pack to evaluate outputs from hybrid-rag-qdrant: +### Integration Example ```typescript -import { RAGPipeline } from 'hybrid-rag-qdrant'; -import { EvaluationEngine, FaithfulnessScorer, RelevanceScorer } from 'rag-eval-pack'; - -const rag = new RAGPipeline({ /* config */ }); -const evalEngine = new EvaluationEngine({ /* config */ }); - -// Run RAG on test queries -const results = []; -for (const sample of evalDataset) { - const ragResult = await rag.query(sample.query); - results.push({ - query: sample.query, - context: ragResult.chunks.map(c => c.content), - ground_truth: sample.ground_truth, - generated_answer: ragResult.answer, - }); -} +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; +import { FaithfulnessScorer } from '@reaatech/rag-eval-metrics'; + +const suite = new EvaluationSuite({ + metrics: ['faithfulness', 'relevance', 'context_precision', 'context_recall'], + judge: { model: 'claude-opus' }, + cost: { budget_limit: 10.00 }, + gates: [ + { name: 'min-faithfulness', type: 'threshold', metric: 'avg_faithfulness', operator: '>=', threshold: 0.85 }, + ], +}); -// Evaluate results -const evalResults = await evalEngine.evaluate(results); +const result = await suite.runFromFile('datasets/eval-samples.jsonl'); -console.log(`Faithfulness: ${evalResults.avg_faithfulness}`); -console.log(`Relevance: ${evalResults.avg_relevance}`); -console.log(`Context Precision: ${evalResults.avg_context_precision}`); -console.log(`Context Recall: ${evalResults.avg_context_recall}`); +console.log(`Faithfulness: ${result.results.metrics.avg_faithfulness}`); +console.log(`Relevance: ${result.results.metrics.avg_relevance}`); +console.log(`Context Precision: ${result.results.metrics.avg_context_precision}`); +console.log(`Context Recall: ${result.results.metrics.avg_context_recall}`); ``` ### Multi-Agent Workflow @@ -440,7 +496,7 @@ console.log(`Context Recall: ${evalResults.avg_context_recall}`); User Query β†’ agent-mesh (orchestrator) β”‚ β–Ό - RAG Retrieval (hybrid-rag-qdrant) + RAG Retrieval β”‚ β–Ό Answer Generation @@ -491,8 +547,6 @@ const runResult = await agent.call('rag_eval.suite.run', { const results = await agent.call('rag_eval.suite.results', { run_id: runResult.run_id, }); - -// Analyze results for improvements ``` ### Pattern 3: CI Gate Enforcement @@ -506,7 +560,6 @@ const gateResult = await agent.call('rag_eval.gate.run', { }); if (!gateResult.passed) { - // Block deployment process.exit(1); } ``` @@ -516,7 +569,6 @@ if (!gateResult.passed) { Monitor and control evaluation costs: ```typescript -// Check budget before expensive operation const budget = await agent.call('rag_eval.judge.cost_check', { eval_result: partialResults, budget: { daily_limit: 50.00 }, @@ -537,14 +589,14 @@ return await agent.call('rag_eval.judge.faithfulness', { /* */ }); ### PII Handling -- **Never log raw content** β€” only hashed identifiers -- **Query text truncated in logs** β€” first 100 characters only -- **Exports sanitized** β€” PII removed before export -- **Context data protected** β€” sensitive information redacted +- Never log raw content β€” only hashed identifiers +- Query text truncated in logs β€” first 100 characters only +- Exports sanitized β€” PII removed before export +- Context data protected β€” sensitive information redacted ### API Key Management -- All LLM API keys from environment variables +- All LLM API keys from environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`) - Never log API keys or tokens - Separate keys per provider for isolation - Key rotation supported without downtime @@ -552,15 +604,12 @@ return await agent.call('rag_eval.judge.faithfulness', { /* */ }); ### Cost Controls ```typescript -const engine = new EvaluationEngine({ - // ... config - costControls: { - maxCostPerSample: 0.05, - maxCostPerRun: 10.00, - maxCostPerDay: 100.00, - alertThresholds: [0.5, 0.75, 0.9], - hardLimit: true, - }, +import { CostTracker } from '@reaatech/rag-eval-cost'; + +const tracker = new CostTracker({ + budgetLimit: 100.00, + hardLimit: true, + alertThresholds: [0.5, 0.75, 0.9], }); ``` @@ -620,15 +669,16 @@ Before deploying a RAG evaluation pipeline to production: - [ ] Reproducibility verified (same inputs β†’ same outputs) - [ ] Provider fallbacks configured for resilience - [ ] Rate limits configured per provider +- [ ] npm token created and added as GitHub secret (`NPM_TOKEN`) +- [ ] GitHub Actions workflow permissions set to read/write +- [ ] First manual publish completed --- ## References -- **ARCHITECTURE.md** β€” System design deep dive +- **ARCHITECTURE.md** β€” System design deep dive and package relationships - **DEV_PLAN.md** β€” Development checklist - **README.md** β€” Quick start and overview - **datasets/examples/** β€” Example evaluation datasets - **MCP Specification** β€” https://modelcontextprotocol.io/ -- **agent-eval-harness/AGENTS.md** β€” Agent trajectory evaluation patterns -- **hybrid-rag-qdrant/AGENTS.md** β€” RAG pipeline patterns diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0c283f0..ec06021 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -7,15 +7,16 @@ β”‚ Client Layer β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ CLI β”‚ β”‚ Library β”‚ β”‚ MCP Client β”‚ β”‚ -β”‚ β”‚ (npx) β”‚ β”‚ (import) β”‚ β”‚ (Agent) β”‚ β”‚ +β”‚ β”‚ (packages/ β”‚ β”‚ (import) β”‚ β”‚ (Agent) β”‚ β”‚ +β”‚ β”‚ cli) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β–Ό + β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Evaluation Core Engine β”‚ +β”‚ Evaluation Suite (@reaatech/rag-eval-suite) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Three-Layer Architecture β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ @@ -26,9 +27,9 @@ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β–Ό + β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Metrics Engine β”‚ +β”‚ Metrics Engine (@reaatech/rag-eval-metrics) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Faithfulnessβ”‚ β”‚ Relevance β”‚ β”‚ Context β”‚ β”‚ Context β”‚ β”‚ β”‚ β”‚ Scorer β”‚ β”‚ Scorer β”‚ β”‚ Precision β”‚ β”‚ Recall β”‚ β”‚ @@ -37,119 +38,148 @@ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ LLM Judge β”‚ β”‚ +β”‚ β”‚ LLM Judge β”‚ (@reaatech/rag-eval-judge) β”‚ β”‚ β”‚ (Calibrated) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β–Ό + β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Cross-Cutting Concerns β”‚ +β”‚ Cross-Cutting Packages β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Dataset Manager β”‚ β”‚ Observability β”‚ β”‚ Reproducibility β”‚ β”‚ -β”‚ β”‚ - Versioning β”‚ β”‚ - Tracing (OTel)β”‚ β”‚ - Seed mgmt β”‚ β”‚ -β”‚ β”‚ - Validation β”‚ β”‚ - Metrics (OTel)β”‚ β”‚ - Deterministic β”‚ β”‚ -β”‚ β”‚ - Generation β”‚ β”‚ - Logging (pino)β”‚ β”‚ - Versioning β”‚ β”‚ +β”‚ β”‚ Dataset Manager β”‚ β”‚ Observability β”‚ β”‚ Cost Tracker β”‚ β”‚ +β”‚ β”‚ (rag-eval- β”‚ β”‚ (rag-eval- β”‚ β”‚ (rag-eval- β”‚ β”‚ +β”‚ β”‚ dataset) β”‚ β”‚ observability) β”‚ β”‚ cost) β”‚ β”‚ +β”‚ β”‚ - Loading β”‚ β”‚ - Tracing (OTel)β”‚ β”‚ - Pricing β”‚ β”‚ +β”‚ β”‚ - Validation β”‚ β”‚ - Metrics (OTel)β”‚ β”‚ - Budgeting β”‚ β”‚ +β”‚ β”‚ - Generation β”‚ β”‚ - Logging (pino)β”‚ β”‚ - Reporting β”‚ β”‚ +β”‚ β”‚ - Versioning β”‚ β”‚ - Dashboard β”‚ β”‚ - Enforcement β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- +## Package Architecture + +### Dependency Graph + +``` +core ← metrics ← suite ← mcp-server, cli + ↑ ↑ + β”œβ”€β”€ cost ← judge ← suite, cli + β”œβ”€β”€ gate ← suite, mcp-server, cli + β”œβ”€β”€ dataset ← suite, cli + └── observability (standalone, re-exported by cli) +``` + +### Package Roles + +| Package | Role | Depends On | Key Exports | +|---------|------|------------|-------------| +| `@reaatech/rag-eval-core` | Foundation types + Zod schemas | (leaf) | `EvaluationSample`, `EvalSuiteConfig`, `GateConfig`, `JudgeConfig`, `CostBreakdown`, schemas | +| `@reaatech/rag-eval-metrics` | Heuristic metric scorers | core | `FaithfulnessScorer`, `RelevanceScorer`, `ContextPrecisionScorer`, `ContextRecallScorer`, `MetricsEngine` | +| `@reaatech/rag-eval-cost` | Cost tracking infrastructure | core | `CostTracker`, `Pricing`, `BudgetManager`, `CostReporter` | +| `@reaatech/rag-eval-judge` | LLM-as-judge | core, cost | `JudgeEngine`, `JudgeCalibrator`, `JudgeCostTracker`, prompts | +| `@reaatech/rag-eval-gate` | Quality gates | core | `GateEngine`, `ThresholdGates`, `BaselineGates`, `CIIntegration` | +| `@reaatech/rag-eval-dataset` | Dataset management | core | `DatasetLoader`, `DatasetValidator`, `DatasetGenerator`, `DatasetVersioning` | +| `@reaatech/rag-eval-observability` | Logging, tracing, metrics | core | `createLogger`, `traceEvalRun`, `recordEvalRun`, `Dashboard` | +| `@reaatech/rag-eval-suite` | Central orchestrator | core, metrics, cost, judge, gate, dataset | `EvaluationSuite` | +| `@reaatech/rag-eval-mcp-server` | MCP server tools | core, metrics, gate, suite | `createMcpServer`, `handleJudgeTool`, `handleSuiteTool`, `handleGateTool` | +| `@reaatech/rag-eval-cli` | CLI + barrel re-export | all of the above | CLI commands, master barrel | + +--- + ## Design Principles -### 1. Three-Layer Architecture +### 1. Composable Packages +- Each package has a single, well-defined responsibility +- Packages depend only on what's below them in the dependency graph +- `@reaatech/rag-eval-core` is the universal leaf β€” every package depends on it +- The CLI package is the master barrel, re-exporting everything for convenience + +### 2. Three-Layer Tool Architecture - **rag_eval.judge.*** β€” Atomic, stateless operations for mid-task self-evaluation - **rag_eval.suite.*** β€” Orchestrated runs for eval-driven development - **rag_eval.gate.*** β€” CI-style pass/fail gates for regression prevention -### 2. Provider-Agnostic -- Any LLM provider can be used for judging (Claude, GPT-4, Gemini, open-source) -- Unified interface for all providers -- Provider-specific optimizations are encapsulated +### 3. Provider-Agnostic +- Any LLM provider can be used for judging (Claude, GPT-4, Gemini) +- Unified interface for all providers via `JudgeEngine` +- Provider-specific optimizations are encapsulated within the judge package -### 3. Reproducibility First +### 4. Reproducibility First - Same inputs always produce same outputs (deterministic seed management) -- Version all configuration and evaluation datasets -- Track eval run metadata for auditability +- All configuration and datasets are versionable +- Run metadata tracked for auditability via `run_id` -### 4. Cost-Aware Evaluation -- LLM-as-judge costs tracked per-request -- Budget limits enforced (soft and hard) -- Cost estimation before running expensive operations +### 5. Cost-Aware Evaluation +- LLM-as-judge costs tracked per-request with token-level detail +- Budget limits enforced at sample, run, and daily levels +- Cost estimation before running expensive operations via `JudgeCostTracker.estimateCost()` -### 5. CI-Native Design -- Exit codes suitable for automation -- JUnit XML and GitHub Actions output formatting -- Fast gate evaluation with caching +### 6. CI-Native Design +- Exit codes suitable for automation (0 = pass, 1 = fail) +- JUnit XML and GitHub Actions output formatting via `CostReporter` +- `CIIntegration` for formatted CI annotations --- -## Component Deep Dive +## Build System -### Three-Layer MCP Tool Architecture +### Monorepo Tooling ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Layer 1: rag_eval.judge.* (Atomic) β”‚ +β”‚ Root Orchestration β”‚ β”‚ β”‚ -β”‚ Fast, stateless, composable operations for mid-task self-evaluation β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ faithfulness β”‚ β”‚ relevance β”‚ β”‚context_precisionβ”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Score answer β”‚ β”‚ Score answer β”‚ β”‚ Score context β”‚ β”‚ -β”‚ β”‚ faithfulness to β”‚ β”‚ relevance to β”‚ β”‚ ranking quality β”‚ β”‚ -β”‚ β”‚ context β”‚ β”‚ user query β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ context_recall β”‚ β”‚ cost_check β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Score context β”‚ β”‚ Verify cost β”‚ β”‚ -β”‚ β”‚ coverage of β”‚ β”‚ within budget β”‚ β”‚ -β”‚ β”‚ ground truth β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ pnpm β”‚ β”‚ turbo β”‚ β”‚ biome β”‚ β”‚changesetsβ”‚ β”‚ +β”‚ β”‚workspacesβ”‚ β”‚ build β”‚ β”‚ lint + β”‚ β”‚ version β”‚ β”‚ +β”‚ β”‚ 10.22 β”‚ β”‚ orchest β”‚ β”‚ format β”‚ β”‚ publish β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β–Ό β–Ό β–Ό β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Per-Package Build β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ tsup src/index.ts --format cjs,esm --dts --clean β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β†’ dist/index.js (ESM) β”‚ β”‚ +β”‚ β”‚ β†’ dist/index.cjs (CJS) β”‚ β”‚ +β”‚ β”‚ β†’ dist/index.d.ts (types) β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Layer 2: rag_eval.suite.* (Orchestrated) β”‚ -β”‚ β”‚ -β”‚ Stateful, longer-running operations for eval-driven development β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ run β”‚ β”‚ status β”‚ β”‚ results β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Execute full β”‚ β”‚ Get evaluation β”‚ β”‚ Retrieve eval β”‚ β”‚ -β”‚ β”‚ evaluation suiteβ”‚ β”‚ run status β”‚ β”‚ results β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ compare β”‚ β”‚ baseline β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Compare two β”‚ β”‚ Set/update β”‚ β”‚ -β”‚ β”‚ evaluation runs β”‚ β”‚ baseline β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +### Build Pipeline (turbo.json) -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Layer 3: rag_eval.gate.* (CI Gates) β”‚ -β”‚ β”‚ -β”‚ Opinionated, blocking operations for CI/CD β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ run β”‚ β”‚ config β”‚ β”‚ diff β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Run CI-style β”‚ β”‚ Get/set gate β”‚ β”‚ Get detailed β”‚ β”‚ -β”‚ β”‚ pass/fail gate β”‚ β”‚ configuration β”‚ β”‚ diff from base β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +```json +{ + "tasks": { + "build": { + "dependsOn": ["^build"], // Build dependencies first + "outputs": ["dist/**"] + }, + "test": { + "dependsOn": ["build"] // Tests need built artifacts + }, + "typecheck": { + "dependsOn": ["^build"] // Cross-package types resolved via tsconfig.typecheck.json + } + } +} ``` +--- + +## Component Deep Dive + ### Faithfulness Scorer ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Faithfulness Scorer β”‚ +β”‚ Package: @reaatech/rag-eval-metrics β”‚ β”‚ β”‚ β”‚ Input: { query, context[], generated_answer } β”‚ β”‚ β”‚ @@ -157,13 +187,13 @@ β”‚ β”‚ Statement β”‚ β”‚ Entailment β”‚ β”‚ Score β”‚ β”‚ β”‚ β”‚ Extraction β”‚ β”‚ Check β”‚ β”‚ Aggregation β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ - Extract β”‚ β”‚ - LLM judge β”‚ β”‚ - Percentage of β”‚ β”‚ -β”‚ β”‚ atomic β”‚ β”‚ - Context β”‚ β”‚ statements β”‚ β”‚ -β”‚ β”‚ statements β”‚ β”‚ entailment β”‚ β”‚ supported by β”‚ β”‚ -β”‚ β”‚ from answer β”‚ β”‚ verification β”‚ β”‚ context β”‚ β”‚ +β”‚ β”‚ - NLP-based β”‚ β”‚ - Context β”‚ β”‚ - Percentage of β”‚ β”‚ +β”‚ β”‚ decomposition β”‚ β”‚ entailment β”‚ β”‚ statements β”‚ β”‚ +β”‚ β”‚ - Atomic claims β”‚ β”‚ verification β”‚ β”‚ supported by β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ - Per-statement β”‚ β”‚ context β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ Output: FaithfulnessResult { score, statements, supported_count } β”‚ +β”‚ Output: { score, statements, supported_count, total_count } β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -172,6 +202,7 @@ ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Relevance Scorer β”‚ +β”‚ Package: @reaatech/rag-eval-metrics β”‚ β”‚ β”‚ β”‚ Input: { query, generated_answer } β”‚ β”‚ β”‚ @@ -179,14 +210,14 @@ β”‚ β”‚ Semantic β”‚ β”‚ Intent β”‚ β”‚ Score β”‚ β”‚ β”‚ β”‚ Similarity β”‚ β”‚ Coverage β”‚ β”‚ Aggregation β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ - Embedding- β”‚ β”‚ - Query intent β”‚ β”‚ - Weighted β”‚ β”‚ -β”‚ β”‚ based β”‚ β”‚ extraction β”‚ β”‚ combination β”‚ β”‚ -β”‚ β”‚ similarity β”‚ β”‚ - Answer β”‚ β”‚ - Semantic β”‚ β”‚ -β”‚ β”‚ (cosine) β”‚ β”‚ coverage β”‚ β”‚ similarity + β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ assessment β”‚ β”‚ intent score β”‚ β”‚ +β”‚ β”‚ - Embedding- β”‚ β”‚ - Decompose β”‚ β”‚ - Weighted β”‚ β”‚ +β”‚ β”‚ based β”‚ β”‚ query into β”‚ β”‚ combination β”‚ β”‚ +β”‚ β”‚ similarity β”‚ β”‚ intents β”‚ β”‚ - Semantic β”‚ β”‚ +β”‚ β”‚ (cosine) β”‚ β”‚ - Check answer β”‚ β”‚ similarity + β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ coverage β”‚ β”‚ intent score β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ Output: RelevanceResult { score, semantic_similarity, intent_score}β”‚ +β”‚ Output: { score, semantic_similarity, intent_score, intents } β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -195,6 +226,7 @@ ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Context Precision Scorer β”‚ +β”‚ Package: @reaatech/rag-eval-metrics β”‚ β”‚ β”‚ β”‚ Input: { query, context[], ground_truth } β”‚ β”‚ β”‚ @@ -208,7 +240,7 @@ β”‚ β”‚ relevance β”‚ β”‚ chunk β”‚ β”‚ - Normalized β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ Output: ContextPrecisionResult { score, map, ndcg, ranked_scores } β”‚ +β”‚ Output: { score, map, ndcg, relevant_ranks } β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -217,12 +249,13 @@ ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Context Recall Scorer β”‚ +β”‚ Package: @reaatech/rag-eval-metrics β”‚ β”‚ β”‚ β”‚ Input: { query, context[], ground_truth } β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Ground Truth β”‚ β”‚ Coverage β”‚ β”‚ Score β”‚ β”‚ -β”‚ β”‚ Analysis β”‚ β”‚ Check β”‚ β”‚ Calculation β”‚ β”‚ +β”‚ β”‚ Decomposition β”‚ β”‚ Check β”‚ β”‚ Calculation β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Extract β”‚ β”‚ - Check if each β”‚ β”‚ - Percentage of β”‚ β”‚ β”‚ β”‚ atomic β”‚ β”‚ ground truth β”‚ β”‚ ground truth β”‚ β”‚ @@ -231,7 +264,7 @@ β”‚ β”‚ β”‚ β”‚ any context β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ Output: ContextRecallResult { score, total_facts, covered_facts } β”‚ +β”‚ Output: { score, total_facts, covered_facts } β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -240,19 +273,23 @@ ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ LLM Judge with Calibration β”‚ +β”‚ Package: @reaatech/rag-eval-judge β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Engine β”‚ β”‚ Calibrator β”‚ β”‚ Prompts β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Provider- β”‚ β”‚ - Human label β”‚ β”‚ - Faithfulness β”‚ β”‚ β”‚ β”‚ agnostic β”‚ β”‚ alignment β”‚ β”‚ - Relevance β”‚ β”‚ -β”‚ β”‚ - Batch β”‚ β”‚ - Temperature β”‚ β”‚ - Context β”‚ β”‚ -β”‚ β”‚ processing β”‚ β”‚ scaling β”‚ β”‚ quality β”‚ β”‚ -β”‚ β”‚ - Parallel β”‚ β”‚ - Multi-judge β”‚ β”‚ - Overall β”‚ β”‚ -β”‚ β”‚ requests β”‚ β”‚ consensus β”‚ β”‚ quality β”‚ β”‚ +β”‚ β”‚ - Multi-model β”‚ β”‚ - Temperature β”‚ β”‚ - Context β”‚ β”‚ +β”‚ β”‚ consensus β”‚ β”‚ scaling β”‚ β”‚ precision β”‚ β”‚ +β”‚ β”‚ - Batch β”‚ β”‚ - Isotonic β”‚ β”‚ - Context β”‚ β”‚ +β”‚ β”‚ processing β”‚ β”‚ regression β”‚ β”‚ recall β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Overall β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ quality β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ Output: JudgeScore { score, explanation, confidence, calibrated } β”‚ +β”‚ Providers: Anthropic (Claude), OpenAI (GPT), Google (Gemini) β”‚ +β”‚ Output: { score, explanation, provider, model, metric } β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -261,19 +298,21 @@ ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Cost Tracker β”‚ +β”‚ Package: @reaatech/rag-eval-cost β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Tracker β”‚ β”‚ Budget Manager β”‚ β”‚ Reporter β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ - Per-eval β”‚ β”‚ - Budget β”‚ β”‚ - Cost per β”‚ β”‚ +β”‚ β”‚ - Per-sample β”‚ β”‚ - Budget β”‚ β”‚ - Cost per β”‚ β”‚ β”‚ β”‚ cost β”‚ β”‚ enforcement β”‚ β”‚ evaluation β”‚ β”‚ -β”‚ β”‚ - Provider- β”‚ β”‚ - Alerts and β”‚ β”‚ - Cost per β”‚ β”‚ -β”‚ β”‚ agnostic β”‚ β”‚ warnings β”‚ β”‚ metric β”‚ β”‚ -β”‚ β”‚ - Metric β”‚ β”‚ - Optimization β”‚ β”‚ - Trends β”‚ β”‚ -β”‚ β”‚ breakdown β”‚ β”‚ recommend β”‚ β”‚ - Export β”‚ β”‚ +β”‚ β”‚ - Provider- β”‚ β”‚ - Alert β”‚ β”‚ - Cost per β”‚ β”‚ +β”‚ β”‚ specific β”‚ β”‚ thresholds β”‚ β”‚ metric β”‚ β”‚ +β”‚ β”‚ pricing β”‚ β”‚ (50/75/90%) β”‚ β”‚ - JUnit XML β”‚ β”‚ +β”‚ β”‚ - Metric β”‚ β”‚ - Hard/soft β”‚ β”‚ - Trends β”‚ β”‚ +β”‚ β”‚ breakdown β”‚ β”‚ stop modes β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ Output: CostBreakdown { total_cost, per_metric, per_sample } β”‚ +β”‚ Output: CostBreakdown { total, by_metric, by_provider, per_sample }β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -284,43 +323,44 @@ ### Complete Evaluation Flow ``` -1. Load evaluation dataset (JSONL format) - β”‚ -2. Validate dataset structure: - - Required fields present - - Valid sample format - - Ground truth format - β”‚ -3. For each sample, calculate metrics: - - Faithfulness: extract statements, verify entailment - - Relevance: semantic similarity, intent coverage - - Context Precision: MAP, NDCG calculation - - Context Recall: ground truth coverage - β”‚ -4. Run LLM judge (if configured): - - Provider-agnostic evaluation - - Batch processing with rate limiting - - Cost tracking per judgment - β”‚ -5. Calculate costs: - - Per-sample token counting - - Provider-specific pricing - - Budget compliance check - β”‚ -6. Aggregate results: - - Overall score calculation - - Per-metric breakdown - - Summary statistics - β”‚ -7. Evaluate gates (if configured): - - Threshold checks - - Baseline comparison - - Pass/fail determination - β”‚ -8. Export results: - - JSON report - - CI-compatible output - - Observability data +1. Load dataset via @reaatech/rag-eval-dataset + - JSONL, JSON, or YAML formats + - Zod validation of every sample + β”‚ +2. Run heuristic metrics via @reaatech/rag-eval-metrics + - Parallel execution with configurable concurrency + - Faithfulness: statement extraction β†’ context entailment + - Relevance: semantic similarity + intent coverage + - Context Precision: MAP + NDCG + - Context Recall: fact decomposition β†’ coverage check + β”‚ +3. Run LLM judge via @reaatech/rag-eval-judge (if configured) + - Provider selection with fallback + - Optional consensus voting across multiple models + - Optional calibration against human labels + - Cost estimation before each call + β”‚ +4. Track costs via @reaatech/rag-eval-cost + - Per-sample token counting with tiktoken + - Provider-specific pricing lookup + - Budget enforcement with configurable thresholds + β”‚ +5. Aggregate results via @reaatech/rag-eval-metrics (MetricsEngine) + - Mean scores per metric + - Standard deviation per metric + - Overall weighted score + - Cost per sample + β”‚ +6. Evaluate gates via @reaatech/rag-eval-gate + - Threshold gates (>=, <=, >, <, ==) + - Baseline comparison gates (regression detection) + - Pass/fail determination with failure messages + β”‚ +7. Export results + - SuiteRunResult with run_id, status, metrics, gate_result + - Optional JSON/Markdown output via CLI + - OpenTelemetry traces and metrics + - Structured Pino logging ``` --- @@ -339,12 +379,13 @@ β”‚ Layer 2: API Keys β”‚ β”‚ - All LLM API keys from environment variables β”‚ β”‚ - Never log API keys or tokens β”‚ -β”‚ - Separate keys per provider β”‚ +β”‚ - Separate keys per provider (ANTHROPIC_API_KEY, OPENAI_API_KEY, β”‚ +β”‚ GOOGLE_API_KEY) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Layer 3: Cost Controls β”‚ -β”‚ - Budget limits enforced β”‚ -β”‚ - Cost estimation before expensive operations β”‚ -β”‚ - Real-time cost monitoring with alerts β”‚ +β”‚ - Budget limits enforced per sample, run, and day β”‚ +β”‚ - Cost estimation before expensive LLM operations β”‚ +β”‚ - Real-time cost monitoring with alert thresholds β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Layer 4: Export Security β”‚ β”‚ - PII sanitization before export β”‚ @@ -358,39 +399,37 @@ - Evaluation content is never logged (only hashed identifiers) - Query identifiers are hashed before logging - Exports are sanitized to remove PII -- Configurable PII patterns for redaction +- Context data is redacted before logging --- ## Observability -### Tracing +### Tracing (OpenTelemetry) -Every evaluation run generates OpenTelemetry spans: +| Span | Package | Attributes | +|------|---------|------------| +| `rag_eval.run` | observability | run_id, samples, config, metrics | +| `metric.faithfulness` | observability | run_id, sample_id, statements, supported | +| `metric.relevance` | observability | run_id, sample_id, similarity, intent | +| `metric.context_precision` | observability | run_id, sample_id, map, ndcg | +| `metric.context_recall` | observability | run_id, sample_id, facts, covered | +| `judge.evaluate` | observability | run_id, sample_id, model, provider, cost | +| `gate.check` | observability | run_id, gate_count, passed | -| Span | Attributes | -|------|------------| -| `rag_eval.run` | samples, config, metrics | -| `metric.faithfulness` | statements, supported | -| `metric.relevance` | similarity, intent | -| `metric.context_precision` | map, ndcg | -| `metric.context_recall` | facts, covered | -| `judge.evaluate` | model, samples, cost | -| `gate.check` | gate_count, passed | +### Metrics (OpenTelemetry) -### Metrics +| Metric | Type | Label | Description | +|--------|------|-------|-------------| +| `rag_eval.runs.total` | Counter | status | Total evaluation runs | +| `rag_eval.samples.evaluated` | Counter | dataset | Samples processed | +| `rag_eval.judge.calls` | Counter | model, status | LLM judge API calls | +| `rag_eval.judge.cost` | Histogram | model | Judge cost per run | +| `rag_eval.gates.result` | Gauge | gate_name | Gate pass/fail (1/0) | +| `rag_eval.cost.per_sample` | Histogram | metric | Cost per sample | +| `rag_eval.metrics.score` | Gauge | metric | Metric score value | -| Metric | Type | Labels | Description | -|--------|------|--------|-------------| -| `rag_eval.runs.total` | Counter | `status` | Total evaluation runs | -| `rag_eval.samples.evaluated` | Counter | `dataset` | Samples processed | -| `rag_eval.judge.calls` | Counter | `model`, `status` | LLM judge API calls | -| `rag_eval.judge.cost` | Histogram | `model` | Judge cost per run | -| `rag_eval.gates.result` | Gauge | `gate_name` | Gate pass/fail (1/0) | -| `rag_eval.cost.per_sample` | Histogram | `metric` | Cost per sample | -| `rag_eval.metrics.score` | Gauge | `metric` | Metric score value | - -### Logging +### Logging (Pino) All logs are structured JSON with standard fields: @@ -414,45 +453,17 @@ All logs are structured JSON with standard fields: --- -## Deployment Architecture - -### GCP Cloud Run - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Cloud Run Service β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ rag-eval-pack Container β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Eval β”‚ β”‚ OTel β”‚ β”‚ Secrets β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ Engine β”‚ β”‚ Sidecar β”‚ β”‚ Mounted β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Config: β”‚ -β”‚ - Min instances: 0 (scale to zero) β”‚ -β”‚ - Max instances: 5 (configurable) β”‚ -β”‚ - Memory: 1GB, CPU: 1 vCPU β”‚ -β”‚ - Timeout: 300s (for large evals) β”‚ -β”‚ β”‚ -β”‚ Secrets: Secret Manager β†’ mounted as env vars β”‚ -β”‚ Observability: OTel β†’ Cloud Monitoring / Datadog β”‚ -β”‚ Storage: GCS for datasets and results β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - ## Failure Modes | Failure | Detection | Recovery | |---------|-----------|----------| | Dataset load error | File not found, parse error | Return detailed error, suggest fixes | -| Invalid sample format | Missing required fields | List missing fields, show expected schema | -| LLM API error | Non-2xx response | Retry with backoff, skip sample, continue | -| Budget exceeded | Cost > budget limit | Stop judge, return partial results | +| Invalid sample format | Missing required fields, Zod validation error | List missing fields, show expected schema | +| LLM API error | Non-2xx response, network timeout | Retry with backoff, fallback to alternate provider, skip sample | +| Budget exceeded | Cost > budget limit | Stop LLM judge, return partial results with status "partial" | | Gate evaluation error | Invalid gate config | Log error, fail open (pass) with warning | | Timeout | Request exceeds timeout | Return partial results, log warning | +| Missing provider credentials | API key not set in environment | Fall back to next provider in fallback list | --- @@ -473,8 +484,8 @@ All logs are structured JSON with standard fields: | Component | Cost (USD) | |-----------|------------| | Heuristic metrics | $0.000 | -| LLM Judge (faithfulness) | $0.01 | -| LLM Judge (relevance) | $0.005 | +| LLM Judge (faithfulness, claude-opus) | $0.01 | +| LLM Judge (relevance, claude-opus) | $0.005 | | **Total (with LLM judge)** | **$0.015** | | **Total (heuristic only)** | **$0.000** | @@ -487,5 +498,3 @@ All logs are structured JSON with standard fields: - **README.md** β€” Quick start and overview - **datasets/examples/** β€” Example evaluation datasets - **MCP Specification** β€” https://modelcontextprotocol.io/ -- **agent-eval-harness/ARCHITECTURE.md** β€” Agent trajectory evaluation patterns -- **hybrid-rag-qdrant/ARCHITECTURE.md** β€” RAG pipeline patterns diff --git a/README.md b/README.md index 59f9f2d..81c0064 100644 --- a/README.md +++ b/README.md @@ -1,298 +1,138 @@ # rag-eval-pack -**RAG evaluation metrics with LLM-as-judge, cost accounting, and CI gates.** +[![CI](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml/badge.svg)](https://github.com/reaatech/rag-eval-pack/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.8-blue)](https://www.typescriptlang.org/) -A comprehensive TypeScript toolkit for evaluating Retrieval-Augmented Generation (RAG) systems. Provides four core metrics (faithfulness, answer relevance, context precision, context recall), LLM-as-judge with calibration, cost tracking, and CI-style regression gates. +> Production-grade RAG evaluation toolkit with LLM-as-judge, cost accounting, and CI/CD regression gates. -## Quick Start - -```bash -# Install -npm install rag-eval-pack - -# Run evaluation -npx rag-eval-pack evaluate \ - --dataset datasets/eval-samples.jsonl \ - --config eval-config.yaml \ - --output results.json - -# Run CI gate -npx rag-eval-pack gate \ - --results results.json \ - --gates gates.yaml \ - --baseline results/baseline.json -``` +This monorepo provides a composable suite of packages for evaluating Retrieval-Augmented Generation (RAG) systems across four core metrics β€” faithfulness, relevance, context precision, and context recall β€” with heuristic scoring, LLM-based judging, budget enforcement, and automated quality gating for CI pipelines. ## Features -- **Four Core Metrics** β€” Faithfulness, relevance, context precision, context recall -- **LLM-as-Judge** β€” Provider-agnostic with calibration and consensus voting -- **Cost Accounting** β€” Per-sample, per-run, and per-day cost tracking with budget limits -- **CI Gates** β€” Threshold and baseline-comparison gates for regression prevention -- **Three-Layer MCP Tools** β€” Atomic (judge), orchestrated (suite), and CI (gate) layers -- **Observability** β€” OpenTelemetry tracing, metrics, and structured logging - -## Ecosystem - -This pack is designed to work alongside: - -- **[hybrid-rag-qdrant](https://github.com/reaatech/hybrid-rag-qdrant)** β€” Hybrid search RAG pipeline (dense + sparse retrieval with Qdrant). Feed its outputs directly into `rag-eval-pack` for quality evaluation. -- **[agent-eval-harness](https://github.com/reaatech/agent-eval-harness)** β€” Agent trajectory evaluation. Use it to assess end-to-end agent behavior, then use `rag-eval-pack` to evaluate the RAG-specific quality of retrieved answers. +- **Four evaluation metrics** β€” faithfulness, relevance, context precision, and context recall with heuristic scorers +- **LLM-as-judge** β€” multi-provider judging (Anthropic, OpenAI, Google) with calibration and consensus voting +- **Cost accounting** β€” per-sample and per-run token tracking with budget enforcement and alert thresholds +- **Quality gates** β€” threshold and baseline-comparison gates with formatted CI output and exit codes +- **MCP server** β€” three-layer tool API (`judge.*`, `suite.*`, `gate.*`) for agent-driven evaluation +- **Dataset management** β€” multi-format loading, Zod validation, synthetic generation, and version tracking +- **Observability** β€” structured Pino logging, OpenTelemetry tracing, and Prometheus-compatible metrics +- **Dual ESM/CJS** β€” every package ships `cjs` and `esm` output for maximum compatibility ## Installation -```bash -npm install rag-eval-pack -``` +### Using the packages -### Environment Variables +Packages are published under the `@reaatech` scope and can be installed individually: ```bash -# LLM API keys (at least one required) -export ANTHROPIC_API_KEY=sk-ant-... -export OPENAI_API_KEY=sk-... -export GOOGLE_API_KEY=... - -# Optional: Observability -export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 -export OTEL_SERVICE_NAME=rag-eval-pack -``` +# Core types and schemas +pnpm add @reaatech/rag-eval-core -## Usage +# Metric scorers +pnpm add @reaatech/rag-eval-metrics -### Programmatic API +# LLM judge +pnpm add @reaatech/rag-eval-judge -```typescript -import { - EvaluationSuite, - FaithfulnessScorer, - GateEngine, - type GateConfig, -} from 'rag-eval-pack'; - -// Single metric scoring (heuristic, no LLM call) -const faithfulness = new FaithfulnessScorer(); -const result = await faithfulness.score({ - query: 'What is the refund policy?', - context: ['Refunds within 14 days.'], - ground_truth: 'Refunds must be requested within 14 days.', - generated_answer: 'You have 14 days to request a refund.', -}); -console.log(`Faithfulness: ${result.score}`); +# Cost tracking +pnpm add @reaatech/rag-eval-cost -// Full evaluation suite with LLM judge -const suite = new EvaluationSuite({ - metrics: ['faithfulness', 'relevance', 'context_precision', 'context_recall'], - judge: { model: 'claude-sonnet-4-6' }, - cost: { budget_limit: 10.00 }, -}); +# Quality gates +pnpm add @reaatech/rag-eval-gate -const { results, gate_result } = await suite.runFromFile( - 'datasets/eval-samples.jsonl' -); -console.log(`Overall: ${results.metrics.overall_score}`); - -// CI gate -const gates: GateConfig[] = [ - { - name: 'min-faithfulness', - type: 'threshold', - metric: 'avg_faithfulness', - operator: '>=', - threshold: 0.85, - }, -]; -const gate = new GateEngine(gates); -const gateResult = gate.evaluate(results); -if (!gateResult.passed) { - console.log('Gates failed:', gateResult.failures); - process.exit(1); -} -``` - -### CLI +# Dataset management +pnpm add @reaatech/rag-eval-dataset -```bash -# Evaluate -npx rag-eval-pack evaluate \ - --dataset datasets/eval-samples.jsonl \ - --config eval-config.yaml \ - --output results.json \ - --format json,markdown - -# Gate check -npx rag-eval-pack gate \ - --results results.json \ - --gates gates.yaml \ - --baseline baseline.json - -# Cost report -npx rag-eval-pack cost \ - --results results.json \ - --format json +# Central orchestrator +pnpm add @reaatech/rag-eval-suite # MCP server -npx rag-eval-pack mcp-server -``` +pnpm add @reaatech/rag-eval-mcp-server @modelcontextprotocol/sdk -## Configuration - -### Evaluation Config - -```yaml -# eval-config.yaml -evaluation: - metrics: - - faithfulness - - relevance - - context_precision - - context_recall - - judge: - model: claude-sonnet-4-6 - calibration: - enabled: true - method: temperature_scaling - human_labels: calibration/human-labels.jsonl - consensus: - enabled: true - voting_strategy: weighted - models: - - id: claude-opus-4-7 - weight: 1 - - id: gpt-4o - weight: 1 - - cost: - budget_limit: 10.00 - max_cost_per_sample: 0.10 - - execution: - parallel_jobs: 5 - retry_attempts: 3 -``` +# CLI tool +pnpm add @reaatech/rag-eval-cli -### Gate Config - -```yaml -# gates.yaml -gates: - - name: min-faithfulness - type: threshold - metric: avg_faithfulness - operator: ">=" - threshold: 0.85 - - - name: min-relevance - type: threshold - metric: avg_relevance - operator: ">=" - threshold: 0.80 - - - name: no-regression - type: baseline-comparison - metric: overall_score - allow_regression: false +# Observability utilities +pnpm add @reaatech/rag-eval-observability ``` -### Dataset Format (JSONL) - -```jsonl -{"query": "What is the refund policy?", "context": ["Refunds within 14 days.", "Contact support for help."], "ground_truth": "Refunds must be requested within 14 days by contacting support.", "generated_answer": "You have 14 days to request a refund."} -{"query": "How do I reset my password?", "context": ["Visit /reset-password.", "Enter your email."], "ground_truth": "Go to /reset-password and enter your email.", "generated_answer": "Visit the password reset page and provide your email."} -``` +### Contributing -## MCP Tools +```bash +# Clone the repository +git clone https://github.com/reaatech/rag-eval-pack.git +cd rag-eval-pack -The pack exposes three layers of MCP tools for agent integration: +# Install dependencies +pnpm install -### Layer 1: rag_eval.judge.* (Atomic) +# Build all packages +pnpm build -| Tool | Description | -|------|-------------| -| `rag_eval.judge.faithfulness` | Score answer faithfulness to context | -| `rag_eval.judge.relevance` | Score answer relevance to query | -| `rag_eval.judge.context_precision` | Score context ranking quality | -| `rag_eval.judge.context_recall` | Score ground truth coverage | -| `rag_eval.judge.cost_check` | Verify cost within budget | +# Run the test suite +pnpm test -### Layer 2: rag_eval.suite.* (Orchestrated) +# Run linting +pnpm lint +``` -| Tool | Description | -|------|-------------| -| `rag_eval.suite.run` | Execute full evaluation suite | -| `rag_eval.suite.status` | Get evaluation run status | -| `rag_eval.suite.results` | Retrieve evaluation results | -| `rag_eval.suite.compare` | Compare two evaluation runs | -| `rag_eval.suite.baseline` | Set baseline for regression | +## Quick Start -### Layer 3: rag_eval.gate.* (CI Gates) +Evaluate a RAG system's output in a few lines: -| Tool | Description | -|------|-------------| -| `rag_eval.gate.run` | Run CI-style pass/fail gate | -| `rag_eval.gate.config` | Get/set gate configuration | -| `rag_eval.gate.diff` | Get detailed diff from baseline | +```typescript +import { EvaluationSuite } from "@reaatech/rag-eval-suite"; -## Architecture +const suite = new EvaluationSuite({ + metrics: ["faithfulness", "relevance", "context_precision", "context_recall"], + judge: { model: "claude-opus" }, + gates: [ + { name: "min-faithfulness", type: "threshold", metric: "avg_faithfulness", operator: ">=", threshold: 0.85 }, + ], + cost: { budget_limit: 10.00 }, +}); -See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed system design. +const result = await suite.runFromFile("datasets/eval-samples.jsonl"); -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ RAG │────▢│ rag-eval- │────▢│ Evaluation β”‚ -β”‚ System β”‚ β”‚ pack β”‚ β”‚ Results β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Three-Layer β”‚ - β”‚ MCP Tools: β”‚ - β”‚ - judge.* β”‚ - β”‚ - suite.* β”‚ - β”‚ - gate.* β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +console.log("Overall score:", result.results.metrics.overall_score); +console.log("Faithfulness:", result.results.metrics.avg_faithfulness); +console.log("Total cost:", result.results.total_cost); +console.log("Gates passed:", result.gate_result?.passed); ``` -## Development +Or use the CLI: ```bash -# Install dependencies -npm install - -# Build -npm run build - -# Test -npm test -npm run test:coverage - -# Lint -npm run lint -npm run lint:fix - -# Type check -npm run typecheck +rag-eval-pack evaluate --dataset dataset.jsonl --output results.json +rag-eval-pack gate --results results.json --gates gates.yaml +rag-eval-pack report --results results.json --output report.md ``` -## Contributing +See [`datasets/examples/`](./datasets/examples/) for sample datasets and configuration files. -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Run tests: `npm test` -5. Run linter: `npm run lint` -6. Submit a pull request +## Packages -See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. +| Package | Description | +| ------- | ----------- | +| [`@reaatech/rag-eval-core`](./packages/core) | Canonical types, Zod schemas, and domain models | +| [`@reaatech/rag-eval-metrics`](./packages/metrics) | Heuristic metric scorers (faithfulness, relevance, precision, recall) | +| [`@reaatech/rag-eval-judge`](./packages/judge) | LLM-as-judge with calibration, consensus, and cost tracking | +| [`@reaatech/rag-eval-cost`](./packages/cost) | Pricing, budgeting, and cost reporting | +| [`@reaatech/rag-eval-gate`](./packages/gate) | Quality gates and CI regression checks | +| [`@reaatech/rag-eval-dataset`](./packages/dataset) | Dataset loading, validation, generation, and versioning | +| [`@reaatech/rag-eval-suite`](./packages/suite) | Central orchestration engine | +| [`@reaatech/rag-eval-mcp-server`](./packages/mcp-server) | MCP server for agent-driven evaluation | +| [`@reaatech/rag-eval-cli`](./packages/cli) | CLI entry point and commands | +| [`@reaatech/rag-eval-observability`](./packages/observability) | Structured logging, tracing, and metrics | -## License +## Documentation -MIT β€” see [LICENSE](LICENSE) for details. +- [`ARCHITECTURE.md`](./ARCHITECTURE.md) β€” System design, package relationships, and data flows +- [`AGENTS.md`](./AGENTS.md) β€” Coding conventions, tool architecture, and development guidelines +- [`CONTRIBUTING.md`](./CONTRIBUTING.md) β€” Contribution workflow and release process +- [`DEV_PLAN.md`](./DEV_PLAN.md) β€” Development checklist and roadmap -## References +## License -- [AGENTS.md](AGENTS.md) β€” Agent development guide -- [ARCHITECTURE.md](ARCHITECTURE.md) β€” System design deep dive -- [DEV_PLAN.md](DEV_PLAN.md) β€” Development checklist -- [MCP Specification](https://modelcontextprotocol.io/) +[MIT](LICENSE) diff --git a/skills/context-precision/skill.md b/skills/context-precision/skill.md index b853281..11d545c 100644 --- a/skills/context-precision/skill.md +++ b/skills/context-precision/skill.md @@ -22,7 +22,7 @@ Context Precision measures how well the retrieved context chunks are ranked, ass ## Usage ```typescript -import { ContextPrecisionScorer } from 'rag-eval-pack'; +import { ContextPrecisionScorer } from '@reaatech/rag-eval-metrics'; const scorer = new ContextPrecisionScorer(); const result = await scorer.score({ diff --git a/skills/context-recall/skill.md b/skills/context-recall/skill.md index 9c9ac1c..b69037b 100644 --- a/skills/context-recall/skill.md +++ b/skills/context-recall/skill.md @@ -22,7 +22,7 @@ Context Recall measures whether the retrieved context contains all the informati ## Usage ```typescript -import { ContextRecallScorer } from 'rag-eval-pack'; +import { ContextRecallScorer } from '@reaatech/rag-eval-metrics'; const scorer = new ContextRecallScorer(); const result = await scorer.score({ diff --git a/skills/cost-accounting/skill.md b/skills/cost-accounting/skill.md index 21465e9..f6d1555 100644 --- a/skills/cost-accounting/skill.md +++ b/skills/cost-accounting/skill.md @@ -23,7 +23,7 @@ Cost Accounting tracks and manages the expenses associated with RAG evaluation, ## Usage ```typescript -import { CostTracker } from 'rag-eval-pack'; +import { CostTracker } from '@reaatech/rag-eval-cost'; const tracker = new CostTracker({ budgetLimit: 10.00, diff --git a/skills/dataset-management/skill.md b/skills/dataset-management/skill.md index 147a305..0d74678 100644 --- a/skills/dataset-management/skill.md +++ b/skills/dataset-management/skill.md @@ -22,7 +22,7 @@ Dataset Management handles the creation, validation, versioning, and maintenance ## Usage ```typescript -import { DatasetLoader } from 'rag-eval-pack'; +import { DatasetLoader } from '@reaatech/rag-eval-dataset'; const loader = new DatasetLoader(); diff --git a/skills/eval-gating/skill.md b/skills/eval-gating/skill.md index 3c2d829..94fd39e 100644 --- a/skills/eval-gating/skill.md +++ b/skills/eval-gating/skill.md @@ -21,7 +21,7 @@ Evaluation Gating provides CI-style pass/fail gates for RAG evaluation, enabling ## Usage ```typescript -import { GateEngine } from 'rag-eval-pack'; +import { GateEngine } from '@reaatech/rag-eval-gate'; const engine = new GateEngine([ { diff --git a/skills/faithfulness-eval/skill.md b/skills/faithfulness-eval/skill.md index 0282a71..ff62bf6 100644 --- a/skills/faithfulness-eval/skill.md +++ b/skills/faithfulness-eval/skill.md @@ -22,7 +22,7 @@ Faithfulness measures whether a RAG system's generated answer is grounded in the ## Usage ```typescript -import { FaithfulnessScorer } from 'rag-eval-pack'; +import { FaithfulnessScorer } from '@reaatech/rag-eval-metrics'; const scorer = new FaithfulnessScorer(); const result = await scorer.score({ diff --git a/skills/llm-judge-rag/skill.md b/skills/llm-judge-rag/skill.md index 622500c..534c229 100644 --- a/skills/llm-judge-rag/skill.md +++ b/skills/llm-judge-rag/skill.md @@ -22,7 +22,7 @@ LLM-as-Judge uses large language models to evaluate RAG output quality, providin ## Usage ```typescript -import { JudgeEngine } from 'rag-eval-pack'; +import { JudgeEngine } from '@reaatech/rag-eval-judge'; const judge = new JudgeEngine({ model: 'claude-opus', diff --git a/skills/rag-eval-suite/skill.md b/skills/rag-eval-suite/skill.md index 8f33cb9..5306796 100644 --- a/skills/rag-eval-suite/skill.md +++ b/skills/rag-eval-suite/skill.md @@ -14,7 +14,7 @@ RAG Eval Suite orchestrates comprehensive evaluation of RAG systems, combining m ## Usage ```typescript -import { EvaluationSuite } from 'rag-eval-pack'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; const suite = new EvaluationSuite({ metrics: ['faithfulness', 'relevance', 'context_precision', 'context_recall'], diff --git a/skills/relevance-eval/skill.md b/skills/relevance-eval/skill.md index 6e60214..ee8a273 100644 --- a/skills/relevance-eval/skill.md +++ b/skills/relevance-eval/skill.md @@ -22,7 +22,7 @@ Relevance measures whether a RAG system's generated answer actually addresses th ## Usage ```typescript -import { RelevanceScorer } from 'rag-eval-pack'; +import { RelevanceScorer } from '@reaatech/rag-eval-metrics'; const scorer = new RelevanceScorer(); const result = await scorer.score({ diff --git a/tests/integration/eval-pipeline.test.ts b/tests/integration/eval-pipeline.test.ts index 6e6d3bc..a1d570c 100644 --- a/tests/integration/eval-pipeline.test.ts +++ b/tests/integration/eval-pipeline.test.ts @@ -1,13 +1,13 @@ -import { describe, it, expect } from 'vitest'; -import { EvaluationSuite } from '../../src/evaluation-suite.js'; -import { GateEngine } from '../../src/gate/engine.js'; -import { DatasetLoader } from '../../src/dataset/loader.js'; import type { - EvaluationSample, - EvalSuiteConfig, - EvalResults, CostBreakdown, -} from '../../src/types/domain.js'; + EvalResults, + EvalSuiteConfig, + EvaluationSample, +} from '@reaatech/rag-eval-core'; +import { DatasetLoader } from '@reaatech/rag-eval-dataset'; +import { GateEngine } from '@reaatech/rag-eval-gate'; +import { EvaluationSuite } from '@reaatech/rag-eval-suite'; +import { describe, expect, it } from 'vitest'; describe('Integration: Evaluation Pipeline', () => { const sampleData: EvaluationSample[] = [ @@ -68,10 +68,11 @@ describe('Integration: Evaluation Pipeline', () => { total: 0.1, by_metric: {}, by_provider: {}, + per_sample: [], }); const createEvalResults = ( - overrides: Partial & { runId: string } + overrides: Partial & { runId: string }, ): EvalResults => ({ run_id: overrides.runId, evaluated_at: new Date().toISOString(), diff --git a/tsconfig.json b/tsconfig.json index be01d5d..bbd6158 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,26 +4,27 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true, + "strict": true, "noImplicitAny": true, - "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, "noImplicitThis": true, + "alwaysStrict": true, "noUnusedLocals": true, "noUnusedParameters": true, + "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": false, - "exactOptionalPropertyTypes": false, - "types": ["node"] + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true, + "verbatimModuleSyntax": true }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "tests"] + "exclude": ["node_modules", "dist", "*.config.js"] } From 93f675645ae659fa8eabb9d2130dc486a8a28878 Mon Sep 17 00:00:00 2001 From: reaatech <138725666+reaatech@users.noreply.github.com> Date: Sat, 2 May 2026 14:55:33 -0700 Subject: [PATCH 3/5] fix: resolve CI audit failure and eval workflow directory error - Add mkdir -p results before eval command to create output directory - Override uuid to >=14.0.0 via pnpm.overrides to fix moderate vulnerability --- .github/workflows/eval.yml | 1 + package.json | 7 ++++++- pnpm-lock.yaml | 11 +++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index 7d5966e..d928137 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -31,6 +31,7 @@ jobs: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | + mkdir -p results node packages/cli/dist/cli.js evaluate \ --dataset datasets/examples/samples.jsonl \ --config datasets/examples/config.yaml \ diff --git a/package.json b/package.json index 5829b0a..79e2ca6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "rag-eval-pack", "version": "0.1.0", "private": true, - "description": "Evaluation toolkit for RAG (Retrieval-Augmented Generation) systems β€” monorepo of composable metrics, judges, gates, and CLI tools", + "description": "Evaluation toolkit for RAG (Retrieval-Augmented Generation) systems \u2014 monorepo of composable metrics, judges, gates, and CLI tools", "type": "module", "scripts": { "build": "turbo run build", @@ -48,5 +48,10 @@ "turbo": "^2.5.0", "typescript": "^5.8.3", "vitest": "^3.1.1" + }, + "pnpm": { + "overrides": { + "uuid": ">=14.0.0" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9997580..6e73dcb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + uuid: '>=14.0.0' + importers: .: @@ -2343,8 +2346,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - uuid@13.0.1: - resolution: {integrity: sha512-9ezox2roIft6ExBVTVqibSd5dc5/47Sw/uY6b4SjQUT2TzQ0tltNquWA46y4xPQmdZYqvnio22SgWd41M86+jw==} + uuid@14.0.0: + resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true vary@1.1.2: @@ -3872,7 +3875,7 @@ snapshots: stopwords-iso: 1.1.0 sylvester: 0.0.21 underscore: 1.13.8 - uuid: 13.0.1 + uuid: 14.0.0 wordnet-db: 3.1.14 transitivePeerDependencies: - '@aws-sdk/credential-providers' @@ -4443,7 +4446,7 @@ snapshots: unpipe@1.0.0: {} - uuid@13.0.1: {} + uuid@14.0.0: {} vary@1.1.2: {} From ee32108332f9e9503ed48f2403de45d58e930213 Mon Sep 17 00:00:00 2001 From: reaatech <138725666+reaatech@users.noreply.github.com> Date: Sat, 2 May 2026 15:00:18 -0700 Subject: [PATCH 4/5] fix: add permissions and error handling to eval workflow - Add pull-requests: write permission for PR comment creation - Add continue-on-error to Comment on PR step as safety net --- .github/workflows/eval.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index d928137..17c9653 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -8,6 +8,9 @@ jobs: evaluate: name: Run Evaluation runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - name: Checkout uses: actions/checkout@v4 @@ -55,6 +58,7 @@ jobs: - name: Comment on PR if: always() + continue-on-error: true uses: actions/github-script@v7 with: script: | From 39e72a7c61861f3ca1918601ee75e74caeb388be Mon Sep 17 00:00:00 2001 From: reaatech <138725666+reaatech@users.noreply.github.com> Date: Sat, 2 May 2026 15:00:43 -0700 Subject: [PATCH 5/5] fix: stop eval workflow from running on PRs The eval workflow requires API keys, example data gate thresholds are deliberately below the example dataset scores, and it is a quality gate, not a CI check. Use workflow_dispatch and push to main only. --- .github/workflows/eval.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index 17c9653..2b47232 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -1,7 +1,11 @@ name: RAG Evaluation +# Runs on workflow_dispatch and push to main only. +# Pull requests should NOT trigger this β€” it requires API keys +# and is a gate, not a CI check. on: - pull_request: + workflow_dispatch: + push: branches: [main] jobs: