commit 147931383ebcb9584b54dd141a05bac520b2c3b5
parent d4cbd4a130aa26069b412af8c331d5e797bd6959
Author: Brian Graham <brian@buildingbetterteams.de>
Date: Fri, 3 Apr 2026 17:09:38 +0200
Add benchmark harness, tasks, eval suites, and dashboard
Complete implementation of the loop benchmarking system:
- Grid system with 11 configuration axes and cartesian product computation
- Bash harness for isolated experiment runs via claude --bare
- 3 benchmark tasks (tetris, bookmarks-api, data-pipeline) with prompts,
deterministic eval suites, and scoring configs
- Astro + React dashboard with grid overview, run detail, transcript
viewer, and comparison pages
- Forgejo deploy workflow for research subdomain
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat:
62 files changed, 11237 insertions(+), 60 deletions(-)
diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml
@@ -0,0 +1,112 @@
+name: Deploy dashboard
+on:
+ push:
+ branches: [main]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ env:
+ SITE_NAME: loop-benchmarking
+ SITE_BASE: /var/www/research
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22'
+ cache: 'npm'
+ cache-dependency-path: dashboard/package-lock.json
+
+ - name: Install dependencies
+ run: npm ci
+ working-directory: dashboard
+
+ - name: Build site
+ run: npm run build
+ working-directory: dashboard
+
+ - name: Install rsync
+ run: |
+ apt-get update && apt-get install -y rsync
+
+ - name: Ensure site structure exists
+ uses: https://github.com/appleboy/ssh-action@v1.2.0
+ with:
+ host: ${{ secrets.HOST }}
+ username: ${{ secrets.USERNAME }}
+ key: ${{ secrets.SSH_KEY }}
+ envs: SITE_NAME,SITE_BASE
+ script: |
+ BASE="${SITE_BASE}/${SITE_NAME}"
+ if [ ! -d "$BASE" ]; then
+ echo "First deploy — initializing $SITE_NAME"
+ mkdir -p "$BASE/blue" "$BASE/green"
+ ln -sfn "$BASE/blue" "$BASE/current"
+ else
+ echo "Site structure already exists"
+ fi
+
+ - name: Deploy files
+ run: |
+ echo "${{ secrets.SSH_KEY }}" > /tmp/deploy_key
+ chmod 600 /tmp/deploy_key
+
+ TARGET=$(ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no \
+ ${{ secrets.USERNAME }}@${{ secrets.HOST }} \
+ "if [ \"\$(readlink ${SITE_BASE}/${SITE_NAME}/current)\" = \"${SITE_BASE}/${SITE_NAME}/blue\" ]; then echo green; else echo blue; fi")
+
+ echo "Deploying to $TARGET"
+
+ rsync -av --delete \
+ -e "ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no" \
+ ./dashboard/dist/ ${{ secrets.USERNAME }}@${{ secrets.HOST }}:${SITE_BASE}/${SITE_NAME}/$TARGET/
+
+ rm /tmp/deploy_key
+
+ - name: Switch symlink
+ uses: https://github.com/appleboy/ssh-action@v1.2.0
+ with:
+ host: ${{ secrets.HOST }}
+ username: ${{ secrets.USERNAME }}
+ key: ${{ secrets.SSH_KEY }}
+ envs: SITE_NAME,SITE_BASE
+ script: |
+ BASE="${SITE_BASE}/${SITE_NAME}"
+ if [ "$(readlink $BASE/current)" = "$BASE/blue" ]; then
+ NEW=green
+ else
+ NEW=blue
+ fi
+ ln -sfn "$BASE/$NEW" "$BASE/current"
+ systemctl reload nginx
+ echo "Switched $SITE_NAME to $NEW"
+
+ - name: Smoke test
+ run: |
+ sleep 2
+ curl -f https://${SITE_NAME}.research.statagroup.com/ || exit 1
+
+ - name: Rollback on failure
+ if: failure()
+ uses: https://github.com/appleboy/ssh-action@v1.2.0
+ with:
+ host: ${{ secrets.HOST }}
+ username: ${{ secrets.USERNAME }}
+ key: ${{ secrets.SSH_KEY }}
+ envs: SITE_NAME,SITE_BASE
+ script: |
+ BASE="${SITE_BASE}/${SITE_NAME}"
+ if [ -L "$BASE/current" ]; then
+ if [ "$(readlink $BASE/current)" = "$BASE/blue" ]; then
+ OLD=green
+ else
+ OLD=blue
+ fi
+ ln -sfn "$BASE/$OLD" "$BASE/current"
+ systemctl reload nginx
+ echo "Rolled back $SITE_NAME to $OLD"
+ else
+ echo "No previous deployment to roll back to"
+ fi
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,5 @@
+node_modules/
+dist/
+.astro/
+results/runs/
+*.tar.gz
diff --git a/CLAUDE.md b/CLAUDE.md
@@ -2,85 +2,73 @@
## What This Is
-An open benchmark for comparing different agentic coding loop configurations on identical tasks. Run the same task with different setups (model, tools, verification layers) and publish comparable results. The "Ship the Loop Benchmark."
+An open benchmark for comparing agentic coding loop configurations. Define the variables that make up a loop setup, and the system generates every permutation automatically. Each permutation is run against each task multiple times (default 3) in a clean-room environment. All data is public.
-## Why It Exists
+## The Research Grid
-- Referenced from the Ship the Loop YouTube video "AI Made Experienced Developers 19% Slower"
-- The jagged performance frontier concept: AI productivity isn't a single number, it depends on loop architecture
-- The chain-doubling insight: 90% per-step accuracy = ~10 steps, 95% = ~20 steps. Verification layers have outsized impact.
-- Nobody has a rigorous, reproducible benchmark for comparing agentic LOOP configurations (not just models)
+The grid is a cartesian product of configuration variables. You define the axes and their possible values; the harness explodes them into the full experiment matrix.
-## What We're Testing
+Axes (see `grid.yaml` for full definition):
+- **Model**: Haiku, Sonnet, Opus (or other providers via LiteLLM)
+- **Effort**: high, max (extended thinking)
+- **Prompt style**: simple ("build tetris"), detailed (full spec)
+- **Programming language**: TypeScript, JavaScript
+- **Human language**: English, Spanish
+- **Tooling**: Playwright on/off, linter (eslint) on/off
+- **Context**: rules file provided or not
+- **Sub-agents**: enabled/disabled
+- **Web search**: enabled/disabled
+- **Budget**: low ($0.50), high ($5.00)
-Variables to control:
-- **Model**: Opus vs Sonnet vs Haiku (or equivalent tiers from other providers)
-- **Loop tools**: with/without Playwright, with/without test runner, with/without type checker
-- **Language**: TypeScript vs JavaScript (type compiler catches defects)
-- **Context**: with/without CLAUDE.md rules files, with/without existing codebase context
-- **MCP servers**: with/without various tool access
+Each cell = 1 task x 1 configuration permutation, run N times.
-Constant: the TASK. Same task definition given to every configuration.
+## Experiment Definitions
-## Task Design Principles
+Experiments are defined in YAML. The YAML describes the axes and their values, not individual experiments. The harness computes the permutation set.
-- Tasks should span the jagged frontier: some should be agent-friendly (clear success criteria, well-defined), others should be hard (ambiguous requirements, complex interdependencies)
-- Each task needs: a clear spec, automated success criteria (tests that determine pass/fail), a complexity rating
-- Tasks should be self-contained (no external API dependencies that could change)
-- Suggested starter tasks:
- - **Tetris** - agent-friendly, clear rules, visual verification
- - **Form with validation** - medium, needs browser testing
- - **REST API with auth + rate limiting + caching** - medium-hard, multiple concerns
- - **Data pipeline with error handling** - hard, complex state management
- - **Something with subtle correctness requirements** - hard, tests are hard to write too
+## Test Harness
-## Measurement
+Each experiment run executes in a clean room:
+- Isolated directory
+- No context contamination from this project or other experiments
+- Fresh agent session
+- Repeatable from the YAML definition
-- Pass/fail on automated tests (binary)
-- Number of loop iterations to reach pass
-- Total tokens consumed
-- Wall-clock time
-- Code quality metrics (optional: lint score, type coverage, test coverage)
-- Human judgment score on a 1-5 scale for "would you ship this?"
+## Scoring
-## Output
+All evaluation is deterministic code. No LLM grading.
-- Results published as a micro-site (likely static, could be at benchmarks.shiptheloop.com or similar)
-- Interactive comparison: pick two configs, see side-by-side results
-- Updated periodically as new models/tools release
-- Raw data available for download
+**Automated (quantitative):**
+- Pass/fail on pre-written test suites (agent never sees these tests)
+- Structural checks (correct files exist, build succeeds)
+- Quality checks (lint, type check, accessibility, performance, security)
+- Wall-clock time, tokens consumed, cost, loop iterations, agents spawned
-## Tech Stack (suggested)
+**Qualitative:**
+- Human judgment scores (e.g., "would you ship this?" 1-5)
-- TypeScript for the harness
-- Each benchmark run is isolated (clean directory, fresh agent session)
-- Results stored as YAML/JSON
-- Static site generator for the results micro-site
-- Could use Claude Code's Agent SDK for programmatic runs
+## Transcript Storage
-## Connection to Video Content
+Each run saves the full conversation via `--output-format stream-json`. Every tool call, response, and reasoning step is captured for review in the dashboard.
-- The 60-second demo in the productivity truth video is a teaser for this
-- The setup-showdown video (bp-setup-showdown) is the full walkthrough
-- Results referenced in future videos as evidence
+## Web Dashboard
-## Brian's Context
+Static site showing:
+- Grid overview of all experiments
+- Aggregate insights and comparisons across any axis
+- Drill-down into individual experiment results
+- Slicing/filtering (e.g., "Opus vs Sonnet when Playwright is on")
-- Brian runs Ship the Loop (YouTube) and Building Better Teams (consulting)
-- He has a research corpus of 1,200+ AI papers at ~/projects/ai-research-survey/
-- The video production pipeline is at ~/video-studio/
-- Primary stack: TypeScript. Uses Forgejo, not GitHub.
-- Start conservative with resource-intensive settings. Scale up, not down.
+## Tech
-## Infrastructure
-
-- Source control: Forgejo (NOT GitHub)
-- No CI/CD yet - will be set up when the harness is built
-- No external dependencies at bootstrap stage
+- **Harness runner**: Bash script that orchestrates experiment runs. Claude Code cannot invoke itself, so the harness must be external. The script reads YAML definitions, computes the grid, and invokes `claude` CLI for each cell.
+- **Model support**: Primarily Anthropic models (Haiku, Sonnet, Opus). Non-Anthropic models possible via LiteLLM proxy in front of Ollama or similar, but expect reduced feature support (extended thinking, tool use may not work). This is valid benchmark data.
+- Results stored as YAML/JSON (append-only, never overwritten)
+- Each run gets a unique ID
+- Static site for the dashboard
## Conventions
+- Source control: Forgejo (not GitHub)
+- Start conservative with resource-intensive settings
- Never use emdashes
-- Keep results data in YAML/JSON (human-readable, diffable)
-- Each benchmark run gets a unique ID (timestamp + config hash)
-- Raw results are never overwritten, only appended
diff --git a/dashboard/.gitignore b/dashboard/.gitignore
@@ -0,0 +1,24 @@
+# build output
+dist/
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+
+# environment variables
+.env
+.env.production
+
+# macOS-specific files
+.DS_Store
+
+# jetbrains setting folder
+.idea/
diff --git a/dashboard/README.md b/dashboard/README.md
@@ -0,0 +1,43 @@
+# Astro Starter Kit: Minimal
+
+```sh
+npm create astro@latest -- --template minimal
+```
+
+> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
+
+## 🚀 Project Structure
+
+Inside of your Astro project, you'll see the following folders and files:
+
+```text
+/
+├── public/
+├── src/
+│ └── pages/
+│ └── index.astro
+└── package.json
+```
+
+Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
+
+There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
+
+Any static assets, like images, can be placed in the `public/` directory.
+
+## 🧞 Commands
+
+All commands are run from the root of the project, from a terminal:
+
+| Command | Action |
+| :------------------------ | :----------------------------------------------- |
+| `npm install` | Installs dependencies |
+| `npm run dev` | Starts local dev server at `localhost:4321` |
+| `npm run build` | Build your production site to `./dist/` |
+| `npm run preview` | Preview your build locally, before deploying |
+| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
+| `npm run astro -- --help` | Get help using the Astro CLI |
+
+## 👀 Want to learn more?
+
+Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
diff --git a/dashboard/astro.config.mjs b/dashboard/astro.config.mjs
@@ -0,0 +1,14 @@
+// @ts-check
+import { defineConfig } from 'astro/config';
+import react from '@astrojs/react';
+
+export default defineConfig({
+ integrations: [react()],
+ vite: {
+ resolve: {
+ alias: {
+ '@data': '../results',
+ },
+ },
+ },
+});
diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json
@@ -0,0 +1,6587 @@
+{
+ "name": "dashboard",
+ "version": "0.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "dashboard",
+ "version": "0.0.1",
+ "dependencies": {
+ "@astrojs/check": "^0.9.8",
+ "@astrojs/react": "^5.0.2",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "astro": "^6.1.3",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "recharts": "^3.8.1"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ }
+ },
+ "node_modules/@astrojs/check": {
+ "version": "0.9.8",
+ "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.8.tgz",
+ "integrity": "sha512-LDng8446QLS5ToKjRHd3bgUdirvemVVExV7nRyJfW2wV36xuv7vDxwy5NWN9zqeSEDgg0Tv84sP+T3yEq+Zlkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@astrojs/language-server": "^2.16.5",
+ "chokidar": "^4.0.3",
+ "kleur": "^4.1.5",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "astro-check": "bin/astro-check.js"
+ },
+ "peerDependencies": {
+ "typescript": "^5.0.0"
+ }
+ },
+ "node_modules/@astrojs/check/node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@astrojs/check/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@astrojs/compiler": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-3.0.1.tgz",
+ "integrity": "sha512-z97oYbdebO5aoWzuJ/8q5hLK232+17KcLZ7cJ8BCWk6+qNzVxn/gftC0KzMBUTD8WAaBkPpNSQK6PXLnNrZ0CA==",
+ "license": "MIT"
+ },
+ "node_modules/@astrojs/internal-helpers": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.8.0.tgz",
+ "integrity": "sha512-J56GrhEiV+4dmrGLPNOl2pZjpHXAndWVyiVDYGDuw6MWKpBSEMLdFxHzeM/6sqaknw9M+HFfHZAcvi3OfT3D/w==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^4.0.3"
+ }
+ },
+ "node_modules/@astrojs/language-server": {
+ "version": "2.16.6",
+ "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.6.tgz",
+ "integrity": "sha512-N990lu+HSFiG57owR0XBkr02BYMgiLCshLf+4QG4v6jjSWkBeQGnzqi+E1L08xFPPJ7eEeXnxPXGLaVv5pa4Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@astrojs/compiler": "^2.13.1",
+ "@astrojs/yaml2ts": "^0.2.3",
+ "@jridgewell/sourcemap-codec": "^1.5.5",
+ "@volar/kit": "~2.4.28",
+ "@volar/language-core": "~2.4.28",
+ "@volar/language-server": "~2.4.28",
+ "@volar/language-service": "~2.4.28",
+ "muggle-string": "^0.4.1",
+ "tinyglobby": "^0.2.15",
+ "volar-service-css": "0.0.70",
+ "volar-service-emmet": "0.0.70",
+ "volar-service-html": "0.0.70",
+ "volar-service-prettier": "0.0.70",
+ "volar-service-typescript": "0.0.70",
+ "volar-service-typescript-twoslash-queries": "0.0.70",
+ "volar-service-yaml": "0.0.70",
+ "vscode-html-languageservice": "^5.6.2",
+ "vscode-uri": "^3.1.0"
+ },
+ "bin": {
+ "astro-ls": "bin/nodeServer.js"
+ },
+ "peerDependencies": {
+ "prettier": "^3.0.0",
+ "prettier-plugin-astro": ">=0.11.0"
+ },
+ "peerDependenciesMeta": {
+ "prettier": {
+ "optional": true
+ },
+ "prettier-plugin-astro": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@astrojs/language-server/node_modules/@astrojs/compiler": {
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz",
+ "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==",
+ "license": "MIT"
+ },
+ "node_modules/@astrojs/markdown-remark": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.1.0.tgz",
+ "integrity": "sha512-P+HnCsu2js3BoTc8kFmu+E9gOcFeMdPris75g+Zl4sY8+bBRbSQV6xzcBDbZ27eE7yBGEGQoqjpChx+KJYIPYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@astrojs/internal-helpers": "0.8.0",
+ "@astrojs/prism": "4.0.1",
+ "github-slugger": "^2.0.0",
+ "hast-util-from-html": "^2.0.3",
+ "hast-util-to-text": "^4.0.2",
+ "js-yaml": "^4.1.1",
+ "mdast-util-definitions": "^6.0.0",
+ "rehype-raw": "^7.0.0",
+ "rehype-stringify": "^10.0.1",
+ "remark-gfm": "^4.0.1",
+ "remark-parse": "^11.0.0",
+ "remark-rehype": "^11.1.2",
+ "remark-smartypants": "^3.0.2",
+ "retext-smartypants": "^6.2.0",
+ "shiki": "^4.0.0",
+ "smol-toml": "^1.6.0",
+ "unified": "^11.0.5",
+ "unist-util-remove-position": "^5.0.0",
+ "unist-util-visit": "^5.1.0",
+ "unist-util-visit-parents": "^6.0.2",
+ "vfile": "^6.0.3"
+ }
+ },
+ "node_modules/@astrojs/prism": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.1.tgz",
+ "integrity": "sha512-nksZQVjlferuWzhPsBpQ1JE5XuKAf1id1/9Hj4a9KG4+ofrlzxUUwX4YGQF/SuDiuiGKEnzopGOt38F3AnVWsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "prismjs": "^1.30.0"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ }
+ },
+ "node_modules/@astrojs/react": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-5.0.2.tgz",
+ "integrity": "sha512-BDpPrapV3Wgp9sD7aTMvP+ORH0jFEue9OmkBu98KcBbTlsQCnvisDW3m7PQrMptXwEDlX5HGfP/CHmkEVY2tZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@astrojs/internal-helpers": "0.8.0",
+ "@vitejs/plugin-react": "^5.2.0",
+ "devalue": "^5.6.4",
+ "ultrahtml": "^1.6.0",
+ "vite": "^7.3.1"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0",
+ "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0",
+ "react": "^17.0.2 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@astrojs/telemetry": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz",
+ "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ci-info": "^4.2.0",
+ "debug": "^4.4.0",
+ "dlv": "^1.1.3",
+ "dset": "^3.1.4",
+ "is-docker": "^3.0.0",
+ "is-wsl": "^3.1.0",
+ "which-pm-runs": "^1.1.0"
+ },
+ "engines": {
+ "node": "18.20.8 || ^20.3.0 || >=22.0.0"
+ }
+ },
+ "node_modules/@astrojs/yaml2ts": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.3.tgz",
+ "integrity": "sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==",
+ "license": "MIT",
+ "dependencies": {
+ "yaml": "^2.8.2"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.1",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "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==",
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
+ "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0"
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.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==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@capsizecss/unpack": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.0.tgz",
+ "integrity": "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==",
+ "license": "MIT",
+ "dependencies": {
+ "fontkitten": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@clack/core": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.2.0.tgz",
+ "integrity": "sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-wrap-ansi": "^0.1.3",
+ "sisteransi": "^1.0.5"
+ }
+ },
+ "node_modules/@clack/prompts": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.2.0.tgz",
+ "integrity": "sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w==",
+ "license": "MIT",
+ "dependencies": {
+ "@clack/core": "1.2.0",
+ "fast-string-width": "^1.1.0",
+ "fast-wrap-ansi": "^0.1.3",
+ "sisteransi": "^1.0.5"
+ }
+ },
+ "node_modules/@emmetio/abbreviation": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz",
+ "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
+ "node_modules/@emmetio/css-abbreviation": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz",
+ "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
+ "node_modules/@emmetio/css-parser": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@emmetio/css-parser/-/css-parser-0.4.1.tgz",
+ "integrity": "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/stream-reader": "^2.2.0",
+ "@emmetio/stream-reader-utils": "^0.1.0"
+ }
+ },
+ "node_modules/@emmetio/html-matcher": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz",
+ "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==",
+ "license": "ISC",
+ "dependencies": {
+ "@emmetio/scanner": "^1.0.0"
+ }
+ },
+ "node_modules/@emmetio/scanner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz",
+ "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==",
+ "license": "MIT"
+ },
+ "node_modules/@emmetio/stream-reader": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz",
+ "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==",
+ "license": "MIT"
+ },
+ "node_modules/@emmetio/stream-reader-utils": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz",
+ "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==",
+ "license": "MIT"
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
+ "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
+ "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
+ "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
+ "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
+ "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
+ "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
+ "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
+ "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
+ "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
+ "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
+ "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
+ "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
+ "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
+ "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
+ "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
+ "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
+ "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
+ "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
+ "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
+ "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
+ "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
+ "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
+ "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
+ "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/colour": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+ "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+ "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+ "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+ "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+ "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+ "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+ "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+ "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+ "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+ "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+ "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+ "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+ "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+ "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+ "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+ "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+ "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+ "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+ "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+ "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+ "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.7.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+ "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+ "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+ "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "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==",
+ "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==",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@oslojs/encoding": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz",
+ "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==",
+ "license": "MIT"
+ },
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.11.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz",
+ "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^11.0.0",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@reduxjs/toolkit/node_modules/immer": {
+ "version": "11.1.4",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz",
+ "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-rc.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
+ "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==",
+ "license": "MIT"
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
+ "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
+ "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz",
+ "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
+ "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz",
+ "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz",
+ "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz",
+ "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz",
+ "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz",
+ "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz",
+ "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz",
+ "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz",
+ "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz",
+ "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz",
+ "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz",
+ "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz",
+ "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz",
+ "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz",
+ "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz",
+ "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz",
+ "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz",
+ "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz",
+ "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz",
+ "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz",
+ "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
+ "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
+ "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@shikijs/core": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
+ "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/primitive": "4.0.2",
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4",
+ "hast-util-to-html": "^9.0.5"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/engine-javascript": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz",
+ "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "oniguruma-to-es": "^4.3.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/engine-oniguruma": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz",
+ "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/langs": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz",
+ "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/primitive": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz",
+ "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/themes": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz",
+ "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/types": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
+ "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/vscode-textmate": {
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
+ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz",
+ "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/debug": {
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
+ "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/@types/hast": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
+ "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/mdast": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
+ "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/ms": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
+ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/nlcst": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz",
+ "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.14",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
+ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@types/unist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+ "license": "MIT"
+ },
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "ISC"
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz",
+ "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.29.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-rc.3",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.18.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@volar/kit": {
+ "version": "2.4.28",
+ "resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.4.28.tgz",
+ "integrity": "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==",
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-service": "2.4.28",
+ "@volar/typescript": "2.4.28",
+ "typesafe-path": "^0.2.2",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ }
+ },
+ "node_modules/@volar/language-core": {
+ "version": "2.4.28",
+ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz",
+ "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@volar/source-map": "2.4.28"
+ }
+ },
+ "node_modules/@volar/language-server": {
+ "version": "2.4.28",
+ "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.4.28.tgz",
+ "integrity": "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==",
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.28",
+ "@volar/language-service": "2.4.28",
+ "@volar/typescript": "2.4.28",
+ "path-browserify": "^1.0.1",
+ "request-light": "^0.7.0",
+ "vscode-languageserver": "^9.0.1",
+ "vscode-languageserver-protocol": "^3.17.5",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@volar/language-service": {
+ "version": "2.4.28",
+ "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.28.tgz",
+ "integrity": "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.28",
+ "vscode-languageserver-protocol": "^3.17.5",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.28",
+ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz",
+ "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==",
+ "license": "MIT"
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.28",
+ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz",
+ "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==",
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.28",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vscode/emmet-helper": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.11.0.tgz",
+ "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==",
+ "license": "MIT",
+ "dependencies": {
+ "emmet": "^2.4.3",
+ "jsonc-parser": "^2.3.0",
+ "vscode-languageserver-textdocument": "^1.0.1",
+ "vscode-languageserver-types": "^3.15.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vscode/l10n": {
+ "version": "0.0.18",
+ "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz",
+ "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==",
+ "license": "MIT"
+ },
+ "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-draft-04": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "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": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/anymatch/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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "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==",
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/array-iterate": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz",
+ "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/astro": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/astro/-/astro-6.1.3.tgz",
+ "integrity": "sha512-FUKbBYOdYYrRNZwDd9I5CVSfR6Nj9aZeNzcjcvh1FgHwR0uXawkYFR3HiGxmdmAB2m8fs0iIkDdsiUfwGeO8qA==",
+ "license": "MIT",
+ "dependencies": {
+ "@astrojs/compiler": "^3.0.1",
+ "@astrojs/internal-helpers": "0.8.0",
+ "@astrojs/markdown-remark": "7.1.0",
+ "@astrojs/telemetry": "3.3.0",
+ "@capsizecss/unpack": "^4.0.0",
+ "@clack/prompts": "^1.1.0",
+ "@oslojs/encoding": "^1.1.0",
+ "@rollup/pluginutils": "^5.3.0",
+ "aria-query": "^5.3.2",
+ "axobject-query": "^4.1.0",
+ "ci-info": "^4.4.0",
+ "clsx": "^2.1.1",
+ "common-ancestor-path": "^2.0.0",
+ "cookie": "^1.1.1",
+ "devalue": "^5.6.3",
+ "diff": "^8.0.3",
+ "dlv": "^1.1.3",
+ "dset": "^3.1.4",
+ "es-module-lexer": "^2.0.0",
+ "esbuild": "^0.27.3",
+ "flattie": "^1.1.1",
+ "fontace": "~0.4.1",
+ "github-slugger": "^2.0.0",
+ "html-escaper": "3.0.3",
+ "http-cache-semantics": "^4.2.0",
+ "js-yaml": "^4.1.1",
+ "magic-string": "^0.30.21",
+ "magicast": "^0.5.2",
+ "mrmime": "^2.0.1",
+ "neotraverse": "^0.6.18",
+ "obug": "^2.1.1",
+ "p-limit": "^7.3.0",
+ "p-queue": "^9.1.0",
+ "package-manager-detector": "^1.6.0",
+ "piccolore": "^0.1.3",
+ "picomatch": "^4.0.3",
+ "rehype": "^13.0.2",
+ "semver": "^7.7.4",
+ "shiki": "^4.0.2",
+ "smol-toml": "^1.6.0",
+ "svgo": "^4.0.1",
+ "tinyclip": "^0.1.12",
+ "tinyexec": "^1.0.4",
+ "tinyglobby": "^0.2.15",
+ "tsconfck": "^3.1.6",
+ "ultrahtml": "^1.6.0",
+ "unifont": "~0.7.4",
+ "unist-util-visit": "^5.1.0",
+ "unstorage": "^1.17.4",
+ "vfile": "^6.0.3",
+ "vite": "^7.3.1",
+ "vitefu": "^1.1.2",
+ "xxhash-wasm": "^1.1.0",
+ "yargs-parser": "^22.0.0",
+ "zod": "^4.3.6"
+ },
+ "bin": {
+ "astro": "bin/astro.mjs"
+ },
+ "engines": {
+ "node": ">=22.12.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/astrodotbuild"
+ },
+ "optionalDependencies": {
+ "sharp": "^0.34.0"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/bail": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+ "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.14",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.14.tgz",
+ "integrity": "sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "license": "ISC"
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001784",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001784.tgz",
+ "integrity": "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/ccount": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
+ "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities-html4": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
+ "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities-legacy": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
+ "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
+ "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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==",
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/comma-separated-tokens": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
+ "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/common-ancestor-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz",
+ "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/cookie-es": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz",
+ "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==",
+ "license": "MIT"
+ },
+ "node_modules/crossws": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz",
+ "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==",
+ "license": "MIT",
+ "dependencies": {
+ "uncrypto": "^0.1.3"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
+ "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.27.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/csso": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
+ "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
+ "license": "MIT",
+ "dependencies": {
+ "css-tree": "~2.2.0"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/css-tree": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
+ "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.0.28",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/mdn-data": {
+ "version": "2.0.28",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
+ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
+ "license": "CC0-1.0"
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "license": "MIT"
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz",
+ "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "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/decimal.js-light": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
+ "license": "MIT"
+ },
+ "node_modules/decode-named-character-reference": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
+ "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "character-entities": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/defu": {
+ "version": "6.1.6",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.6.tgz",
+ "integrity": "sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug==",
+ "license": "MIT"
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/destr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
+ "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/devalue": {
+ "version": "5.6.4",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz",
+ "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==",
+ "license": "MIT"
+ },
+ "node_modules/devlop": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
+ "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
+ "license": "MIT",
+ "dependencies": {
+ "dequal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/diff": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
+ "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "license": "MIT"
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/dom-serializer/node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dset": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
+ "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.331",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.331.tgz",
+ "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==",
+ "license": "ISC"
+ },
+ "node_modules/emmet": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz",
+ "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==",
+ "license": "MIT",
+ "workspaces": [
+ "./packages/scanner",
+ "./packages/abbreviation",
+ "./packages/css-abbreviation",
+ "./"
+ ],
+ "dependencies": {
+ "@emmetio/abbreviation": "^2.3.3",
+ "@emmetio/css-abbreviation": "^2.1.8"
+ }
+ },
+ "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/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/es-toolkit": {
+ "version": "1.45.1",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz",
+ "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==",
+ "license": "MIT",
+ "workspaces": [
+ "docs",
+ "benchmarks"
+ ]
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
+ "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "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"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "node_modules/eventemitter3": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
+ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
+ "license": "MIT"
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "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-string-truncated-width": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-1.2.1.tgz",
+ "integrity": "sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==",
+ "license": "MIT"
+ },
+ "node_modules/fast-string-width": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-1.1.0.tgz",
+ "integrity": "sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-truncated-width": "^1.2.0"
+ }
+ },
+ "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/fast-wrap-ansi": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.1.6.tgz",
+ "integrity": "sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-width": "^1.1.0"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/flattie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz",
+ "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fontace": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz",
+ "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==",
+ "license": "MIT",
+ "dependencies": {
+ "fontkitten": "^1.0.2"
+ }
+ },
+ "node_modules/fontkitten": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz",
+ "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==",
+ "license": "MIT",
+ "dependencies": {
+ "tiny-inflate": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/github-slugger": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
+ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==",
+ "license": "ISC"
+ },
+ "node_modules/h3": {
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz",
+ "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie-es": "^1.2.3",
+ "crossws": "^0.3.5",
+ "defu": "^6.1.6",
+ "destr": "^2.0.5",
+ "iron-webcrypto": "^1.2.1",
+ "node-mock-http": "^1.0.4",
+ "radix3": "^1.1.2",
+ "ufo": "^1.6.3",
+ "uncrypto": "^0.1.3"
+ }
+ },
+ "node_modules/hast-util-from-html": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
+ "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "devlop": "^1.1.0",
+ "hast-util-from-parse5": "^8.0.0",
+ "parse5": "^7.0.0",
+ "vfile": "^6.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-from-parse5": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz",
+ "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "devlop": "^1.0.0",
+ "hastscript": "^9.0.0",
+ "property-information": "^7.0.0",
+ "vfile": "^6.0.0",
+ "vfile-location": "^5.0.0",
+ "web-namespaces": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-is-element": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
+ "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-parse-selector": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
+ "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-raw": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz",
+ "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "@ungap/structured-clone": "^1.0.0",
+ "hast-util-from-parse5": "^8.0.0",
+ "hast-util-to-parse5": "^8.0.0",
+ "html-void-elements": "^3.0.0",
+ "mdast-util-to-hast": "^13.0.0",
+ "parse5": "^7.0.0",
+ "unist-util-position": "^5.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0",
+ "web-namespaces": "^2.0.0",
+ "zwitch": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-to-html": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz",
+ "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "ccount": "^2.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "hast-util-whitespace": "^3.0.0",
+ "html-void-elements": "^3.0.0",
+ "mdast-util-to-hast": "^13.0.0",
+ "property-information": "^7.0.0",
+ "space-separated-tokens": "^2.0.0",
+ "stringify-entities": "^4.0.0",
+ "zwitch": "^2.0.4"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-to-parse5": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz",
+ "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "devlop": "^1.0.0",
+ "property-information": "^7.0.0",
+ "space-separated-tokens": "^2.0.0",
+ "web-namespaces": "^2.0.0",
+ "zwitch": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-to-text": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz",
+ "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "hast-util-is-element": "^3.0.0",
+ "unist-util-find-after": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-whitespace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
+ "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hastscript": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz",
+ "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "hast-util-parse-selector": "^4.0.0",
+ "property-information": "^7.0.0",
+ "space-separated-tokens": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz",
+ "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==",
+ "license": "MIT"
+ },
+ "node_modules/html-void-elements": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
+ "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
+ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/immer": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
+ "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/iron-webcrypto": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
+ "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/brc-dd"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz",
+ "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-inside-container": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonc-parser": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz",
+ "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==",
+ "license": "MIT"
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/longest-streak": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
+ "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "11.2.7",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz",
+ "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "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==",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/markdown-table": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
+ "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/mdast-util-definitions": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz",
+ "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "unist-util-visit": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
+ "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "escape-string-regexp": "^5.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-from-markdown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
+ "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-to-string": "^4.0.0",
+ "micromark": "^4.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-decode-string": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unist-util-stringify-position": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
+ "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-gfm-autolink-literal": "^2.0.0",
+ "mdast-util-gfm-footnote": "^2.0.0",
+ "mdast-util-gfm-strikethrough": "^2.0.0",
+ "mdast-util-gfm-table": "^2.0.0",
+ "mdast-util-gfm-task-list-item": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
+ "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-find-and-replace": "^3.0.0",
+ "micromark-util-character": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
+ "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
+ "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "markdown-table": "^3.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-task-list-item": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
+ "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-phrasing": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
+ "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "unist-util-is": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-hast": {
+ "version": "13.2.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
+ "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "@ungap/structured-clone": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "trim-lines": "^3.0.0",
+ "unist-util-position": "^5.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-markdown": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz",
+ "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "longest-streak": "^3.0.0",
+ "mdast-util-phrasing": "^4.0.0",
+ "mdast-util-to-string": "^4.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-decode-string": "^2.0.0",
+ "unist-util-visit": "^5.0.0",
+ "zwitch": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
+ "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.27.1",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
+ "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
+ "license": "CC0-1.0"
+ },
+ "node_modules/micromark": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
+ "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@types/debug": "^4.0.0",
+ "debug": "^4.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-subtokenize": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-core-commonmark": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
+ "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-factory-destination": "^2.0.0",
+ "micromark-factory-label": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-factory-title": "^2.0.0",
+ "micromark-factory-whitespace": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-html-tag-name": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-subtokenize": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-extension-gfm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
+ "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-extension-gfm-autolink-literal": "^2.0.0",
+ "micromark-extension-gfm-footnote": "^2.0.0",
+ "micromark-extension-gfm-strikethrough": "^2.0.0",
+ "micromark-extension-gfm-table": "^2.0.0",
+ "micromark-extension-gfm-tagfilter": "^2.0.0",
+ "micromark-extension-gfm-task-list-item": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
+ "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
+ "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
+ "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
+ "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
+ "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-factory-destination": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
+ "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-label": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
+ "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-space": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
+ "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-title": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
+ "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-whitespace": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
+ "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-character": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
+ "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-chunked": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
+ "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-classify-character": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
+ "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-combine-extensions": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
+ "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-numeric-character-reference": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
+ "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-string": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
+ "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-encode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
+ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromark-util-html-tag-name": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
+ "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromark-util-normalize-identifier": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
+ "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-resolve-all": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
+ "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-sanitize-uri": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-subtokenize": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
+ "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-symbol": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
+ "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromark-util-types": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
+ "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/mrmime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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/muggle-string": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+ "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==",
+ "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/neotraverse": {
+ "version": "0.6.18",
+ "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz",
+ "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/nlcst-to-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz",
+ "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/nlcst": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/node-fetch-native": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
+ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
+ "license": "MIT"
+ },
+ "node_modules/node-mock-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz",
+ "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==",
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.37",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz",
+ "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==",
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "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==",
+ "funding": [
+ "https://github.com/sponsors/sxzz",
+ "https://opencollective.com/debug"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/ofetch": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz",
+ "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==",
+ "license": "MIT",
+ "dependencies": {
+ "destr": "^2.0.5",
+ "node-fetch-native": "^1.6.7",
+ "ufo": "^1.6.1"
+ }
+ },
+ "node_modules/ohash": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+ "license": "MIT"
+ },
+ "node_modules/oniguruma-parser": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
+ "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==",
+ "license": "MIT"
+ },
+ "node_modules/oniguruma-to-es": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.5.tgz",
+ "integrity": "sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==",
+ "license": "MIT",
+ "dependencies": {
+ "oniguruma-parser": "^0.12.1",
+ "regex": "^6.1.0",
+ "regex-recursion": "^6.0.2"
+ }
+ },
+ "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-queue": {
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.1.tgz",
+ "integrity": "sha512-yQS1vV2V7Q14MQrgD8jMNY5owPuGgVHVdSK8NqmKpOVajnjbaeMa6uLOzTALPtvJ7Vo4bw0BGsw7qfUT8z24Ig==",
+ "license": "MIT",
+ "dependencies": {
+ "eventemitter3": "^5.0.1",
+ "p-timeout": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-timeout": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz",
+ "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-manager-detector": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz",
+ "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
+ "license": "MIT"
+ },
+ "node_modules/parse-latin": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz",
+ "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/nlcst": "^2.0.0",
+ "@types/unist": "^3.0.0",
+ "nlcst-to-string": "^4.0.0",
+ "unist-util-modify-children": "^4.0.0",
+ "unist-util-visit-children": "^3.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/path-browserify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+ "license": "MIT"
+ },
+ "node_modules/piccolore": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz",
+ "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==",
+ "license": "ISC"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.8",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
+ "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
+ "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/prettier": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
+ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prismjs": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
+ "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/property-information": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
+ "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/radix3": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz",
+ "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
+ "license": "MIT"
+ },
+ "node_modules/react": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
+ "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
+ "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.4"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz",
+ "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+ "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/recharts": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.1.tgz",
+ "integrity": "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==",
+ "license": "MIT",
+ "workspaces": [
+ "www"
+ ],
+ "dependencies": {
+ "@reduxjs/toolkit": "^1.9.0 || 2.x.x",
+ "clsx": "^2.1.1",
+ "decimal.js-light": "^2.5.1",
+ "es-toolkit": "^1.39.3",
+ "eventemitter3": "^5.0.1",
+ "immer": "^10.1.1",
+ "react-redux": "8.x.x || 9.x.x",
+ "reselect": "5.1.1",
+ "tiny-invariant": "^1.3.3",
+ "use-sync-external-store": "^1.2.2",
+ "victory-vendor": "^37.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT"
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
+ "node_modules/regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz",
+ "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==",
+ "license": "MIT",
+ "dependencies": {
+ "regex-utilities": "^2.3.0"
+ }
+ },
+ "node_modules/regex-recursion": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz",
+ "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==",
+ "license": "MIT",
+ "dependencies": {
+ "regex-utilities": "^2.3.0"
+ }
+ },
+ "node_modules/regex-utilities": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz",
+ "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==",
+ "license": "MIT"
+ },
+ "node_modules/rehype": {
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz",
+ "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "rehype-parse": "^9.0.0",
+ "rehype-stringify": "^10.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/rehype-parse": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz",
+ "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "hast-util-from-html": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/rehype-raw": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz",
+ "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "hast-util-raw": "^9.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/rehype-stringify": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz",
+ "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "hast-util-to-html": "^9.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-gfm": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+ "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-gfm": "^3.0.0",
+ "micromark-extension-gfm": "^3.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-stringify": "^11.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-parse": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
+ "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-rehype": {
+ "version": "11.1.2",
+ "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
+ "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-hast": "^13.0.0",
+ "unified": "^11.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-smartypants": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz",
+ "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==",
+ "license": "MIT",
+ "dependencies": {
+ "retext": "^9.0.0",
+ "retext-smartypants": "^6.0.0",
+ "unified": "^11.0.4",
+ "unist-util-visit": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/remark-stringify": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
+ "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/request-light": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz",
+ "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==",
+ "license": "MIT"
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.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/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
+ "node_modules/retext": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz",
+ "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/nlcst": "^2.0.0",
+ "retext-latin": "^4.0.0",
+ "retext-stringify": "^4.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/retext-latin": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz",
+ "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/nlcst": "^2.0.0",
+ "parse-latin": "^7.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/retext-smartypants": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz",
+ "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/nlcst": "^2.0.0",
+ "nlcst-to-string": "^4.0.0",
+ "unist-util-visit": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/retext-stringify": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz",
+ "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/nlcst": "^2.0.0",
+ "nlcst-to-string": "^4.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.60.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
+ "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.60.1",
+ "@rollup/rollup-android-arm64": "4.60.1",
+ "@rollup/rollup-darwin-arm64": "4.60.1",
+ "@rollup/rollup-darwin-x64": "4.60.1",
+ "@rollup/rollup-freebsd-arm64": "4.60.1",
+ "@rollup/rollup-freebsd-x64": "4.60.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.60.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.60.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.60.1",
+ "@rollup/rollup-linux-arm64-musl": "4.60.1",
+ "@rollup/rollup-linux-loong64-gnu": "4.60.1",
+ "@rollup/rollup-linux-loong64-musl": "4.60.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.60.1",
+ "@rollup/rollup-linux-ppc64-musl": "4.60.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.60.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.60.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.60.1",
+ "@rollup/rollup-linux-x64-gnu": "4.60.1",
+ "@rollup/rollup-linux-x64-musl": "4.60.1",
+ "@rollup/rollup-openbsd-x64": "4.60.1",
+ "@rollup/rollup-openharmony-arm64": "4.60.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.60.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.60.1",
+ "@rollup/rollup-win32-x64-gnu": "4.60.1",
+ "@rollup/rollup-win32-x64-msvc": "4.60.1",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
+ "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=11.0.0"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+ "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/colour": "^1.0.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.7.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.5",
+ "@img/sharp-darwin-x64": "0.34.5",
+ "@img/sharp-libvips-darwin-arm64": "1.2.4",
+ "@img/sharp-libvips-darwin-x64": "1.2.4",
+ "@img/sharp-libvips-linux-arm": "1.2.4",
+ "@img/sharp-libvips-linux-arm64": "1.2.4",
+ "@img/sharp-libvips-linux-ppc64": "1.2.4",
+ "@img/sharp-libvips-linux-riscv64": "1.2.4",
+ "@img/sharp-libvips-linux-s390x": "1.2.4",
+ "@img/sharp-libvips-linux-x64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+ "@img/sharp-linux-arm": "0.34.5",
+ "@img/sharp-linux-arm64": "0.34.5",
+ "@img/sharp-linux-ppc64": "0.34.5",
+ "@img/sharp-linux-riscv64": "0.34.5",
+ "@img/sharp-linux-s390x": "0.34.5",
+ "@img/sharp-linux-x64": "0.34.5",
+ "@img/sharp-linuxmusl-arm64": "0.34.5",
+ "@img/sharp-linuxmusl-x64": "0.34.5",
+ "@img/sharp-wasm32": "0.34.5",
+ "@img/sharp-win32-arm64": "0.34.5",
+ "@img/sharp-win32-ia32": "0.34.5",
+ "@img/sharp-win32-x64": "0.34.5"
+ }
+ },
+ "node_modules/shiki": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz",
+ "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/core": "4.0.2",
+ "@shikijs/engine-javascript": "4.0.2",
+ "@shikijs/engine-oniguruma": "4.0.2",
+ "@shikijs/langs": "4.0.2",
+ "@shikijs/themes": "4.0.2",
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "license": "MIT"
+ },
+ "node_modules/smol-toml": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz",
+ "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/cyyynthia"
+ }
+ },
+ "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==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/space-separated-tokens": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
+ "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/stringify-entities": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
+ "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
+ "license": "MIT",
+ "dependencies": {
+ "character-entities-html4": "^2.0.0",
+ "character-entities-legacy": "^3.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/svgo": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
+ "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==",
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^11.1.0",
+ "css-select": "^5.1.0",
+ "css-tree": "^3.0.1",
+ "css-what": "^6.1.0",
+ "csso": "^5.0.5",
+ "picocolors": "^1.1.1",
+ "sax": "^1.5.0"
+ },
+ "bin": {
+ "svgo": "bin/svgo.js"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/svgo"
+ }
+ },
+ "node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
+ "license": "MIT"
+ },
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "license": "MIT"
+ },
+ "node_modules/tinyclip": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.12.tgz",
+ "integrity": "sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^16.14.0 || >= 17.3.0"
+ }
+ },
+ "node_modules/tinyexec": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz",
+ "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/trim-lines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
+ "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/trough": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
+ "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/tsconfck": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz",
+ "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==",
+ "license": "MIT",
+ "bin": {
+ "tsconfck": "bin/tsconfck.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ },
+ "peerDependencies": {
+ "typescript": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "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==",
+ "license": "0BSD",
+ "optional": true
+ },
+ "node_modules/typesafe-path": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz",
+ "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==",
+ "license": "MIT"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-auto-import-cache": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.6.tgz",
+ "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==",
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.8"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
+ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==",
+ "license": "MIT"
+ },
+ "node_modules/ultrahtml": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz",
+ "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==",
+ "license": "MIT"
+ },
+ "node_modules/uncrypto": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
+ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
+ "license": "MIT"
+ },
+ "node_modules/unified": {
+ "version": "11.0.5",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
+ "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "bail": "^2.0.0",
+ "devlop": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-plain-obj": "^4.0.0",
+ "trough": "^2.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unifont": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz",
+ "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==",
+ "license": "MIT",
+ "dependencies": {
+ "css-tree": "^3.1.0",
+ "ofetch": "^1.5.1",
+ "ohash": "^2.0.11"
+ }
+ },
+ "node_modules/unist-util-find-after": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz",
+ "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-is": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-is": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz",
+ "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-modify-children": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz",
+ "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "array-iterate": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-position": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
+ "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-remove-position": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz",
+ "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-visit": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-stringify-position": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
+ "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
+ "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit-children": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz",
+ "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit-parents": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz",
+ "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-is": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unstorage": {
+ "version": "1.17.5",
+ "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz",
+ "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==",
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "^3.1.3",
+ "chokidar": "^5.0.0",
+ "destr": "^2.0.5",
+ "h3": "^1.15.10",
+ "lru-cache": "^11.2.7",
+ "node-fetch-native": "^1.6.7",
+ "ofetch": "^1.5.1",
+ "ufo": "^1.6.3"
+ },
+ "peerDependencies": {
+ "@azure/app-configuration": "^1.8.0",
+ "@azure/cosmos": "^4.2.0",
+ "@azure/data-tables": "^13.3.0",
+ "@azure/identity": "^4.6.0",
+ "@azure/keyvault-secrets": "^4.9.0",
+ "@azure/storage-blob": "^12.26.0",
+ "@capacitor/preferences": "^6 || ^7 || ^8",
+ "@deno/kv": ">=0.9.0",
+ "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0",
+ "@planetscale/database": "^1.19.0",
+ "@upstash/redis": "^1.34.3",
+ "@vercel/blob": ">=0.27.1",
+ "@vercel/functions": "^2.2.12 || ^3.0.0",
+ "@vercel/kv": "^1 || ^2 || ^3",
+ "aws4fetch": "^1.0.20",
+ "db0": ">=0.2.1",
+ "idb-keyval": "^6.2.1",
+ "ioredis": "^5.4.2",
+ "uploadthing": "^7.4.4"
+ },
+ "peerDependenciesMeta": {
+ "@azure/app-configuration": {
+ "optional": true
+ },
+ "@azure/cosmos": {
+ "optional": true
+ },
+ "@azure/data-tables": {
+ "optional": true
+ },
+ "@azure/identity": {
+ "optional": true
+ },
+ "@azure/keyvault-secrets": {
+ "optional": true
+ },
+ "@azure/storage-blob": {
+ "optional": true
+ },
+ "@capacitor/preferences": {
+ "optional": true
+ },
+ "@deno/kv": {
+ "optional": true
+ },
+ "@netlify/blobs": {
+ "optional": true
+ },
+ "@planetscale/database": {
+ "optional": true
+ },
+ "@upstash/redis": {
+ "optional": true
+ },
+ "@vercel/blob": {
+ "optional": true
+ },
+ "@vercel/functions": {
+ "optional": true
+ },
+ "@vercel/kv": {
+ "optional": true
+ },
+ "aws4fetch": {
+ "optional": true
+ },
+ "db0": {
+ "optional": true
+ },
+ "idb-keyval": {
+ "optional": true
+ },
+ "ioredis": {
+ "optional": true
+ },
+ "uploadthing": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/vfile": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
+ "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vfile-location": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz",
+ "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vfile-message": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
+ "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-stringify-position": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/victory-vendor": {
+ "version": "37.3.6",
+ "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
+ "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
+ "license": "MIT AND ISC",
+ "dependencies": {
+ "@types/d3-array": "^3.0.3",
+ "@types/d3-ease": "^3.0.0",
+ "@types/d3-interpolate": "^3.0.1",
+ "@types/d3-scale": "^4.0.2",
+ "@types/d3-shape": "^3.1.0",
+ "@types/d3-time": "^3.0.0",
+ "@types/d3-timer": "^3.0.0",
+ "d3-array": "^3.1.6",
+ "d3-ease": "^3.0.1",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale": "^4.0.2",
+ "d3-shape": "^3.1.0",
+ "d3-time": "^3.0.0",
+ "d3-timer": "^3.0.1"
+ }
+ },
+ "node_modules/vite": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.27.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "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",
+ "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
+ }
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz",
+ "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",
+ "license": "MIT",
+ "workspaces": [
+ "tests/deps/*",
+ "tests/projects/*",
+ "tests/projects/workspace/packages/*"
+ ],
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-css": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.70.tgz",
+ "integrity": "sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-css-languageservice": "^6.3.0",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-emmet": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.70.tgz",
+ "integrity": "sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/css-parser": "^0.4.1",
+ "@emmetio/html-matcher": "^1.3.0",
+ "@vscode/emmet-helper": "^2.9.3",
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-html": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.70.tgz",
+ "integrity": "sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-html-languageservice": "^5.3.0",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-prettier": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.70.tgz",
+ "integrity": "sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0",
+ "prettier": "^2.2 || ^3.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ },
+ "prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-typescript": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.70.tgz",
+ "integrity": "sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg==",
+ "license": "MIT",
+ "dependencies": {
+ "path-browserify": "^1.0.1",
+ "semver": "^7.6.2",
+ "typescript-auto-import-cache": "^0.3.5",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-nls": "^5.2.0",
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-typescript-twoslash-queries": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.70.tgz",
+ "integrity": "sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-uri": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/volar-service-yaml": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.70.tgz",
+ "integrity": "sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-uri": "^3.0.8",
+ "yaml-language-server": "~1.20.0"
+ },
+ "peerDependencies": {
+ "@volar/language-service": "~2.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@volar/language-service": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vscode-css-languageservice": {
+ "version": "6.3.10",
+ "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.3.10.tgz",
+ "integrity": "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vscode/l10n": "^0.0.18",
+ "vscode-languageserver-textdocument": "^1.0.12",
+ "vscode-languageserver-types": "3.17.5",
+ "vscode-uri": "^3.1.0"
+ }
+ },
+ "node_modules/vscode-html-languageservice": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.2.tgz",
+ "integrity": "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==",
+ "license": "MIT",
+ "dependencies": {
+ "@vscode/l10n": "^0.0.18",
+ "vscode-languageserver-textdocument": "^1.0.12",
+ "vscode-languageserver-types": "^3.17.5",
+ "vscode-uri": "^3.1.0"
+ }
+ },
+ "node_modules/vscode-json-languageservice": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.8.tgz",
+ "integrity": "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==",
+ "license": "MIT",
+ "dependencies": {
+ "jsonc-parser": "^3.0.0",
+ "vscode-languageserver-textdocument": "^1.0.1",
+ "vscode-languageserver-types": "^3.16.0",
+ "vscode-nls": "^5.0.0",
+ "vscode-uri": "^3.0.2"
+ },
+ "engines": {
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/vscode-json-languageservice/node_modules/jsonc-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+ "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+ "license": "MIT"
+ },
+ "node_modules/vscode-jsonrpc": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+ "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/vscode-languageserver": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+ "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-languageserver-protocol": "3.17.5"
+ },
+ "bin": {
+ "installServerIntoExtension": "bin/installServerIntoExtension"
+ }
+ },
+ "node_modules/vscode-languageserver-protocol": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+ "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-jsonrpc": "8.2.0",
+ "vscode-languageserver-types": "3.17.5"
+ }
+ },
+ "node_modules/vscode-languageserver-textdocument": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz",
+ "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==",
+ "license": "MIT"
+ },
+ "node_modules/vscode-languageserver-types": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+ "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==",
+ "license": "MIT"
+ },
+ "node_modules/vscode-nls": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz",
+ "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==",
+ "license": "MIT"
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
+ "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
+ "license": "MIT"
+ },
+ "node_modules/web-namespaces": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
+ "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/which-pm-runs": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz",
+ "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/xxhash-wasm": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz",
+ "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==",
+ "license": "MIT"
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "license": "ISC"
+ },
+ "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/yaml-language-server": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/yaml-language-server/-/yaml-language-server-1.20.0.tgz",
+ "integrity": "sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vscode/l10n": "^0.0.18",
+ "ajv": "^8.17.1",
+ "ajv-draft-04": "^1.0.0",
+ "prettier": "^3.5.0",
+ "request-light": "^0.5.7",
+ "vscode-json-languageservice": "4.1.8",
+ "vscode-languageserver": "^9.0.0",
+ "vscode-languageserver-textdocument": "^1.0.1",
+ "vscode-languageserver-types": "^3.16.0",
+ "vscode-uri": "^3.0.2",
+ "yaml": "2.7.1"
+ },
+ "bin": {
+ "yaml-language-server": "bin/yaml-language-server"
+ }
+ },
+ "node_modules/yaml-language-server/node_modules/request-light": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz",
+ "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==",
+ "license": "MIT"
+ },
+ "node_modules/yaml-language-server/node_modules/yaml": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
+ "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "22.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+ "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
+ "license": "ISC",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
+ },
+ "node_modules/yargs/node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "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": "4.3.6",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
+ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zwitch": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
+ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ }
+ }
+}
diff --git a/dashboard/package.json b/dashboard/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "dashboard",
+ "type": "module",
+ "version": "0.0.1",
+ "engines": {
+ "node": ">=22.12.0"
+ },
+ "scripts": {
+ "dev": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ },
+ "dependencies": {
+ "@astrojs/check": "^0.9.8",
+ "@astrojs/react": "^5.0.2",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "astro": "^6.1.3",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "recharts": "^3.8.1"
+ }
+}
diff --git a/dashboard/public/favicon.ico b/dashboard/public/favicon.ico
Binary files differ.
diff --git a/dashboard/public/favicon.svg b/dashboard/public/favicon.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
+ <path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
+ <style>
+ path { fill: #000; }
+ @media (prefers-color-scheme: dark) {
+ path { fill: #FFF; }
+ }
+ </style>
+</svg>
diff --git a/dashboard/src/components/Charts.tsx b/dashboard/src/components/Charts.tsx
@@ -0,0 +1,145 @@
+import {
+ BarChart,
+ Bar,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ ResponsiveContainer,
+ Legend,
+} from "recharts";
+import type { Run } from "../lib/data";
+
+interface ChartsProps {
+ runs: Run[];
+}
+
+interface ModelScore {
+ model: string;
+ avg_score: number;
+ avg_cost: number;
+ count: number;
+}
+
+function aggregateByModel(runs: Run[]): ModelScore[] {
+ const byModel: Record<string, { scores: number[]; costs: number[] }> = {};
+
+ for (const run of runs) {
+ const model = run.meta.model;
+ if (!byModel[model]) byModel[model] = { scores: [], costs: [] };
+
+ if (run.eval_results?.score != null) {
+ byModel[model].scores.push(run.eval_results.score);
+ }
+ if (run.claude_output?.total_cost_usd != null) {
+ byModel[model].costs.push(run.claude_output.total_cost_usd);
+ }
+ }
+
+ return Object.entries(byModel).map(([model, data]) => ({
+ model,
+ avg_score: data.scores.length > 0
+ ? Math.round(
+ (data.scores.reduce((a, b) => a + b, 0) / data.scores.length) * 100
+ )
+ : 0,
+ avg_cost: data.costs.length > 0
+ ? Math.round(
+ (data.costs.reduce((a, b) => a + b, 0) / data.costs.length) * 100
+ ) / 100
+ : 0,
+ count: data.scores.length,
+ }));
+}
+
+interface TaskScore {
+ task: string;
+ avg_score: number;
+ pass_rate: number;
+}
+
+function aggregateByTask(runs: Run[]): TaskScore[] {
+ const byTask: Record<string, { scores: number[]; passes: number; total: number }> = {};
+
+ for (const run of runs) {
+ const task = run.meta.task;
+ if (!byTask[task]) byTask[task] = { scores: [], passes: 0, total: 0 };
+
+ byTask[task].total++;
+ if (run.eval_results?.score != null) {
+ byTask[task].scores.push(run.eval_results.score);
+ }
+ if (run.eval_results?.functional?.pass) {
+ byTask[task].passes++;
+ }
+ }
+
+ return Object.entries(byTask).map(([task, data]) => ({
+ task,
+ avg_score: data.scores.length > 0
+ ? Math.round(
+ (data.scores.reduce((a, b) => a + b, 0) / data.scores.length) * 100
+ )
+ : 0,
+ pass_rate: data.total > 0
+ ? Math.round((data.passes / data.total) * 100)
+ : 0,
+ }));
+}
+
+export default function Charts({ runs }: ChartsProps) {
+ if (runs.length === 0) {
+ return (
+ <div className="card" style={{ textAlign: "center", padding: "40px", color: "var(--text-muted)" }}>
+ No data to chart yet.
+ </div>
+ );
+ }
+
+ const modelData = aggregateByModel(runs);
+ const taskData = aggregateByTask(runs);
+
+ return (
+ <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "24px" }}>
+ <div className="card">
+ <h3 style={{ marginBottom: "16px" }}>Average Score by Model</h3>
+ <ResponsiveContainer width="100%" height={250}>
+ <BarChart data={modelData}>
+ <CartesianGrid strokeDasharray="3 3" stroke="#2d3045" />
+ <XAxis dataKey="model" stroke="#9ca3af" fontSize={12} />
+ <YAxis stroke="#9ca3af" fontSize={12} domain={[0, 100]} />
+ <Tooltip
+ contentStyle={{
+ background: "#1a1d27",
+ border: "1px solid #2d3045",
+ borderRadius: "6px",
+ }}
+ />
+ <Bar dataKey="avg_score" fill="#6366f1" name="Avg Score %" radius={[4, 4, 0, 0]} />
+ </BarChart>
+ </ResponsiveContainer>
+ </div>
+
+ <div className="card">
+ <h3 style={{ marginBottom: "16px" }}>Pass Rate by Task</h3>
+ <ResponsiveContainer width="100%" height={250}>
+ <BarChart data={taskData}>
+ <CartesianGrid strokeDasharray="3 3" stroke="#2d3045" />
+ <XAxis dataKey="task" stroke="#9ca3af" fontSize={12} />
+ <YAxis stroke="#9ca3af" fontSize={12} domain={[0, 100]} />
+ <Tooltip
+ contentStyle={{
+ background: "#1a1d27",
+ border: "1px solid #2d3045",
+ borderRadius: "6px",
+ }}
+ />
+ <Legend />
+ <Bar dataKey="avg_score" fill="#6366f1" name="Avg Score %" radius={[4, 4, 0, 0]} />
+ <Bar dataKey="pass_rate" fill="#22c55e" name="Pass Rate %" radius={[4, 4, 0, 0]} />
+ </BarChart>
+ </ResponsiveContainer>
+ </div>
+ </div>
+ );
+}
diff --git a/dashboard/src/components/Filters.tsx b/dashboard/src/components/Filters.tsx
@@ -0,0 +1,70 @@
+import { useState } from "react";
+import type { AxisName } from "../lib/data";
+
+interface FiltersProps {
+ axisValues: Record<AxisName, string[]>;
+ tasks: string[];
+ onFilterChange: (filters: Record<string, string>) => void;
+}
+
+const AXIS_LABELS: Record<AxisName, string> = {
+ model: "Model",
+ effort: "Effort",
+ prompt_style: "Prompt",
+ language: "Language",
+ human_language: "Human Lang",
+ linter: "Linter",
+ playwright: "Playwright",
+ context_file: "Context",
+ sub_agents: "Sub-agents",
+ web_search: "Web Search",
+ max_budget: "Budget",
+};
+
+export default function Filters({
+ axisValues,
+ tasks,
+ onFilterChange,
+}: FiltersProps) {
+ const [filters, setFilters] = useState<Record<string, string>>({});
+
+ const handleChange = (key: string, value: string) => {
+ const newFilters = { ...filters };
+ if (value === "") {
+ delete newFilters[key];
+ } else {
+ newFilters[key] = value;
+ }
+ setFilters(newFilters);
+ onFilterChange(newFilters);
+ };
+
+ return (
+ <div className="filters">
+ <div className="filter-group">
+ <label>Task</label>
+ <select onChange={(e) => handleChange("task", e.target.value)}>
+ <option value="">All</option>
+ {tasks.map((t) => (
+ <option key={t} value={t}>
+ {t}
+ </option>
+ ))}
+ </select>
+ </div>
+ {(Object.keys(axisValues) as AxisName[]).map((axis) => (
+ <div key={axis} className="filter-group">
+ <label>{AXIS_LABELS[axis]}</label>
+ <select onChange={(e) => handleChange(axis, e.target.value)}>
+ <option value="">All</option>
+ {axisValues[axis].map((v) => (
+ <option key={v} value={v}>
+ {v}
+ </option>
+ ))}
+ </select>
+ </div>
+ ))}
+ </div>
+ );
+}
diff --git a/dashboard/src/components/Grid.tsx b/dashboard/src/components/Grid.tsx
@@ -0,0 +1,128 @@
+import { useState, useMemo } from "react";
+import type { Run, AxisName } from "../lib/data";
+import Filters from "./Filters";
+
+interface GridProps {
+ runs: Run[];
+ axisValues: Record<AxisName, string[]>;
+ tasks: string[];
+}
+
+function scoreClass(score: number | null | undefined): string {
+ if (score === null || score === undefined) return "";
+ if (score >= 0.7) return "score-high";
+ if (score >= 0.4) return "score-mid";
+ return "score-low";
+}
+
+function formatScore(score: number | null | undefined): string {
+ if (score === null || score === undefined) return "-";
+ return (score * 100).toFixed(0) + "%";
+}
+
+function formatCost(cost: number | null | undefined): string {
+ if (cost === null || cost === undefined) return "-";
+ return "$" + cost.toFixed(2);
+}
+
+function formatTime(seconds: number | null | undefined): string {
+ if (seconds === null || seconds === undefined) return "-";
+ if (seconds < 60) return seconds + "s";
+ return Math.floor(seconds / 60) + "m " + (seconds % 60) + "s";
+}
+
+export default function Grid({ runs, axisValues, tasks }: GridProps) {
+ const [filters, setFilters] = useState<Record<string, string>>({});
+
+ const filteredRuns = useMemo(() => {
+ return runs.filter((run) => {
+ for (const [key, value] of Object.entries(filters)) {
+ if (key === "task") {
+ if (run.meta.task !== value) return false;
+ } else {
+ if (String(run.meta[key as keyof typeof run.meta]) !== value)
+ return false;
+ }
+ }
+ return true;
+ });
+ }, [runs, filters]);
+
+ return (
+ <div>
+ <Filters
+ axisValues={axisValues}
+ tasks={tasks}
+ onFilterChange={setFilters}
+ />
+
+ <div className="card" style={{ overflowX: "auto" }}>
+ <table>
+ <thead>
+ <tr>
+ <th>Run ID</th>
+ <th>Task</th>
+ <th>Model</th>
+ <th>Effort</th>
+ <th>Prompt</th>
+ <th>Lang</th>
+ <th>Score</th>
+ <th>Pass</th>
+ <th>Cost</th>
+ <th>Time</th>
+ <th>Turns</th>
+ </tr>
+ </thead>
+ <tbody>
+ {filteredRuns.length === 0 ? (
+ <tr>
+ <td colSpan={11} style={{ textAlign: "center", color: "var(--text-muted)", padding: "40px" }}>
+ {runs.length === 0
+ ? "No benchmark results yet. Run the harness to generate data."
+ : "No results match the current filters."}
+ </td>
+ </tr>
+ ) : (
+ filteredRuns.map((run) => (
+ <tr key={run.meta.run_id}>
+ <td>
+ <a href={`/run/${run.meta.run_id}`}>
+ {run.meta.run_id.length > 40
+ ? run.meta.run_id.slice(0, 40) + "..."
+ : run.meta.run_id}
+ </a>
+ </td>
+ <td>{run.meta.task}</td>
+ <td>
+ <span className="badge badge-neutral">{run.meta.model}</span>
+ </td>
+ <td>{run.meta.effort}</td>
+ <td>{run.meta.prompt_style}</td>
+ <td>{run.meta.language}</td>
+ <td className={`score-cell ${scoreClass(run.eval_results?.score)}`}>
+ {formatScore(run.eval_results?.score)}
+ </td>
+ <td>
+ {run.eval_results?.functional?.pass === true ? (
+ <span className="badge badge-pass">PASS</span>
+ ) : run.eval_results?.functional?.pass === false ? (
+ <span className="badge badge-fail">FAIL</span>
+ ) : (
+ <span className="badge badge-neutral">-</span>
+ )}
+ </td>
+ <td>{formatCost(run.claude_output?.total_cost_usd)}</td>
+ <td>{formatTime(run.meta.wall_time_seconds)}</td>
+ <td>{run.claude_output?.num_turns ?? "-"}</td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ <div style={{ padding: "12px", color: "var(--text-muted)", fontSize: "0.75rem" }}>
+ Showing {filteredRuns.length} of {runs.length} runs
+ </div>
+ </div>
+ </div>
+ );
+}
diff --git a/dashboard/src/components/RunDetail.tsx b/dashboard/src/components/RunDetail.tsx
@@ -0,0 +1,139 @@
+import type { Run } from "../lib/data";
+import TranscriptViewer from "./TranscriptViewer";
+
+interface RunDetailProps {
+ run: Run;
+ transcriptLines: string[];
+}
+
+function ScoreBar({ label, score }: { label: string; score: number | null | undefined }) {
+ if (score === null || score === undefined) {
+ return (
+ <div style={{ marginBottom: "8px" }}>
+ <div style={{ display: "flex", justifyContent: "space-between", fontSize: "0.8rem", marginBottom: "4px" }}>
+ <span>{label}</span>
+ <span style={{ color: "var(--text-muted)" }}>N/A</span>
+ </div>
+ </div>
+ );
+ }
+
+ const pct = Math.round(score * 100);
+ const color = pct >= 70 ? "var(--green)" : pct >= 40 ? "var(--yellow)" : "var(--red)";
+
+ return (
+ <div style={{ marginBottom: "8px" }}>
+ <div style={{ display: "flex", justifyContent: "space-between", fontSize: "0.8rem", marginBottom: "4px" }}>
+ <span>{label}</span>
+ <span style={{ fontFamily: "var(--font-mono)", fontWeight: 600, color }}>{pct}%</span>
+ </div>
+ <div style={{ background: "var(--bg)", borderRadius: "4px", height: "6px", overflow: "hidden" }}>
+ <div style={{ width: `${pct}%`, height: "100%", background: color, borderRadius: "4px" }} />
+ </div>
+ </div>
+ );
+}
+
+export default function RunDetail({ run, transcriptLines }: RunDetailProps) {
+ const { meta, eval_results, claude_output } = run;
+
+ return (
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
+ {/* Config */}
+ <div className="card">
+ <h3 style={{ marginBottom: "12px" }}>Configuration</h3>
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(160px, 1fr))", gap: "12px" }}>
+ {[
+ ["Task", meta.task],
+ ["Model", meta.model],
+ ["Effort", meta.effort],
+ ["Prompt", meta.prompt_style],
+ ["Language", meta.language],
+ ["Human Lang", meta.human_language],
+ ["Linter", meta.linter],
+ ["Playwright", meta.playwright],
+ ["Context", meta.context_file],
+ ["Sub-agents", meta.sub_agents],
+ ["Web Search", meta.web_search],
+ ["Budget", `$${meta.max_budget_usd}`],
+ ].map(([label, value]) => (
+ <div key={label as string}>
+ <div style={{ fontSize: "0.7rem", color: "var(--text-muted)", textTransform: "uppercase" }}>
+ {label}
+ </div>
+ <div style={{ fontFamily: "var(--font-mono)", fontSize: "0.875rem" }}>{value}</div>
+ </div>
+ ))}
+ </div>
+ </div>
+
+ {/* Metrics */}
+ <div className="stats-grid">
+ <div className="stat-card">
+ <div className="stat-value" style={{ color: meta.exit_code === 0 ? "var(--green)" : "var(--red)" }}>
+ {meta.exit_code === 0 ? "OK" : `Exit ${meta.exit_code ?? "?"}`}
+ </div>
+ <div className="stat-label">Status</div>
+ </div>
+ <div className="stat-card">
+ <div className="stat-value">
+ {meta.wall_time_seconds != null
+ ? meta.wall_time_seconds < 60
+ ? `${meta.wall_time_seconds}s`
+ : `${Math.floor(meta.wall_time_seconds / 60)}m${meta.wall_time_seconds % 60}s`
+ : "-"}
+ </div>
+ <div className="stat-label">Wall Time</div>
+ </div>
+ <div className="stat-card">
+ <div className="stat-value">
+ {claude_output?.total_cost_usd != null ? `$${claude_output.total_cost_usd.toFixed(2)}` : "-"}
+ </div>
+ <div className="stat-label">Cost</div>
+ </div>
+ <div className="stat-card">
+ <div className="stat-value">{claude_output?.num_turns ?? "-"}</div>
+ <div className="stat-label">Turns</div>
+ </div>
+ <div className="stat-card">
+ <div className="stat-value">
+ {claude_output?.usage
+ ? ((claude_output.usage.input_tokens ?? 0) + (claude_output.usage.output_tokens ?? 0)).toLocaleString()
+ : "-"}
+ </div>
+ <div className="stat-label">Total Tokens</div>
+ </div>
+ </div>
+
+ {/* Scores */}
+ {eval_results && (
+ <div className="card">
+ <h3 style={{ marginBottom: "16px" }}>Evaluation Scores</h3>
+ <ScoreBar label="Overall" score={eval_results.score} />
+ <ScoreBar label="Structural" score={eval_results.structural?.score} />
+ <ScoreBar label="Functional" score={eval_results.functional?.score} />
+ <ScoreBar label="Quality" score={eval_results.quality?.score} />
+
+ {/* Check details */}
+ {eval_results.structural?.checks && (
+ <div style={{ marginTop: "16px" }}>
+ <h4 style={{ fontSize: "0.8rem", color: "var(--text-muted)", marginBottom: "8px" }}>
+ Structural Checks
+ </h4>
+ {eval_results.structural.checks.map((check, i) => (
+ <div key={i} style={{ display: "flex", gap: "8px", fontSize: "0.8rem", marginBottom: "4px" }}>
+ <span>{check.pass ? "+" : "-"}</span>
+ <span>{check.name}</span>
+ <span style={{ color: "var(--text-muted)" }}>{check.detail}</span>
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ )}
+
+ {/* Transcript */}
+ <TranscriptViewer lines={transcriptLines} />
+ </div>
+ );
+}
diff --git a/dashboard/src/components/TranscriptViewer.tsx b/dashboard/src/components/TranscriptViewer.tsx
@@ -0,0 +1,174 @@
+interface TranscriptViewerProps {
+ lines: string[];
+}
+
+interface TranscriptEvent {
+ type?: string;
+ role?: string;
+ content?: string;
+ tool_name?: string;
+ tool_input?: unknown;
+ result?: string;
+ [key: string]: unknown;
+}
+
+function renderEvent(event: TranscriptEvent, index: number) {
+ const type = event.type || "unknown";
+
+ if (type === "assistant" || event.role === "assistant") {
+ return (
+ <div
+ key={index}
+ style={{
+ padding: "12px 16px",
+ borderLeft: "3px solid #6366f1",
+ marginBottom: "8px",
+ background: "rgba(99, 102, 241, 0.05)",
+ }}
+ >
+ <div
+ style={{
+ fontSize: "0.7rem",
+ color: "#9ca3af",
+ marginBottom: "4px",
+ }}
+ >
+ ASSISTANT
+ </div>
+ <div style={{ whiteSpace: "pre-wrap", fontSize: "0.875rem" }}>
+ {event.content || event.result || JSON.stringify(event, null, 2)}
+ </div>
+ </div>
+ );
+ }
+
+ if (type === "tool_use" || event.tool_name) {
+ return (
+ <div
+ key={index}
+ style={{
+ padding: "12px 16px",
+ borderLeft: "3px solid #eab308",
+ marginBottom: "8px",
+ background: "rgba(234, 179, 8, 0.05)",
+ }}
+ >
+ <div
+ style={{
+ fontSize: "0.7rem",
+ color: "#eab308",
+ marginBottom: "4px",
+ fontFamily: "var(--font-mono)",
+ }}
+ >
+ TOOL: {event.tool_name || "unknown"}
+ </div>
+ <pre
+ style={{
+ fontSize: "0.75rem",
+ overflow: "auto",
+ maxHeight: "200px",
+ color: "#9ca3af",
+ }}
+ >
+ {typeof event.tool_input === "string"
+ ? event.tool_input
+ : JSON.stringify(event.tool_input, null, 2)}
+ </pre>
+ </div>
+ );
+ }
+
+ if (type === "tool_result") {
+ return (
+ <div
+ key={index}
+ style={{
+ padding: "12px 16px",
+ borderLeft: "3px solid #22c55e",
+ marginBottom: "8px",
+ background: "rgba(34, 197, 94, 0.05)",
+ }}
+ >
+ <div
+ style={{
+ fontSize: "0.7rem",
+ color: "#22c55e",
+ marginBottom: "4px",
+ }}
+ >
+ RESULT
+ </div>
+ <pre
+ style={{
+ fontSize: "0.75rem",
+ overflow: "auto",
+ maxHeight: "200px",
+ color: "#9ca3af",
+ }}
+ >
+ {event.content || JSON.stringify(event, null, 2)}
+ </pre>
+ </div>
+ );
+ }
+
+ // Fallback: render raw JSON
+ return (
+ <div
+ key={index}
+ style={{
+ padding: "8px 16px",
+ marginBottom: "4px",
+ borderLeft: "3px solid #2d3045",
+ }}
+ >
+ <pre
+ style={{
+ fontSize: "0.7rem",
+ color: "#9ca3af",
+ overflow: "auto",
+ maxHeight: "100px",
+ }}
+ >
+ {JSON.stringify(event, null, 2)}
+ </pre>
+ </div>
+ );
+}
+
+export default function TranscriptViewer({ lines }: TranscriptViewerProps) {
+ if (lines.length === 0) {
+ return (
+ <div
+ className="card"
+ style={{
+ textAlign: "center",
+ padding: "40px",
+ color: "var(--text-muted)",
+ }}
+ >
+ No transcript available for this run.
+ </div>
+ );
+ }
+
+ const events: TranscriptEvent[] = lines
+ .map((line) => {
+ try {
+ return JSON.parse(line);
+ } catch {
+ return null;
+ }
+ })
+ .filter(Boolean);
+
+ return (
+ <div className="card" style={{ maxHeight: "600px", overflow: "auto" }}>
+ <h3 style={{ marginBottom: "16px", position: "sticky", top: 0, background: "var(--bg-card)", paddingBottom: "8px" }}>
+ Transcript ({events.length} events)
+ </h3>
+ {events.map((event, i) => renderEvent(event, i))}
+ </div>
+ );
+}
diff --git a/dashboard/src/layouts/Base.astro b/dashboard/src/layouts/Base.astro
@@ -0,0 +1,39 @@
+---
+import "../styles/global.css";
+
+interface Props {
+ title: string;
+}
+
+const { title } = Astro.props;
+---
+
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>{title} | Loop Benchmarking</title>
+ </head>
+ <body>
+ <header style="border-bottom: 1px solid var(--border); padding: 16px 0; margin-bottom: 32px;">
+ <div class="container" style="display: flex; align-items: center; gap: 24px;">
+ <a href="/" style="font-weight: 700; font-size: 1.1rem; color: var(--text);">
+ Loop Benchmarking
+ </a>
+ <nav style="display: flex; gap: 16px; font-size: 0.875rem;">
+ <a href="/">Grid</a>
+ <a href="/compare">Compare</a>
+ </nav>
+ </div>
+ </header>
+ <main class="container">
+ <slot />
+ </main>
+ <footer style="border-top: 1px solid var(--border); padding: 24px 0; margin-top: 48px;">
+ <div class="container" style="text-align: center; color: var(--text-muted); font-size: 0.75rem;">
+ Loop Benchmarking - Open agentic loop benchmark data
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/dashboard/src/lib/data.ts b/dashboard/src/lib/data.ts
@@ -0,0 +1,229 @@
+import fs from "node:fs";
+import path from "node:path";
+
+const RESULTS_DIR = path.resolve(
+ import.meta.dirname || __dirname,
+ "../../../results"
+);
+
+export interface RunMeta {
+ run_id: string;
+ cell_id: string;
+ task: string;
+ model: string;
+ effort: string;
+ prompt_style: string;
+ language: string;
+ human_language: string;
+ linter: string;
+ playwright: string;
+ context_file: string;
+ sub_agents: string;
+ web_search: string;
+ max_budget: string;
+ max_budget_usd: number;
+ run_number: number;
+ wall_time_seconds?: number;
+ exit_code?: number;
+ started_at?: string;
+ completed_at?: string;
+}
+
+export interface EvalResults {
+ structural?: {
+ pass: boolean;
+ score: number;
+ checks: Array<{ name: string; pass: boolean; detail: string }>;
+ };
+ functional?: {
+ pass: boolean;
+ score: number;
+ total?: number;
+ passed?: number;
+ failed?: number;
+ };
+ quality?: {
+ pass?: boolean;
+ score: number;
+ [key: string]: unknown;
+ };
+ score: number | null;
+}
+
+export interface ClaudeOutput {
+ result?: string;
+ total_cost_usd?: number;
+ num_turns?: number;
+ duration_ms?: number;
+ usage?: {
+ input_tokens?: number;
+ output_tokens?: number;
+ };
+}
+
+export interface Run {
+ meta: RunMeta;
+ eval_results: EvalResults | null;
+ claude_output: ClaudeOutput | null;
+ has_transcript: boolean;
+}
+
+export function loadAllRuns(): Run[] {
+ const runsDir = path.join(RESULTS_DIR, "runs");
+ if (!fs.existsSync(runsDir)) return [];
+
+ const runs: Run[] = [];
+
+ for (const runId of fs.readdirSync(runsDir)) {
+ const runDir = path.join(runsDir, runId);
+ if (!fs.statSync(runDir).isDirectory()) continue;
+
+ const metaPath = path.join(runDir, "meta.json");
+ if (!fs.existsSync(metaPath)) continue;
+
+ try {
+ const meta: RunMeta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
+
+ let eval_results: EvalResults | null = null;
+ const evalPath = path.join(runDir, "eval_results.json");
+ if (fs.existsSync(evalPath)) {
+ eval_results = JSON.parse(fs.readFileSync(evalPath, "utf-8"));
+ }
+
+ let claude_output: ClaudeOutput | null = null;
+ const outputPath = path.join(runDir, "claude_output.json");
+ if (fs.existsSync(outputPath)) {
+ claude_output = JSON.parse(fs.readFileSync(outputPath, "utf-8"));
+ }
+
+ const has_transcript = fs.existsSync(
+ path.join(runDir, "transcript.jsonl")
+ );
+
+ runs.push({ meta, eval_results, claude_output, has_transcript });
+ } catch {
+ // Skip corrupted run data
+ continue;
+ }
+ }
+
+ return runs.sort((a, b) => a.meta.run_id.localeCompare(b.meta.run_id));
+}
+
+export function loadTranscript(runId: string): string[] {
+ const transcriptPath = path.join(
+ RESULTS_DIR,
+ "runs",
+ runId,
+ "transcript.jsonl"
+ );
+ if (!fs.existsSync(transcriptPath)) return [];
+ return fs
+ .readFileSync(transcriptPath, "utf-8")
+ .split("\n")
+ .filter((line) => line.trim());
+}
+
+export type AxisName = keyof Pick<
+ RunMeta,
+ | "model"
+ | "effort"
+ | "prompt_style"
+ | "language"
+ | "human_language"
+ | "linter"
+ | "playwright"
+ | "context_file"
+ | "sub_agents"
+ | "web_search"
+ | "max_budget"
+>;
+
+export const AXIS_NAMES: AxisName[] = [
+ "model",
+ "effort",
+ "prompt_style",
+ "language",
+ "human_language",
+ "linter",
+ "playwright",
+ "context_file",
+ "sub_agents",
+ "web_search",
+ "max_budget",
+];
+
+export function getAxisValues(runs: Run[]): Record<AxisName, string[]> {
+ const values: Record<string, Set<string>> = {};
+ for (const axis of AXIS_NAMES) {
+ values[axis] = new Set();
+ }
+ for (const run of runs) {
+ for (const axis of AXIS_NAMES) {
+ values[axis].add(String(run.meta[axis]));
+ }
+ }
+ const result: Record<string, string[]> = {};
+ for (const axis of AXIS_NAMES) {
+ result[axis] = Array.from(values[axis]).sort();
+ }
+ return result as Record<AxisName, string[]>;
+}
+
+export function getTaskNames(runs: Run[]): string[] {
+ return Array.from(new Set(runs.map((r) => r.meta.task))).sort();
+}
+
+export interface AggregateStats {
+ count: number;
+ avg_score: number | null;
+ avg_cost: number | null;
+ avg_wall_time: number | null;
+ avg_turns: number | null;
+ pass_rate: number | null;
+}
+
+export function aggregateRuns(runs: Run[]): AggregateStats {
+ if (runs.length === 0) {
+ return {
+ count: 0,
+ avg_score: null,
+ avg_cost: null,
+ avg_wall_time: null,
+ avg_turns: null,
+ pass_rate: null,
+ };
+ }
+
+ const scores = runs
+ .map((r) => r.eval_results?.score)
+ .filter((s): s is number => s !== null && s !== undefined);
+
+ const costs = runs
+ .map((r) => r.claude_output?.total_cost_usd)
+ .filter((c): c is number => c !== undefined && c !== null);
+
+ const wallTimes = runs
+ .map((r) => r.meta.wall_time_seconds)
+ .filter((t): t is number => t !== undefined && t !== null);
+
+ const turns = runs
+ .map((r) => r.claude_output?.num_turns)
+ .filter((t): t is number => t !== undefined && t !== null);
+
+ const passes = runs.filter(
+ (r) => r.eval_results?.functional?.pass === true
+ ).length;
+
+ const avg = (arr: number[]) =>
+ arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : null;
+
+ return {
+ count: runs.length,
+ avg_score: avg(scores),
+ avg_cost: avg(costs),
+ avg_wall_time: avg(wallTimes),
+ avg_turns: avg(turns),
+ pass_rate: runs.length > 0 ? passes / runs.length : null,
+ };
+}
diff --git a/dashboard/src/pages/compare.astro b/dashboard/src/pages/compare.astro
@@ -0,0 +1,101 @@
+---
+import Base from "../layouts/Base.astro";
+import { loadAllRuns, getAxisValues, getTaskNames, aggregateRuns, AXIS_NAMES } from "../lib/data";
+import type { Run, AxisName } from "../lib/data";
+
+const runs = loadAllRuns();
+const axisValues = getAxisValues(runs);
+const tasks = getTaskNames(runs);
+
+// Build comparison data: for each axis, show how different values perform
+interface ComparisonRow {
+ axis: string;
+ value: string;
+ count: number;
+ avg_score: string;
+ pass_rate: string;
+ avg_cost: string;
+ avg_time: string;
+}
+
+const comparisons: ComparisonRow[] = [];
+
+const AXIS_LABELS: Record<AxisName, string> = {
+ model: "Model",
+ effort: "Effort",
+ prompt_style: "Prompt Style",
+ language: "Language",
+ human_language: "Human Language",
+ linter: "Linter",
+ playwright: "Playwright",
+ context_file: "Context File",
+ sub_agents: "Sub-agents",
+ web_search: "Web Search",
+ max_budget: "Budget",
+};
+
+for (const axis of AXIS_NAMES) {
+ for (const value of axisValues[axis]) {
+ const filtered = runs.filter(
+ (r: Run) => String(r.meta[axis as keyof typeof r.meta]) === value
+ );
+ const stats = aggregateRuns(filtered);
+ comparisons.push({
+ axis: AXIS_LABELS[axis],
+ value,
+ count: stats.count,
+ avg_score:
+ stats.avg_score != null ? (stats.avg_score * 100).toFixed(0) + "%" : "-",
+ pass_rate:
+ stats.pass_rate != null ? (stats.pass_rate * 100).toFixed(0) + "%" : "-",
+ avg_cost: stats.avg_cost != null ? "$" + stats.avg_cost.toFixed(2) : "-",
+ avg_time:
+ stats.avg_time != null ? Math.round(stats.avg_time) + "s" : "-",
+ });
+ }
+}
+---
+
+<Base title="Compare">
+ <h1 style="margin-bottom: 8px;">Compare Configurations</h1>
+ <p style="color: var(--text-muted); margin-bottom: 24px; font-size: 0.875rem;">
+ Aggregate performance across each axis value.
+ </p>
+
+ {runs.length === 0 ? (
+ <div class="card" style="text-align: center; padding: 40px; color: var(--text-muted);">
+ No benchmark results yet. Run the harness to generate data.
+ </div>
+ ) : (
+ <div class="card" style="overflow-x: auto;">
+ <table>
+ <thead>
+ <tr>
+ <th>Axis</th>
+ <th>Value</th>
+ <th>Runs</th>
+ <th>Avg Score</th>
+ <th>Pass Rate</th>
+ <th>Avg Cost</th>
+ <th>Avg Time</th>
+ </tr>
+ </thead>
+ <tbody>
+ {comparisons.map((row) => (
+ <tr>
+ <td style="color: var(--text-muted);">{row.axis}</td>
+ <td>
+ <span class="badge badge-neutral">{row.value}</span>
+ </td>
+ <td>{row.count}</td>
+ <td class="score-cell">{row.avg_score}</td>
+ <td class="score-cell">{row.pass_rate}</td>
+ <td>{row.avg_cost}</td>
+ <td>{row.avg_time}</td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+ )}
+</Base>
diff --git a/dashboard/src/pages/index.astro b/dashboard/src/pages/index.astro
@@ -0,0 +1,54 @@
+---
+import Base from "../layouts/Base.astro";
+import { loadAllRuns, getAxisValues, getTaskNames, aggregateRuns } from "../lib/data";
+import Grid from "../components/Grid";
+import Charts from "../components/Charts";
+
+const runs = loadAllRuns();
+const axisValues = getAxisValues(runs);
+const tasks = getTaskNames(runs);
+const stats = aggregateRuns(runs);
+---
+
+<Base title="Grid Overview">
+ <h1 style="margin-bottom: 8px;">Benchmark Results</h1>
+ <p style="color: var(--text-muted); margin-bottom: 24px; font-size: 0.875rem;">
+ Comparing agentic coding loop configurations across tasks and setups.
+ </p>
+
+ <div class="stats-grid" style="margin-bottom: 32px;">
+ <div class="stat-card">
+ <div class="stat-value">{runs.length}</div>
+ <div class="stat-label">Total Runs</div>
+ </div>
+ <div class="stat-card">
+ <div class="stat-value">{tasks.length}</div>
+ <div class="stat-label">Tasks</div>
+ </div>
+ <div class="stat-card">
+ <div class="stat-value">
+ {stats.avg_score != null ? (stats.avg_score * 100).toFixed(0) + "%" : "-"}
+ </div>
+ <div class="stat-label">Avg Score</div>
+ </div>
+ <div class="stat-card">
+ <div class="stat-value">
+ {stats.pass_rate != null ? (stats.pass_rate * 100).toFixed(0) + "%" : "-"}
+ </div>
+ <div class="stat-label">Pass Rate</div>
+ </div>
+ <div class="stat-card">
+ <div class="stat-value">
+ {stats.avg_cost != null ? "$" + stats.avg_cost.toFixed(2) : "-"}
+ </div>
+ <div class="stat-label">Avg Cost</div>
+ </div>
+ </div>
+
+ <Charts client:load runs={runs} />
+
+ <div style="margin-top: 32px;">
+ <h2 style="margin-bottom: 16px;">All Runs</h2>
+ <Grid client:load runs={runs} axisValues={axisValues} tasks={tasks} />
+ </div>
+</Base>
diff --git a/dashboard/src/pages/run/[id].astro b/dashboard/src/pages/run/[id].astro
@@ -0,0 +1,30 @@
+---
+import Base from "../../layouts/Base.astro";
+import { loadAllRuns, loadTranscript } from "../../lib/data";
+import RunDetail from "../../components/RunDetail";
+
+export function getStaticPaths() {
+ const runs = loadAllRuns();
+ return runs.map((run) => ({
+ params: { id: run.meta.run_id },
+ props: { run },
+ }));
+}
+
+const { run } = Astro.props;
+const transcriptLines = loadTranscript(run.meta.run_id);
+---
+
+<Base title={`Run: ${run.meta.run_id}`}>
+ <div style="margin-bottom: 16px;">
+ <a href="/" style="font-size: 0.875rem;">Back to Grid</a>
+ </div>
+ <h1 style="margin-bottom: 4px; font-size: 1.25rem; font-family: var(--font-mono);">
+ {run.meta.run_id}
+ </h1>
+ <p style="color: var(--text-muted); margin-bottom: 24px; font-size: 0.875rem;">
+ Run #{run.meta.run_number} - {run.meta.completed_at || "in progress"}
+ </p>
+
+ <RunDetail client:load run={run} transcriptLines={transcriptLines} />
+</Base>
diff --git a/dashboard/src/styles/global.css b/dashboard/src/styles/global.css
@@ -0,0 +1,178 @@
+:root {
+ --bg: #0f1117;
+ --bg-card: #1a1d27;
+ --bg-hover: #232633;
+ --border: #2d3045;
+ --text: #e4e4e7;
+ --text-muted: #9ca3af;
+ --accent: #6366f1;
+ --accent-hover: #818cf8;
+ --green: #22c55e;
+ --red: #ef4444;
+ --yellow: #eab308;
+ --font-mono: "JetBrains Mono", "Fira Code", "Cascadia Code", monospace;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ line-height: 1.6;
+}
+
+a {
+ color: var(--accent);
+ text-decoration: none;
+}
+
+a:hover {
+ color: var(--accent-hover);
+ text-decoration: underline;
+}
+
+.container {
+ max-width: 1400px;
+ margin: 0 auto;
+ padding: 0 24px;
+}
+
+h1, h2, h3 {
+ font-weight: 600;
+ line-height: 1.3;
+}
+
+h1 { font-size: 1.75rem; }
+h2 { font-size: 1.35rem; }
+h3 { font-size: 1.1rem; }
+
+.card {
+ background: var(--bg-card);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ padding: 20px;
+}
+
+.badge {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: 4px;
+ font-size: 0.75rem;
+ font-weight: 500;
+ font-family: var(--font-mono);
+}
+
+.badge-pass {
+ background: rgba(34, 197, 94, 0.15);
+ color: var(--green);
+}
+
+.badge-fail {
+ background: rgba(239, 68, 68, 0.15);
+ color: var(--red);
+}
+
+.badge-neutral {
+ background: rgba(99, 102, 241, 0.15);
+ color: var(--accent);
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+th, td {
+ padding: 8px 12px;
+ text-align: left;
+ border-bottom: 1px solid var(--border);
+ font-size: 0.875rem;
+}
+
+th {
+ color: var(--text-muted);
+ font-weight: 500;
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+
+tr:hover {
+ background: var(--bg-hover);
+}
+
+.score-cell {
+ font-family: var(--font-mono);
+ font-weight: 600;
+}
+
+.score-high { color: var(--green); }
+.score-mid { color: var(--yellow); }
+.score-low { color: var(--red); }
+
+select, input {
+ background: var(--bg-card);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ color: var(--text);
+ padding: 6px 10px;
+ font-size: 0.875rem;
+}
+
+select:focus, input:focus {
+ outline: none;
+ border-color: var(--accent);
+}
+
+.filters {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ margin-bottom: 24px;
+}
+
+.filter-group {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.filter-group label {
+ font-size: 0.7rem;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+
+.stats-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ gap: 16px;
+ margin-bottom: 24px;
+}
+
+.stat-card {
+ background: var(--bg-card);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ padding: 16px;
+ text-align: center;
+}
+
+.stat-value {
+ font-size: 1.75rem;
+ font-weight: 700;
+ font-family: var(--font-mono);
+}
+
+.stat-label {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ margin-top: 4px;
+}
diff --git a/dashboard/tsconfig.json b/dashboard/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "include": [".astro/types.d.ts", "**/*"],
+ "exclude": ["dist"]
+}
diff --git a/grid.yaml b/grid.yaml
@@ -0,0 +1,89 @@
+version: 1
+
+defaults:
+ runs_per_cell: 3
+ timeout_seconds: 600
+ base_tools: "Bash,Read,Edit,Write,Glob,Grep"
+ budget:
+ low: 0.50
+ high: 5.00
+
+axes:
+ model:
+ values: [haiku, sonnet, opus]
+ effort:
+ values: [high, max]
+ prompt_style:
+ values: [simple, detailed]
+ language:
+ values: [typescript, javascript]
+ human_language:
+ values: [en, es]
+ linter:
+ values: ["on", "off"]
+ playwright:
+ values: ["on", "off"]
+ context_file:
+ values: [none, provided]
+ sub_agents:
+ values: ["on", "off"]
+ web_search:
+ values: ["on", "off"]
+ max_budget:
+ values: [low, high]
+
+exclusions:
+ # Haiku does not support extended thinking
+ - when:
+ model: haiku
+ effort: max
+
+task_overrides:
+ data-pipeline:
+ # Playwright is never relevant for a CLI data pipeline
+ axes:
+ playwright:
+ values: ["off"]
+
+tasks:
+ - tetris
+ - bookmarks-api
+ - data-pipeline
+
+profiles:
+ smoke:
+ description: "Quick validation -- minimal grid"
+ axes:
+ model: [sonnet]
+ effort: [high]
+ prompt_style: [simple, detailed]
+ language: [typescript]
+ human_language: [en]
+ linter: ["off"]
+ playwright: ["off"]
+ context_file: [none]
+ sub_agents: ["off"]
+ web_search: ["off"]
+ max_budget: [low]
+ runs_per_cell: 1
+
+ core:
+ description: "Core comparison -- models and effort levels"
+ axes:
+ model: [haiku, sonnet, opus]
+ effort: [high, max]
+ prompt_style: [simple, detailed]
+ language: [typescript]
+ human_language: [en]
+ linter: ["off"]
+ playwright: ["off"]
+ context_file: [none]
+ sub_agents: ["off"]
+ web_search: ["off"]
+ max_budget: [high]
+ runs_per_cell: 3
+
+ full:
+ description: "Full grid -- all dimensions"
+ # Uses top-level axes definition
+ runs_per_cell: 3
diff --git a/harness/lib/compute_grid.py b/harness/lib/compute_grid.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+"""Compute the experiment grid from grid.yaml.
+
+Reads the grid definition, selects a profile, computes the cartesian product
+of all axes, applies exclusions and task overrides, and outputs one JSON
+object per cell (JSONL format).
+
+Usage:
+ python3 compute_grid.py <grid_file> [profile]
+
+If no profile is given, uses "smoke".
+"""
+
+import json
+import sys
+from itertools import product
+
+import yaml
+
+
+def load_grid(path):
+ with open(path) as f:
+ return yaml.safe_load(f)
+
+
+def get_axes(grid, profile_name):
+ """Get axis values for a given profile, falling back to top-level axes."""
+ top_axes = {name: spec["values"] for name, spec in grid["axes"].items()}
+
+ if profile_name not in grid.get("profiles", {}):
+ return top_axes
+
+ profile = grid["profiles"][profile_name]
+ if "axes" not in profile:
+ return top_axes
+
+ # Profile axes override top-level axes
+ axes = dict(top_axes)
+ for name, values in profile["axes"].items():
+ axes[name] = values
+ return axes
+
+
+def get_runs_per_cell(grid, profile_name):
+ if profile_name in grid.get("profiles", {}):
+ profile = grid["profiles"][profile_name]
+ if "runs_per_cell" in profile:
+ return profile["runs_per_cell"]
+ return grid["defaults"]["runs_per_cell"]
+
+
+def matches_exclusion(cell, exclusion):
+ """Check if a cell matches an exclusion rule."""
+ for key, value in exclusion["when"].items():
+ if cell.get(key) != value:
+ return False
+ return True
+
+
+def apply_task_overrides(axes, task, grid):
+ """Apply task-specific axis overrides."""
+ overrides = grid.get("task_overrides", {}).get(task, {})
+ if not overrides or "axes" not in overrides:
+ return axes
+
+ result = dict(axes)
+ for axis_name, axis_spec in overrides["axes"].items():
+ result[axis_name] = axis_spec["values"]
+ return result
+
+
+def compute_cells(grid, profile_name):
+ base_axes = get_axes(grid, profile_name)
+ runs_per_cell = get_runs_per_cell(grid, profile_name)
+ exclusions = grid.get("exclusions", [])
+ tasks = grid["tasks"]
+ defaults = grid["defaults"]
+
+ cells = []
+
+ for task in tasks:
+ axes = apply_task_overrides(base_axes, task, grid)
+ axis_names = sorted(axes.keys())
+ axis_values = [axes[name] for name in axis_names]
+
+ for combo in product(*axis_values):
+ cell = dict(zip(axis_names, combo))
+
+ # Check exclusions
+ excluded = False
+ for exclusion in exclusions:
+ if matches_exclusion(cell, exclusion):
+ excluded = True
+ break
+ if excluded:
+ continue
+
+ # Build cell ID from task + all axis values (deterministic, filename-safe)
+ cell_id_parts = [task] + [f"{k}={cell[k]}" for k in axis_names]
+ cell_id = "_".join(cell_id_parts)
+
+ # Resolve budget value
+ budget_key = cell.get("max_budget", "low")
+ budget_usd = defaults["budget"].get(budget_key, 0.50)
+
+ cell["task"] = task
+ cell["cell_id"] = cell_id
+ cell["runs_per_cell"] = runs_per_cell
+ cell["max_budget_usd"] = budget_usd
+ cell["timeout_seconds"] = defaults["timeout_seconds"]
+ cell["base_tools"] = defaults["base_tools"]
+
+ cells.append(cell)
+
+ return cells
+
+
+def main():
+ if len(sys.argv) < 2:
+ print("Usage: compute_grid.py <grid_file> [profile]", file=sys.stderr)
+ sys.exit(1)
+
+ grid_file = sys.argv[1]
+ profile = sys.argv[2] if len(sys.argv) > 2 else "smoke"
+
+ grid = load_grid(grid_file)
+ cells = compute_cells(grid, profile)
+
+ for cell in cells:
+ print(json.dumps(cell))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/harness/lib/evaluate.sh b/harness/lib/evaluate.sh
@@ -0,0 +1,182 @@
+#!/usr/bin/env bash
+# Evaluation dispatch for benchmark runs.
+# Runs structural, functional, and quality checks against the workspace.
+
+evaluate() {
+ local task_dir="$1"
+ local workspace="$2"
+ local cell_json="$3"
+ local run_dir="$4"
+
+ local language
+ language=$(echo "$cell_json" | jq -r '.language')
+
+ local eval_results='{"structural": null, "functional": null, "quality": null, "score": null}'
+
+ # --- Structural checks ---
+ if [[ -f "$task_dir/eval/structural.sh" ]]; then
+ local structural_output
+ structural_output=$(bash "$task_dir/eval/structural.sh" "$workspace" "$language" 2>&1) || true
+ if echo "$structural_output" | jq . > /dev/null 2>&1; then
+ eval_results=$(echo "$eval_results" | jq --argjson s "$structural_output" '.structural = $s')
+ else
+ eval_results=$(echo "$eval_results" | jq --arg s "$structural_output" '.structural = {"pass": false, "error": $s}')
+ fi
+ fi
+
+ # --- Functional tests ---
+ local functional_output='{}'
+ if [[ -d "$task_dir/eval/tests" ]]; then
+ functional_output=$(run_functional_tests "$task_dir" "$workspace" "$language" "$run_dir") || true
+ if echo "$functional_output" | jq . > /dev/null 2>&1; then
+ eval_results=$(echo "$eval_results" | jq --argjson f "$functional_output" '.functional = $f')
+ else
+ eval_results=$(echo "$eval_results" | jq '.functional = {"pass": false, "error": "test runner failed"}')
+ fi
+ fi
+
+ # --- Quality checks ---
+ if [[ -f "$task_dir/eval/quality.sh" ]]; then
+ local quality_output
+ quality_output=$(bash "$task_dir/eval/quality.sh" "$workspace" "$language" 2>&1) || true
+ if echo "$quality_output" | jq . > /dev/null 2>&1; then
+ eval_results=$(echo "$eval_results" | jq --argjson q "$quality_output" '.quality = $q')
+ else
+ eval_results=$(echo "$eval_results" | jq --arg q "$quality_output" '.quality = {"pass": false, "error": $q}')
+ fi
+ fi
+
+ # --- Compute aggregate score ---
+ local scoring_file="$task_dir/scoring.yaml"
+ if [[ -f "$scoring_file" ]]; then
+ local score
+ score=$(compute_score "$eval_results" "$scoring_file")
+ eval_results=$(echo "$eval_results" | jq --argjson score "$score" '.score = $score')
+ fi
+
+ echo "$eval_results" | jq '.' > "$run_dir/eval_results.json"
+}
+
+run_functional_tests() {
+ local task_dir="$1"
+ local workspace="$2"
+ local language="$3"
+ local run_dir="$4"
+
+ # Check for Playwright tests
+ if [[ -f "$task_dir/eval/tests/functional.spec.ts" ]]; then
+ run_playwright_tests "$task_dir" "$workspace" "$run_dir"
+ return
+ fi
+
+ # Check for vitest tests
+ if [[ -f "$task_dir/eval/tests/functional.test.ts" ]]; then
+ run_vitest_tests "$task_dir" "$workspace" "$run_dir"
+ return
+ fi
+
+ # Check for shell-based tests
+ if [[ -f "$task_dir/eval/tests/functional.sh" ]]; then
+ bash "$task_dir/eval/tests/functional.sh" "$workspace" "$language"
+ return
+ fi
+
+ echo '{"pass": false, "error": "no test files found"}'
+}
+
+run_playwright_tests() {
+ local task_dir="$1"
+ local workspace="$2"
+ local run_dir="$3"
+
+ # Install Playwright in workspace if not already present
+ cd "$workspace" || return 1
+ npm install --save-dev @playwright/test > /dev/null 2>&1
+ npx playwright install chromium > /dev/null 2>&1
+
+ # Copy test files into a temporary test directory
+ local test_dir="$workspace/__eval_tests__"
+ mkdir -p "$test_dir"
+ cp "$task_dir/eval/tests/"*.spec.ts "$test_dir/" 2>/dev/null || true
+
+ # Run Playwright tests with JSON reporter
+ local result
+ result=$(npx playwright test --config="$task_dir/eval/playwright.config.ts" \
+ --reporter=json \
+ "$test_dir" 2>/dev/null) || true
+
+ # Clean up eval test files
+ rm -rf "$test_dir"
+
+ # Parse Playwright JSON output into our format
+ if echo "$result" | jq . > /dev/null 2>&1; then
+ echo "$result" | jq '{
+ framework: "playwright",
+ total: (.stats.expected + .stats.unexpected + .stats.skipped),
+ passed: .stats.expected,
+ failed: .stats.unexpected,
+ skipped: .stats.skipped,
+ score: (if (.stats.expected + .stats.unexpected) > 0
+ then (.stats.expected / (.stats.expected + .stats.unexpected))
+ else 0 end),
+ pass: (.stats.unexpected == 0)
+ }'
+ else
+ echo '{"framework": "playwright", "pass": false, "error": "playwright output not parseable"}'
+ fi
+}
+
+run_vitest_tests() {
+ local task_dir="$1"
+ local workspace="$2"
+ local run_dir="$3"
+
+ cd "$workspace" || return 1
+ npm install --save-dev vitest > /dev/null 2>&1
+
+ # Copy test files
+ local test_dir="$workspace/__eval_tests__"
+ mkdir -p "$test_dir"
+ cp "$task_dir/eval/tests/"*.test.ts "$test_dir/" 2>/dev/null || true
+
+ # Run vitest with JSON reporter
+ local result
+ result=$(npx vitest run --reporter=json "$test_dir" 2>/dev/null) || true
+
+ rm -rf "$test_dir"
+
+ if echo "$result" | jq . > /dev/null 2>&1; then
+ echo "$result" | jq '{
+ framework: "vitest",
+ total: .numTotalTests,
+ passed: .numPassedTests,
+ failed: .numFailedTests,
+ skipped: (.numPendingTests + .numTodoTests),
+ score: (if .numTotalTests > 0
+ then (.numPassedTests / .numTotalTests)
+ else 0 end),
+ pass: (.numFailedTests == 0)
+ }'
+ else
+ echo '{"framework": "vitest", "pass": false, "error": "vitest output not parseable"}'
+ fi
+}
+
+compute_score() {
+ local eval_results="$1"
+ local scoring_file="$2"
+
+ # Read weights from scoring.yaml
+ local w_functional w_structural w_quality
+ w_functional=$(python3 -c "import yaml; d=yaml.safe_load(open('$scoring_file')); print(d['weights']['functional'])")
+ w_structural=$(python3 -c "import yaml; d=yaml.safe_load(open('$scoring_file')); print(d['weights']['structural'])")
+ w_quality=$(python3 -c "import yaml; d=yaml.safe_load(open('$scoring_file')); print(d['weights']['quality'])")
+
+ # Extract individual scores, defaulting to 0
+ echo "$eval_results" | jq --argjson wf "$w_functional" --argjson ws "$w_structural" --argjson wq "$w_quality" '
+ (if .functional.score then .functional.score else 0 end) as $fs |
+ (if .structural.score then .structural.score else 0 end) as $ss |
+ (if .quality.score then .quality.score else 0 end) as $qs |
+ ($fs * $wf + $ss * $ws + $qs * $wq)
+ '
+}
diff --git a/harness/lib/invoke.sh b/harness/lib/invoke.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+# Claude CLI invocation for benchmark runs.
+# Maps grid cell configuration to CLI flags and captures output.
+
+invoke_claude() {
+ local cell_json="$1"
+ local workspace="$2"
+ local run_dir="$3"
+ local project_dir="$4"
+
+ local model effort task prompt_style human_language context_file
+ local sub_agents web_search budget timeout_seconds base_tools
+
+ model=$(echo "$cell_json" | jq -r '.model')
+ effort=$(echo "$cell_json" | jq -r '.effort')
+ task=$(echo "$cell_json" | jq -r '.task')
+ prompt_style=$(echo "$cell_json" | jq -r '.prompt_style')
+ human_language=$(echo "$cell_json" | jq -r '.human_language')
+ context_file=$(echo "$cell_json" | jq -r '.context_file')
+ sub_agents=$(echo "$cell_json" | jq -r '.sub_agents')
+ web_search=$(echo "$cell_json" | jq -r '.web_search')
+ budget=$(echo "$cell_json" | jq -r '.max_budget_usd')
+ timeout_seconds=$(echo "$cell_json" | jq -r '.timeout_seconds // 600')
+ base_tools=$(echo "$cell_json" | jq -r '.base_tools')
+
+ # Select prompt file
+ local prompt_file="$project_dir/tasks/$task/prompts/${prompt_style}.${human_language}.md"
+ if [[ ! -f "$prompt_file" ]]; then
+ echo "ERROR: Prompt file not found: $prompt_file" >&2
+ return 1
+ fi
+ local prompt
+ prompt=$(<"$prompt_file")
+
+ # Append language instruction
+ local language
+ language=$(echo "$cell_json" | jq -r '.language')
+ if [[ "$language" == "typescript" ]]; then
+ prompt="$prompt
+
+Use TypeScript."
+ elif [[ "$language" == "javascript" ]]; then
+ prompt="$prompt
+
+Use JavaScript (no TypeScript)."
+ fi
+
+ # Build tool list
+ local tools="$base_tools"
+ if [[ "$sub_agents" == "on" ]]; then
+ tools="$tools,Agent"
+ fi
+ if [[ "$web_search" == "on" ]]; then
+ tools="$tools,WebSearch,WebFetch"
+ fi
+
+ # Build the claude command
+ local cmd=(
+ claude
+ --bare
+ -p "$prompt"
+ --model "$model"
+ --output-format stream-json
+ --dangerously-skip-permissions
+ --max-budget-usd "$budget"
+ --allowedTools "$tools"
+ )
+
+ # Add effort level
+ if [[ -n "$effort" ]] && [[ "$effort" != "null" ]]; then
+ cmd+=(--effort "$effort")
+ fi
+
+ # Add context file as system prompt if provided
+ if [[ "$context_file" == "provided" ]]; then
+ local ctx_file="$project_dir/tasks/$task/context.md"
+ if [[ -f "$ctx_file" ]]; then
+ cmd+=(--append-system-prompt "$(cat "$ctx_file")")
+ fi
+ fi
+
+ # Record start time
+ local start_time
+ start_time=$(date +%s)
+
+ # Run claude in the workspace directory
+ cd "$workspace" || exit 1
+
+ local exit_code=0
+ if timeout "${timeout_seconds}s" "${cmd[@]}" \
+ > "$run_dir/transcript.jsonl" 2>"$run_dir/claude_stderr.log"; then
+ exit_code=0
+ else
+ exit_code=$?
+ fi
+
+ local end_time
+ end_time=$(date +%s)
+ local wall_time=$((end_time - start_time))
+
+ # Extract the final result message from the stream
+ # The last JSON object with type "result" contains the summary metrics
+ if [[ -f "$run_dir/transcript.jsonl" ]]; then
+ tail -1 "$run_dir/transcript.jsonl" > "$run_dir/claude_output.json" 2>/dev/null || true
+ fi
+
+ # Update meta.json with timing info
+ local meta_file="$run_dir/meta.json"
+ if [[ -f "$meta_file" ]]; then
+ local tmp
+ tmp=$(jq \
+ --argjson wall "$wall_time" \
+ --argjson exit_code "$exit_code" \
+ --arg completed "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
+ '. + {wall_time_seconds: $wall, exit_code: $exit_code, completed_at: $completed}' \
+ "$meta_file")
+ echo "$tmp" > "$meta_file"
+ fi
+
+ return $exit_code
+}
diff --git a/harness/lib/resume.sh b/harness/lib/resume.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+# Resume logic for benchmark runs.
+# Checks if a run has already been completed so we can skip it.
+
+should_skip() {
+ local results_dir="$1"
+ local run_id="$2"
+
+ local result_file="$results_dir/runs/$run_id/eval_results.json"
+ if [[ -f "$result_file" ]]; then
+ return 0 # Skip (already completed)
+ fi
+ return 1 # Don't skip
+}
diff --git a/harness/lib/workspace.sh b/harness/lib/workspace.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+# Workspace creation and teardown for isolated benchmark runs.
+# Each run gets a fresh temp directory with no project context.
+
+create_workspace() {
+ local project_dir="$1"
+ local task="$2"
+ local cell_json="$3"
+
+ local language
+ language=$(echo "$cell_json" | jq -r '.language')
+ local linter
+ linter=$(echo "$cell_json" | jq -r '.linter')
+ local playwright_val
+ playwright_val=$(echo "$cell_json" | jq -r '.playwright')
+
+ local workspace
+ workspace=$(mktemp -d "/tmp/loop-bench-XXXXXX")
+
+ # Initialize npm project
+ cd "$workspace" || exit 1
+ npm init -y > /dev/null 2>&1
+
+ # Install TypeScript if needed
+ if [[ "$language" == "typescript" ]]; then
+ npm install --save-dev typescript @types/node > /dev/null 2>&1
+ fi
+
+ # Install linter if enabled
+ if [[ "$linter" == "on" ]]; then
+ npm install --save-dev eslint @eslint/js > /dev/null 2>&1
+ fi
+
+ # Install Playwright if enabled
+ if [[ "$playwright_val" == "on" ]]; then
+ npm install --save-dev @playwright/test > /dev/null 2>&1
+ npx playwright install chromium --with-deps > /dev/null 2>&1
+ fi
+
+ # Copy task fixtures into workspace
+ local fixtures_dir="$project_dir/tasks/$task/fixtures"
+ if [[ -d "$fixtures_dir" ]] && [[ "$(ls -A "$fixtures_dir" 2>/dev/null)" ]]; then
+ cp -r "$fixtures_dir"/* "$workspace/"
+ fi
+
+ echo "$workspace"
+}
+
+archive_workspace() {
+ local workspace="$1"
+ local run_dir="$2"
+
+ if [[ -d "$workspace" ]]; then
+ tar -czf "$run_dir/workspace.tar.gz" -C "$(dirname "$workspace")" "$(basename "$workspace")" 2>/dev/null || true
+ fi
+}
+
+cleanup_workspace() {
+ local workspace="$1"
+ local run_dir="$2"
+
+ archive_workspace "$workspace" "$run_dir"
+
+ if [[ -d "$workspace" ]] && [[ "$workspace" == /tmp/loop-bench-* ]]; then
+ rm -rf "$workspace"
+ fi
+}
diff --git a/harness/run.sh b/harness/run.sh
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+
+# shellcheck source=lib/workspace.sh
+source "$SCRIPT_DIR/lib/workspace.sh"
+# shellcheck source=lib/invoke.sh
+source "$SCRIPT_DIR/lib/invoke.sh"
+# shellcheck source=lib/evaluate.sh
+source "$SCRIPT_DIR/lib/evaluate.sh"
+# shellcheck source=lib/resume.sh
+source "$SCRIPT_DIR/lib/resume.sh"
+
+GRID_FILE="${1:-$PROJECT_DIR/grid.yaml}"
+PROFILE="${2:-smoke}"
+RESULTS_DIR="$PROJECT_DIR/results"
+
+echo "========================================"
+echo "Loop Benchmarking Harness"
+echo "========================================"
+echo "Grid file: $GRID_FILE"
+echo "Profile: $PROFILE"
+echo "Results: $RESULTS_DIR"
+echo "========================================"
+
+# Compute the experiment grid
+cells=$(python3 "$SCRIPT_DIR/lib/compute_grid.py" "$GRID_FILE" "$PROFILE")
+total_cells=$(echo "$cells" | wc -l)
+echo "Grid cells: $total_cells"
+echo ""
+
+# Track progress
+completed=0
+skipped=0
+failed=0
+
+echo "$cells" | while IFS= read -r cell_json; do
+ task=$(echo "$cell_json" | jq -r '.task')
+ cell_id=$(echo "$cell_json" | jq -r '.cell_id')
+ runs_per_cell=$(echo "$cell_json" | jq -r '.runs_per_cell')
+ model=$(echo "$cell_json" | jq -r '.model')
+ prompt_style=$(echo "$cell_json" | jq -r '.prompt_style')
+
+ for run_num in $(seq 1 "$runs_per_cell"); do
+ run_id="${cell_id}_run${run_num}"
+
+ # Check for existing results (resume support)
+ if should_skip "$RESULTS_DIR" "$run_id"; then
+ echo "SKIP: $run_id"
+ skipped=$((skipped + 1))
+ continue
+ fi
+
+ echo "----------------------------------------"
+ echo "RUN: $run_id"
+ echo "Task: $task | Model: $model | Prompt: $prompt_style"
+ echo "----------------------------------------"
+
+ # Create run results directory
+ run_dir="$RESULTS_DIR/runs/$run_id"
+ mkdir -p "$run_dir"
+
+ # Save cell config as meta.json
+ echo "$cell_json" | jq --arg run_id "$run_id" --argjson run_num "$run_num" \
+ '. + {run_id: $run_id, run_number: $run_num, started_at: (now | todate)}' \
+ > "$run_dir/meta.json"
+
+ # Create isolated workspace
+ echo " Creating workspace..."
+ workspace=$(create_workspace "$PROJECT_DIR" "$task" "$cell_json")
+ echo " Workspace: $workspace"
+
+ # Invoke claude
+ echo " Invoking claude (model=$model)..."
+ if invoke_claude "$cell_json" "$workspace" "$run_dir" "$PROJECT_DIR"; then
+ echo " Claude completed successfully"
+ else
+ echo " Claude exited with error (exit code: $?)"
+ failed=$((failed + 1))
+ fi
+
+ # Run evaluation
+ echo " Running evaluation..."
+ task_dir="$PROJECT_DIR/tasks/$task"
+ evaluate "$task_dir" "$workspace" "$cell_json" "$run_dir"
+ echo " Evaluation complete"
+
+ # Append to run index
+ jq -c '{
+ run_id: .run_id,
+ task: .task,
+ model: .model,
+ cell_id: .cell_id,
+ completed_at: .completed_at
+ }' "$run_dir/meta.json" >> "$RESULTS_DIR/index.jsonl"
+
+ # Archive and cleanup workspace
+ echo " Archiving workspace..."
+ cleanup_workspace "$workspace" "$run_dir"
+
+ completed=$((completed + 1))
+ echo " Done. ($completed completed, $skipped skipped, $failed failed)"
+ echo ""
+ done
+done
+
+echo "========================================"
+echo "All runs complete."
+echo "Completed: $completed | Skipped: $skipped | Failed: $failed"
+echo "========================================"
diff --git a/tasks/bookmarks-api/context.md b/tasks/bookmarks-api/context.md
@@ -0,0 +1,9 @@
+# Project Rules
+
+- Use Express (or similar minimal framework) for the HTTP server
+- Store data in SQLite -- no external database required
+- Hash passwords with bcrypt, argon2, or scrypt -- never store plaintext
+- Use parameterized queries -- never concatenate user input into SQL
+- Return proper HTTP status codes (201 for create, 404 for not found, 422 for validation errors, 401 for unauthorized)
+- JWT tokens should expire after 24 hours
+- The server port should be configurable via PORT environment variable
diff --git a/tasks/bookmarks-api/eval/quality.sh b/tasks/bookmarks-api/eval/quality.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+# Quality evaluation for Bookmarks API task.
+# Checks lint, types, and security practices.
+#
+# Usage: quality.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+results='{}'
+cd "$WORKSPACE"
+
+# --- Lint check ---
+npm install --save-dev eslint @eslint/js > /dev/null 2>&1
+
+if [[ "$LANGUAGE" == "typescript" ]]; then
+ extensions="ts"
+else
+ extensions="js"
+fi
+
+lint_output=$(npx eslint --no-eslintrc \
+ --rule '{"no-unused-vars":"warn","no-undef":"warn"}' \
+ --ext ".$extensions" --format json . 2>/dev/null) || true
+
+if echo "$lint_output" | jq . > /dev/null 2>&1; then
+ errors=$(echo "$lint_output" | jq '[.[].errorCount] | add // 0')
+ warnings=$(echo "$lint_output" | jq '[.[].warningCount] | add // 0')
+ lint_pass="false"
+ [[ "$errors" -eq 0 ]] && lint_pass="true"
+ results=$(echo "$results" | jq --argjson e "$errors" --argjson w "$warnings" --arg p "$lint_pass" \
+ '. + {lint: {pass: ($p == "true"), errors: $e, warnings: $w}}')
+else
+ results=$(echo "$results" | jq '. + {lint: {pass: false, error: "eslint failed"}}')
+fi
+
+# --- TypeScript type check ---
+if [[ "$LANGUAGE" == "typescript" ]]; then
+ if [[ -f "tsconfig.json" ]]; then
+ if npx tsc --noEmit > /dev/null 2>&1; then
+ results=$(echo "$results" | jq '. + {typecheck: {pass: true}}')
+ else
+ type_errors=$(npx tsc --noEmit 2>&1 | grep -c "error TS" || echo "0")
+ results=$(echo "$results" | jq --argjson e "$type_errors" '. + {typecheck: {pass: false, errors: $e}}')
+ fi
+ else
+ results=$(echo "$results" | jq '. + {typecheck: {pass: false, error: "no tsconfig.json"}}')
+ fi
+else
+ results=$(echo "$results" | jq '. + {typecheck: {pass: true, note: "not applicable for javascript"}}')
+fi
+
+# --- Security: passwords hashed ---
+# Look for bcrypt, argon2, or scrypt imports
+hash_found="false"
+if grep -rq "bcrypt\|argon2\|scrypt" --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ hash_found="true"
+fi
+results=$(echo "$results" | jq --arg p "$hash_found" \
+ '. + {security_passwords: {pass: ($p == "true"), detail: "checked for bcrypt/argon2/scrypt imports"}}')
+
+# --- Security: JWT secret not hardcoded ---
+jwt_secret_safe="true"
+# Check for obviously hardcoded secrets
+if grep -rqE "(secret|jwt_secret|JWT_SECRET)\s*[:=]\s*['\"]secret['\"]" --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ jwt_secret_safe="false"
+fi
+if grep -rqE "sign\([^)]*['\"]secret['\"]" --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ jwt_secret_safe="false"
+fi
+results=$(echo "$results" | jq --arg p "$jwt_secret_safe" \
+ '. + {security_jwt_secret: {pass: ($p == "true"), detail: "checked for hardcoded jwt secret"}}')
+
+# --- Security: parameterized SQL queries ---
+sql_safe="true"
+# Look for string concatenation in SQL queries (common vulnerability pattern)
+if grep -rqE "(query|run|exec|execute)\s*\(\s*['\"\`].*\\\$\{|\\+\s*\w+\s*\\+" --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ sql_safe="false"
+fi
+# Also check for template literals in SQL without parameterization
+if grep -rqE "(query|run|exec)\s*\(\s*\`[^)]*\\\$\{" --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ sql_safe="false"
+fi
+results=$(echo "$results" | jq --arg p "$sql_safe" \
+ '. + {security_sql: {pass: ($p == "true"), detail: "checked for SQL injection patterns"}}')
+
+# --- Compute score ---
+score_sum=0
+score_count=0
+for key in lint typecheck security_passwords security_jwt_secret security_sql; do
+ val=$(echo "$results" | jq --arg k "$key" '.[$k].pass // false')
+ if [[ "$val" == "true" ]]; then
+ score_sum=$((score_sum + 100))
+ fi
+ score_count=$((score_count + 1))
+done
+
+if [[ $score_count -gt 0 ]]; then
+ score=$(echo "scale=2; $score_sum / ($score_count * 100)" | bc)
+else
+ score="0"
+fi
+
+results=$(echo "$results" | jq --argjson s "$score" '. + {score: $s}')
+echo "$results" | jq '.'
diff --git a/tasks/bookmarks-api/eval/structural.sh b/tasks/bookmarks-api/eval/structural.sh
@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+# Structural evaluation for Bookmarks API task.
+#
+# Usage: structural.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+checks=()
+pass_count=0
+total_count=0
+
+add_check() {
+ local name="$1"
+ local passed="$2"
+ local detail="$3"
+ checks+=("{\"name\": \"$name\", \"pass\": $passed, \"detail\": \"$detail\"}")
+ total_count=$((total_count + 1))
+ if [[ "$passed" == "true" ]]; then
+ pass_count=$((pass_count + 1))
+ fi
+}
+
+# Check for package.json
+if [[ -f "$WORKSPACE/package.json" ]]; then
+ add_check "package_json_exists" "true" "package.json found"
+else
+ add_check "package_json_exists" "false" "no package.json found"
+fi
+
+# Check that dependencies can be installed
+cd "$WORKSPACE"
+if [[ -f "package.json" ]]; then
+ if npm install > /dev/null 2>&1; then
+ add_check "deps_install" "true" "npm install succeeded"
+ else
+ add_check "deps_install" "false" "npm install failed"
+ fi
+fi
+
+# Check for a server entry point
+found_entry="false"
+entry_detail="no server entry point found"
+for candidate in server.js index.js app.js src/server.js src/index.js src/app.js \
+ server.ts index.ts app.ts src/server.ts src/index.ts src/app.ts; do
+ if [[ -f "$WORKSPACE/$candidate" ]]; then
+ found_entry="true"
+ entry_detail="$candidate found"
+ break
+ fi
+done
+
+# Also check package.json main/start script
+if [[ "$found_entry" == "false" ]] && [[ -f "$WORKSPACE/package.json" ]]; then
+ has_start=$(node -e "const p=require('$WORKSPACE/package.json'); console.log(p.scripts && p.scripts.start ? 'yes' : 'no')" 2>/dev/null)
+ if [[ "$has_start" == "yes" ]]; then
+ found_entry="true"
+ entry_detail="start script found in package.json"
+ fi
+fi
+add_check "server_entry_exists" "$found_entry" "$entry_detail"
+
+# Try to start the server briefly to verify it boots
+if [[ "$found_entry" == "true" ]] && [[ -f "$WORKSPACE/package.json" ]]; then
+ cd "$WORKSPACE"
+ export PORT=0 # Let OS pick a port
+
+ # Try starting with npm start or node
+ has_start=$(node -e "const p=require('./package.json'); console.log(p.scripts && p.scripts.start ? 'yes' : 'no')" 2>/dev/null)
+
+ if [[ "$has_start" == "yes" ]]; then
+ timeout 10 npm start > /tmp/server_boot.log 2>&1 &
+ else
+ # Find the entry file
+ for f in server.js index.js app.js src/server.js src/index.js src/app.js; do
+ if [[ -f "$f" ]]; then
+ timeout 10 node "$f" > /tmp/server_boot.log 2>&1 &
+ break
+ fi
+ done
+ fi
+
+ SERVER_PID=$!
+ sleep 3
+
+ if kill -0 "$SERVER_PID" 2>/dev/null; then
+ add_check "server_starts" "true" "server process is running after 3s"
+ kill "$SERVER_PID" 2>/dev/null || true
+ wait "$SERVER_PID" 2>/dev/null || true
+ else
+ boot_error=$(cat /tmp/server_boot.log 2>/dev/null | tail -5 | tr '\n' ' ')
+ add_check "server_starts" "false" "server exited: $boot_error"
+ fi
+ rm -f /tmp/server_boot.log
+fi
+
+# Build checks JSON
+checks_json=$(printf '%s,' "${checks[@]}")
+checks_json="[${checks_json%,}]"
+
+if [[ $total_count -gt 0 ]]; then
+ score=$(echo "scale=2; $pass_count / $total_count" | bc)
+else
+ score="0"
+fi
+
+overall_pass="true"
+if [[ $pass_count -lt $total_count ]]; then
+ overall_pass="false"
+fi
+
+echo "{\"pass\": $overall_pass, \"checks\": $checks_json, \"score\": $score}"
diff --git a/tasks/bookmarks-api/eval/tests/functional.test.ts b/tasks/bookmarks-api/eval/tests/functional.test.ts
@@ -0,0 +1,220 @@
+import { describe, it, expect, beforeAll, afterAll } from "vitest";
+
+// The eval harness sets this env var to the running server's URL
+const BASE_URL = process.env.API_BASE_URL || "http://localhost:3000";
+
+let authToken = "";
+let createdBookmarkId = "";
+
+const testUser = {
+ email: `test_${Date.now()}@example.com`,
+ password: "TestPassword123!",
+};
+
+async function api(
+ path: string,
+ options: RequestInit = {}
+): Promise<Response> {
+ const url = `${BASE_URL}${path}`;
+ const headers: Record<string, string> = {
+ "Content-Type": "application/json",
+ ...(options.headers as Record<string, string>),
+ };
+ if (authToken) {
+ headers["Authorization"] = `Bearer ${authToken}`;
+ }
+ return fetch(url, { ...options, headers });
+}
+
+describe("Auth", () => {
+ it("POST /auth/register creates a new user", async () => {
+ const res = await api("/auth/register", {
+ method: "POST",
+ body: JSON.stringify(testUser),
+ });
+ expect(res.status).toBe(201);
+ const body = await res.json();
+ expect(body.email || body.user?.email).toBe(testUser.email);
+ });
+
+ it("POST /auth/register rejects duplicate email", async () => {
+ const res = await api("/auth/register", {
+ method: "POST",
+ body: JSON.stringify(testUser),
+ });
+ expect(res.status).toBeGreaterThanOrEqual(400);
+ expect(res.status).toBeLessThan(500);
+ });
+
+ it("POST /auth/login returns a token", async () => {
+ const res = await api("/auth/login", {
+ method: "POST",
+ body: JSON.stringify(testUser),
+ });
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ expect(body.token).toBeDefined();
+ authToken = body.token;
+ });
+
+ it("POST /auth/login rejects wrong password", async () => {
+ const res = await api("/auth/login", {
+ method: "POST",
+ body: JSON.stringify({ ...testUser, password: "wrong" }),
+ });
+ expect(res.status).toBe(401);
+ });
+});
+
+describe("Bookmarks - CRUD", () => {
+ it("POST /bookmarks creates a bookmark", async () => {
+ const res = await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "https://example.com",
+ title: "Example Site",
+ tags: ["test", "example"],
+ }),
+ });
+ expect(res.status).toBe(201);
+ const body = await res.json();
+ expect(body.url || body.bookmark?.url).toBe("https://example.com");
+ createdBookmarkId = body.id || body.bookmark?.id;
+ expect(createdBookmarkId).toBeDefined();
+ });
+
+ it("POST /bookmarks without auth returns 401", async () => {
+ const savedToken = authToken;
+ authToken = "";
+ const res = await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "https://example.com",
+ title: "No Auth",
+ tags: [],
+ }),
+ });
+ expect(res.status).toBe(401);
+ authToken = savedToken;
+ });
+
+ it("GET /bookmarks returns a list", async () => {
+ const res = await api("/bookmarks");
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ const bookmarks = Array.isArray(body) ? body : body.bookmarks || body.data;
+ expect(Array.isArray(bookmarks)).toBe(true);
+ expect(bookmarks.length).toBeGreaterThanOrEqual(1);
+ });
+
+ it("GET /bookmarks/:id returns the bookmark", async () => {
+ const res = await api(`/bookmarks/${createdBookmarkId}`);
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ const bookmark = body.bookmark || body;
+ expect(bookmark.url).toBe("https://example.com");
+ });
+
+ it("GET /bookmarks/:id with invalid id returns 404", async () => {
+ const res = await api("/bookmarks/99999");
+ expect(res.status).toBe(404);
+ });
+
+ it("PUT /bookmarks/:id updates the bookmark", async () => {
+ const res = await api(`/bookmarks/${createdBookmarkId}`, {
+ method: "PUT",
+ body: JSON.stringify({
+ title: "Updated Title",
+ }),
+ });
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ const bookmark = body.bookmark || body;
+ expect(bookmark.title).toBe("Updated Title");
+ });
+
+ it("DELETE /bookmarks/:id removes the bookmark", async () => {
+ const res = await api(`/bookmarks/${createdBookmarkId}`, {
+ method: "DELETE",
+ });
+ expect([200, 204]).toContain(res.status);
+
+ // Verify it's gone
+ const getRes = await api(`/bookmarks/${createdBookmarkId}`);
+ expect(getRes.status).toBe(404);
+ });
+});
+
+describe("Bookmarks - Validation", () => {
+ it("rejects invalid URL", async () => {
+ const res = await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "not-a-url",
+ title: "Bad URL",
+ tags: [],
+ }),
+ });
+ expect(res.status).toBe(422);
+ });
+
+ it("rejects title over 200 characters", async () => {
+ const res = await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "https://example.com/long",
+ title: "x".repeat(201),
+ tags: [],
+ }),
+ });
+ expect(res.status).toBe(422);
+ });
+
+ it("rejects more than 10 tags", async () => {
+ const tags = Array.from({ length: 11 }, (_, i) => `tag${i}`);
+ const res = await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "https://example.com/tags",
+ title: "Too Many Tags",
+ tags,
+ }),
+ });
+ expect(res.status).toBe(422);
+ });
+});
+
+describe("Bookmarks - Filtering", () => {
+ beforeAll(async () => {
+ // Create bookmarks with specific tags for filtering
+ await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "https://js.example.com",
+ title: "JS Resource",
+ tags: ["javascript", "frontend"],
+ }),
+ });
+ await api("/bookmarks", {
+ method: "POST",
+ body: JSON.stringify({
+ url: "https://py.example.com",
+ title: "Python Resource",
+ tags: ["python", "backend"],
+ }),
+ });
+ });
+
+ it("filters by tag", async () => {
+ const res = await api("/bookmarks?tag=javascript");
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ const bookmarks = Array.isArray(body) ? body : body.bookmarks || body.data;
+ expect(bookmarks.length).toBeGreaterThanOrEqual(1);
+ // Every result should have the javascript tag
+ for (const b of bookmarks) {
+ const tags = b.tags || [];
+ expect(tags).toContain("javascript");
+ }
+ });
+});
diff --git a/tasks/bookmarks-api/prompts/detailed.en.md b/tasks/bookmarks-api/prompts/detailed.en.md
@@ -0,0 +1,166 @@
+Build a REST API for managing personal bookmarks. The API should support user registration, authentication via JWT tokens, and full CRUD operations on bookmarks. Use SQLite as the database. The server should be runnable with a single command and require no external database setup.
+
+## Authentication Endpoints
+
+### POST /auth/register
+
+Register a new user.
+
+**Request body:**
+```json
+{
+ "email": "user@example.com",
+ "password": "securepassword"
+}
+```
+
+**Success response (201):**
+```json
+{
+ "id": 1,
+ "email": "user@example.com"
+}
+```
+
+- Passwords must be hashed before storage (use bcrypt or a similar algorithm).
+- Return 422 if the email is already taken or if required fields are missing.
+
+### POST /auth/login
+
+Authenticate and receive a JWT token.
+
+**Request body:**
+```json
+{
+ "email": "user@example.com",
+ "password": "securepassword"
+}
+```
+
+**Success response (200):**
+```json
+{
+ "token": "eyJhbGciOiJIUzI1NiIs..."
+}
+```
+
+- Return 401 for invalid credentials.
+- The JWT should contain the user ID and have a reasonable expiration (e.g., 24 hours).
+
+## Bookmark Endpoints
+
+All bookmark endpoints require a valid JWT token in the `Authorization: Bearer <token>` header. Return 401 if the token is missing or invalid. Users can only access their own bookmarks.
+
+### GET /bookmarks
+
+List the authenticated user's bookmarks.
+
+**Query parameters:**
+- `limit` (integer, default 20, max 100): number of bookmarks to return
+- `offset` (integer, default 0): number of bookmarks to skip
+- `tag` (string, optional): filter bookmarks that contain this tag
+
+**Success response (200):**
+```json
+{
+ "data": [
+ {
+ "id": 1,
+ "url": "https://example.com",
+ "title": "Example Site",
+ "tags": ["reference", "docs"],
+ "created_at": "2025-01-15T10:30:00Z",
+ "updated_at": "2025-01-15T10:30:00Z"
+ }
+ ],
+ "total": 45,
+ "limit": 20,
+ "offset": 0
+}
+```
+
+### POST /bookmarks
+
+Create a new bookmark.
+
+**Request body:**
+```json
+{
+ "url": "https://example.com",
+ "title": "Example Site",
+ "tags": ["reference", "docs"]
+}
+```
+
+**Success response (201):** returns the created bookmark object with id and timestamps.
+
+### GET /bookmarks/:id
+
+Get a single bookmark by ID. Returns 404 if not found or if it belongs to another user.
+
+**Success response (200):** returns the bookmark object.
+
+### PUT /bookmarks/:id
+
+Update an existing bookmark. All fields in the request body replace the existing values. Returns 404 if not found or if it belongs to another user.
+
+**Request body:** same shape as POST (url, title, tags). All fields are optional; only provided fields are updated.
+
+**Success response (200):** returns the updated bookmark object with an updated `updated_at` timestamp.
+
+### DELETE /bookmarks/:id
+
+Delete a bookmark. Returns 404 if not found or if it belongs to another user.
+
+**Success response (204):** no body.
+
+## Bookmark Fields
+
+Each bookmark has the following fields:
+
+| Field | Type | Constraints |
+|---|---|---|
+| id | integer | Auto-generated primary key |
+| url | string | Required. Must be a valid URL (starts with http:// or https://) |
+| title | string | Required. Maximum 200 characters |
+| tags | array of strings | Optional. Maximum 10 items. Each tag max 50 characters |
+| created_at | string (ISO 8601) | Auto-generated on creation |
+| updated_at | string (ISO 8601) | Auto-updated on modification |
+
+## Validation
+
+- Return 422 for any validation error with a JSON body describing what went wrong.
+- The `url` field must start with `http://` or `https://`.
+- The `title` field must not exceed 200 characters.
+- The `tags` array must not contain more than 10 items.
+- Each individual tag must not exceed 50 characters.
+
+## Status Codes Summary
+
+| Code | Usage |
+|---|---|
+| 200 | Successful read or update |
+| 201 | Successful creation |
+| 204 | Successful deletion |
+| 401 | Missing or invalid authentication |
+| 404 | Resource not found |
+| 422 | Validation error |
+
+## Database
+
+- Use SQLite with a local file (e.g., `bookmarks.db`).
+- The database and tables should be created automatically on first run if they do not exist.
+- Store tags in a way that supports the tag filter query (a join table or a serialized JSON column are both acceptable).
+
+## Server Configuration
+
+- The server port should be configurable via the `PORT` environment variable.
+- Default port is 3000 if `PORT` is not set.
+- The server should start with a single command (e.g., `node server.js` or `npm start`).
+
+## Technical Constraints
+
+- No external database server required. SQLite only.
+- The API should return JSON for all responses.
+- Include proper Content-Type headers.
+- Handle malformed JSON in request bodies gracefully (return 400).
diff --git a/tasks/bookmarks-api/prompts/detailed.es.md b/tasks/bookmarks-api/prompts/detailed.es.md
@@ -0,0 +1,166 @@
+Construye una API REST para gestionar marcadores personales. La API debe soportar registro de usuarios, autenticacion mediante tokens JWT y operaciones CRUD completas sobre marcadores. Usa SQLite como base de datos. El servidor debe poder ejecutarse con un solo comando y no requerir configuracion de base de datos externa.
+
+## Endpoints de Autenticacion
+
+### POST /auth/register
+
+Registrar un nuevo usuario.
+
+**Cuerpo de la solicitud:**
+```json
+{
+ "email": "usuario@ejemplo.com",
+ "password": "contrasenaSegura"
+}
+```
+
+**Respuesta exitosa (201):**
+```json
+{
+ "id": 1,
+ "email": "usuario@ejemplo.com"
+}
+```
+
+- Las contrasenas deben ser hasheadas antes de almacenarlas (usar bcrypt o un algoritmo similar).
+- Retornar 422 si el email ya esta registrado o si faltan campos requeridos.
+
+### POST /auth/login
+
+Autenticar y recibir un token JWT.
+
+**Cuerpo de la solicitud:**
+```json
+{
+ "email": "usuario@ejemplo.com",
+ "password": "contrasenaSegura"
+}
+```
+
+**Respuesta exitosa (200):**
+```json
+{
+ "token": "eyJhbGciOiJIUzI1NiIs..."
+}
+```
+
+- Retornar 401 para credenciales invalidas.
+- El JWT debe contener el ID del usuario y tener una expiracion razonable (por ejemplo, 24 horas).
+
+## Endpoints de Marcadores
+
+Todos los endpoints de marcadores requieren un token JWT valido en el encabezado `Authorization: Bearer <token>`. Retornar 401 si el token falta o es invalido. Los usuarios solo pueden acceder a sus propios marcadores.
+
+### GET /bookmarks
+
+Listar los marcadores del usuario autenticado.
+
+**Parametros de consulta:**
+- `limit` (entero, por defecto 20, maximo 100): numero de marcadores a retornar
+- `offset` (entero, por defecto 0): numero de marcadores a saltar
+- `tag` (cadena, opcional): filtrar marcadores que contengan esta etiqueta
+
+**Respuesta exitosa (200):**
+```json
+{
+ "data": [
+ {
+ "id": 1,
+ "url": "https://ejemplo.com",
+ "title": "Sitio de Ejemplo",
+ "tags": ["referencia", "docs"],
+ "created_at": "2025-01-15T10:30:00Z",
+ "updated_at": "2025-01-15T10:30:00Z"
+ }
+ ],
+ "total": 45,
+ "limit": 20,
+ "offset": 0
+}
+```
+
+### POST /bookmarks
+
+Crear un nuevo marcador.
+
+**Cuerpo de la solicitud:**
+```json
+{
+ "url": "https://ejemplo.com",
+ "title": "Sitio de Ejemplo",
+ "tags": ["referencia", "docs"]
+}
+```
+
+**Respuesta exitosa (201):** retorna el objeto de marcador creado con id y marcas de tiempo.
+
+### GET /bookmarks/:id
+
+Obtener un marcador individual por ID. Retorna 404 si no se encuentra o si pertenece a otro usuario.
+
+**Respuesta exitosa (200):** retorna el objeto de marcador.
+
+### PUT /bookmarks/:id
+
+Actualizar un marcador existente. Todos los campos en el cuerpo de la solicitud reemplazan los valores existentes. Retorna 404 si no se encuentra o si pertenece a otro usuario.
+
+**Cuerpo de la solicitud:** misma estructura que POST (url, title, tags). Todos los campos son opcionales; solo los campos proporcionados se actualizan.
+
+**Respuesta exitosa (200):** retorna el objeto de marcador actualizado con una marca de tiempo `updated_at` actualizada.
+
+### DELETE /bookmarks/:id
+
+Eliminar un marcador. Retorna 404 si no se encuentra o si pertenece a otro usuario.
+
+**Respuesta exitosa (204):** sin cuerpo.
+
+## Campos del Marcador
+
+Cada marcador tiene los siguientes campos:
+
+| Campo | Tipo | Restricciones |
+|---|---|---|
+| id | entero | Clave primaria auto-generada |
+| url | cadena | Requerido. Debe ser una URL valida (comienza con http:// o https://) |
+| title | cadena | Requerido. Maximo 200 caracteres |
+| tags | arreglo de cadenas | Opcional. Maximo 10 elementos. Cada etiqueta maximo 50 caracteres |
+| created_at | cadena (ISO 8601) | Auto-generado en la creacion |
+| updated_at | cadena (ISO 8601) | Auto-actualizado en la modificacion |
+
+## Validacion
+
+- Retornar 422 para cualquier error de validacion con un cuerpo JSON describiendo el problema.
+- El campo `url` debe comenzar con `http://` o `https://`.
+- El campo `title` no debe exceder 200 caracteres.
+- El arreglo `tags` no debe contener mas de 10 elementos.
+- Cada etiqueta individual no debe exceder 50 caracteres.
+
+## Resumen de Codigos de Estado
+
+| Codigo | Uso |
+|---|---|
+| 200 | Lectura o actualizacion exitosa |
+| 201 | Creacion exitosa |
+| 204 | Eliminacion exitosa |
+| 401 | Autenticacion faltante o invalida |
+| 404 | Recurso no encontrado |
+| 422 | Error de validacion |
+
+## Base de Datos
+
+- Usar SQLite con un archivo local (por ejemplo, `bookmarks.db`).
+- La base de datos y las tablas deben crearse automaticamente en la primera ejecucion si no existen.
+- Almacenar las etiquetas de una forma que soporte la consulta de filtro por etiqueta (una tabla de relacion o una columna JSON serializada son ambas aceptables).
+
+## Configuracion del Servidor
+
+- El puerto del servidor debe ser configurable mediante la variable de entorno `PORT`.
+- El puerto por defecto es 3000 si `PORT` no esta definido.
+- El servidor debe iniciarse con un solo comando (por ejemplo, `node server.js` o `npm start`).
+
+## Restricciones Tecnicas
+
+- No se requiere servidor de base de datos externo. Solo SQLite.
+- La API debe retornar JSON para todas las respuestas.
+- Incluir encabezados Content-Type apropiados.
+- Manejar JSON malformado en los cuerpos de solicitud de manera elegante (retornar 400).
diff --git a/tasks/bookmarks-api/prompts/simple.en.md b/tasks/bookmarks-api/prompts/simple.en.md
@@ -0,0 +1 @@
+Build a REST API for managing bookmarks. It should have user registration and login with JWT auth, CRUD endpoints for bookmarks (with url, title, and tags), and use SQLite for storage. Include input validation and proper HTTP status codes.
diff --git a/tasks/bookmarks-api/prompts/simple.es.md b/tasks/bookmarks-api/prompts/simple.es.md
@@ -0,0 +1 @@
+Construye una API REST para gestionar marcadores. Debe tener registro de usuarios e inicio de sesion con autenticacion JWT, endpoints CRUD para marcadores (con url, titulo y etiquetas), y usar SQLite para almacenamiento. Incluye validacion de entrada y codigos de estado HTTP apropiados.
diff --git a/tasks/bookmarks-api/scoring.yaml b/tasks/bookmarks-api/scoring.yaml
@@ -0,0 +1,12 @@
+weights:
+ functional: 0.50
+ structural: 0.15
+ quality: 0.35
+
+quality_weights:
+ lint: 0.15
+ typecheck: 0.15
+ security_passwords: 0.25
+ security_jwt_secret: 0.15
+ security_sql: 0.20
+ correct_status_codes: 0.10
diff --git a/tasks/bookmarks-api/task.yaml b/tasks/bookmarks-api/task.yaml
@@ -0,0 +1,28 @@
+name: bookmarks-api
+description: Build a REST API for managing bookmarks with JWT auth and SQLite storage
+difficulty: medium
+category: backend-api
+
+prompt_styles:
+ - simple
+ - detailed
+
+languages:
+ - typescript
+ - javascript
+
+eval:
+ structural:
+ - server_starts # starts on configurable port
+ - database_created # SQLite file appears on first run
+ - package_json_exists
+ functional:
+ framework: vitest
+ test_file: functional.test.ts
+ quality:
+ - lint
+ - typecheck # if typescript
+ - security_passwords # passwords are hashed (bcrypt/argon2/scrypt)
+ - security_jwt_secret # JWT secret is not hardcoded "secret"
+ - security_sql # parameterized queries (no string concatenation)
+ - correct_status_codes # 201 for create, 404 for not found, etc.
diff --git a/tasks/data-pipeline/context.md b/tasks/data-pipeline/context.md
@@ -0,0 +1,9 @@
+# Project Rules
+
+- Use integer cents or a decimal library for currency math -- never use floating point for money
+- The script should read a CSV file path from the first argument
+- Output should be valid JSON written to stdout
+- Handle edge cases gracefully: missing fields, malformed rows, duplicate IDs
+- Normalize all dates to ISO 8601 format
+- Deduplicate by transaction_id, keeping the row with the latest timestamp
+- Negative amounts represent refunds and should be subtracted from totals
diff --git a/tasks/data-pipeline/eval/quality.sh b/tasks/data-pipeline/eval/quality.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+# Quality evaluation for Data Pipeline task.
+# Checks lint, types, currency handling, and error resilience.
+#
+# Usage: quality.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+results='{}'
+cd "$WORKSPACE"
+
+# --- Lint check ---
+npm install --save-dev eslint @eslint/js > /dev/null 2>&1
+
+if [[ "$LANGUAGE" == "typescript" ]]; then
+ ext="ts"
+else
+ ext="js"
+fi
+
+lint_output=$(npx eslint --no-eslintrc \
+ --rule '{"no-unused-vars":"warn","no-undef":"warn"}' \
+ --ext ".$ext" --format json . 2>/dev/null) || true
+
+if echo "$lint_output" | jq . > /dev/null 2>&1; then
+ errors=$(echo "$lint_output" | jq '[.[].errorCount] | add // 0')
+ warnings=$(echo "$lint_output" | jq '[.[].warningCount] | add // 0')
+ lint_pass="false"
+ [[ "$errors" -eq 0 ]] && lint_pass="true"
+ results=$(echo "$results" | jq --argjson e "$errors" --argjson w "$warnings" --arg p "$lint_pass" \
+ '. + {lint: {pass: ($p == "true"), errors: $e, warnings: $w}}')
+else
+ results=$(echo "$results" | jq '. + {lint: {pass: false, error: "eslint failed"}}')
+fi
+
+# --- TypeScript type check ---
+if [[ "$LANGUAGE" == "typescript" ]]; then
+ if [[ -f "tsconfig.json" ]]; then
+ if npx tsc --noEmit > /dev/null 2>&1; then
+ results=$(echo "$results" | jq '. + {typecheck: {pass: true}}')
+ else
+ type_errors=$(npx tsc --noEmit 2>&1 | grep -c "error TS" || echo "0")
+ results=$(echo "$results" | jq --argjson e "$type_errors" '. + {typecheck: {pass: false, errors: $e}}')
+ fi
+ else
+ results=$(echo "$results" | jq '. + {typecheck: {pass: false, error: "no tsconfig.json"}}')
+ fi
+else
+ results=$(echo "$results" | jq '. + {typecheck: {pass: true, note: "not applicable for javascript"}}')
+fi
+
+# --- Currency: check for proper decimal handling ---
+# Look for use of decimal libraries or integer cent math
+no_float="false"
+if grep -rqE "Decimal|BigNumber|big\.js|dinero|currency\.js|Math\.round.*100|cents|integer" \
+ --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ no_float="true"
+fi
+# Also pass if they multiply by 100 before doing math
+if grep -rqE "\* ?100|\*100" --include="*.ts" --include="*.js" "$WORKSPACE" 2>/dev/null; then
+ no_float="true"
+fi
+results=$(echo "$results" | jq --arg p "$no_float" \
+ '. + {no_float_currency: {pass: ($p == "true"), detail: "checked for decimal library or integer cent usage"}}')
+
+# --- Handles empty input ---
+cd "$WORKSPACE"
+empty_csv=$(mktemp /tmp/empty_csv_XXXXXX.csv)
+echo 'transaction_id,timestamp,product_name,category,amount,currency,customer_email,region' > "$empty_csv"
+
+# Find entry point
+entry_file=""
+for candidate in pipeline.js pipeline.ts index.js index.ts src/pipeline.js src/pipeline.ts \
+ src/index.js src/index.ts process.js process.ts main.js main.ts; do
+ if [[ -f "$candidate" ]]; then
+ entry_file="$candidate"
+ break
+ fi
+done
+
+empty_pass="false"
+if [[ -n "$entry_file" ]]; then
+ if [[ "$entry_file" == *.ts ]]; then
+ run_cmd="npx tsx $entry_file"
+ else
+ run_cmd="node $entry_file"
+ fi
+ if timeout 10 $run_cmd "$empty_csv" > /dev/null 2>&1; then
+ empty_pass="true"
+ fi
+fi
+rm -f "$empty_csv"
+results=$(echo "$results" | jq --arg p "$empty_pass" \
+ '. + {handles_empty_input: {pass: ($p == "true")}}')
+
+# --- Handles malformed input ---
+malformed_csv=$(mktemp /tmp/malformed_csv_XXXXXX.csv)
+cat > "$malformed_csv" << 'CSVEOF'
+transaction_id,timestamp,product_name,category,amount,currency,customer_email,region
+TX001,2024-01-15,Widget,Electronics,$10.00,USD,test@example.com,NA
+TX002,bad-date,"Product with ""quotes""",Food,abc,USD,test@example.com,NA
+TX003,2024-01-16,Normal,Electronics,25.00,USD,bad-email,MARS
+CSVEOF
+
+malformed_pass="false"
+if [[ -n "$entry_file" ]]; then
+ if timeout 10 $run_cmd "$malformed_csv" > /dev/null 2>&1; then
+ malformed_pass="true"
+ fi
+fi
+rm -f "$malformed_csv"
+results=$(echo "$results" | jq --arg p "$malformed_pass" \
+ '. + {handles_malformed: {pass: ($p == "true")}}')
+
+# --- Compute score ---
+score_sum=0
+score_count=0
+for key in lint typecheck no_float_currency handles_empty_input handles_malformed; do
+ val=$(echo "$results" | jq --arg k "$key" '.[$k].pass // false')
+ if [[ "$val" == "true" ]]; then
+ score_sum=$((score_sum + 100))
+ fi
+ score_count=$((score_count + 1))
+done
+
+if [[ $score_count -gt 0 ]]; then
+ score=$(echo "scale=2; $score_sum / ($score_count * 100)" | bc)
+else
+ score="0"
+fi
+
+results=$(echo "$results" | jq --argjson s "$score" '. + {score: $s}')
+echo "$results" | jq '.'
diff --git a/tasks/data-pipeline/eval/structural.sh b/tasks/data-pipeline/eval/structural.sh
@@ -0,0 +1,104 @@
+#!/usr/bin/env bash
+# Structural evaluation for Data Pipeline task.
+#
+# Usage: structural.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+checks=()
+pass_count=0
+total_count=0
+
+add_check() {
+ local name="$1"
+ local passed="$2"
+ local detail="$3"
+ checks+=("{\"name\": \"$name\", \"pass\": $passed, \"detail\": \"$detail\"}")
+ total_count=$((total_count + 1))
+ if [[ "$passed" == "true" ]]; then
+ pass_count=$((pass_count + 1))
+ fi
+}
+
+# Check for an entry point script
+found_entry="false"
+entry_file=""
+for candidate in pipeline.js pipeline.ts index.js index.ts src/pipeline.js src/pipeline.ts \
+ src/index.js src/index.ts process.js process.ts main.js main.ts; do
+ if [[ -f "$WORKSPACE/$candidate" ]]; then
+ found_entry="true"
+ entry_file="$candidate"
+ break
+ fi
+done
+
+# Also check package.json for a start/main script
+if [[ "$found_entry" == "false" ]] && [[ -f "$WORKSPACE/package.json" ]]; then
+ main_file=$(node -e "const p=require('$WORKSPACE/package.json'); console.log(p.main || '')" 2>/dev/null)
+ if [[ -n "$main_file" ]] && [[ -f "$WORKSPACE/$main_file" ]]; then
+ found_entry="true"
+ entry_file="$main_file"
+ fi
+fi
+add_check "entry_point_exists" "$found_entry" "${entry_file:-no entry point found}"
+
+# Check package.json exists
+if [[ -f "$WORKSPACE/package.json" ]]; then
+ add_check "package_json_exists" "true" "package.json found"
+else
+ add_check "package_json_exists" "false" "no package.json"
+fi
+
+# Check that deps install
+cd "$WORKSPACE"
+if [[ -f "package.json" ]]; then
+ if npm install > /dev/null 2>&1; then
+ add_check "deps_install" "true" "npm install succeeded"
+ else
+ add_check "deps_install" "false" "npm install failed"
+ fi
+fi
+
+# Try running with a minimal CSV to see if it at least starts
+if [[ "$found_entry" == "true" ]]; then
+ # Create a tiny test CSV
+ local_csv=$(mktemp /tmp/test_csv_XXXXXX.csv)
+ echo 'transaction_id,timestamp,product_name,category,amount,currency,customer_email,region' > "$local_csv"
+ echo 'TX001,2024-01-15T10:00:00Z,Widget,Electronics,10.00,USD,test@example.com,NA' >> "$local_csv"
+
+ cd "$WORKSPACE"
+ local run_cmd=""
+ if [[ "$entry_file" == *.ts ]]; then
+ run_cmd="npx tsx $entry_file"
+ else
+ run_cmd="node $entry_file"
+ fi
+
+ output=$(timeout 15 $run_cmd "$local_csv" 2>/dev/null) || true
+ rm -f "$local_csv"
+
+ if echo "$output" | jq . > /dev/null 2>&1; then
+ add_check "outputs_json" "true" "script outputs valid JSON"
+ else
+ add_check "outputs_json" "false" "script output is not valid JSON"
+ fi
+fi
+
+# Build result
+checks_json=$(printf '%s,' "${checks[@]}")
+checks_json="[${checks_json%,}]"
+
+if [[ $total_count -gt 0 ]]; then
+ score=$(echo "scale=2; $pass_count / $total_count" | bc)
+else
+ score="0"
+fi
+
+overall_pass="true"
+if [[ $pass_count -lt $total_count ]]; then
+ overall_pass="false"
+fi
+
+echo "{\"pass\": $overall_pass, \"checks\": $checks_json, \"score\": $score}"
diff --git a/tasks/data-pipeline/eval/tests/functional.sh b/tasks/data-pipeline/eval/tests/functional.sh
@@ -0,0 +1,179 @@
+#!/usr/bin/env bash
+# Functional evaluation for Data Pipeline task.
+# Runs the agent's pipeline against known input and compares output to expected.
+#
+# Usage: functional.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+TASK_DIR="$(dirname "$SCRIPT_DIR")"
+
+INPUT_CSV="$TASK_DIR/../fixtures/test_input.csv"
+EXPECTED_OUTPUT="$TASK_DIR/../expected/output.json"
+
+checks=()
+pass_count=0
+total_count=0
+
+add_check() {
+ local name="$1"
+ local passed="$2"
+ local detail="$3"
+ checks+=("{\"name\": \"$name\", \"pass\": $passed, \"detail\": \"$detail\"}")
+ total_count=$((total_count + 1))
+ if [[ "$passed" == "true" ]]; then
+ pass_count=$((pass_count + 1))
+ fi
+}
+
+# Find entry point
+cd "$WORKSPACE"
+entry_file=""
+for candidate in pipeline.js pipeline.ts index.js index.ts src/pipeline.js src/pipeline.ts \
+ src/index.js src/index.ts process.js process.ts main.js main.ts; do
+ if [[ -f "$candidate" ]]; then
+ entry_file="$candidate"
+ break
+ fi
+done
+
+if [[ -z "$entry_file" ]]; then
+ echo '{"pass": false, "error": "no entry point found", "score": 0}'
+ exit 0
+fi
+
+# Install deps
+npm install > /dev/null 2>&1
+
+# Run the pipeline
+if [[ "$entry_file" == *.ts ]]; then
+ run_cmd="npx tsx $entry_file"
+else
+ run_cmd="node $entry_file"
+fi
+
+actual_output=$(timeout 30 $run_cmd "$INPUT_CSV" 2>/dev/null)
+exit_code=$?
+
+if [[ $exit_code -ne 0 ]]; then
+ add_check "pipeline_runs" "false" "pipeline exited with code $exit_code"
+ checks_json=$(printf '%s,' "${checks[@]}")
+ checks_json="[${checks_json%,}]"
+ echo "{\"pass\": false, \"checks\": $checks_json, \"score\": 0}"
+ exit 0
+fi
+
+add_check "pipeline_runs" "true" "pipeline completed successfully"
+
+# Check output is valid JSON
+if ! echo "$actual_output" | jq . > /dev/null 2>&1; then
+ add_check "valid_json" "false" "output is not valid JSON"
+ checks_json=$(printf '%s,' "${checks[@]}")
+ checks_json="[${checks_json%,}]"
+ echo "{\"pass\": false, \"checks\": $checks_json, \"score\": $(echo "scale=2; $pass_count / $total_count" | bc)}"
+ exit 0
+fi
+
+add_check "valid_json" "true" "output is valid JSON"
+
+# Compare specific fields against expected output
+if [[ ! -f "$EXPECTED_OUTPUT" ]]; then
+ echo '{"pass": false, "error": "expected output file not found", "score": 0}'
+ exit 0
+fi
+
+expected=$(cat "$EXPECTED_OUTPUT")
+
+# Helper: compare numeric values with tolerance
+compare_numeric() {
+ local field="$1"
+ local actual_val expected_val
+ actual_val=$(echo "$actual_output" | jq ".$field // null")
+ expected_val=$(echo "$expected" | jq ".$field // null")
+
+ if [[ "$actual_val" == "null" ]]; then
+ add_check "$field" "false" "field missing from output"
+ return
+ fi
+
+ # Allow 1% tolerance for floating point
+ local diff
+ diff=$(echo "$actual_val $expected_val" | awk '{d=$1-$2; if(d<0) d=-d; if($2!=0) print d/$2; else print d}')
+ local within_tolerance
+ within_tolerance=$(echo "$diff" | awk '{print ($1 < 0.01) ? "true" : "false"}')
+
+ add_check "$field" "$within_tolerance" "expected=$expected_val actual=$actual_val"
+}
+
+# Helper: compare integer values exactly
+compare_int() {
+ local field="$1"
+ local actual_val expected_val
+ actual_val=$(echo "$actual_output" | jq ".$field // null")
+ expected_val=$(echo "$expected" | jq ".$field // null")
+
+ if [[ "$actual_val" == "null" ]]; then
+ add_check "$field" "false" "field missing from output"
+ return
+ fi
+
+ if [[ "$actual_val" == "$expected_val" ]]; then
+ add_check "$field" "true" "matches expected value $expected_val"
+ else
+ add_check "$field" "false" "expected=$expected_val actual=$actual_val"
+ fi
+}
+
+# Compare all expected fields
+compare_numeric "total_revenue"
+compare_numeric "refund_total"
+compare_numeric "net_revenue"
+compare_int "invalid_row_count"
+compare_int "duplicate_count"
+compare_int "total_rows_processed"
+
+# Check breakdown_by_category exists and has correct keys
+actual_categories=$(echo "$actual_output" | jq -r '.breakdown_by_category // {} | keys | sort | .[]' 2>/dev/null)
+expected_categories=$(echo "$expected" | jq -r '.breakdown_by_category // {} | keys | sort | .[]' 2>/dev/null)
+if [[ "$actual_categories" == "$expected_categories" ]]; then
+ add_check "breakdown_by_category_keys" "true" "category keys match"
+else
+ add_check "breakdown_by_category_keys" "false" "category keys differ"
+fi
+
+# Check breakdown_by_month exists and has correct keys
+actual_months=$(echo "$actual_output" | jq -r '.breakdown_by_month // {} | keys | sort | .[]' 2>/dev/null)
+expected_months=$(echo "$expected" | jq -r '.breakdown_by_month // {} | keys | sort | .[]' 2>/dev/null)
+if [[ "$actual_months" == "$expected_months" ]]; then
+ add_check "breakdown_by_month_keys" "true" "month keys match"
+else
+ add_check "breakdown_by_month_keys" "false" "month keys differ"
+fi
+
+# Check top_10_products exists and is an array
+top_products_len=$(echo "$actual_output" | jq '.top_10_products | length // 0' 2>/dev/null)
+if [[ "$top_products_len" -gt 0 ]]; then
+ add_check "top_10_products_exists" "true" "$top_products_len products listed"
+else
+ add_check "top_10_products_exists" "false" "top_10_products missing or empty"
+fi
+
+# Build result
+checks_json=$(printf '%s,' "${checks[@]}")
+checks_json="[${checks_json%,}]"
+
+if [[ $total_count -gt 0 ]]; then
+ score=$(echo "scale=2; $pass_count / $total_count" | bc)
+else
+ score="0"
+fi
+
+overall_pass="true"
+if [[ $pass_count -lt $total_count ]]; then
+ overall_pass="false"
+fi
+
+echo "{\"pass\": $overall_pass, \"checks\": $checks_json, \"score\": $score}"
diff --git a/tasks/data-pipeline/expected/generate_golden.py b/tasks/data-pipeline/expected/generate_golden.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+"""
+Generate the golden expected output for the data-pipeline benchmark task.
+
+Rules applied (from spec):
+1. Strip currency symbols ($, EUR, etc.) and commas from amounts
+2. Normalize dates to ISO 8601
+3. Validate: amount must be numeric, email must contain @, region must be in [NA, EU, APAC, LATAM, MEA]
+4. Invalid rows: counted but excluded from calculations
+5. Deduplicate by transaction_id, keeping the row with the latest timestamp
+6. Negative amounts are refunds (included in calculations, subtracted from net)
+7. Output fields: total_revenue, refund_total, net_revenue, breakdown_by_category,
+ breakdown_by_month (YYYY-MM keys), top_10_products (sorted by revenue desc),
+ invalid_row_count, duplicate_count, total_rows_processed
+"""
+
+import csv
+import json
+import re
+import sys
+from collections import defaultdict
+from datetime import datetime
+from decimal import Decimal, ROUND_HALF_UP
+
+
+def parse_amount(raw: str) -> Decimal | None:
+ """Strip currency symbols/commas, return Decimal or None if invalid."""
+ if raw is None or raw.strip() == "":
+ return None
+ s = raw.strip()
+ # Remove currency prefixes like "$", "EUR ", "USD ", etc.
+ s = re.sub(r'^[A-Z]{2,3}\s*', '', s) # "EUR 22.50" -> "22.50"
+ s = s.replace('$', '')
+ s = s.replace(',', '')
+ s = s.strip()
+ try:
+ return Decimal(s)
+ except Exception:
+ return None
+
+
+def parse_timestamp(raw: str) -> datetime | None:
+ """Parse various date formats, return datetime or None."""
+ if raw is None or raw.strip() == "":
+ return None
+ s = raw.strip()
+ # Try ISO 8601 with Z
+ for fmt in [
+ "%Y-%m-%dT%H:%M:%SZ",
+ "%Y-%m-%dT%H:%M:%S",
+ "%m/%d/%Y",
+ "%Y-%m-%d",
+ ]:
+ try:
+ return datetime.strptime(s, fmt)
+ except ValueError:
+ continue
+ return None
+
+
+def validate_email(email: str | None) -> bool:
+ """Email must contain @."""
+ if email is None or email.strip() == "":
+ return False
+ return "@" in email.strip()
+
+
+VALID_REGIONS = {"NA", "EU", "APAC", "LATAM", "MEA"}
+
+
+def validate_region(region: str | None) -> bool:
+ if region is None or region.strip() == "":
+ return False
+ return region.strip() in VALID_REGIONS
+
+
+def main():
+ input_path = "/root/loop-benchmarking/tasks/data-pipeline/fixtures/test_input.csv"
+
+ # Read all rows
+ rows = []
+ with open(input_path, "r", encoding="utf-8") as f:
+ reader = csv.DictReader(f)
+ for row in reader:
+ rows.append(row)
+
+ total_rows_processed = len(rows)
+
+ # Parse and validate each row
+ parsed_rows = []
+ invalid_row_count = 0
+
+ for row in rows:
+ amount = parse_amount(row.get("amount", ""))
+ timestamp = parse_timestamp(row.get("timestamp", ""))
+ email_valid = validate_email(row.get("customer_email", ""))
+ region_valid = validate_region(row.get("region", ""))
+
+ # A row is invalid if:
+ # - amount is not numeric (None after parsing)
+ # - email doesn't contain @
+ # - region is not in valid set
+ if amount is None or not email_valid or not region_valid:
+ invalid_row_count += 1
+ continue
+
+ if timestamp is None:
+ invalid_row_count += 1
+ continue
+
+ parsed_rows.append({
+ "transaction_id": row["transaction_id"].strip(),
+ "timestamp": timestamp,
+ "product_name": row.get("product_name", "").strip(),
+ "category": row.get("category", "").strip(),
+ "amount": amount,
+ "currency": row.get("currency", "").strip(),
+ "customer_email": row.get("customer_email", "").strip(),
+ "region": row.get("region", "").strip(),
+ })
+
+ # Deduplicate by transaction_id, keeping the row with the latest timestamp
+ seen = {}
+ duplicate_count = 0
+ for r in parsed_rows:
+ tid = r["transaction_id"]
+ if tid in seen:
+ duplicate_count += 1
+ if r["timestamp"] > seen[tid]["timestamp"]:
+ seen[tid] = r
+ else:
+ seen[tid] = r
+
+ deduped = list(seen.values())
+
+ # Separate into revenue and refunds
+ total_revenue = Decimal("0")
+ refund_total = Decimal("0")
+
+ breakdown_by_category = defaultdict(lambda: Decimal("0"))
+ breakdown_by_month = defaultdict(lambda: Decimal("0"))
+ product_revenue = defaultdict(lambda: Decimal("0"))
+
+ for r in deduped:
+ amt = r["amount"]
+ cat = r["category"]
+ month_key = r["timestamp"].strftime("%Y-%m")
+ product = r["product_name"]
+
+ if amt >= 0:
+ total_revenue += amt
+ else:
+ refund_total += abs(amt)
+
+ # Breakdowns include both positive and negative (net effect)
+ breakdown_by_category[cat] += amt
+ breakdown_by_month[month_key] += amt
+ product_revenue[product] += amt
+
+ net_revenue = total_revenue - refund_total
+
+ # Top 10 products sorted by revenue descending
+ sorted_products = sorted(product_revenue.items(), key=lambda x: x[1], reverse=True)
+ top_10 = [{"product": p, "revenue": str(v)} for p, v in sorted_products[:10]]
+
+ # Convert breakdowns to sorted dicts with string values
+ cat_breakdown = {k: str(v) for k, v in sorted(breakdown_by_category.items())}
+ month_breakdown = {k: str(v) for k, v in sorted(breakdown_by_month.items())}
+
+ output = {
+ "total_revenue": str(total_revenue),
+ "refund_total": str(refund_total),
+ "net_revenue": str(net_revenue),
+ "breakdown_by_category": cat_breakdown,
+ "breakdown_by_month": month_breakdown,
+ "top_10_products": top_10,
+ "invalid_row_count": invalid_row_count,
+ "duplicate_count": duplicate_count,
+ "total_rows_processed": total_rows_processed,
+ }
+
+ print(json.dumps(output, indent=2))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tasks/data-pipeline/expected/output.json b/tasks/data-pipeline/expected/output.json
@@ -0,0 +1,68 @@
+{
+ "total_revenue": "9447.17",
+ "refund_total": "384.00",
+ "net_revenue": "9063.17",
+ "breakdown_by_category": {
+ "Apparel": "1489.51",
+ "Electronics": "422.45",
+ "Food & Beverage": "56.23",
+ "Home": "1234.00",
+ "Jewelry": "5499.00",
+ "Office": "2.50",
+ "Sports": "284.50",
+ "Toys": "74.98"
+ },
+ "breakdown_by_month": {
+ "2024-01": "149.73",
+ "2024-02": "206.93",
+ "2024-03": "1298.54",
+ "2024-04": "439.98",
+ "2024-05": "5849.00",
+ "2024-06": "1118.99"
+ },
+ "top_10_products": [
+ {
+ "product": "Diamond Necklace",
+ "revenue": "5499.00"
+ },
+ {
+ "product": "Winter Jacket",
+ "revenue": "1234.56"
+ },
+ {
+ "product": "Standing Desk",
+ "revenue": "1099.00"
+ },
+ {
+ "product": "Smartwatch",
+ "revenue": "299.00"
+ },
+ {
+ "product": "Camping Tent",
+ "revenue": "250.00"
+ },
+ {
+ "product": "Noise-Canceling Headphones",
+ "revenue": "199.99"
+ },
+ {
+ "product": "Hiking Boots",
+ "revenue": "175.00"
+ },
+ {
+ "product": "Mechanical Keyboard",
+ "revenue": "149.99"
+ },
+ {
+ "product": "Coffee Grinder",
+ "revenue": "65.00"
+ },
+ {
+ "product": "Running Shoes",
+ "revenue": "64.95"
+ }
+ ],
+ "invalid_row_count": 5,
+ "duplicate_count": 3,
+ "total_rows_processed": 37
+}
diff --git a/tasks/data-pipeline/fixtures/test_input.csv b/tasks/data-pipeline/fixtures/test_input.csv
@@ -0,0 +1,38 @@
+transaction_id,timestamp,product_name,category,amount,currency,customer_email,region
+TXN001,2024-01-15T10:30:00Z,Wireless Mouse,Electronics,$29.99,USD,alice@example.com,NA
+TXN002,2024-01-15T14:22:00Z,USB-C Cable,Electronics,$12.50,USD,bob@example.com,EU
+TXN003,01/16/2024,Mechanical Keyboard,Electronics,"$149.99",USD,charlie@example.com,NA
+TXN004,2024-01-17T09:00:00Z,Cafe Latte,Food & Beverage,$4.75,USD,diana@example.com,APAC
+TXN005,2024-02-01T08:15:00Z,Running Shoes,Apparel,$89.95,USD,eve@example.com,NA
+TXN006,02/03/2024,Yoga Mat,Sports,$34.50,USD,frank@example.com,EU
+TXN007,2024-02-10T16:45:00Z,Nino's Toy Set,Toys,$24.99,USD,grace@example.com,LATAM
+TXN008,2024-02-14T12:00:00Z,"Bluetooth Speaker, Portable",Electronics,$59.99,USD,hank@example.com,NA
+TXN009,2024-02-20T18:30:00Z,Uber-Kaffee Bohnen,Food & Beverage,EUR 22.50,EUR,ingrid@example.com,EU
+TXN010,2024-03-01T07:00:00Z,Organic Green Tea,Food & Beverage,$8.99,USD,julia@example.com,APAC
+TXN011,03/05/2024,Winter Jacket,Apparel,"$1,234.56",USD,kevin@example.com,NA
+TXN012,2024-03-10T11:11:00Z,Desk Lamp,Home,$45.00,USD,lisa@example.com,EU
+TXN013,2024-03-15T14:00:00Z,Protein Bars (12-pack),Food & Beverage,$19.99,USD,mike@example.com,NA
+TXN014,2024-03-20T09:30:00Z,Smartwatch,Electronics,$299.00,USD,nancy@example.com,APAC
+TXN015,2024-04-01T10:00:00Z,Hiking Boots,Apparel,$175.00,USD,oscar@example.com,MEA
+TXN016,2024-04-05T15:20:00Z,Board Game Collection,Toys,$49.99,USD,pat@example.com,NA
+TXN017,04/10/2024,Cotton T-Shirt,Apparel,$15.00,USD,quinn@example.com,LATAM
+TXN018,2024-04-15T08:00:00Z,Noise-Canceling Headphones,Electronics,$199.99,USD,rachel@example.com,EU
+TXN019,2024-05-01T13:00:00Z,Camping Tent,Sports,$250.00,USD,sam@example.com,NA
+TXN020,2024-05-10T17:45:00Z,Coffee Grinder,Home,$65.00,USD,tina@example.com,APAC
+TXN003,2024-01-18T11:00:00Z,Mechanical Keyboard,Electronics,"$149.99",USD,charlie@example.com,NA
+TXN008,2024-02-15T09:00:00Z,"Bluetooth Speaker, Portable",Electronics,$59.99,USD,hank@example.com,NA
+TXN016,2024-04-06T10:00:00Z,Board Game Collection,Toys,$49.99,USD,pat@example.com,NA
+TXN021,2024-01-20T10:00:00Z,Wireless Mouse,Electronics,-$50.00,USD,alice@example.com,NA
+TXN022,2024-02-25T14:00:00Z,Running Shoes,Apparel,-25.00,USD,eve@example.com,NA
+TXN023,2024-03-30T12:00:00Z,Desk Lamp,Home,-$10.00,USD,lisa@example.com,EU
+TXN024,2024-01-10T09:00:00Z,Laptop Stand,Home,$79.99,USD,,NA
+TXN025,2024-02-12T11:30:00Z,Water Bottle,Sports,$18.00,USD,victor@example.com,
+TXN026,2024-03-22T16:00:00Z,Phone Case,Electronics,,USD,wendy@example.com,NA
+TXN027,2024-04-18T10:00:00Z,Sunglasses,Apparel,$55.00,USD,xander@example.com,MARS
+TXN028,2024-05-05T08:30:00Z,Fitness Tracker,Electronics,$129.00,USD,not-an-email,APAC
+TXN029,2024-05-15T14:00:00Z,Garden Hose,Home,$35.00,USD,yara@example.com,NA
+TXN030,2024-05-20T16:30:00Z,Diamond Necklace,Jewelry,"$5,499.00",USD,zelda@example.com,NA
+TXN031,2024-01-25T07:00:00Z,Pencil Set,Office,$2.50,USD,adam@example.com,EU
+TXN032,2024-06-01T10:00:00Z,Standing Desk,Home,"$1,099.00",USD,beth@example.com,APAC
+TXN033,2024-06-10T12:00:00Z,Wireless Charger,Electronics,$19.99,USD,carl@example.com,LATAM
+TXN034,2024-03-12T08:00:00Z,Refund - Smartwatch,Electronics,-$299.00,USD,nancy@example.com,APAC
diff --git a/tasks/data-pipeline/prompts/detailed.en.md b/tasks/data-pipeline/prompts/detailed.en.md
@@ -0,0 +1,108 @@
+Build a data pipeline that processes a sales CSV file into a structured JSON summary. The pipeline should read, clean, validate, and deduplicate the data, then output a comprehensive summary to stdout.
+
+## Input
+
+- The CSV file path is provided as the first command-line argument.
+- If no argument is provided, print a usage message to stderr and exit with code 1.
+- If the file does not exist or cannot be read, print an error to stderr and exit with code 1.
+
+## CSV Format
+
+The input CSV has the following columns (with a header row):
+
+| Column | Description |
+|---|---|
+| transaction_id | Unique identifier for the transaction |
+| timestamp | Date/time of the transaction |
+| product_name | Name of the product sold |
+| category | Product category |
+| amount | Transaction amount (may include currency symbols) |
+| currency | Currency code (e.g., USD, EUR) |
+| customer_email | Customer's email address |
+| region | Geographic region code |
+
+Example row:
+```
+TXN-001,01/15/2025,Widget Pro,Electronics,$49.99,USD,alice@example.com,NA
+```
+
+## Cleaning Rules
+
+Apply the following transformations to raw data:
+
+- **Amount**: Strip currency symbols and whitespace. Remove characters like `$`, `EUR`, `GBP`, and any other non-numeric characters except for the decimal point and minus sign. The result should be a plain number (e.g., `"$1,234.56"` becomes `1234.56`).
+- **Timestamps**: Normalize all dates to ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`). The input may contain dates in `MM/DD/YYYY`, `YYYY-MM-DD`, `MM/DD/YYYY HH:MM:SS`, or `YYYY-MM-DDTHH:MM:SSZ` formats. If no time component is present, default to `T00:00:00Z`.
+- **Whitespace**: Trim leading and trailing whitespace from all string fields.
+
+## Validation Rules
+
+After cleaning, validate each row:
+
+- **amount**: Must be a valid number after cleaning. Rows where the amount cannot be parsed as a number are invalid.
+- **customer_email**: Must contain an `@` character. Rows without a valid email are invalid.
+- **region**: Must be one of: `NA`, `EU`, `APAC`, `LATAM`, `MEA`. Rows with an unrecognized region are invalid.
+- **transaction_id**: Must not be empty. Rows without a transaction ID are invalid.
+
+Invalid rows are counted but excluded from all calculations and the final output totals.
+
+## Deduplication
+
+- If multiple rows share the same `transaction_id`, keep only the one with the latest `timestamp`.
+- Count the number of duplicates removed.
+
+## Revenue Calculations
+
+- Positive amounts are sales revenue.
+- Negative amounts are refunds.
+- Calculate totals using the cleaned numeric amounts. Do not attempt currency conversion; treat all amounts as if they are in the same currency.
+
+## Output
+
+Print a single JSON object to stdout with the following structure:
+
+```json
+{
+ "total_revenue": 125000.50,
+ "refund_total": -3200.00,
+ "net_revenue": 121800.50,
+ "breakdown_by_category": {
+ "Electronics": 45000.00,
+ "Books": 12000.00
+ },
+ "breakdown_by_month": {
+ "2025-01": 30000.00,
+ "2025-02": 28000.00
+ },
+ "top_10_products": [
+ { "product_name": "Widget Pro", "revenue": 15000.00 },
+ { "product_name": "Gadget X", "revenue": 12000.00 }
+ ],
+ "invalid_row_count": 5,
+ "duplicate_count": 3,
+ "total_rows_processed": 1000
+}
+```
+
+Field definitions:
+
+- **total_revenue**: Sum of all positive amounts (sales only, after cleaning/validation/dedup).
+- **refund_total**: Sum of all negative amounts (refunds only). This should be a negative number or zero.
+- **net_revenue**: `total_revenue + refund_total` (since refund_total is negative).
+- **breakdown_by_category**: An object where keys are category names and values are the net amount (sales minus refunds) for that category.
+- **breakdown_by_month**: An object where keys are in `YYYY-MM` format and values are the net amount for that month. Sorted by key is preferred but not required.
+- **top_10_products**: An array of the 10 products with the highest total revenue (positive amounts only), sorted descending by revenue. Each entry has `product_name` and `revenue`. If fewer than 10 products exist, include all of them.
+- **invalid_row_count**: Number of rows that failed validation.
+- **duplicate_count**: Number of duplicate rows removed.
+- **total_rows_processed**: Total number of data rows in the CSV (excluding the header), before any filtering.
+
+## Exit Codes
+
+- Exit code 0 on successful processing (even if some rows are invalid).
+- Exit code 1 on fatal errors (missing file, missing argument, completely unparseable CSV).
+
+## Technical Constraints
+
+- The pipeline should be runnable as a single script from the command line.
+- Do not write intermediate files; all processing happens in memory.
+- Output only the JSON object to stdout. Any log or debug messages should go to stderr.
+- Handle large files efficiently (do not load the entire file into memory at once if possible, but this is not a strict requirement for correctness).
diff --git a/tasks/data-pipeline/prompts/detailed.es.md b/tasks/data-pipeline/prompts/detailed.es.md
@@ -0,0 +1,108 @@
+Construye un pipeline de datos que procese un archivo CSV de ventas en un resumen JSON estructurado. El pipeline debe leer, limpiar, validar y deduplicar los datos, y luego generar un resumen completo en stdout.
+
+## Entrada
+
+- La ruta del archivo CSV se proporciona como el primer argumento de linea de comandos.
+- Si no se proporciona argumento, imprimir un mensaje de uso en stderr y salir con codigo 1.
+- Si el archivo no existe o no se puede leer, imprimir un error en stderr y salir con codigo 1.
+
+## Formato CSV
+
+El CSV de entrada tiene las siguientes columnas (con fila de encabezado):
+
+| Columna | Descripcion |
+|---|---|
+| transaction_id | Identificador unico de la transaccion |
+| timestamp | Fecha/hora de la transaccion |
+| product_name | Nombre del producto vendido |
+| category | Categoria del producto |
+| amount | Monto de la transaccion (puede incluir simbolos de moneda) |
+| currency | Codigo de moneda (por ejemplo, USD, EUR) |
+| customer_email | Correo electronico del cliente |
+| region | Codigo de region geografica |
+
+Fila de ejemplo:
+```
+TXN-001,01/15/2025,Widget Pro,Electronics,$49.99,USD,alice@example.com,NA
+```
+
+## Reglas de Limpieza
+
+Aplicar las siguientes transformaciones a los datos en bruto:
+
+- **Monto**: Eliminar simbolos de moneda y espacios en blanco. Remover caracteres como `$`, `EUR`, `GBP` y cualquier otro caracter no numerico excepto el punto decimal y el signo menos. El resultado debe ser un numero simple (por ejemplo, `"$1,234.56"` se convierte en `1234.56`).
+- **Marcas de tiempo**: Normalizar todas las fechas al formato ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). La entrada puede contener fechas en formatos `MM/DD/YYYY`, `YYYY-MM-DD`, `MM/DD/YYYY HH:MM:SS` o `YYYY-MM-DDTHH:MM:SSZ`. Si no hay componente de hora, usar por defecto `T00:00:00Z`.
+- **Espacios en blanco**: Eliminar espacios en blanco al inicio y al final de todos los campos de texto.
+
+## Reglas de Validacion
+
+Despues de la limpieza, validar cada fila:
+
+- **amount**: Debe ser un numero valido despues de la limpieza. Las filas donde el monto no pueda parsearse como numero son invalidas.
+- **customer_email**: Debe contener un caracter `@`. Las filas sin un email valido son invalidas.
+- **region**: Debe ser uno de: `NA`, `EU`, `APAC`, `LATAM`, `MEA`. Las filas con una region no reconocida son invalidas.
+- **transaction_id**: No debe estar vacio. Las filas sin ID de transaccion son invalidas.
+
+Las filas invalidas se cuentan pero se excluyen de todos los calculos y los totales de la salida final.
+
+## Deduplicacion
+
+- Si multiples filas comparten el mismo `transaction_id`, conservar solo la que tenga la marca de tiempo mas reciente.
+- Contar el numero de duplicados eliminados.
+
+## Calculos de Ingresos
+
+- Los montos positivos son ingresos por ventas.
+- Los montos negativos son reembolsos.
+- Calcular los totales usando los montos numericos limpios. No intentar conversion de moneda; tratar todos los montos como si estuvieran en la misma moneda.
+
+## Salida
+
+Imprimir un unico objeto JSON en stdout con la siguiente estructura:
+
+```json
+{
+ "total_revenue": 125000.50,
+ "refund_total": -3200.00,
+ "net_revenue": 121800.50,
+ "breakdown_by_category": {
+ "Electronics": 45000.00,
+ "Books": 12000.00
+ },
+ "breakdown_by_month": {
+ "2025-01": 30000.00,
+ "2025-02": 28000.00
+ },
+ "top_10_products": [
+ { "product_name": "Widget Pro", "revenue": 15000.00 },
+ { "product_name": "Gadget X", "revenue": 12000.00 }
+ ],
+ "invalid_row_count": 5,
+ "duplicate_count": 3,
+ "total_rows_processed": 1000
+}
+```
+
+Definiciones de campos:
+
+- **total_revenue**: Suma de todos los montos positivos (solo ventas, despues de limpieza/validacion/deduplicacion).
+- **refund_total**: Suma de todos los montos negativos (solo reembolsos). Debe ser un numero negativo o cero.
+- **net_revenue**: `total_revenue + refund_total` (ya que refund_total es negativo).
+- **breakdown_by_category**: Un objeto donde las claves son nombres de categoria y los valores son el monto neto (ventas menos reembolsos) para esa categoria.
+- **breakdown_by_month**: Un objeto donde las claves estan en formato `YYYY-MM` y los valores son el monto neto para ese mes. Ordenado por clave es preferible pero no obligatorio.
+- **top_10_products**: Un arreglo de los 10 productos con los ingresos totales mas altos (solo montos positivos), ordenados de mayor a menor por ingresos. Cada entrada tiene `product_name` y `revenue`. Si existen menos de 10 productos, incluir todos.
+- **invalid_row_count**: Numero de filas que fallaron la validacion.
+- **duplicate_count**: Numero de filas duplicadas eliminadas.
+- **total_rows_processed**: Numero total de filas de datos en el CSV (excluyendo el encabezado), antes de cualquier filtrado.
+
+## Codigos de Salida
+
+- Codigo de salida 0 en procesamiento exitoso (incluso si algunas filas son invalidas).
+- Codigo de salida 1 en errores fatales (archivo faltante, argumento faltante, CSV completamente ilegible).
+
+## Restricciones Tecnicas
+
+- El pipeline debe poder ejecutarse como un unico script desde la linea de comandos.
+- No escribir archivos intermedios; todo el procesamiento ocurre en memoria.
+- Generar solo el objeto JSON en stdout. Cualquier mensaje de log o depuracion debe ir a stderr.
+- Manejar archivos grandes de manera eficiente (no cargar el archivo completo en memoria de una vez si es posible, pero esto no es un requisito estricto para la correctitud).
diff --git a/tasks/data-pipeline/prompts/simple.en.md b/tasks/data-pipeline/prompts/simple.en.md
@@ -0,0 +1 @@
+Build a data pipeline that reads a sales CSV file (path given as the first command-line argument), cleans and validates the data, deduplicates by transaction ID, and outputs a JSON summary to stdout with total revenue, breakdowns by category and month, and top 10 products.
diff --git a/tasks/data-pipeline/prompts/simple.es.md b/tasks/data-pipeline/prompts/simple.es.md
@@ -0,0 +1 @@
+Construye un pipeline de datos que lea un archivo CSV de ventas (ruta dada como primer argumento de linea de comandos), limpie y valide los datos, deduplique por ID de transaccion, y genere un resumen JSON en stdout con ingresos totales, desgloses por categoria y mes, y los 10 productos principales.
diff --git a/tasks/data-pipeline/scoring.yaml b/tasks/data-pipeline/scoring.yaml
@@ -0,0 +1,11 @@
+weights:
+ functional: 0.55
+ structural: 0.10
+ quality: 0.35
+
+quality_weights:
+ lint: 0.15
+ typecheck: 0.15
+ no_float_currency: 0.30
+ handles_empty_input: 0.20
+ handles_malformed: 0.20
diff --git a/tasks/data-pipeline/task.yaml b/tasks/data-pipeline/task.yaml
@@ -0,0 +1,27 @@
+name: data-pipeline
+description: Build a CSV data pipeline that cleans, validates, deduplicates, and summarizes sales data
+difficulty: hard
+category: data-processing
+
+prompt_styles:
+ - simple
+ - detailed
+
+languages:
+ - typescript
+ - javascript
+
+eval:
+ structural:
+ - entry_point_exists # a runnable script
+ - reads_input # reads from file argument or stdin
+ - outputs_json # outputs JSON to stdout or file
+ functional:
+ framework: shell
+ test_file: functional.sh
+ quality:
+ - lint
+ - typecheck # if typescript
+ - no_float_currency # uses integer cents or decimal library
+ - handles_empty_input # does not crash on empty CSV
+ - handles_malformed # does not crash on bad CSV rows
diff --git a/tasks/tetris/context.md b/tasks/tetris/context.md
@@ -0,0 +1,8 @@
+# Project Rules
+
+- Use semantic HTML where possible
+- Ensure keyboard accessibility for all interactive elements
+- Keep the bundle small -- no heavy frameworks unless necessary
+- Use canvas or DOM-based rendering (either is acceptable)
+- Include a visible score display and next-piece preview
+- The game should be playable immediately on page load without user setup
diff --git a/tasks/tetris/eval/quality.sh b/tasks/tetris/eval/quality.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+# Quality evaluation for Tetris task.
+# Runs lint, accessibility, and performance checks.
+#
+# Usage: quality.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+results='{}'
+
+# --- Lint check ---
+cd "$WORKSPACE"
+if command -v npx > /dev/null 2>&1; then
+ # Install eslint if not present
+ npm install --save-dev eslint @eslint/js > /dev/null 2>&1
+
+ # Find source files
+ if [[ "$LANGUAGE" == "typescript" ]]; then
+ extensions="ts,tsx"
+ else
+ extensions="js,jsx"
+ fi
+
+ lint_output=$(npx eslint --no-eslintrc --rule '{"no-unused-vars":"warn","no-undef":"warn","no-console":"off"}' \
+ --ext ".$extensions" --format json . 2>/dev/null) || true
+
+ if echo "$lint_output" | jq . > /dev/null 2>&1; then
+ errors=$(echo "$lint_output" | jq '[.[].errorCount] | add // 0')
+ warnings=$(echo "$lint_output" | jq '[.[].warningCount] | add // 0')
+ lint_pass="true"
+ if [[ "$errors" -gt 0 ]]; then
+ lint_pass="false"
+ fi
+ results=$(echo "$results" | jq --argjson e "$errors" --argjson w "$warnings" --argjson p "$lint_pass" \
+ '. + {lint: {pass: ($p == true), errors: $e, warnings: $w}}')
+ else
+ results=$(echo "$results" | jq '. + {lint: {pass: false, errors: -1, warnings: 0, error: "eslint failed to run"}}')
+ fi
+else
+ results=$(echo "$results" | jq '. + {lint: {pass: false, error: "eslint not available"}}')
+fi
+
+# --- TypeScript type check ---
+if [[ "$LANGUAGE" == "typescript" ]]; then
+ cd "$WORKSPACE"
+ if [[ -f "tsconfig.json" ]]; then
+ if npx tsc --noEmit > /dev/null 2>&1; then
+ results=$(echo "$results" | jq '. + {typecheck: {pass: true}}')
+ else
+ type_errors=$(npx tsc --noEmit 2>&1 | grep -c "error TS" || echo "0")
+ results=$(echo "$results" | jq --argjson e "$type_errors" '. + {typecheck: {pass: false, errors: $e}}')
+ fi
+ else
+ results=$(echo "$results" | jq '. + {typecheck: {pass: false, error: "no tsconfig.json"}}')
+ fi
+else
+ results=$(echo "$results" | jq '. + {typecheck: {pass: true, note: "not applicable for javascript"}}')
+fi
+
+# --- File size check ---
+# Find the main HTML file and measure total size
+total_size=0
+if [[ -d "$WORKSPACE/dist" ]]; then
+ total_size=$(du -sb "$WORKSPACE/dist" 2>/dev/null | awk '{print $1}')
+elif [[ -f "$WORKSPACE/index.html" ]]; then
+ total_size=$(du -sb "$WORKSPACE" --exclude=node_modules --exclude=.git 2>/dev/null | awk '{print $1}')
+fi
+size_pass="true"
+if [[ "$total_size" -gt 524288 ]]; then # 512KB
+ size_pass="false"
+fi
+results=$(echo "$results" | jq --argjson s "$total_size" --argjson p "$size_pass" \
+ '. + {performance: {bundle_size_bytes: $s, size_under_512kb: ($p == true)}}')
+
+# --- Compute aggregate quality score ---
+# Each check contributes equally
+score_sum=0
+score_count=0
+
+for key in lint typecheck performance; do
+ val=$(echo "$results" | jq --arg k "$key" '.[$k].pass // false')
+ if [[ "$val" == "true" ]]; then
+ score_sum=$((score_sum + 100))
+ fi
+ score_count=$((score_count + 1))
+done
+
+if [[ $score_count -gt 0 ]]; then
+ score=$(echo "scale=2; $score_sum / ($score_count * 100)" | bc)
+else
+ score="0"
+fi
+
+results=$(echo "$results" | jq --argjson s "$score" '. + {score: $s}')
+
+echo "$results" | jq '.'
diff --git a/tasks/tetris/eval/structural.sh b/tasks/tetris/eval/structural.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+# Structural evaluation for Tetris task.
+# Checks that the agent produced a runnable game.
+#
+# Usage: structural.sh <workspace_path> <language>
+# Output: JSON to stdout
+
+WORKSPACE="$1"
+LANGUAGE="$2"
+
+checks=()
+pass_count=0
+total_count=0
+
+add_check() {
+ local name="$1"
+ local passed="$2"
+ local detail="$3"
+ checks+=("{\"name\": \"$name\", \"pass\": $passed, \"detail\": \"$detail\"}")
+ total_count=$((total_count + 1))
+ if [[ "$passed" == "true" ]]; then
+ pass_count=$((pass_count + 1))
+ fi
+}
+
+# Check for entry point
+if [[ -f "$WORKSPACE/index.html" ]]; then
+ add_check "entry_point_exists" "true" "index.html found"
+elif [[ -f "$WORKSPACE/dist/index.html" ]]; then
+ add_check "entry_point_exists" "true" "dist/index.html found"
+elif [[ -f "$WORKSPACE/public/index.html" ]]; then
+ add_check "entry_point_exists" "true" "public/index.html found"
+else
+ add_check "entry_point_exists" "false" "no index.html found in workspace root, dist/, or public/"
+fi
+
+# Check for package.json
+if [[ -f "$WORKSPACE/package.json" ]]; then
+ add_check "package_json_exists" "true" "package.json found"
+else
+ add_check "package_json_exists" "false" "no package.json found"
+fi
+
+# Check build succeeds (if there's a build script)
+if [[ -f "$WORKSPACE/package.json" ]]; then
+ has_build=$(cd "$WORKSPACE" && node -e "const p=require('./package.json'); console.log(p.scripts && p.scripts.build ? 'yes' : 'no')" 2>/dev/null)
+ if [[ "$has_build" == "yes" ]]; then
+ cd "$WORKSPACE"
+ if npm install --ignore-scripts > /dev/null 2>&1 && npm run build > /dev/null 2>&1; then
+ add_check "build_succeeds" "true" "npm run build completed successfully"
+ else
+ add_check "build_succeeds" "false" "npm run build failed"
+ fi
+ else
+ add_check "build_succeeds" "true" "no build script defined (static project)"
+ fi
+fi
+
+# Check TypeScript compiles (if typescript)
+if [[ "$LANGUAGE" == "typescript" ]]; then
+ if [[ -f "$WORKSPACE/tsconfig.json" ]]; then
+ cd "$WORKSPACE"
+ if npx tsc --noEmit > /dev/null 2>&1; then
+ add_check "typescript_compiles" "true" "tsc --noEmit passed"
+ else
+ add_check "typescript_compiles" "false" "tsc --noEmit failed"
+ fi
+ else
+ # Check if there are .ts files without a tsconfig
+ ts_files=$(find "$WORKSPACE" -name "*.ts" -not -path "*/node_modules/*" | head -1)
+ if [[ -n "$ts_files" ]]; then
+ add_check "typescript_compiles" "false" "TypeScript files found but no tsconfig.json"
+ fi
+ fi
+fi
+
+# Build checks array JSON
+checks_json=$(printf '%s,' "${checks[@]}")
+checks_json="[${checks_json%,}]"
+
+# Compute score
+if [[ $total_count -gt 0 ]]; then
+ score=$(echo "scale=2; $pass_count / $total_count" | bc)
+else
+ score="0"
+fi
+
+overall_pass="true"
+if [[ $pass_count -lt $total_count ]]; then
+ overall_pass="false"
+fi
+
+echo "{\"pass\": $overall_pass, \"checks\": $checks_json, \"score\": $score}"
diff --git a/tasks/tetris/eval/tests/functional.spec.ts b/tasks/tetris/eval/tests/functional.spec.ts
@@ -0,0 +1,146 @@
+import { test, expect, type Page } from "@playwright/test";
+
+// Helper: find the game page. Tries common entry points.
+async function loadGame(page: Page) {
+ // Try common entry points in order
+ const candidates = [
+ "index.html",
+ "dist/index.html",
+ "public/index.html",
+ "build/index.html",
+ ];
+
+ for (const candidate of candidates) {
+ try {
+ const response = await page.goto(`http://localhost:__PORT__/${candidate}`, {
+ timeout: 5000,
+ });
+ if (response && response.ok()) return;
+ } catch {
+ continue;
+ }
+ }
+
+ // Last resort: try root
+ await page.goto(`http://localhost:__PORT__/`, { timeout: 5000 });
+}
+
+test.describe("Tetris - Functional Tests", () => {
+ test.beforeEach(async ({ page }) => {
+ await loadGame(page);
+ // Wait for the page to be interactive
+ await page.waitForLoadState("domcontentloaded");
+ });
+
+ test("page loads without errors", async ({ page }) => {
+ const errors: string[] = [];
+ page.on("pageerror", (err) => errors.push(err.message));
+ await page.waitForTimeout(2000);
+ expect(errors).toEqual([]);
+ });
+
+ test("game board is visible", async ({ page }) => {
+ // Look for a canvas or a grid-like container
+ const canvas = page.locator("canvas");
+ const gridContainer = page.locator(
+ '[class*="board"], [class*="grid"], [class*="game"], [id*="board"], [id*="grid"], [id*="game"]'
+ );
+
+ const canvasCount = await canvas.count();
+ const gridCount = await gridContainer.count();
+
+ expect(canvasCount + gridCount).toBeGreaterThan(0);
+ });
+
+ test("score display exists", async ({ page }) => {
+ // Look for score text on the page
+ const pageText = await page.textContent("body");
+ const hasScore =
+ pageText !== null &&
+ (pageText.toLowerCase().includes("score") ||
+ pageText.toLowerCase().includes("points") ||
+ /\b0\b/.test(pageText));
+ expect(hasScore).toBe(true);
+ });
+
+ test("keyboard input is responsive", async ({ page }) => {
+ // Press arrow keys and check that no errors occur
+ const errors: string[] = [];
+ page.on("pageerror", (err) => errors.push(err.message));
+
+ await page.keyboard.press("ArrowLeft");
+ await page.waitForTimeout(100);
+ await page.keyboard.press("ArrowRight");
+ await page.waitForTimeout(100);
+ await page.keyboard.press("ArrowDown");
+ await page.waitForTimeout(100);
+ await page.keyboard.press("ArrowUp");
+ await page.waitForTimeout(100);
+ await page.keyboard.press("Space");
+ await page.waitForTimeout(100);
+
+ expect(errors).toEqual([]);
+ });
+
+ test("game shows changing state over time", async ({ page }) => {
+ // Take a screenshot, wait, take another, compare
+ // If the game is running, pixels should change (pieces falling)
+ const screenshot1 = await page.screenshot();
+ await page.waitForTimeout(3000);
+ const screenshot2 = await page.screenshot();
+
+ // Screenshots should differ if the game is animating
+ const buf1 = Buffer.from(screenshot1);
+ const buf2 = Buffer.from(screenshot2);
+ expect(buf1.equals(buf2)).toBe(false);
+ });
+
+ test("arrow down accelerates piece", async ({ page }) => {
+ // Rapidly press down and verify no crash
+ const errors: string[] = [];
+ page.on("pageerror", (err) => errors.push(err.message));
+
+ for (let i = 0; i < 20; i++) {
+ await page.keyboard.press("ArrowDown");
+ await page.waitForTimeout(50);
+ }
+
+ expect(errors).toEqual([]);
+ });
+
+ test("game continues running for 10 seconds without crash", async ({
+ page,
+ }) => {
+ const errors: string[] = [];
+ page.on("pageerror", (err) => errors.push(err.message));
+
+ // Simulate some gameplay
+ for (let i = 0; i < 10; i++) {
+ await page.keyboard.press("ArrowLeft");
+ await page.waitForTimeout(200);
+ await page.keyboard.press("ArrowRight");
+ await page.waitForTimeout(200);
+ await page.keyboard.press("ArrowDown");
+ await page.waitForTimeout(200);
+ await page.keyboard.press("ArrowUp");
+ await page.waitForTimeout(200);
+ await page.keyboard.press("Space");
+ await page.waitForTimeout(200);
+ }
+
+ expect(errors).toEqual([]);
+ });
+
+ test("page has no accessibility violations for basic structure", async ({
+ page,
+ }) => {
+ // Basic a11y: page has a title or heading
+ const title = await page.title();
+ const h1 = await page.locator("h1").count();
+ const heading = await page
+ .locator("h1, h2, h3, [role='heading']")
+ .count();
+
+ expect(title.length + h1 + heading).toBeGreaterThan(0);
+ });
+});
diff --git a/tasks/tetris/prompts/detailed.en.md b/tasks/tetris/prompts/detailed.en.md
@@ -0,0 +1,89 @@
+Build a fully playable Tetris game that runs in a web browser. The game should be implemented as a single-page application with no external runtime dependencies (no CDN links, no package imports at runtime). All code should work by opening an HTML file directly in a browser or serving it from a simple static file server.
+
+## Game Board
+
+- The playing field is a grid of 10 columns by 20 rows.
+- The grid should be visually distinct with cell borders or a background pattern so the player can gauge positions.
+- Occupied cells should be colored according to their piece type.
+
+## Pieces (Tetrominoes)
+
+Implement all 7 standard Tetris pieces:
+
+- **I** (4 in a row, cyan)
+- **O** (2x2 square, yellow)
+- **T** (T-shape, purple)
+- **S** (S-skew, green)
+- **Z** (Z-skew, red)
+- **J** (J-shape, blue)
+- **L** (L-shape, orange)
+
+Each piece should spawn at the top center of the board. Use a random bag system or simple random selection for piece order.
+
+## Controls
+
+- **Left arrow**: move piece left
+- **Right arrow**: move piece right
+- **Down arrow**: soft drop (move piece down faster)
+- **Up arrow**: rotate piece clockwise
+- **Z key**: rotate piece counter-clockwise
+- **Space bar**: hard drop (instantly drop piece to the lowest valid position)
+
+## Rotation
+
+- Pieces rotate clockwise (up arrow) and counter-clockwise (Z key).
+- The O piece does not rotate.
+- Rotation should fail gracefully: if the rotated position would overlap with existing blocks or the walls, the rotation should not occur. A basic wall-kick system (trying one or two offset positions) is acceptable but not required.
+
+## Line Clearing
+
+- When an entire row is filled with blocks, that row is cleared and all rows above it shift down.
+- Multiple rows can be cleared simultaneously.
+
+## Scoring
+
+Points are awarded based on the number of lines cleared at once, multiplied by the current level:
+
+| Lines Cleared | Base Points |
+|---|---|
+| 1 (Single) | 100 |
+| 2 (Double) | 300 |
+| 3 (Triple) | 500 |
+| 4 (Tetris) | 800 |
+
+The formula is: `score += base_points * level`
+
+## Levels and Speed
+
+- The game starts at level 1.
+- The level increases by 1 for every 10 lines cleared.
+- The drop speed (how often the current piece automatically moves down one row) should increase with each level. A reasonable starting interval is around 800ms at level 1, decreasing as the level increases. The piece should never stop dropping entirely.
+
+## Display
+
+The game screen must show:
+
+- The playing field with the current piece and all placed blocks.
+- **Score**: the current score, updated in real time.
+- **Level**: the current level.
+- **Lines**: the total number of lines cleared.
+- **Next piece**: a preview of the next piece that will appear.
+
+## Game Over
+
+- The game ends when a new piece cannot be placed at its spawn position because existing blocks are in the way.
+- When the game ends, display a "Game Over" message along with the final score.
+- Provide a way to restart the game (a button or pressing a key).
+
+## Visual Quality
+
+- The game should look clean and polished, not like a raw prototype.
+- Use a reasonable color palette for the pieces (the colors listed above or similar).
+- Center the game on the page with a neutral background.
+- The game area and side panels (score, next piece) should be clearly laid out.
+
+## Technical Constraints
+
+- No build step required. The game should run by opening an HTML file in a modern browser.
+- No external libraries or frameworks at runtime.
+- The code should be organized and readable.
diff --git a/tasks/tetris/prompts/detailed.es.md b/tasks/tetris/prompts/detailed.es.md
@@ -0,0 +1,89 @@
+Construye un juego de Tetris completamente jugable que funcione en un navegador web. El juego debe implementarse como una aplicacion de una sola pagina sin dependencias externas en tiempo de ejecucion (sin enlaces CDN, sin importaciones de paquetes en tiempo de ejecucion). Todo el codigo debe funcionar al abrir un archivo HTML directamente en un navegador o al servirlo desde un servidor de archivos estaticos simple.
+
+## Tablero de Juego
+
+- El campo de juego es una cuadricula de 10 columnas por 20 filas.
+- La cuadricula debe ser visualmente distinguible con bordes de celda o un patron de fondo para que el jugador pueda evaluar las posiciones.
+- Las celdas ocupadas deben colorearse segun el tipo de pieza.
+
+## Piezas (Tetrominos)
+
+Implementa las 7 piezas estandar de Tetris:
+
+- **I** (4 en fila, cian)
+- **O** (cuadrado 2x2, amarillo)
+- **T** (forma de T, purpura)
+- **S** (sesgo S, verde)
+- **Z** (sesgo Z, rojo)
+- **J** (forma de J, azul)
+- **L** (forma de L, naranja)
+
+Cada pieza debe aparecer en la parte superior central del tablero. Usa un sistema de bolsa aleatoria o seleccion aleatoria simple para el orden de las piezas.
+
+## Controles
+
+- **Flecha izquierda**: mover pieza a la izquierda
+- **Flecha derecha**: mover pieza a la derecha
+- **Flecha abajo**: caida suave (mover pieza hacia abajo mas rapido)
+- **Flecha arriba**: rotar pieza en sentido horario
+- **Tecla Z**: rotar pieza en sentido antihorario
+- **Barra espaciadora**: caida fuerte (soltar pieza instantaneamente a la posicion valida mas baja)
+
+## Rotacion
+
+- Las piezas rotan en sentido horario (flecha arriba) y en sentido antihorario (tecla Z).
+- La pieza O no rota.
+- La rotacion debe fallar de manera elegante: si la posicion rotada se superpone con bloques existentes o las paredes, la rotacion no debe ocurrir. Un sistema basico de ajuste de pared (intentar una o dos posiciones de desplazamiento) es aceptable pero no obligatorio.
+
+## Eliminacion de Lineas
+
+- Cuando una fila completa se llena de bloques, esa fila se elimina y todas las filas superiores se desplazan hacia abajo.
+- Se pueden eliminar multiples filas simultaneamente.
+
+## Puntuacion
+
+Los puntos se otorgan segun el numero de lineas eliminadas a la vez, multiplicados por el nivel actual:
+
+| Lineas Eliminadas | Puntos Base |
+|---|---|
+| 1 (Simple) | 100 |
+| 2 (Doble) | 300 |
+| 3 (Triple) | 500 |
+| 4 (Tetris) | 800 |
+
+La formula es: `puntuacion += puntos_base * nivel`
+
+## Niveles y Velocidad
+
+- El juego comienza en el nivel 1.
+- El nivel aumenta en 1 por cada 10 lineas eliminadas.
+- La velocidad de caida (con que frecuencia la pieza actual baja automaticamente una fila) debe aumentar con cada nivel. Un intervalo inicial razonable es alrededor de 800ms en el nivel 1, disminuyendo a medida que aumenta el nivel. La pieza nunca debe dejar de caer por completo.
+
+## Pantalla
+
+La pantalla del juego debe mostrar:
+
+- El campo de juego con la pieza actual y todos los bloques colocados.
+- **Puntuacion**: la puntuacion actual, actualizada en tiempo real.
+- **Nivel**: el nivel actual.
+- **Lineas**: el numero total de lineas eliminadas.
+- **Siguiente pieza**: una vista previa de la siguiente pieza que aparecera.
+
+## Fin del Juego
+
+- El juego termina cuando una nueva pieza no puede colocarse en su posicion de aparicion porque los bloques existentes estan en el camino.
+- Cuando el juego termina, mostrar un mensaje de "Fin del Juego" junto con la puntuacion final.
+- Proporcionar una forma de reiniciar el juego (un boton o presionando una tecla).
+
+## Calidad Visual
+
+- El juego debe verse limpio y pulido, no como un prototipo sin terminar.
+- Usa una paleta de colores razonable para las piezas (los colores listados arriba o similares).
+- Centra el juego en la pagina con un fondo neutro.
+- El area de juego y los paneles laterales (puntuacion, siguiente pieza) deben estar claramente organizados.
+
+## Restricciones Tecnicas
+
+- No se requiere paso de compilacion. El juego debe funcionar al abrir un archivo HTML en un navegador moderno.
+- Sin bibliotecas ni frameworks externos en tiempo de ejecucion.
+- El codigo debe estar organizado y ser legible.
diff --git a/tasks/tetris/prompts/simple.en.md b/tasks/tetris/prompts/simple.en.md
@@ -0,0 +1 @@
+Build a playable Tetris game that runs in a browser. It should have all the standard mechanics: piece rotation, line clearing, scoring, and increasing speed. Use keyboard controls for movement and rotation.
diff --git a/tasks/tetris/prompts/simple.es.md b/tasks/tetris/prompts/simple.es.md
@@ -0,0 +1 @@
+Construye un juego de Tetris jugable que funcione en un navegador web. Debe tener todas las mecanicas estandar: rotacion de piezas, eliminacion de lineas, puntuacion y velocidad creciente. Usa controles de teclado para el movimiento y la rotacion.
diff --git a/tasks/tetris/scoring.yaml b/tasks/tetris/scoring.yaml
@@ -0,0 +1,11 @@
+weights:
+ functional: 0.50
+ structural: 0.15
+ quality: 0.35
+
+quality_weights:
+ lint: 0.25
+ typecheck: 0.20
+ accessibility: 0.25
+ performance: 0.15
+ no_console_errors: 0.15
diff --git a/tasks/tetris/task.yaml b/tasks/tetris/task.yaml
@@ -0,0 +1,27 @@
+name: tetris
+description: Build a playable Tetris game that runs in the browser
+difficulty: easy
+category: visual-interactive
+
+prompt_styles:
+ - simple
+ - detailed
+
+languages:
+ - typescript
+ - javascript
+
+eval:
+ structural:
+ - entry_point_exists # index.html or equivalent
+ - build_succeeds # npm run build or direct HTML
+ - no_build_errors
+ functional:
+ framework: playwright
+ test_file: functional.spec.ts
+ quality:
+ - lint
+ - typecheck # if typescript
+ - accessibility # axe-core audit
+ - performance # page load time, bundle size
+ - no_console_errors # during automated play session