diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4fb2e344b0..b60ee0e7bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ concurrency: cancel-in-progress: true jobs: - # Cheap path gate for pull requests. PRs confined to docs/site/release-notes + # Cheap path gate for pull requests. PRs confined to docs/release-notes # (or top-level Markdown) skip the heavy Go jobs, and PRs that cannot affect # the desktop module skip the desktop jobs. Job-level `if` reports skipped, # which satisfies the required status checks (lint, race, test) — a @@ -32,7 +32,6 @@ jobs: outputs: code: ${{ steps.filter.outputs.code }} desktop: ${{ steps.filter.outputs.desktop }} - site: ${{ steps.filter.outputs.site }} sdk: ${{ steps.filter.outputs.sdk }} steps: - uses: actions/checkout@v7 @@ -40,7 +39,7 @@ jobs: fetch-depth: 0 - id: filter run: | - code=true; desktop=true; site=true; sdk=true + code=true; desktop=true; sdk=true base="" if [ "${{ github.event_name }}" = "pull_request" ]; then base="${{ github.event.pull_request.base.sha }}" @@ -50,21 +49,20 @@ jobs: if [ -n "$base" ] && git cat-file -e "$base^{commit}" 2>/dev/null; then files=$(git diff --name-only "$base" HEAD) if [ -n "$files" ]; then - code=false; desktop=false; site=false; sdk=false + code=false; desktop=false; sdk=false # Root-module CI: desktop/ is a separate module, so only the # clearly unrelated paths below can skip it. - if echo "$files" | grep -qvE '^(docs/|site/|release-notes/|desktop/|workers/|[^/]+\.md$)'; then code=true; fi + if echo "$files" | grep -qvE '^(docs/|release-notes/|desktop/|workers/|[^/]+\.md$)'; then code=true; fi # desktop/ imports the root kernel via `replace reasonix => ../`, # so only this clearly-unrelated set is safe to skip. - if echo "$files" | grep -qvE '^(docs/|site/|release-notes/|workers/|benchmarks/|npm/|[^/]+\.md$)'; then desktop=true; fi - if echo "$files" | grep -q '^site/'; then site=true; fi + if echo "$files" | grep -qvE '^(docs/|release-notes/|workers/|benchmarks/|npm/|[^/]+\.md$)'; then desktop=true; fi # sdk/go is a nested module invisible to root `go test ./...`; # its DTOs are generated from internal/extension/protocol, so # both paths must trigger the sdk job. if echo "$files" | grep -qE '^(sdk/|internal/extension/)'; then sdk=true; fi fi fi - { echo "code=$code"; echo "desktop=$desktop"; echo "site=$site"; echo "sdk=$sdk"; } >> "$GITHUB_OUTPUT" + { echo "code=$code"; echo "desktop=$desktop"; echo "sdk=$sdk"; } >> "$GITHUB_OUTPUT" # The ruleset requires the per-OS check names (test (ubuntu-latest) etc.). # A matrix job skipped at job level reports no per-leg checks at all, so @@ -464,27 +462,6 @@ jobs: .github/workflows/release-studio.yml \ .github/workflows/ci.yml - # The site/ auth client has security-sensitive redirect-validation logic - # (safeNext) covered by node:test unit tests. Those tests use only Node - # builtins, so no `npm install` is needed — run them directly on every PR so - # a regression in redirect validation fails the build instead of shipping. - site: - needs: changes - if: always() && (github.event_name != 'pull_request' || needs.changes.outputs.site != 'false') - runs-on: ubuntu-latest - defaults: - run: - working-directory: site - steps: - - uses: actions/checkout@v7 - - - uses: actions/setup-node@v7 - with: - node-version: "24" - - - name: test - run: npm test - govulncheck: needs: changes if: always() && (github.event_name != 'pull_request' || needs.changes.outputs.code != 'false') diff --git a/.gitignore b/.gitignore index e03ad70b6f..2bdb346a07 100644 --- a/.gitignore +++ b/.gitignore @@ -25,11 +25,6 @@ /catalog-detector /tool-surface-cache -# Website (Astro) build output -/site/dist/ -/site/.astro/ -/site/_preview.png - # Go test/build scratch *.test *.out @@ -80,7 +75,6 @@ desktop/**/.reasonix/ Thumbs.db .idea/ .vscode/ -/site/public/av/ benchmarks/context-maintenance-e2e/run/ @@ -90,7 +84,6 @@ temp/ # Official theme art intermediate outputs / caches scripts/official-theme-art/out/ scripts/official-theme-art/__pycache__/ -site/.generated/ # Committed pointer at REASONIX.md; overrides a global CLAUDE.md ignore rule. !/CLAUDE.md diff --git a/site/astro.config.mjs b/site/astro.config.mjs deleted file mode 100644 index 90d4203134..0000000000 --- a/site/astro.config.mjs +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from 'astro/config'; -import sitemap from '@astrojs/sitemap'; - -// Served from the custom domain reasonix.io at the site root. -export default defineConfig({ - site: 'https://reasonix.io', - // Documentation code samples intentionally use source newlines as content. - // Astro 7's JSX-style compression removes those newlines unless disabled. - compressHTML: false, - build: { assets: 'static' }, - integrations: [sitemap({ - filter: (page) => !/\/changelog\/(?:stable|preview)\/?$/.test(page) && - !/\/changelog\/v\d+\.\d+\.\d+-/.test(page), - })], -}); diff --git a/site/package-lock.json b/site/package-lock.json deleted file mode 100644 index 9c3732de88..0000000000 --- a/site/package-lock.json +++ /dev/null @@ -1,4295 +0,0 @@ -{ - "name": "reasonix-site", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "reasonix-site", - "dependencies": { - "@astrojs/sitemap": "^3.7.3", - "@fontsource-variable/inter": "^5.3.0", - "@fontsource-variable/jetbrains-mono": "^5.3.0", - "astro": "^7.1.6" - }, - "devDependencies": { - "sharp": "^0.35.3" - } - }, - "node_modules/@astrojs/compiler-binding": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.3.2.tgz", - "integrity": "sha512-8w/9CWmYrAJJ8N0SY3O43ws2BgxoW6u3QsD8u2mE140lMYAlwh+tlNoUeSBq22wVheFuiBbR212l6ixZ2IIgCQ==", - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@astrojs/compiler-binding-darwin-arm64": "0.3.2", - "@astrojs/compiler-binding-darwin-x64": "0.3.2", - "@astrojs/compiler-binding-linux-arm64-gnu": "0.3.2", - "@astrojs/compiler-binding-linux-arm64-musl": "0.3.2", - "@astrojs/compiler-binding-linux-x64-gnu": "0.3.2", - "@astrojs/compiler-binding-linux-x64-musl": "0.3.2", - "@astrojs/compiler-binding-wasm32-wasi": "0.3.2", - "@astrojs/compiler-binding-win32-arm64-msvc": "0.3.2", - "@astrojs/compiler-binding-win32-x64-msvc": "0.3.2" - } - }, - "node_modules/@astrojs/compiler-binding-darwin-arm64": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.3.2.tgz", - "integrity": "sha512-MM8tn8CSimcfytaOla4b6acN8mKWiL/rlAA1fpT3/Wl7dNGSE4y8FjTN/zJVNnb63CsLWG5zZwCt01TXtDKh9g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-darwin-x64": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.3.2.tgz", - "integrity": "sha512-2lXOlzf8xb7jLomRsf/aswh61/NnGusynB2OwFkK6k4pmOtpfXMYnG0PLfXrEvxXYj69NdCnmUYXtHDd+JOOag==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.3.2.tgz", - "integrity": "sha512-BmU3kWj7qnLrd4vzm49zFEPJ5oFnn1tCT4Vt9hZbqdU5Cmb8GZl7fn6VFsnNfe7B18a2gIFtVzbLINtYl5kBjQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.3.2.tgz", - "integrity": "sha512-f0heT9ZZEseSu5bHCeb80eL2DH07ArE6U9xi1WT/PEusNjzPmEr3GJsjG1tRLo5VYUUYX7h3ScaqGmGrMOVGmw==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.3.2.tgz", - "integrity": "sha512-M8fOUt0itRpqiGyoEA/ij184s8O+hqbCz3+YozRusOOM3osgGljpDThhbKAJjqh82wOo6FioQ4w8PBvU1XMD5Q==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-linux-x64-musl": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.3.2.tgz", - "integrity": "sha512-/Kebk8sO6HnLeSd691JkaAPfN7CqR9/KEXmWvyNPkaKNGmj8rTZ/lf2uXtnPu92Lan84UrKdIKVPy1fSo2encQ==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-wasm32-wasi": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.3.2.tgz", - "integrity": "sha512-pUA6xbcOSB7DhfzIArB8BCAkFfAIqriiR7zl5zOStd6oU2G0kIKj+GUdGnyXyhfiv881Hffyk5tC0mR18sDjDw==", - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.2.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.3.2.tgz", - "integrity": "sha512-ESruf+6Qkl1trHUFxI6GSf6t52j8yN2kCNSzMWdzt7V/T09tFHrYzrVaJQohb2C9bJUH76pNvX6Zb51+xCQc9Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.3.2.tgz", - "integrity": "sha512-wzzVrEbOwbsLWOdEbocskjMRx2aZPxJ7ZbmL+jnpBamFwmigm+2M/wzuM6JWncocgYwLic1csSpalBh96kQKXA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@astrojs/compiler-rs": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.3.2.tgz", - "integrity": "sha512-xlx/T7JovIKduu4ucbTQUxQ5+Q8wxkHxhLjnZk3VlJbhbQ9RLvvuDk1p2YYFYFQ5y14dVm3FGGO4isQXa4F+Tg==", - "license": "MIT", - "dependencies": { - "@astrojs/compiler-binding": "0.3.2" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/@astrojs/internal-helpers": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.2.tgz", - "integrity": "sha512-yt7fMgPYqSM4Tmr+taTW6Per+hjJ8Pk6lA1PAcDyqzOt8HzJ6Kje5WzCxA2Sd+9wsUW7uhkLeoTMK0cXPwH9rQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.4", - "@types/mdast": "^4.0.4", - "js-yaml": "^4.3.0", - "picomatch": "^4.0.4", - "retext-smartypants": "^6.2.0", - "shiki": "^4.0.2", - "smol-toml": "^1.6.0", - "unified": "^11.0.5" - } - }, - "node_modules/@astrojs/markdown-satteri": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.5.tgz", - "integrity": "sha512-CvWVEFAbay7YO+i9SaqDJubipA5ckiVB89QWoMJ5XC0m5CtFg8JwZ7Kau6X9sYY7FZURH0w2l03ISH2jOS/RDQ==", - "license": "MIT", - "dependencies": { - "@astrojs/internal-helpers": "0.10.2", - "@astrojs/prism": "4.0.2", - "github-slugger": "^2.0.0", - "hast-util-from-html": "^2.0.3", - "satteri": "^0.9.1" - } - }, - "node_modules/@astrojs/prism": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", - "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", - "license": "MIT", - "dependencies": { - "prismjs": "^1.30.0" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/@astrojs/sitemap": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.3.tgz", - "integrity": "sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==", - "license": "MIT", - "dependencies": { - "sitemap": "^9.0.0", - "stream-replace-string": "^2.0.0", - "zod": "^4.3.6" - } - }, - "node_modules/@astrojs/telemetry": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", - "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", - "license": "MIT", - "dependencies": { - "ci-info": "^4.4.0", - "dset": "^3.1.4", - "is-docker": "^4.0.0", - "package-manager-detector": "^1.6.0" - }, - "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bruits/satteri-darwin-arm64": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.9.5.tgz", - "integrity": "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@bruits/satteri-darwin-x64": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.9.5.tgz", - "integrity": "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@bruits/satteri-linux-arm64-gnu": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.9.5.tgz", - "integrity": "sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-linux-arm64-musl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.9.5.tgz", - "integrity": "sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-linux-x64-gnu": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.9.5.tgz", - "integrity": "sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-linux-x64-musl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.9.5.tgz", - "integrity": "sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-wasm32-wasi": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.9.5.tgz", - "integrity": "sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==", - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@bruits/satteri-win32-arm64-msvc": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.9.5.tgz", - "integrity": "sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@bruits/satteri-win32-x64-msvc": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.9.5.tgz", - "integrity": "sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "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.4.1", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.1.tgz", - "integrity": "sha512-FILJa1gGKEFTGZAJE9RpVhrjKz3c3h4ar60dSv6cGuDqufQ84YEIS3GAGvZiN+H6yaLbbvTFNejjCC4tXpZEuw==", - "license": "MIT", - "dependencies": { - "fast-wrap-ansi": "^0.2.0", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" - } - }, - "node_modules/@clack/prompts": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.5.1.tgz", - "integrity": "sha512-zccHj2z2oCCO4yrDiRSlFOxWerGqRiysP7a5jPK6uoI9URKAquwY42Dd/iUP8JWHxEzdRe4TlbvZCo8z1/mhrw==", - "license": "MIT", - "dependencies": { - "@clack/core": "1.4.1", - "fast-string-width": "^3.0.2", - "fast-wrap-ansi": "^0.2.0", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" - } - }, - "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@fontsource-variable/inter": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.3.0.tgz", - "integrity": "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource-variable/jetbrains-mono": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource-variable/jetbrains-mono/-/jetbrains-mono-5.3.0.tgz", - "integrity": "sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "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==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", - "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.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", - "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.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "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/@napi-rs/wasm-runtime": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", - "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" - } - }, - "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/@oxc-project/types": { - "version": "0.139.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", - "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", - "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", - "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", - "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", - "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", - "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", - "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", - "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", - "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", - "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", - "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", - "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", - "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", - "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", - "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", - "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "license": "MIT" - }, - "node_modules/@shikijs/core": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.4.2.tgz", - "integrity": "sha512-StyzbAyxg2/tBGf78gwbBkGyeQ73lf8UiJArFaQhTQIDqQOCKPCQFanvrs4/Yv3Yfyc+ONInJM6K+FMIf+P+kA==", - "license": "MIT", - "dependencies": { - "@shikijs/primitive": "4.4.2", - "@shikijs/types": "4.4.2", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5", - "hast-util-to-html": "^9.0.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/engine-javascript": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.4.2.tgz", - "integrity": "sha512-MnIkeqWdVPUWsxlx8gKLVCJFTsqrQJgpTPBPpQwaFeJ56lOnJxj5aN2LUFnfxUEcvOQuNocmbaMnVrCEln6rkw==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.2", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.6" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.4.2.tgz", - "integrity": "sha512-GLhowz1+jixjz+wiZ3wMnOn1jTxiFCGl2PkXufivbnwPHKuyw1AYqu5/hbWhZZ2oAb0NP05WUJhYeigY14drnw==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.2", - "@shikijs/vscode-textmate": "^10.0.2" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/langs": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.4.2.tgz", - "integrity": "sha512-8DfeusD+Zdv/eYIDdXyJTUnSMHt+aAWjAOCXV20HNGAHRlInXpG8wh421v6B91WOm9TFwRLN+b/LG5F2NAIojg==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.2" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/primitive": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.4.2.tgz", - "integrity": "sha512-l6fQQKsOMlz72n38fztmSgZ76MO6KSWuw8o+GJ+FhmqrpC9pIOJNQNXGgbb5yX2AwpzlEHwsaLPnk/8o4Fm+rA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.2", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/themes": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.4.2.tgz", - "integrity": "sha512-H0CFoL07ddDC2Dd6EdrPYNkRhUR6YCkJlnuYFceYYUJJA5TIm2b5B33qqiDYryBExgbKMndFJPb2u1gTuqO37g==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.2" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/types": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.4.2.tgz", - "integrity": "sha512-PFYitV4vpDr/iPCIhnHp+Q4ftic5N5VeNJ3KQ1O8gn3h2ar8qgwMAXF7tq4m1CWaMS60fV4VqF6vfnWH4F7vqQ==", - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5" - }, - "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/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", - "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", - "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/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/node": { - "version": "24.13.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", - "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/sax": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", - "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", - "license": "ISC" - }, - "node_modules/am-i-vibing": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.4.0.tgz", - "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==", - "license": "MIT", - "dependencies": { - "process-ancestry": "^0.1.0" - }, - "bin": { - "am-i-vibing": "dist/cli.mjs" - } - }, - "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/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "license": "MIT" - }, - "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/astro": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/astro/-/astro-7.2.0.tgz", - "integrity": "sha512-lLTYzx3fOvCmtwD3JVBLQcbORbIOW1/j0R+3IvJx/XKwMGrk7mFnF0BYSOeRiNw1qHUR5mdA6+hRnyvyDfqrWQ==", - "license": "MIT", - "dependencies": { - "@astrojs/compiler-rs": "^0.3.2", - "@astrojs/internal-helpers": "0.10.2", - "@astrojs/markdown-satteri": "0.3.5", - "@astrojs/telemetry": "3.3.3", - "@capsizecss/unpack": "^4.0.0", - "@clack/prompts": "^1.1.0", - "@oslojs/encoding": "^1.1.0", - "am-i-vibing": "^0.4.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": "^2.0.1", - "devalue": "^5.8.1", - "diff": "^8.0.3", - "dset": "^3.1.4", - "es-module-lexer": "^2.0.0", - "esbuild": "^0.28.0", - "flattie": "^1.1.1", - "fontace": "~0.4.1", - "get-tsconfig": "5.0.0-beta.4", - "github-slugger": "^2.0.0", - "html-escaper": "3.0.3", - "http-cache-semantics": "^4.2.0", - "js-yaml": "^4.3.0", - "jsonc-parser": "^3.3.1", - "magic-string": "^1.0.0", - "magicast": "^0.5.2", - "mrmime": "^2.0.1", - "neotraverse": "^1.0.1", - "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.4", - "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", - "ultrahtml": "^1.6.0", - "unifont": "~0.7.4", - "unstorage": "^1.17.5", - "vite": "^8.0.13", - "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 || ^0.35.0" - }, - "peerDependencies": { - "@astrojs/markdown-remark": "7.2.2" - }, - "peerDependenciesMeta": { - "@astrojs/markdown-remark": { - "optional": true - } - } - }, - "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/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/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-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/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/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/cookie": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", - "integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==", - "license": "MIT", - "engines": { - "node": ">=22" - }, - "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/defu": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", - "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "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", - "engines": { - "node": ">=8" - } - }, - "node_modules/devalue": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", - "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", - "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/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/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.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, - "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-string-truncated-width": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", - "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", - "license": "MIT" - }, - "node_modules/fast-string-width": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", - "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", - "license": "MIT", - "dependencies": { - "fast-string-truncated-width": "^3.0.2" - } - }, - "node_modules/fast-wrap-ansi": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", - "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", - "license": "MIT", - "dependencies": { - "fast-string-width": "^3.0.2" - } - }, - "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/get-tsconfig": { - "version": "5.0.0-beta.4", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.4.tgz", - "integrity": "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==", - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "engines": { - "node": ">=20.20.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "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-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-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-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/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": "4.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", - "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=20" - }, - "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/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "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/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-string": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.1.0.tgz", - "integrity": "sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", - "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.3", - "@babel/types": "^7.29.0", - "source-map-js": "^1.2.1" - } - }, - "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/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-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-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-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-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/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", - "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": "1.0.1", - "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", - "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", - "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/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.2", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.2.tgz", - "integrity": "sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==", - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT", - "engines": { - "node": ">=12.20.0" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", - "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", - "license": "MIT" - }, - "node_modules/oniguruma-to-es": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", - "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", - "license": "MIT", - "dependencies": { - "oniguruma-parser": "^0.12.2", - "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.3.0", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.0.tgz", - "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==", - "license": "MIT", - "dependencies": { - "eventemitter3": "^5.0.4", - "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/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/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.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", - "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", - "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.16", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "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/process-ancestry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", - "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/property-information": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", - "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", - "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/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/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/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "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/rolldown": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", - "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.139.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.5", - "@rolldown/binding-darwin-arm64": "1.1.5", - "@rolldown/binding-darwin-x64": "1.1.5", - "@rolldown/binding-freebsd-x64": "1.1.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", - "@rolldown/binding-linux-arm64-gnu": "1.1.5", - "@rolldown/binding-linux-arm64-musl": "1.1.5", - "@rolldown/binding-linux-ppc64-gnu": "1.1.5", - "@rolldown/binding-linux-s390x-gnu": "1.1.5", - "@rolldown/binding-linux-x64-gnu": "1.1.5", - "@rolldown/binding-linux-x64-musl": "1.1.5", - "@rolldown/binding-openharmony-arm64": "1.1.5", - "@rolldown/binding-wasm32-wasi": "1.1.5", - "@rolldown/binding-win32-arm64-msvc": "1.1.5", - "@rolldown/binding-win32-x64-msvc": "1.1.5" - } - }, - "node_modules/satteri": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.9.5.tgz", - "integrity": "sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.5", - "@types/hast": "^3.0.4", - "@types/mdast": "^4.0.4", - "@types/unist": "^3.0.3" - }, - "optionalDependencies": { - "@bruits/satteri-darwin-arm64": "0.9.5", - "@bruits/satteri-darwin-x64": "0.9.5", - "@bruits/satteri-linux-arm64-gnu": "0.9.5", - "@bruits/satteri-linux-arm64-musl": "0.9.5", - "@bruits/satteri-linux-x64-gnu": "0.9.5", - "@bruits/satteri-linux-x64-musl": "0.9.5", - "@bruits/satteri-wasm32-wasi": "0.9.5", - "@bruits/satteri-win32-arm64-msvc": "0.9.5", - "@bruits/satteri-win32-x64-msvc": "0.9.5" - } - }, - "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/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@img/colour": "^1.1.0", - "detect-libc": "^2.1.2", - "semver": "^7.8.5" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/shiki": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.4.2.tgz", - "integrity": "sha512-P8F/dFhRevaw2uSdeIYlq/5SXZNY85DPtmXQ947gD1Zj2JqO5AkNvVVBar0Me9JkFx3uzVud/qOtP5ek9NEQGA==", - "license": "MIT", - "dependencies": { - "@shikijs/core": "4.4.2", - "@shikijs/engine-javascript": "4.4.2", - "@shikijs/engine-oniguruma": "4.4.2", - "@shikijs/langs": "4.4.2", - "@shikijs/themes": "4.4.2", - "@shikijs/types": "4.4.2", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5" - }, - "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/sitemap": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz", - "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==", - "license": "MIT", - "dependencies": { - "@types/node": "^24.9.2", - "@types/sax": "^1.2.1", - "arg": "^5.0.0", - "sax": "^1.4.1" - }, - "bin": { - "sitemap": "dist/esm/cli.js" - }, - "engines": { - "node": ">=20.19.5", - "npm": ">=10.8.2" - } - }, - "node_modules/smol-toml": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.1.tgz", - "integrity": "sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==", - "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/stream-replace-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", - "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", - "license": "MIT" - }, - "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/svgo": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", - "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", - "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/tinyclip": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.14.tgz", - "integrity": "sha512-F1oWdz8tjT17qe1d5JgDK6z03WGOhYYAN0lK3/D/fzNiy93xswLLEw7pk+3g05onhAy6Bsc6PLNUGhdgVjemMQ==", - "license": "MIT", - "engines": { - "node": "^16.14.0 || >= 17.3.0" - } - }, - "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/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/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/ufo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", - "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/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "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-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-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-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-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/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/vite": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", - "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.17", - "rolldown": "~1.1.5", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/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/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/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/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/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.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "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/site/package.json b/site/package.json deleted file mode 100644 index 66af3e1375..0000000000 --- a/site/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "reasonix-site", - "type": "module", - "private": true, - "scripts": { - "dev": "astro dev", - "prebuild": "node scripts/fetch-community.mjs && node scripts/fetch-publications.mjs", - "build": "astro build", - "preview": "astro preview", - "test": "node --test src/scripts/*.test.mjs" - }, - "dependencies": { - "@astrojs/sitemap": "^3.7.3", - "@fontsource-variable/inter": "^5.3.0", - "@fontsource-variable/jetbrains-mono": "^5.3.0", - "astro": "^7.1.6" - }, - "devDependencies": { - "sharp": "^0.35.3" - }, - "overrides": { - "esbuild": "0.28.1" - } -} diff --git a/site/public/favicon.svg b/site/public/favicon.svg deleted file mode 100644 index a781d2b639..0000000000 --- a/site/public/favicon.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/site/public/logo.svg b/site/public/logo.svg deleted file mode 100644 index 44a73c42c2..0000000000 --- a/site/public/logo.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/site/public/og.png b/site/public/og.png deleted file mode 100644 index cee00921d9..0000000000 Binary files a/site/public/og.png and /dev/null differ diff --git a/site/public/robots.txt b/site/public/robots.txt deleted file mode 100644 index 679c4964ad..0000000000 --- a/site/public/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Allow: / - -Sitemap: https://reasonix.io/sitemap-index.xml diff --git a/site/scripts/fetch-community.mjs b/site/scripts/fetch-community.mjs deleted file mode 100644 index 514bf1c4b6..0000000000 --- a/site/scripts/fetch-community.mjs +++ /dev/null @@ -1,63 +0,0 @@ -// Prebuild: fetch live community stats + bake contributor avatars into public/av/. -// Never fails the build — falls back to the committed snapshot on any error. -import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; -import sharp from 'sharp'; - -const repo = 'esengine/DeepSeek-Reasonix'; -const api = `https://api.github.com/repos/${repo}`; -const headers = { 'User-Agent': 'reasonix-site', Accept: 'application/vnd.github+json' }; -if (process.env.GITHUB_TOKEN) headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; - -const fallback = JSON.parse(await readFile('src/data/contributors.json', 'utf8')); -let { stars, mergedPrs, contributors, list } = fallback; - -try { - const r = await fetch(`${api}/contributors?per_page=100`, { headers }); - if (r.ok) { - const humans = (await r.json()) - .filter((c) => c.type === 'User') - .map((c) => ({ login: c.login, avatar: String(c.avatar_url).split('?')[0], url: c.html_url, c: c.contributions })); - if (humans.length) { list = humans; contributors = humans.length; } - } -} catch {} -try { - const r = await fetch(api, { headers }); - if (r.ok) { const d = await r.json(); if (typeof d.stargazers_count === 'number') stars = d.stargazers_count; } -} catch {} -try { - const r = await fetch(`https://api.github.com/search/issues?q=repo:${repo}+is:pr+is:merged&per_page=1`, { headers }); - if (r.ok) { const d = await r.json(); if (typeof d.total_count === 'number') mergedPrs = d.total_count; } -} catch {} - -// 64px is the largest rendered avatar; bake at 2x. GitHub honours ?s= for its -// own CDN but serves some custom avatars unscaled and in whatever format was -// uploaded, so re-encode rather than trusting the response. -const AVATAR_PX = 128; - -await rm('public/av', { recursive: true, force: true }); -await mkdir('public/av', { recursive: true }); -let baked = 0; -let bakedBytes = 0; -const out = await Promise.all(list.map(async (c) => { - const remote = `${c.avatar}?s=${AVATAR_PX}`; - try { - const r = await fetch(remote); - if (!r.ok) throw new Error(String(r.status)); - const webp = await sharp(Buffer.from(await r.arrayBuffer())) - .resize(AVATAR_PX, AVATAR_PX, { fit: 'cover' }) - .webp({ quality: 80 }) - .toBuffer(); - await writeFile(`public/av/${c.login}.webp`, webp); - baked++; - bakedBytes += webp.byteLength; - return { ...c, avatar: `/av/${c.login}.webp` }; - } catch { - return { ...c, avatar: remote }; - } -})); - -await writeFile('src/data/community.json', JSON.stringify({ stars, mergedPrs, contributors, list: out }, null, 2) + '\n'); -console.log( - `community: ${contributors} contributors · ${stars} stars · ${mergedPrs} merged PRs · ` + - `${baked}/${out.length} avatars baked (${(bakedBytes / 1024).toFixed(0)} KB)`, -); diff --git a/site/scripts/fetch-publications.mjs b/site/scripts/fetch-publications.mjs deleted file mode 100644 index e9c2bd8c9d..0000000000 --- a/site/scripts/fetch-publications.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import { mkdir, readFile, writeFile } from "node:fs/promises"; -import { resolve } from "node:path"; -import { validateReleaseEvent } from "../../scripts/release-event.mjs"; - -const siteRoot = resolve(import.meta.dirname, ".."); -const repoRoot = resolve(siteRoot, ".."); -const catalog = JSON.parse(await readFile(resolve(repoRoot, "release-notes/releases.json"), "utf8")); -const output = resolve(siteRoot, ".generated/publications.json"); -const headers = { - Accept: "application/vnd.github+json", - "User-Agent": "reasonix-site-publications", -}; -if (process.env.GITHUB_TOKEN) headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; - -const publications = []; -for (const release of catalog.releases) { - // Legacy entries predate publication markers and remain public. Every new - // reviewed entry fails closed until its exact CLI release carries the marker - // uploaded by the all-surface postflight. - if (!release.status || release.status === "published") { - publications.push(release.version); - continue; - } - const tag = `v${release.version}`; - try { - const response = await fetch( - `https://api.github.com/repos/esengine/DeepSeek-Reasonix/releases/tags/${encodeURIComponent(tag)}`, - { headers, signal: AbortSignal.timeout(20_000) }, - ); - if (!response.ok) continue; - const githubRelease = await response.json(); - const marker = githubRelease.assets?.find((asset) => asset.name === "release-event.json" && asset.size > 0); - if (!marker?.browser_download_url) continue; - const markerResponse = await fetch(marker.browser_download_url, { - headers, - signal: AbortSignal.timeout(20_000), - }); - if (!markerResponse.ok) continue; - const event = await markerResponse.json(); - validateReleaseEvent(event, release); - publications.push(release.version); - } catch { - // A reviewed release must never become public because an upstream lookup - // failed. The next Pages build retries after the release postflight. - } -} - -await mkdir(resolve(siteRoot, ".generated"), { recursive: true }); -await writeFile(output, `${JSON.stringify({ schemaVersion: 1, publications }, null, 2)}\n`); -console.log(`Resolved ${publications.length} public release note(s).`); diff --git a/site/src/components/ChangelogPage.astro b/site/src/components/ChangelogPage.astro deleted file mode 100644 index 19afc1f0db..0000000000 --- a/site/src/components/ChangelogPage.astro +++ /dev/null @@ -1,266 +0,0 @@ ---- -import Base from '../layouts/Base.astro'; -import SiteHeader from './SiteHeader.astro'; -import type { ReleaseItem, ReleaseRecord } from '../data/releases'; -import { releasePath } from '../data/releases'; -import '../styles/changelog.css'; - -const { release, releases, canonical } = Astro.props as { - release: ReleaseRecord; - releases: ReleaseRecord[]; - canonical?: string; -}; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const repo = 'https://github.com/esengine/DeepSeek-Reasonix'; -const prHref = (ref: number) => `${repo}/pull/${ref}`; - -const isPreview = release.channel === 'prerelease'; -const latestForChannel = releases[0]; -const downloadHref = isPreview ? 'https://reasonix.io/?download=desktop#start' : release.links.download; - -const kindLabel = (kind: string) => ({ - new: { en: 'New', zh: '新增' }, - improved: { en: 'Improved', zh: '改进' }, - fixed: { en: 'Fixed', zh: '修复' }, - security: { en: 'Security', zh: '安全' }, -}[kind] ?? { en: kind, zh: kind }); - -const surfaceLabel = (surface: string) => ({ - agent: { en: 'Agent', zh: 'Agent' }, - desktop: { en: 'Desktop', zh: '桌面端' }, - cli: { en: 'CLI', zh: 'CLI' }, - mcp: { en: 'MCP', zh: 'MCP' }, - security: { en: 'Security', zh: '安全' }, - provider: { en: 'Provider', zh: '模型服务' }, - plugin: { en: 'Plugins', zh: '插件' }, -}[surface] ?? { en: surface, zh: surface }); - -/* Sections render only when they have content; numbering is sequential. */ -const sectionDefs = [ - ...(release.guides.length ? [{ id: 'guides', en: 'Guides', zh: '使用攻略' }] : []), - { id: 'highlights', en: 'Highlights', zh: '重点内容' }, - ...(['new', 'improved', 'fixed'] as const) - .filter((kind) => release.changes[kind].length) - .map((kind) => ({ id: kind, ...kindLabel(kind) })), - ...(release.upgrade.length ? [{ id: 'upgrade', en: 'Upgrade notes', zh: '升级提醒' }] : []), - ...(release.risks.length ? [{ id: 'risks', en: 'Risk notes', zh: '风险提示' }] : []), - ...(release.contributors.length ? [{ id: 'thanks', en: 'Thanks', zh: '致谢' }] : []), -]; -const sectionNum = new Map(sectionDefs.map((s, i) => [s.id, String(i + 1).padStart(2, '0')])); -const tocItems = [...sectionDefs, { id: 'download', en: 'Download', zh: '下载与安装' }]; - -/* Version rail: group by minor, show the latest few patches per group, - older ones behind a native
expander. */ -const minorKey = (v: string) => v.split('.').slice(0, 2).join('.'); -const railGroups: { key: string; items: ReleaseRecord[] }[] = []; -for (const item of releases) { - const key = minorKey(item.version); - const last = railGroups[railGroups.length - 1]; - if (last && last.key === key) last.items.push(item); - else railGroups.push({ key, items: [item] }); -} -const RAIL_VISIBLE = 3; - -const titleEn = `Reasonix v${release.version} release notes`; -const titleZh = `Reasonix v${release.version} 更新日志`; -const description = release.summary.en; ---- - - - - -
-
- - -
- -
- - -
-
-
- {isPreview && Historical archive历史归档} - -
-

Reasonix v{release.version}

-
- {release.surfaces.map((surface) => { - const label = surfaceLabel(surface); - return {label.en}{label.zh}; - })} -
- {release.builds && ( -
- CLI {release.builds.cli} - Desktop {release.builds.desktop} - npm {release.builds.npm} -
- )} -

{release.summary.en}{release.summary.zh}

-
- - {release.guides.length > 0 && ( -
-
{sectionNum.get('guides')}

Start here使用攻略

- -
- )} - -
-
{sectionNum.get('highlights')}

Highlights重点内容

-
- {release.highlights.map((item, index) => { - const kind = kindLabel(item.kind); - return ( -
-
{String(index + 1).padStart(2, '0')}
-
-
{kind.en}{kind.zh}
-

{item.title.en}{item.title.zh}

-

{item.body.en}{item.body.zh}

- {item.refs?.length &&
{item.refs.map((ref) => #{ref})}
} -
-
- ); - })} -
-
- - {(['new', 'improved', 'fixed'] as const).map((kind) => { - const items = release.changes[kind]; - if (!items.length) return null; - const label = kindLabel(kind); - return ( -
-
{sectionNum.get(kind)}

{label.en}{label.zh}

-
- {items.map((item: ReleaseItem) => ( -
-

{item.title.en}{item.title.zh}

-

{item.body.en}{item.body.zh}

- {item.refs?.length &&
{item.refs.map((ref) => #{ref})}
} -
- ))} -
-
- ); - })} - - {release.upgrade.length > 0 && ( -
-
{sectionNum.get('upgrade')}

Upgrade notes升级提醒

-
- {release.upgrade.map((item) => ( -
-
{item.level === 'warning' ? '!' : 'i'}
-
-

{item.title.en}{item.title.zh}

-

{item.body.en}{item.body.zh}

- {item.refs?.length &&
{item.refs.map((ref) => #{ref})}
} -
-
- ))} -
-
- )} - - {release.risks.length > 0 && ( -
-
{sectionNum.get('risks')}

Risk notes风险提示

-
- {release.risks.map((item) => ( -
-

{item.title.en}{item.title.zh}

-

{item.body.en}{item.body.zh}

- {item.refs?.length &&
{item.refs.map((ref) => #{ref})}
} -
- ))} -
-
- )} - - {release.contributors.length > 0 && ( -
-
{sectionNum.get('thanks')}

Thanks致谢

-

This release was shaped by:感谢本版本的贡献者:

-
{release.contributors.map((name) => @{name})}
-
- )} - -
-
-

Ready when you are准备好即可升级

-

Ship with a safer Reasonix.升级到更可靠的 Reasonix。

-
- -
-
- - -
-
- - - - - diff --git a/site/src/components/SiteHeader.astro b/site/src/components/SiteHeader.astro deleted file mode 100644 index f2923410be..0000000000 --- a/site/src/components/SiteHeader.astro +++ /dev/null @@ -1,130 +0,0 @@ ---- -type ActiveItem = 'features' | 'surfaces' | 'skills' | 'community' | 'docs' | 'changelog'; - -const { - active, - scrolled = false, - accountSlot = false, -} = Astro.props as { - active?: ActiveItem; - scrolled?: boolean; - accountSlot?: boolean; -}; - -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const repo = 'https://github.com/esengine/DeepSeek-Reasonix'; -const items: Array<{ - id: ActiveItem; - href: string; - en: string; - zh: string; - secondary?: boolean; -}> = [ - { id: 'features', href: `${base}/#features`, en: 'Features', zh: '特性' }, - { id: 'surfaces', href: `${base}/#surfaces`, en: 'Surfaces', zh: '使用形态', secondary: true }, - { id: 'skills', href: `${base}/skills/`, en: 'Skills', zh: '技能市场' }, - { id: 'community', href: `${base}/#community`, en: 'Community', zh: '社区', secondary: true }, - { id: 'docs', href: `${base}/docs/`, en: 'Docs', zh: '文档' }, - { id: 'changelog', href: `${base}/changelog/`, en: 'Changelog', zh: '更新日志' }, -]; ---- - -
- - -
diff --git a/site/src/data/community.json b/site/src/data/community.json deleted file mode 100644 index 10e105dca2..0000000000 --- a/site/src/data/community.json +++ /dev/null @@ -1,595 +0,0 @@ -{ - "stars": 29222, - "mergedPrs": 2816, - "contributors": 98, - "list": [ - { - "login": "SivanCola", - "avatar": "/av/SivanCola.webp", - "url": "https://github.com/SivanCola", - "c": 2311 - }, - { - "login": "esengine", - "avatar": "/av/esengine.webp", - "url": "https://github.com/esengine", - "c": 518 - }, - { - "login": "ttmouse", - "avatar": "/av/ttmouse.webp", - "url": "https://github.com/ttmouse", - "c": 121 - }, - { - "login": "lifu963", - "avatar": "/av/lifu963.webp", - "url": "https://github.com/lifu963", - "c": 105 - }, - { - "login": "HUQIANTAO", - "avatar": "/av/HUQIANTAO.webp", - "url": "https://github.com/HUQIANTAO", - "c": 74 - }, - { - "login": "GTC2080", - "avatar": "/av/GTC2080.webp", - "url": "https://github.com/GTC2080", - "c": 61 - }, - { - "login": "light-front-theory", - "avatar": "/av/light-front-theory.webp", - "url": "https://github.com/light-front-theory", - "c": 56 - }, - { - "login": "Li-Charles-One", - "avatar": "/av/Li-Charles-One.webp", - "url": "https://github.com/Li-Charles-One", - "c": 49 - }, - { - "login": "eghrhegpe", - "avatar": "/av/eghrhegpe.webp", - "url": "https://github.com/eghrhegpe", - "c": 28 - }, - { - "login": "CVEngineer66", - "avatar": "/av/CVEngineer66.webp", - "url": "https://github.com/CVEngineer66", - "c": 16 - }, - { - "login": "JesonChou", - "avatar": "/av/JesonChou.webp", - "url": "https://github.com/JesonChou", - "c": 15 - }, - { - "login": "HaoyueQin", - "avatar": "/av/HaoyueQin.webp", - "url": "https://github.com/HaoyueQin", - "c": 14 - }, - { - "login": "SuMuxi66", - "avatar": "/av/SuMuxi66.webp", - "url": "https://github.com/SuMuxi66", - "c": 11 - }, - { - "login": "lanshi17", - "avatar": "/av/lanshi17.webp", - "url": "https://github.com/lanshi17", - "c": 11 - }, - { - "login": "CnsMaple", - "avatar": "/av/CnsMaple.webp", - "url": "https://github.com/CnsMaple", - "c": 9 - }, - { - "login": "cyq1017", - "avatar": "/av/cyq1017.webp", - "url": "https://github.com/cyq1017", - "c": 9 - }, - { - "login": "ipanta", - "avatar": "/av/ipanta.webp", - "url": "https://github.com/ipanta", - "c": 8 - }, - { - "login": "XTLine", - "avatar": "/av/XTLine.webp", - "url": "https://github.com/XTLine", - "c": 8 - }, - { - "login": "YoungDan-hero", - "avatar": "/av/YoungDan-hero.webp", - "url": "https://github.com/YoungDan-hero", - "c": 8 - }, - { - "login": "paradoxSCH", - "avatar": "/av/paradoxSCH.webp", - "url": "https://github.com/paradoxSCH", - "c": 8 - }, - { - "login": "wade19990814-hue", - "avatar": "/av/wade19990814-hue.webp", - "url": "https://github.com/wade19990814-hue", - "c": 7 - }, - { - "login": "SauronSkywalker", - "avatar": "/av/SauronSkywalker.webp", - "url": "https://github.com/SauronSkywalker", - "c": 7 - }, - { - "login": "yizeyi18", - "avatar": "/av/yizeyi18.webp", - "url": "https://github.com/yizeyi18", - "c": 6 - }, - { - "login": "ashishexee", - "avatar": "/av/ashishexee.webp", - "url": "https://github.com/ashishexee", - "c": 6 - }, - { - "login": "erphenheimer", - "avatar": "/av/erphenheimer.webp", - "url": "https://github.com/erphenheimer", - "c": 6 - }, - { - "login": "Bernardxu123", - "avatar": "/av/Bernardxu123.webp", - "url": "https://github.com/Bernardxu123", - "c": 6 - }, - { - "login": "lizhengwu", - "avatar": "/av/lizhengwu.webp", - "url": "https://github.com/lizhengwu", - "c": 6 - }, - { - "login": "qiaone", - "avatar": "/av/qiaone.webp", - "url": "https://github.com/qiaone", - "c": 5 - }, - { - "login": "mchenziyi", - "avatar": "/av/mchenziyi.webp", - "url": "https://github.com/mchenziyi", - "c": 4 - }, - { - "login": "ferstar", - "avatar": "/av/ferstar.webp", - "url": "https://github.com/ferstar", - "c": 4 - }, - { - "login": "zhangsanouo", - "avatar": "/av/zhangsanouo.webp", - "url": "https://github.com/zhangsanouo", - "c": 4 - }, - { - "login": "par73e", - "avatar": "/av/par73e.webp", - "url": "https://github.com/par73e", - "c": 4 - }, - { - "login": "liaoyl830", - "avatar": "/av/liaoyl830.webp", - "url": "https://github.com/liaoyl830", - "c": 3 - }, - { - "login": "jiaxindeyang-a11y", - "avatar": "/av/jiaxindeyang-a11y.webp", - "url": "https://github.com/jiaxindeyang-a11y", - "c": 3 - }, - { - "login": "nostalgia296", - "avatar": "/av/nostalgia296.webp", - "url": "https://github.com/nostalgia296", - "c": 3 - }, - { - "login": "Diarica", - "avatar": "/av/Diarica.webp", - "url": "https://github.com/Diarica", - "c": 3 - }, - { - "login": "yekern", - "avatar": "/av/yekern.webp", - "url": "https://github.com/yekern", - "c": 3 - }, - { - "login": "maoxin1234", - "avatar": "/av/maoxin1234.webp", - "url": "https://github.com/maoxin1234", - "c": 3 - }, - { - "login": "lightfront", - "avatar": "/av/lightfront.webp", - "url": "https://github.com/lightfront", - "c": 3 - }, - { - "login": "ikelvingo", - "avatar": "/av/ikelvingo.webp", - "url": "https://github.com/ikelvingo", - "c": 3 - }, - { - "login": "ffff2004", - "avatar": "/av/ffff2004.webp", - "url": "https://github.com/ffff2004", - "c": 3 - }, - { - "login": "kekexunxun", - "avatar": "/av/kekexunxun.webp", - "url": "https://github.com/kekexunxun", - "c": 3 - }, - { - "login": "Tatlatat", - "avatar": "/av/Tatlatat.webp", - "url": "https://github.com/Tatlatat", - "c": 3 - }, - { - "login": "PaulDing98", - "avatar": "/av/PaulDing98.webp", - "url": "https://github.com/PaulDing98", - "c": 3 - }, - { - "login": "AtmoOmen", - "avatar": "/av/AtmoOmen.webp", - "url": "https://github.com/AtmoOmen", - "c": 3 - }, - { - "login": "billycat", - "avatar": "/av/billycat.webp", - "url": "https://github.com/billycat", - "c": 2 - }, - { - "login": "xianyu-sheng", - "avatar": "/av/xianyu-sheng.webp", - "url": "https://github.com/xianyu-sheng", - "c": 2 - }, - { - "login": "heshuimu", - "avatar": "/av/heshuimu.webp", - "url": "https://github.com/heshuimu", - "c": 2 - }, - { - "login": "drafish", - "avatar": "/av/drafish.webp", - "url": "https://github.com/drafish", - "c": 2 - }, - { - "login": "yhemeo613", - "avatar": "/av/yhemeo613.webp", - "url": "https://github.com/yhemeo613", - "c": 2 - }, - { - "login": "wqshan-cn", - "avatar": "/av/wqshan-cn.webp", - "url": "https://github.com/wqshan-cn", - "c": 2 - }, - { - "login": "warvyvr", - "avatar": "/av/warvyvr.webp", - "url": "https://github.com/warvyvr", - "c": 2 - }, - { - "login": "Xio-Shark", - "avatar": "/av/Xio-Shark.webp", - "url": "https://github.com/Xio-Shark", - "c": 2 - }, - { - "login": "LVGG", - "avatar": "/av/LVGG.webp", - "url": "https://github.com/LVGG", - "c": 2 - }, - { - "login": "assoyuan", - "avatar": "/av/assoyuan.webp", - "url": "https://github.com/assoyuan", - "c": 2 - }, - { - "login": "closss", - "avatar": "/av/closss.webp", - "url": "https://github.com/closss", - "c": 2 - }, - { - "login": "iysun", - "avatar": "/av/iysun.webp", - "url": "https://github.com/iysun", - "c": 2 - }, - { - "login": "whale-fall-ouo", - "avatar": "/av/whale-fall-ouo.webp", - "url": "https://github.com/whale-fall-ouo", - "c": 2 - }, - { - "login": "sudoviber", - "avatar": "/av/sudoviber.webp", - "url": "https://github.com/sudoviber", - "c": 2 - }, - { - "login": "qiukeren", - "avatar": "/av/qiukeren.webp", - "url": "https://github.com/qiukeren", - "c": 2 - }, - { - "login": "nanami7777777", - "avatar": "/av/nanami7777777.webp", - "url": "https://github.com/nanami7777777", - "c": 2 - }, - { - "login": "alxbnct", - "avatar": "/av/alxbnct.webp", - "url": "https://github.com/alxbnct", - "c": 1 - }, - { - "login": "Zhuocheng-Lang", - "avatar": "/av/Zhuocheng-Lang.webp", - "url": "https://github.com/Zhuocheng-Lang", - "c": 1 - }, - { - "login": "dcs02280653-collab", - "avatar": "/av/dcs02280653-collab.webp", - "url": "https://github.com/dcs02280653-collab", - "c": 1 - }, - { - "login": "dengbushi", - "avatar": "/av/dengbushi.webp", - "url": "https://github.com/dengbushi", - "c": 1 - }, - { - "login": "h4rk8s", - "avatar": "/av/h4rk8s.webp", - "url": "https://github.com/h4rk8s", - "c": 1 - }, - { - "login": "myipanta", - "avatar": "/av/myipanta.webp", - "url": "https://github.com/myipanta", - "c": 1 - }, - { - "login": "jackijianxa", - "avatar": "/av/jackijianxa.webp", - "url": "https://github.com/jackijianxa", - "c": 1 - }, - { - "login": "jbts6", - "avatar": "/av/jbts6.webp", - "url": "https://github.com/jbts6", - "c": 1 - }, - { - "login": "ji-tz", - "avatar": "/av/ji-tz.webp", - "url": "https://github.com/ji-tz", - "c": 1 - }, - { - "login": "kabaka9527", - "avatar": "/av/kabaka9527.webp", - "url": "https://github.com/kabaka9527", - "c": 1 - }, - { - "login": "9710willy", - "avatar": "/av/9710willy.webp", - "url": "https://github.com/9710willy", - "c": 1 - }, - { - "login": "onenewcode", - "avatar": "/av/onenewcode.webp", - "url": "https://github.com/onenewcode", - "c": 1 - }, - { - "login": "Ninot1Quyi", - "avatar": "/av/Ninot1Quyi.webp", - "url": "https://github.com/Ninot1Quyi", - "c": 1 - }, - { - "login": "xiaoshuai1024", - "avatar": "/av/xiaoshuai1024.webp", - "url": "https://github.com/xiaoshuai1024", - "c": 1 - }, - { - "login": "rixzkiye", - "avatar": "/av/rixzkiye.webp", - "url": "https://github.com/rixzkiye", - "c": 1 - }, - { - "login": "taibai233", - "avatar": "/av/taibai233.webp", - "url": "https://github.com/taibai233", - "c": 1 - }, - { - "login": "ying-hua", - "avatar": "/av/ying-hua.webp", - "url": "https://github.com/ying-hua", - "c": 1 - }, - { - "login": "yuanchenglu", - "avatar": "/av/yuanchenglu.webp", - "url": "https://github.com/yuanchenglu", - "c": 1 - }, - { - "login": "zhuguang-ZFG", - "avatar": "/av/zhuguang-ZFG.webp", - "url": "https://github.com/zhuguang-ZFG", - "c": 1 - }, - { - "login": "zlwu", - "avatar": "/av/zlwu.webp", - "url": "https://github.com/zlwu", - "c": 1 - }, - { - "login": "xinrenH", - "avatar": "/av/xinrenH.webp", - "url": "https://github.com/xinrenH", - "c": 1 - }, - { - "login": "zdjmrq", - "avatar": "/av/zdjmrq.webp", - "url": "https://github.com/zdjmrq", - "c": 1 - }, - { - "login": "i1j", - "avatar": "/av/i1j.webp", - "url": "https://github.com/i1j", - "c": 1 - }, - { - "login": "Abysstsuki", - "avatar": "/av/Abysstsuki.webp", - "url": "https://github.com/Abysstsuki", - "c": 1 - }, - { - "login": "themarchrain", - "avatar": "/av/themarchrain.webp", - "url": "https://github.com/themarchrain", - "c": 1 - }, - { - "login": "wudiandy", - "avatar": "/av/wudiandy.webp", - "url": "https://github.com/wudiandy", - "c": 1 - }, - { - "login": "EMEEEEMMMM", - "avatar": "/av/EMEEEEMMMM.webp", - "url": "https://github.com/EMEEEEMMMM", - "c": 1 - }, - { - "login": "HBLADEH", - "avatar": "/av/HBLADEH.webp", - "url": "https://github.com/HBLADEH", - "c": 1 - }, - { - "login": "HHHEEEWWW", - "avatar": "/av/HHHEEEWWW.webp", - "url": "https://github.com/HHHEEEWWW", - "c": 1 - }, - { - "login": "HorusJiang", - "avatar": "/av/HorusJiang.webp", - "url": "https://github.com/HorusJiang", - "c": 1 - }, - { - "login": "J3y0r", - "avatar": "/av/J3y0r.webp", - "url": "https://github.com/J3y0r", - "c": 1 - }, - { - "login": "JimmyDaddy", - "avatar": "/av/JimmyDaddy.webp", - "url": "https://github.com/JimmyDaddy", - "c": 1 - }, - { - "login": "LegGasai", - "avatar": "/av/LegGasai.webp", - "url": "https://github.com/LegGasai", - "c": 1 - }, - { - "login": "gcoder1991", - "avatar": "/av/gcoder1991.webp", - "url": "https://github.com/gcoder1991", - "c": 1 - }, - { - "login": "LouF666", - "avatar": "/av/LouF666.webp", - "url": "https://github.com/LouF666", - "c": 1 - }, - { - "login": "MaitreyeeDeshmukh", - "avatar": "/av/MaitreyeeDeshmukh.webp", - "url": "https://github.com/MaitreyeeDeshmukh", - "c": 1 - }, - { - "login": "ERroooooR", - "avatar": "/av/ERroooooR.webp", - "url": "https://github.com/ERroooooR", - "c": 1 - } - ] -} diff --git a/site/src/data/contributors.json b/site/src/data/contributors.json deleted file mode 100644 index 75e9d52109..0000000000 --- a/site/src/data/contributors.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "stars": 20843, - "mergedPrs": 1779, - "contributors": 41, - "list": [ - { "login": "esengine", "avatar": "https://avatars.githubusercontent.com/u/18465053", "url": "https://github.com/esengine", "c": 310 }, - { "login": "SivanCola", "avatar": "https://avatars.githubusercontent.com/u/32437197", "url": "https://github.com/SivanCola", "c": 158 }, - { "login": "HUQIANTAO", "avatar": "https://avatars.githubusercontent.com/u/58421104", "url": "https://github.com/HUQIANTAO", "c": 73 }, - { "login": "GTC2080", "avatar": "https://avatars.githubusercontent.com/u/140309575", "url": "https://github.com/GTC2080", "c": 16 }, - { "login": "CVEngineer66", "avatar": "https://avatars.githubusercontent.com/u/129239603", "url": "https://github.com/CVEngineer66", "c": 10 }, - { "login": "Li-Charles-One", "avatar": "https://avatars.githubusercontent.com/u/258708209", "url": "https://github.com/Li-Charles-One", "c": 10 }, - { "login": "SuMuxi66", "avatar": "https://avatars.githubusercontent.com/u/96619914", "url": "https://github.com/SuMuxi66", "c": 9 }, - { "login": "lanshi17", "avatar": "https://avatars.githubusercontent.com/u/94416777", "url": "https://github.com/lanshi17", "c": 9 }, - { "login": "paradoxSCH", "avatar": "https://avatars.githubusercontent.com/u/64133628", "url": "https://github.com/paradoxSCH", "c": 7 }, - { "login": "wade19990814-hue", "avatar": "https://avatars.githubusercontent.com/u/280641290", "url": "https://github.com/wade19990814-hue", "c": 7 }, - { "login": "YoungDan-hero", "avatar": "https://avatars.githubusercontent.com/u/66891653", "url": "https://github.com/YoungDan-hero", "c": 6 }, - { "login": "lizhengwu", "avatar": "https://avatars.githubusercontent.com/u/38285521", "url": "https://github.com/lizhengwu", "c": 5 }, - { "login": "Bernardxu123", "avatar": "https://avatars.githubusercontent.com/u/85089406", "url": "https://github.com/Bernardxu123", "c": 5 }, - { "login": "CnsMaple", "avatar": "https://avatars.githubusercontent.com/u/92523839", "url": "https://github.com/CnsMaple", "c": 5 }, - { "login": "AtmoOmen", "avatar": "https://avatars.githubusercontent.com/u/110901588", "url": "https://github.com/AtmoOmen", "c": 3 }, - { "login": "Tatlatat", "avatar": "https://avatars.githubusercontent.com/u/269959336", "url": "https://github.com/Tatlatat", "c": 3 }, - { "login": "kekexunxun", "avatar": "https://avatars.githubusercontent.com/u/44473551", "url": "https://github.com/kekexunxun", "c": 3 }, - { "login": "jiaxindeyang-a11y", "avatar": "https://avatars.githubusercontent.com/u/278341870", "url": "https://github.com/jiaxindeyang-a11y", "c": 3 }, - { "login": "nostalgia296", "avatar": "https://avatars.githubusercontent.com/u/207565364", "url": "https://github.com/nostalgia296", "c": 2 }, - { "login": "yhemeo613", "avatar": "https://avatars.githubusercontent.com/u/138780695", "url": "https://github.com/yhemeo613", "c": 2 }, - { "login": "ttmouse", "avatar": "https://avatars.githubusercontent.com/u/8982044", "url": "https://github.com/ttmouse", "c": 2 }, - { "login": "iysun", "avatar": "https://avatars.githubusercontent.com/u/102790274", "url": "https://github.com/iysun", "c": 2 }, - { "login": "closss", "avatar": "https://avatars.githubusercontent.com/u/106432698", "url": "https://github.com/closss", "c": 2 }, - { "login": "XTLine", "avatar": "https://avatars.githubusercontent.com/u/140948646", "url": "https://github.com/XTLine", "c": 2 }, - { "login": "LVGG", "avatar": "https://avatars.githubusercontent.com/u/20256205", "url": "https://github.com/LVGG", "c": 2 }, - { "login": "xinrenH", "avatar": "https://avatars.githubusercontent.com/u/121069519", "url": "https://github.com/xinrenH", "c": 1 }, - { "login": "lightfront", "avatar": "https://avatars.githubusercontent.com/u/13162893", "url": "https://github.com/lightfront", "c": 1 }, - { "login": "lifu963", "avatar": "https://avatars.githubusercontent.com/u/56394323", "url": "https://github.com/lifu963", "c": 1 }, - { "login": "kabaka9527", "avatar": "https://avatars.githubusercontent.com/u/142149737", "url": "https://github.com/kabaka9527", "c": 1 }, - { "login": "dcs02280653-collab", "avatar": "https://avatars.githubusercontent.com/u/272150807", "url": "https://github.com/dcs02280653-collab", "c": 1 }, - { "login": "ashishexee", "avatar": "https://avatars.githubusercontent.com/u/144021866", "url": "https://github.com/ashishexee", "c": 1 }, - { "login": "alxbnct", "avatar": "https://avatars.githubusercontent.com/u/52067352", "url": "https://github.com/alxbnct", "c": 1 }, - { "login": "PorunC", "avatar": "https://avatars.githubusercontent.com/u/63705582", "url": "https://github.com/PorunC", "c": 1 }, - { "login": "ERroooooR", "avatar": "https://avatars.githubusercontent.com/u/121479279", "url": "https://github.com/ERroooooR", "c": 1 }, - { "login": "LegGasai", "avatar": "https://avatars.githubusercontent.com/u/75920107", "url": "https://github.com/LegGasai", "c": 1 }, - { "login": "JimmyDaddy", "avatar": "https://avatars.githubusercontent.com/u/16460813", "url": "https://github.com/JimmyDaddy", "c": 1 }, - { "login": "drafish", "avatar": "https://avatars.githubusercontent.com/u/18543527", "url": "https://github.com/drafish", "c": 1 }, - { "login": "HorusJiang", "avatar": "https://avatars.githubusercontent.com/u/29286555", "url": "https://github.com/HorusJiang", "c": 1 }, - { "login": "HBLADEH", "avatar": "https://avatars.githubusercontent.com/u/27012363", "url": "https://github.com/HBLADEH", "c": 1 }, - { "login": "Nahiyi", "avatar": "https://avatars.githubusercontent.com/u/163129774", "url": "https://github.com/Nahiyi", "c": 1 }, - { "login": "i1j", "avatar": "https://avatars.githubusercontent.com/u/35729767", "url": "https://github.com/i1j", "c": 1 } - ] -} diff --git a/site/src/data/releases.ts b/site/src/data/releases.ts deleted file mode 100644 index cb6efe5784..0000000000 --- a/site/src/data/releases.ts +++ /dev/null @@ -1,70 +0,0 @@ -import source from '../../../release-notes/releases.json'; -import { readFileSync } from 'node:fs'; -import { resolve } from 'node:path'; - -export type LocalizedText = { en: string; zh: string }; - -export type ReleaseItem = { - title: LocalizedText; - body: LocalizedText; - refs?: number[]; -}; - -export type ReleaseHighlight = ReleaseItem & { - kind: 'new' | 'improved' | 'fixed' | 'security'; -}; - -export type ReleaseGuide = ReleaseItem & { href: string }; -export type ReleaseUpgrade = ReleaseItem & { level: 'info' | 'warning' }; - -export type ReleaseRecord = { - version: string; - releaseId?: string; - baseVersion?: string; - date: string; - channel: 'stable' | 'prerelease'; - status?: 'reviewed' | 'published'; - candidateSha?: string; - previousRelease?: string; - builds?: { cli: string; desktop: string; npm: string }; - title: LocalizedText; - summary: LocalizedText; - surfaces: string[]; - guides: ReleaseGuide[]; - highlights: ReleaseHighlight[]; - changes: { new: ReleaseItem[]; improved: ReleaseItem[]; fixed: ReleaseItem[] }; - upgrade: ReleaseUpgrade[]; - risks: ReleaseItem[]; - contributors: string[]; - links: { github: string; compare: string; download: string }; -}; - -export const releaseCatalog = source as { schemaVersion: number; releases: ReleaseRecord[] }; -export const allReleases = releaseCatalog.releases; - -let publishedIds = new Set(); -try { - const generated = JSON.parse( - readFileSync(resolve(process.cwd(), '.generated/publications.json'), 'utf8'), - ) as { publications?: string[] }; - publishedIds = new Set(generated.publications ?? []); -} catch { - // Before prebuild, preserve legacy entries and fail closed for reviewed - // releases that require a successful all-surface publication marker. -} - -export const publishedReleases = allReleases.filter( - (release) => !release.status || release.status === 'published' || publishedIds.has(release.version), -); -// Public navigation contains official releases only. Historical prereleases -// remain addressable by their exact version URL for compatibility. -export const releases = publishedReleases.filter((release) => release.channel === 'stable'); -export const stableReleases = releases; -export const previewReleases = publishedReleases.filter((release) => release.channel === 'prerelease'); -export const latestStableRelease = stableReleases[0]; -export const latestPreviewRelease = previewReleases[0]; -export const latestRelease = latestStableRelease; - -export function releasePath(version: string): string { - return `/changelog/v${version}/`; -} diff --git a/site/src/layouts/Account.astro b/site/src/layouts/Account.astro deleted file mode 100644 index 94da6c5e4d..0000000000 --- a/site/src/layouts/Account.astro +++ /dev/null @@ -1,36 +0,0 @@ ---- -import Base from './Base.astro'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const repo = 'https://github.com/esengine/DeepSeek-Reasonix'; -const { title, description, titleEn, titleZh, wide } = Astro.props; ---- - - - -
-
- -
-
- - - - - diff --git a/site/src/layouts/Base.astro b/site/src/layouts/Base.astro deleted file mode 100644 index 155a615028..0000000000 --- a/site/src/layouts/Base.astro +++ /dev/null @@ -1,47 +0,0 @@ ---- -import '../styles/global.css'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const { title, description, titleEn, titleZh, canonical: canonicalOverride, noindex = false } = Astro.props; -const canonical = canonicalOverride ?? new URL(Astro.url.pathname, Astro.site).href; -const ogImage = new URL(`${base}/og.png`, Astro.site).href; ---- - - - - - - {title} - - {noindex && } - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/src/layouts/Community.astro b/site/src/layouts/Community.astro deleted file mode 100644 index b2d784fab1..0000000000 --- a/site/src/layouts/Community.astro +++ /dev/null @@ -1,103 +0,0 @@ ---- -import "../styles/community.css"; -const { title, description, active } = Astro.props; -const canonical = new URL(Astro.url.pathname, Astro.site).href; ---- - - - - - - {title} - - - - - - - - - - - - - -
- -
- - - - - - diff --git a/site/src/pages/404.astro b/site/src/pages/404.astro deleted file mode 100644 index a5ade30c29..0000000000 --- a/site/src/pages/404.astro +++ /dev/null @@ -1,37 +0,0 @@ ---- -import Base from '../layouts/Base.astro'; -import SiteHeader from '../components/SiteHeader.astro'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); ---- - - - - - - - - -
-
-
404
-

This page went cold.这一页冷掉了。

-

The page you're looking for doesn't exist — but the session is still warm.你找的页面不存在——但会话还热着。

- - -
-
- diff --git a/site/src/pages/account.astro b/site/src/pages/account.astro deleted file mode 100644 index 11fad02ee4..0000000000 --- a/site/src/pages/account.astro +++ /dev/null @@ -1,73 +0,0 @@ ---- -import Account from '../layouts/Account.astro'; ---- - -
-

Loading your account…正在加载账号…

-
- - -
diff --git a/site/src/pages/changelog/[version].astro b/site/src/pages/changelog/[version].astro deleted file mode 100644 index bd53943fb4..0000000000 --- a/site/src/pages/changelog/[version].astro +++ /dev/null @@ -1,18 +0,0 @@ ---- -import ChangelogPage from '../../components/ChangelogPage.astro'; -import { allReleases, publishedReleases, releases } from '../../data/releases'; - -export function getStaticPaths() { - const publishedVersions = new Set(publishedReleases.map((release) => release.version)); - return allReleases.map((release) => ({ - params: { version: `v${release.version}` }, - props: { release, published: publishedVersions.has(release.version) }, - })); -} - -const { release, published } = Astro.props; -if (!published) { - return Astro.redirect('/changelog/'); -} ---- - diff --git a/site/src/pages/changelog/index.astro b/site/src/pages/changelog/index.astro deleted file mode 100644 index ba21d014c2..0000000000 --- a/site/src/pages/changelog/index.astro +++ /dev/null @@ -1,10 +0,0 @@ ---- -import ChangelogPage from '../../components/ChangelogPage.astro'; -import { latestStableRelease, releases, releasePath } from '../../data/releases'; - -/* /changelog/ renders the latest release but canonicalizes to its version URL - to avoid duplicate content with /changelog/vX.Y.Z/. */ -const canonical = new URL(releasePath(latestStableRelease.version), Astro.site).href; ---- - - diff --git a/site/src/pages/changelog/preview.astro b/site/src/pages/changelog/preview.astro deleted file mode 100644 index d2f4da27ee..0000000000 --- a/site/src/pages/changelog/preview.astro +++ /dev/null @@ -1,3 +0,0 @@ ---- -return Astro.redirect('/changelog/', 301); ---- diff --git a/site/src/pages/changelog/stable.astro b/site/src/pages/changelog/stable.astro deleted file mode 100644 index d2f4da27ee..0000000000 --- a/site/src/pages/changelog/stable.astro +++ /dev/null @@ -1,3 +0,0 @@ ---- -return Astro.redirect('/changelog/', 301); ---- diff --git a/site/src/pages/community/guidelines.astro b/site/src/pages/community/guidelines.astro deleted file mode 100644 index b628f29e1b..0000000000 --- a/site/src/pages/community/guidelines.astro +++ /dev/null @@ -1,14 +0,0 @@ ---- -import Community from "../../layouts/Community.astro"; ---- - -
-
Community社区/Guidelines规范
-

Community guidelines社区规范

-

A small forum works when everyone keeps it useful and kind. A few things worth knowing.一个小论坛,靠大家保持有用与友善才能运转。几点值得先了解。

- -

Be kind & on-topic友善、切题

Assume good faith, search before asking, and keep threads focused. Format code in fenced ``` blocks.与人为善、提问前先搜索、保持话题聚焦。代码请放进 ``` 围栏块。

-

Trust levels信任等级

Everyone signs in with their Reasonix account. New accounts start limited — no links, a small daily post cap — and unlock more as they read and contribute. It keeps the forum spam-free without getting in real members' way.所有人用 Reasonix 账号登录。新账号有限制——不能发链接、每日发帖上限较低——随着阅读与贡献逐步解锁。既挡住广告,又不妨碍真实成员。

-

Moderation审核

Flag anything off — a few flags auto-hide a post for review. Moderators can restrict accounts that abuse the forum. All moderator actions are logged.发现不妥就举报——几次举报会自动隐藏帖子待审。版主可限制滥用论坛的账号。所有版主操作都有记录。

-
-
diff --git a/site/src/pages/community/index.astro b/site/src/pages/community/index.astro deleted file mode 100644 index 813af44734..0000000000 --- a/site/src/pages/community/index.astro +++ /dev/null @@ -1,58 +0,0 @@ ---- -import Community from "../../layouts/Community.astro"; ---- - -
-
-
-
-
Reasonix CommunityReasonix 社区
-

Discussions讨论区

-

Ask questions, share skills, and shape a DeepSeek-native agent — with the makers and other builders.提问、分享技能、一起打磨这个 DeepSeek 原生 Agent —— 和作者及其他构建者。

-
- ✎ New topic✎ 发起话题 -
-
-
- -
-
-

Categories分区

-
-
·

Loading…加载中…

-
- -
-
- - -
-
-
-
-
-
-
-
- - -
-
diff --git a/site/src/pages/community/new.astro b/site/src/pages/community/new.astro deleted file mode 100644 index b47f9ba341..0000000000 --- a/site/src/pages/community/new.astro +++ /dev/null @@ -1,28 +0,0 @@ ---- -import Community from "../../layouts/Community.astro"; ---- - -
-
Community/New topic发起话题
-

Start a discussion发起讨论

- - - - -
-
diff --git a/site/src/pages/community/topic.astro b/site/src/pages/community/topic.astro deleted file mode 100644 index b5818f23b5..0000000000 --- a/site/src/pages/community/topic.astro +++ /dev/null @@ -1,42 +0,0 @@ ---- -import Community from "../../layouts/Community.astro"; ---- - -
-
- Community社区/ - …/ - Loading…加载中… -
-
-

-
-

-
-
-
- -
-
-
-
-
-
- -
-
- - -
-
diff --git a/site/src/pages/device.astro b/site/src/pages/device.astro deleted file mode 100644 index b385c42748..0000000000 --- a/site/src/pages/device.astro +++ /dev/null @@ -1,34 +0,0 @@ ---- -import Account from '../layouts/Account.astro'; ---- - -
-

Checking your session…正在检查登录状态…

-
- - -
diff --git a/site/src/pages/docs.astro b/site/src/pages/docs.astro deleted file mode 100644 index 57b4ecbd04..0000000000 --- a/site/src/pages/docs.astro +++ /dev/null @@ -1,414 +0,0 @@ ---- -import Base from '../layouts/Base.astro'; -import SiteHeader from '../components/SiteHeader.astro'; - -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const repo = 'https://github.com/esengine/DeepSeek-Reasonix'; -const desktopStableFallback = `${repo}/releases/latest/download`; -const goVer = 'latest'; ---- - - - - -
- - -
-
- Reasonix docsReasonix 文档 -

Install, configure, and run coding work locally.安装、配置,并在本地运行编码任务。

-

This page is the concise website guide. It covers the normal path first, then links out to the full repo docs when you need every field or internal contract.这是官网上的精简使用说明:先讲最常用路径,再把完整字段和工程契约链接到仓库文档。

- -
- -

CLI / TUICLI / TUI

-

Install the terminal app with one command on macOS, Linux, Windows, or WSL. reasonix opens the interactive TUI; reasonix run is the headless automation entry.一条命令安装终端应用,支持 macOS、Linux、Windows 或 WSL。reasonix 打开交互式 TUI;reasonix run 用于无界面自动执行。

-
# npm (recommended · 推荐) -npm i -g reasonix - -# Homebrew -brew install esengine/reasonix/reasonix
-
-
- Use the CLI when适合用 CLI -

You live in the terminal, want fast repo work, or need scriptable reasonix run automation.你主要在终端工作、需要快速处理仓库任务,或要用 reasonix run 做自动化。

-
-
- Use the desktop app when适合用桌面端 -

You want visual sessions, settings, MCP status, checkpoints, approvals, and bot connections in one place.你希望在一个界面里管理会话、设置、MCP 状态、checkpoint、审批和 Bot 连接。

-
-
-
- Terminal-first workflow终端优先工作流 -
    -
  • Interactive TUI with Plan, Ask, Auto, YOLO, transcript scrolling, and tool approval prompts.交互式 TUI 支持 Plan、Ask、Auto、YOLO、对话滚动与工具审批提示。
  • -
  • Drag-select transcript text to copy through the verified local system clipboard; SSH uses a clearly labelled OSC 52 fallback. Run /mouse to use your terminal's native selection instead.拖选对话文本会通过可验证的本地系统剪贴板复制;SSH 使用明确标记的 OSC 52 回退。也可用 /mouse 切回终端原生选择。
  • -
  • Text paste stays terminal-native. Image paste is explicit: Ctrl+V on macOS/Linux, Alt+V on Windows, or /paste-image, with a live Pasting image… footer state.文本粘贴保持终端原生;图片粘贴使用独立入口:macOS/Linux 按 Ctrl+V,Windows 按 Alt+V,或运行 /paste-image,读取时底栏显示“正在粘贴图片…”。
  • -
  • Scriptable runs through reasonix run, including piped input and explicit model selection.可脚本化的 reasonix run,支持管道输入和显式模型选择。
  • -
-
-
!To install the legacy 0.x version, pin it explicitly with npm i -g reasonix@0.53.2. The commands above, Homebrew, and desktop/release downloads install Reasonix 1.x; the current desktop download build is {goVer}.如需安装 legacy 0.x 版本,请显式 pin: npm i -g reasonix@0.53.2。上方命令、Homebrew 与桌面端/Release 下载对应 Reasonix 1.x;当前桌面端下载构建为 {goVer}。
- -

Desktop app桌面端

-
-
- Native app · {goVer}原生桌面端 · {goVer} -

Use Reasonix with a full desktop workspace用完整桌面工作区运行 Reasonix

-

The desktop app runs the same local Reasonix engine as the CLI, with visual sessions, settings, MCP status, memory, checkpoints, tool approvals, and IM bot connections in one place.桌面端运行与 CLI 相同的本地 Reasonix 引擎,并把可视化会话、设置、MCP 状态、记忆、检查点、工具审批和 IM Bot 连接集中到一个工作区。

-
- - -
    -
  • Open and resume project sessions from a visual sidebar.从可视化侧边栏打开和恢复项目会话。
  • -
  • Approve tools, review checkpoints, and rewind code or conversation without leaving the app.在应用内审批工具、查看 checkpoint,并回退代码或对话。
  • -
  • Connect Feishu, Lark, or WeChat bots from Settings and handle remote approvals locally.在设置中连接飞书、Lark 或微信 Bot,并在本地处理远程审批。
  • -
-
-

macOS quarantine warningmacOS 隔离属性提示

-

Use this only when Reasonix was downloaded from the official site or GitHub release, moved to /Applications, and macOS still says the app cannot be opened, cannot be verified, or is damaged. This removes the quarantine flag that macOS attaches to downloaded apps.仅在 Reasonix 来自官网或 GitHub Release、已经放入 /Applications,但 macOS 仍提示“无法打开”“无法验证开发者”或“应用已损坏”时使用。它会移除 macOS 给下载应用附加的隔离属性。

-
# Quit Reasonix first, then run in Terminal. -sudo xattr -rd com.apple.quarantine /Applications/Reasonix.app
-
!Only run this for an official Reasonix app you trust. If the app is installed somewhere else, replace /Applications/Reasonix.app with that exact app path, then reopen Reasonix.只对可信的官方 Reasonix 应用执行这条命令。如果安装在其他位置,请把 /Applications/Reasonix.app 替换为实际 app 路径,然后重新打开 Reasonix。
- -

Quick start快速上手

-

First run is minimal — reasonix setup walks you through picking a provider and key, then saves it under Reasonix home. Then point Reasonix at a repo and start a session:首次运行很简单——reasonix setup 引导你选择 provider 并填写密钥,然后保存到 Reasonix home。接着指向仓库、开始会话:

-
cd your-project -reasonix
-

Then just describe the task:然后直接描述任务:

-
› add retry with backoff to the http client -› refactor the auth flow, keep the public API stable -› why is the worker leaking memory?
-

Run /init when you want project memory, then leave the session running — context is append-only, so every new turn starts from a cache hit instead of a cold start.需要项目记忆时运行 /init,然后让会话持续运行——上下文只追加,每一轮都从缓存命中开始,而不是冷启动。

- -

Web frontendWeb 前端

-

reasonix web starts the same local Reasonix engine and opens its browser UI. Inside the CLI, /web hands the current session to that UI. Keep reasonix serve for supervisors, tunnels, reverse proxies, and remote development boxes.reasonix web 会启动同一个本地 Reasonix 引擎并打开浏览器 UI;在 CLI 中执行 /web 可把当前会话交接到该界面。进程托管、tunnel、反向代理和远程开发机继续使用 reasonix serve。

-
cd your-project -reasonix web
-
- Browser UI浏览器界面 -

Chat, approvals, goals, todos, and balance聊天、审批、Goal、Todo 与余额

-
    -
  • Use chat, tool approvals, session history, rewind, fork, summarize, model switching, and reasoning-effort controls from the browser.在浏览器里使用聊天、工具审批、会话历史、rewind、fork、summarize、模型切换与 reasoning effort 控件。
  • -
  • Start or inspect Goal work, and follow the live todo panel fed by the todo_write tool.启动或查看 Goal,并跟随由 todo_write 工具驱动的实时 Todo 面板。
  • -
  • Show provider balance when configured; pass --model, --max-steps, or --resume for one-off launches.已配置 provider 时显示余额;临时启动可传 --model、--max-steps 或 --resume。
  • -
-
-

reasonix web starts at 127.0.0.1:8787, walks upward when the port is busy, and defaults to an automatically generated token. reasonix serve keeps its config-driven auth_mode = "none" default; enable auth before making Serve reachable from another machine.reasonix web 从 127.0.0.1:8787 开始监听,端口占用时自动递增,并默认生成 Token。reasonix serve 保持由配置决定的 auth_mode = "none" 默认值;如果其他机器可以访问 Serve,请先开启认证。

-
# token auth prints a share URL with #token=... -reasonix serve --auth token -reasonix serve --addr 0.0.0.0:8787 --auth token - -# password auth can use a startup password or a stored bcrypt hash -reasonix serve --auth password --password 'temporary-password' -reasonix serve --hash-password --password 'strong-password'
-
# ~/.reasonix/config.toml -[serve] -auth_mode = "password" # none|token|password -password_hash = "$2a$12$..." -behind_proxy = true # only behind a trusted reverse proxy
- -

Configuration配置

-

Reasonix talks directly to configured OpenAI-compatible providers such as DeepSeek or MiMo with your own API keys. Provider config stores only the key name in api_key_env; the actual secret saved by reasonix setup or desktop Settings lives in the global <Reasonix home>/.env.Reasonix 使用你自己的 API Key 直连配置好的 OpenAI-compatible provider,例如 DeepSeek 或 MiMo。Provider 配置只在 api_key_env 里记录密钥名称;通过 reasonix setup 或桌面端设置保存的真实密钥会写入全局 <Reasonix home>/.env。

-
reasonix setup -# saves provider keys to <Reasonix home>/.env, for example: -DEEPSEEK_API_KEY=sk-...
-

Project .env files are not provider-key fallbacks. They are only used for workspace-scoped variable expansion in MCP/plugin settings. Persistent options live in the config file.项目 .env 不是 provider key 的 fallback。它只用于 MCP/plugin 配置里的工作区级变量展开。持久化选项见配置文件。

-
-
Global secret file全局密钥文件<Reasonix home>/.env
-
Project config项目配置./reasonix.toml
-
User config用户配置~/.reasonix/config.toml
-
- -

Prefix cache前缀缓存

-

DeepSeek bills cached prefix tokens at a fraction of fresh computation. Most agents waste this: they reorder messages, rewrite summaries mid-session, or inject volatile timestamps — every change invalidates the cache from that point on.DeepSeek 对缓存前缀 token 的计费远低于新计算。多数智能体浪费了这一点:重排消息、会话中改写摘要、注入易变的时间戳——任何改动都会让其后的缓存全部失效。

-

Reasonix serializes context deterministically and only ever appends. The practical effect: hours-long sessions where 90%+ of every request replays from cache, and input-token cost collapses to ~1/5.Reasonix 以确定性方式序列化上下文,并且永远只追加。实际效果:数小时的会话中每次请求 90% 以上从缓存重放,输入 token 成本降到约 1/5。

-

Automatic compaction starts at 80% of the model context by default. Desktop Settings and reasonix config compact-ratio share the user-level value; choose 65–85%, or use --local for a project override. Lower values compact earlier and can reduce prefix-cache reuse.自动压缩默认在模型上下文达到 80% 时启动。桌面端设置与 reasonix config compact-ratio 共用用户级设置;可在 65–85% 之间选择,也可用 --local 添加项目覆盖。阈值越低越早压缩,也可能降低前缀缓存复用率。

- -

Permissions & sandbox权限与沙箱

-

Permissions gate each tool call: deny > ask > allow > fallback. Read-only tools generally pass; writers fall back to [permissions] mode. Ask is not read-only: an approved writer can still run. The sandbox is the enforced capability boundary. Headless reasonix run defaults to Ask and fails closed when a writer needs approval; use -y, --auto, or --permission-mode auto for intentional unattended writes. [permissions] allow_dynamic_bash = true is an advanced opt-in that lets an Allow fallback cover nested or indirect Bash. Explicit ask and deny rules still apply.权限逐个把关工具调用:deny > ask > allow > 兜底。只读工具通常放行;写工具回退到 [permissions] mode。Ask 不是只读:writer 获得批准后仍会执行;沙箱才是强制能力边界。无界面的 reasonix run 默认使用 Ask,写操作需要审批时会安全拒绝;要显式启用无人值守写入,请使用 -y、--auto 或 --permission-mode auto。高级用户可设置 [permissions] allow_dynamic_bash = true,让 Allow fallback 覆盖嵌套或间接 Bash。显式 ask 与 deny 规则仍然生效。

-

The sandbox is enforcement: file-writers refuse any path outside [sandbox] workspace_root (default: the current dir), resolving symlinks and .. so a link cannot tunnel out. bash = "enforce" jails shell commands when an OS sandbox backend is available (Seatbelt on macOS, bubblewrap on Linux); without one, bash is refused instead of running unconfined. Install the backend or set bash = "off" to explicitly restore the pre-1.16 unconfined behavior.沙箱负责强制执行:写文件工具拒绝 [sandbox] workspace_root(默认当前目录)之外的任何路径,并解析符号链接与 ..,防止借链接逃逸。bash = "enforce" 会在存在 OS 沙箱后端时隔离 shell 命令(macOS Seatbelt、Linux bubblewrap);没有后端时会拒绝执行 bash,而不是非隔离运行。安装对应后端,或显式设置 bash = "off" 来恢复 1.16 之前的非隔离行为。

- -

Extensions & sidecars扩展与 Sidecar

-

Plugin packages have two layers. Declarative contributions ship skills, agents, commands, prompts, hooks, MCP servers, and themes. A Manifest v2 runtime adds an out-of-process Sidecar speaking the stable Extension Protocol v1; it can intercept runtime events, own replacement strategies, contribute streaming model Providers, and publish structured UI. Native Manifest v2 is an explicit capability boundary: Reasonix loads only resources declared in reasonix-plugin.json and does not implicitly import host-specific companion files such as a root CLAUDE.md or .mcp.json. Codex and Claude compatibility manifests keep their own mappings; Claude manifests do not load a plugin-root CLAUDE.md as project context.插件包分为两层:声明式贡献可以分发 skills、agents、commands、prompts、hooks、MCP server 与主题;Manifest v2 的 runtime 则启动独立 Sidecar,通过稳定的 Extension Protocol v1 拦截运行时事件、持有替换策略、提供流式模型 Provider,并发布结构化 UI。原生 Manifest v2 是显式能力边界:Reasonix 只加载 reasonix-plugin.json 中声明的资源,不会隐式导入根 CLAUDE.md、.mcp.json 等宿主专用伴随文件。Codex 与 Claude 兼容 manifest 继续采用各自映射;Claude manifest 不会把插件根 CLAUDE.md 当作项目上下文。

-
-
- MCP or Extension Protocol?MCP 还是 Extension Protocol? -

Use MCP for portable tools, prompts, and resources. Use a code extension when the feature must participate in the Agent lifecycle, replace host behavior, provide models, or render native surfaces.可移植的工具、提示词与资源优先使用 MCP;需要进入 Agent 生命周期、替换宿主行为、提供模型或原生界面时,才使用代码型扩展。

-
-
- Stable and cache-aware稳定且缓存友好 -

Each turn pins one runtime generation. Sidecars initialize with four-way concurrency inside one shared 30-second startup budget. No-op reloads keep the prompt prefix byte-identical; stable replacements remain cacheable, while per-turn timestamps or random values in prompts and schemas destroy reuse.每个回合固定使用一个 runtime generation;Sidecar 最多 4 路并行初始化,并共享 30 秒总启动预算。空操作重载保持提示词前缀字节不变;稳定替换仍可缓存,把时间戳或随机值逐回合写入提示词与 Schema 则会破坏复用。

-
-
-

The repository includes a complete starter with its manifest, Go Sidecar, build commands, linked installation, reload loop, and visible input rewrite:仓库提供了完整 starter,包含 Manifest、Go Sidecar、构建命令、链接安装、重载循环与可观察的输入改写:

-
git clone https://github.com/esengine/DeepSeek-Reasonix.git -cd DeepSeek-Reasonix/sdk/go/examples/starterextension -go build -o bin/starter-extension.exe . -plugin_root="$(pwd -P)" -reasonix plugin install "$plugin_root" --dry-run -reasonix plugin install "$plugin_root" --link --replace --yes -# Start a session, or reload while idle -/reload
-

On Windows PowerShell, set $pluginRoot = (Resolve-Path .).Path and pass $pluginRoot to both install commands. Then send starter: explain sidecars to verify the intercept. The first public Go SDK release is sdk/go/v1.0.0; before that immutable tag exists, use the starter from a source checkout.Windows PowerShell 请先设置 $pluginRoot = (Resolve-Path .).Path,再把 $pluginRoot 传给两条安装命令。随后发送 starter: 解释 Sidecar 验证拦截。Go SDK 的首个公开版本是 sdk/go/v1.0.0;该不可变标签发布前,请直接从源码 checkout 使用 starter。

-
!Full trust: a code Sidecar runs outside the Reasonix sandbox with the inherited environment and can override permission decisions. Dry-run the install, review the runtime command and declared capabilities, and install only code you trust completely.完全信任:代码型 Sidecar 运行在 Reasonix Sandbox 之外,继承宿主环境并可覆盖权限决定。请先 dry-run,检查 Runtime 命令与声明能力,只安装完全信任的代码。
-

Continue with the extension guide, Manifest v2 reference, Go SDK, and wire protocol.后续请阅读扩展指南、Manifest v2 参考、Go SDK和线协议。

- -

Plugins (MCP)插件(MCP)

-

Reasonix is an MCP client. A [[plugins]] entry's type selects the transport: stdio launches a local subprocess, while http connects to a Streamable HTTP server with optional headers expanded from the environment. Tools surface to the model as mcp__<server>__<tool>.Reasonix 是一个 MCP 客户端。[[plugins]] 条目的 type 选择传输方式:stdio 启动本地子进程;http 连接 Streamable HTTP server,可从环境变量展开静态 headers。工具以 mcp__<server>__<tool> 呈现给模型。

-
# reasonix.toml -[[plugins]] # local stdio server -name = "example" -command = "reasonix-plugin-example" - -[[plugins]] # remote server over Streamable HTTP -name = "stripe" -type = "http" -url = "https://mcp.stripe.com" -headers = { Authorization = "Bearer ${STRIPE_KEY}" }
-

Installing an MCP server is the authorization decision, so its tools are directly usable without server-level, per-tool, writer, or destructive approval settings. Repository-declared servers require one exact identity confirmation before startup and ask again only when that identity changes. Explicit global deny rules still win. readOnlyHint and destructiveHint remain internal facts for parallel dispatch, Plan restrictions, strict read-only children, and cached-to-live safety reclassification; schema-only changes refresh the next-session cache without interrupting an authorized call. Plan hard-blocks MCP writer/destructive targets and unauthorized readers; read_only_task / read_only_skill never expose writers.安装 MCP server 本身就是授权决定,安装后工具直接可用,不再需要 server、逐工具、writer 或 destructive 审批设置。仓库声明的 server 只在启动前确认一次精确身份,身份变化时才重新确认;显式全局 deny 仍然优先。readOnlyHint 与 destructiveHint 只作为并行调度、Plan 限制、严格只读子会话和缓存到实时安全分类复核的内部事实;仅 schema 变化会刷新下一会话缓存,不再中断已授权调用。Plan 会硬阻断 MCP writer/destructive 目标和未授权 reader;read_only_task / read_only_skill 完全不暴露 writer。

-

MCP prompts also become slash commands such as /mcp__server__prompt, and MCP resources can be referenced with @server:uri. Enabled servers connect in the background after a session starts; use /mcp or the desktop MCP panel to inspect, refresh, reconnect, or disable servers. Already have an .mcp.json? Put it in the project root; Reasonix reads the Claude Code mcpServers schema as-is and lets reasonix.toml win on name collisions.MCP prompts 也会变成 /mcp__server__prompt 这样的斜杠命令,MCP resources 可通过 @server:uri 引用。启用的 server 会在会话开始后后台连接;用 /mcp 或桌面端 MCP 面板查看、刷新、重连或临时禁用。已有 .mcp.json?放到项目根目录即可;Reasonix 会原样读取 Claude Code 的 mcpServers schema,同名时 reasonix.toml 优先。

- -

Editor integration (ACP)编辑器接入(ACP)

-

Reasonix implements Agent Client Protocol (ACP) v1 as an NDJSON JSON-RPC 2.0 agent over stdio. An ACP-compatible editor or host starts reasonix acp, opens workspace-scoped sessions, and receives streamed messages, tool activity, plans, permission requests, and configuration updates.Reasonix 实现了 Agent Client Protocol(ACP)v1,通过 stdio 提供 NDJSON JSON-RPC 2.0 agent。兼容 ACP 的编辑器或 host 启动 reasonix acp、打开工作区会话,并接收流式消息、工具活动、计划、权限请求和配置更新。

-
reasonix acp # use the configured default model -reasonix acp --model <name> # choose the startup model -reasonix acp --profile delivery # economy | balanced | delivery
-
-
- Independent sessions独立会话 -

Each session owns its workspace, history, model, reasoning effort, execution setting, collaboration mode, approval posture, and host-supplied MCP servers.每个会话独立持有工作区、历史、模型、推理强度、执行设定、协作模式、审批策略和 host 提供的 MCP server。

-
-
- Editor-owned capabilities编辑器持有的能力 -

When advertised by the client, file operations use unsaved editor buffers and foreground commands run in a client-owned terminal.客户端声明相关能力后,文件操作会经过编辑器未保存的 buffer,前台命令则在客户端持有的 terminal 中运行。

-
-
-

Reasonix also advertises the vendor method _reasonix.io/session/steer through agentCapabilities._meta. A host may call it while session/prompt is active to queue user guidance for the next safe model boundary without cancelling the turn. Clients must discover the method first and treat InvalidRequest as not queued.Reasonix 还会通过 agentCapabilities._meta 声明厂商方法 _reasonix.io/session/steer。Host 可在 session/prompt 活动期间调用它,把用户引导排入下一个安全模型边界,而无需取消当前回合。客户端必须先发现该方法,并把 InvalidRequest 视为“未入队”。

-
iACP steering is a namespaced ACP v1 extension, not a core session/steer method and not the unreleased ACP v2 session/inject proposal. See the complete ACP integration guide for lifecycle methods, capability negotiation, MCP transport shapes, compatibility, errors, and a client checklist.ACP 回合中引导是带命名空间的 ACP v1 扩展,不是核心 session/steer 方法,也不是尚未发布的 ACP v2 session/inject 提案。生命周期方法、能力协商、MCP transport 结构、兼容性、错误处理和客户端检查清单见完整 ACP 接入文档。
- -

Memory & rewind记忆与回退

-

Reasonix keeps project memory in REASONIX.md or AGENTS.md, and stores approved auto-memory facts under Reasonix home. During turns, read-only history and memory tools retrieve prior sessions, compacted archives, and saved facts on demand instead of injecting noisy dynamic state into the stable prompt prefix.Reasonix 将项目记忆放在 REASONIX.md 或 AGENTS.md,并把经过批准的 auto-memory fact 存在 Reasonix home 下。运行时,只读 history 与 memory 工具按需检索历史会话、压缩归档和已保存事实,而不是把易变状态塞进稳定 prompt 前缀。

-

Agent-initiated remember and forget always ask for fresh approval, even in YOLO. /memory shows active and archived facts; /forget archives rather than permanently erasing a fact from traceability.模型主动调用 remember 与 forget 时,即使在 YOLO 下也会重新请求批准。/memory 可查看 active 与 archived facts;/forget 会归档而不是永久抹掉可追溯记录。

-

Rewind is snapshot-based, not git-based. Press double Esc in the CLI, use /rewind, or use the desktop hover control to restore code, conversation, or both from an earlier turn without touching .git.回退基于文件快照,不是 git。CLI 中双击 Esc、使用 /rewind,或在桌面端用户消息上使用 hover 控件,即可从较早 turn 恢复代码、对话或两者,不会触碰 .git。

- -

CLI & slash commands命令行与斜杠命令

-
reasonix setup # first-run: pick provider + keys -reasonix # interactive session, prompts before writes -reasonix run "<task>" # headless Ask; writers fail closed -reasonix run -y "<task>" # opt into unattended ordinary writes -reasonix web # open the local browser UI -reasonix serve # supervised or remote HTTP+SSE frontend -reasonix bot doctor # check saved IM bot connections
-
reasonix config compact-ratio # effective value + source -reasonix config compact-ratio 75 # user-global default -reasonix config compact-ratio --local 75 # project override
-

Run reasonix upgrade to install the latest official release. Legacy channel arguments and saved channel settings remain accepted during the 1.x compatibility period, but they resolve to the same official release and are removed when configuration is saved.运行 reasonix upgrade 安装最新正式版。1.x 兼容期内仍接受旧渠道参数与已保存设置,但它们都会解析为同一正式版,并在下次保存配置时移除。

-
reasonix upgrade -reasonix upgrade
-

Inside a session, slash commands run locally — /help lists them all:会话中,斜杠命令在本地运行——/help 列出全部:

-
/compact /new /clear /rewind /tree -/branch /switch /todo /model /mouse /mcp -/skills /hooks /memory /sandbox /docs -/language /theme /work-mode /paste-image /goal -/reasoning-language /output-style /help
-

Shift+Tab cycles Ask → Auto → Plan, while Ctrl+Y toggles YOLO independently. Use /theme auto|light|dark for the terminal background mode or choose a named accent from bare /theme. Long drafts grow and then scroll inside the composer; wheel events over the transcript continue to scroll the conversation.Shift+Tab 按 Ask → Auto → Plan 循环,Ctrl+Y 独立切换 YOLO。用 /theme auto|light|dark 选择终端背景模式,也可从不带参数的 /theme 中选择命名强调色。长草稿会先增长,超过上限后在输入框内滚动;鼠标位于 transcript 时仍滚动对话。

-

The responsive footer shows the active permission posture and interaction state first. Wide terminals keep model, effort, and execution setting together on the right, with available Git, cache, context, compaction, job, and balance telemetry below. ready means the composer is idle; pickers, approvals, image paste, shell mode, and other interactions replace it. Narrow terminals move or compact complete groups, and visible labels follow /language.响应式底栏优先显示当前权限姿态和交互状态;终端较宽时,模型、推理强度和执行设定在右侧成组显示,下方按可用性显示 Git、缓存、上下文、压缩余量、任务和余额。“就绪”表示输入框空闲;选择器、审批、图片粘贴、shell 模式等活动会替换它。窄终端会移动或压缩完整信息组,可见标签跟随 /language。

-

Mouse capture is on by default so Reasonix can handle transcript selection, wheel scroll, and the scrollbar. Turn it off with /mouse, or start with REASONIX_DISABLE_MOUSE=1, when you prefer the terminal's own selection behavior.默认会开启鼠标接管,用于对话选中、滚轮滚动和滚动条。需要终端自己的选中行为时,用 /mouse 关闭;也可以用 REASONIX_DISABLE_MOUSE=1 默认关闭。

-

In a local session, releasing an in-app text selection copies through the native system clipboard and shows success only after the write completes. SSH falls back to a clearly labelled OSC 52 request. Text paste remains your terminal's bracketed-paste shortcut, such as Cmd+V on macOS. Image paste is separate: use Ctrl+V on macOS/Linux, Alt+V on Windows, or /paste-image; the footer shows Pasting image… while the attachment is prepared.本地会话中,应用内文本选区会写入系统剪贴板,只有写入完成后才提示成功;SSH 会回退到明确标记的 OSC 52 请求。文本继续使用终端原生 bracketed-paste 快捷键,例如 macOS 的 Cmd+V。图片粘贴使用独立入口:macOS/Linux 按 Ctrl+V,Windows 按 Alt+V,或运行 /paste-image;附件准备期间底栏显示“正在粘贴图片…”。

-

/branch [name] forks the current conversation tip, /switch <id|name> loads another branch, and /clear confirms before discarding unsaved context. Custom commands are Markdown files under .reasonix/commands/ or ~/.reasonix/commands/./branch [name] 从当前会话尖端分叉,/switch <id|name> 加载另一条分支,/clear 会确认后丢弃未保存上下文。自定义命令是 .reasonix/commands/ 或 ~/.reasonix/commands/ 下的 Markdown 文件。

-

/goal is for long-running objectives. Ordinary chat never changes mode automatically. Goal selects a simple (10), write (20), or research (40) turn budget and pauses after four turns without host-verifiable progress. /goal status shows the runtime, /goal pause suspends, and /goal resume continues. Every class uses the same Goal state machine, structured update_goal reports, host receipts, Delivery readiness, and bounded evaluator. Legacy research archives are read-only and new Goals never create them./goal 用于长目标。普通聊天不会自动切换模式。Goal 自动选择简单(10)、写入(20)或研究(40)轮预算,连续 4 轮无宿主可验证进展会暂停。/goal status 显示运行摘要,/goal pause 暂停,/goal resume 继续。所有预算类别共用同一个 Goal 状态机、结构化 update_goal、宿主 receipt、Delivery readiness 与有界 evaluator。旧研究归档保持只读,新 Goal 不再创建这些目录。

-

Use @path to inject files or directories, and @server:uri for MCP resources. Plan Mode is an explicit user choice: select it in the desktop collaboration control or cycle to it with Shift+Tab in the CLI. reasonix config reasoning-language auto|zh|en updates the user default from scripts; --local remains available for settings that support project-local overrides.用 @path 注入文件或目录,用 @server:uri 引入 MCP resource。计划模式始终由用户显式选择:桌面端在协作方式中选择,CLI 用 Shift+Tab 切换。脚本中可用 reasonix config reasoning-language auto|zh|en 更新用户级默认值;--local 仍可用于支持项目级覆盖的设置。

- -

Built-in documentation search内置文档检索

-

Every CLI and Desktop release bundles the reviewed Markdown guides and release-note catalog from that exact source revision. Search is local and offline, and every result identifies the product version, source revision, and corpus digest. Release CI rejects a build when its embedded corpus does not match the release candidate, so an installed version keeps version-matched guidance instead of silently switching to newer website content.每个 CLI 与桌面端版本都会内置该源码 revision 对应的、经过审查的 Markdown 指南和更新日志目录。检索完全在本地离线完成,每条结果都会标明产品版本、源码 revision 与语料 digest。发布 CI 会拒绝内置语料与候选版本不匹配的构建,因此已安装版本始终使用与自身版本匹配的说明,不会静默切换到更新的官网内容。

-
/docs # corpus version, revision, digest, and examples -/docs 1.19.5 changelog # search locally, then answer with the configured AI -/docs 1.19.5 更新日志 # 中文问题会优先返回中文证据
-

Bare /docs only displays local corpus information and does not call a model. With a question, Reasonix retrieves version-matched evidence first, then asks the AI configured for the current session to produce a sourced answer. Ordinary natural-language questions can also trigger the read-only docs tool automatically, but the slash command guarantees retrieval before the answer instead of relying on the model to choose the tool.直接输入 /docs 只显示本地语料信息,不调用模型。带问题时,Reasonix 会先检索与版本匹配的证据,再交给当前会话配置的 AI 生成带来源的回答。普通自然语言问题也可能自动触发只读 docs 工具;斜杠命令则保证先检索再回答,不依赖模型自行决定是否调用工具。

-
iCustom commands and compatible plugin or skill aliases keep ownership of /docs. If it is already taken, choose the built-in entry shown in the slash menu—normally /reasonix:docs, or the next free reasonix:-qualified name. Reasonix never overwrites the existing command. CLI and Desktop use the same rule; a remote Desktop displays the command catalog resolved by its host.自定义命令以及兼容插件或 Skill 别名会继续拥有 /docs。如果该名称已被占用,请使用斜杠菜单中显示的内置入口——通常是 /reasonix:docs,或下一个空闲的 reasonix: 限定名。Reasonix 不会覆盖已有命令。CLI 与桌面端遵循同一规则;远程桌面端显示由主机解析后的命令目录。
-

For the complete retrieval contract, corpus filters, tool schema, and maintainer release checks, see the full guide and tool contract.完整检索约定、语料筛选、工具 schema 与维护者发版检查见完整指南和工具契约。

- -

Config file配置文件

-

Resolution order: flags > ./reasonix.toml > global config.toml under Reasonix home > compatible legacy config > built-in defaults. Starting with v1.8.1, Reasonix home is ~/.reasonix on macOS/Linux and %APPDATA%\reasonix on Windows; set REASONIX_HOME only for tests, CI, or portable installs.解析顺序:flags > ./reasonix.toml > Reasonix home 下的全局 config.toml > 兼容 legacy config > 内置默认值。从 v1.8.1 起,Reasonix home 在 macOS/Linux 为 ~/.reasonix,Windows 为 %APPDATA%\reasonix;只有测试、CI 或便携安装才需要设置 REASONIX_HOME。

-
# ~/.reasonix/config.toml (macOS/Linux) -default_model = "deepseek-flash" - -[ui] -shortcut_layout = "desktop" # optional compatibility setting - -[agent] -reasoning_language = "auto" # auto|zh|en -compact_ratio = 0.8 # editable as 65–85% in Settings or CLI -planner_model = "deepseek-pro" # optional read-only planner - -[[providers]] -name = "deepseek-flash" -kind = "openai" -base_url = "https://api.deepseek.com" -model = "deepseek-v4-flash" -api_key_env = "DEEPSEEK_API_KEY" - -[tools] -enabled = [] # empty = all built-ins -bash_timeout_seconds = 120 -mcp_call_timeout_seconds = 300 - -[permissions] -mode = "ask" # ask|allow|deny -deny = ["Bash(rm -rf*)", "Bash(git push*)"] -allow = ["Bash(go test:*)"] - -[sandbox] -workspace_root = "" # empty = current dir -allow_write = ["/tmp"] -forbid_read = ["${HOME}/.ssh"] - -[serve] -auth_mode = "none" # none|token|password -behind_proxy = false # true only behind trusted proxy - -[[plugins]] -name = "example" -command = "reasonix-plugin-example" -call_timeout_seconds = 600
-

Legacy config, credentials, memory, and sessions are migrated non-destructively when v1.8.1+ starts. If Reasonix was opened before old paths were available, run /migrate from the CLI TUI or desktop composer. For the full schema and every field's contract, see SPEC.md §5.v1.8.1+ 启动时会非破坏性迁移 legacy config、credentials、memory 与 sessions。如果旧路径尚不可用时已经打开过 Reasonix,可在 CLI TUI 或桌面端 composer 中运行 /migrate。完整 schema 与每个字段的契约见 SPEC.md §5。

- -

Desktop & bots桌面端与 Bot

-

The desktop app shares the same config, global provider-key file, controller, permissions, sandbox, MCP lifecycle, memory, and checkpoint model as the CLI. Desktop-only settings such as shortcuts and bot connections are stored under Reasonix home.桌面端与 CLI 共用同一套 config、全局 provider 密钥文件、controller、权限、沙箱、MCP 生命周期、记忆与 checkpoint 模型。快捷键、Bot 连接等桌面端设置存储在 Reasonix home 下。

-

From Settings -> Bots, connect Feishu, Lark, or WeChat, then send Reasonix messages from IM. The local desktop runtime handles model calls, tools, approvals, and sandboxing, while IM receives progress, approval cards or text commands, and final results. Headless gateways can be started with reasonix bot start --channels feishu,lark,weixin --dir /path/to/project.在 Settings -> Bots 中连接飞书、Lark 或微信后,即可从 IM 给 Reasonix 发消息。本地桌面运行时负责模型调用、工具、审批和沙箱,IM 侧接收进度、审批卡片或文本命令以及最终结果。也可以用 reasonix bot start --channels feishu,lark,weixin --dir /path/to/project 启动 headless gateway。

- -
- -

One engine, four surfaces →一个引擎,四个入口 →

-

Terminal, desktop app, browser, and ACP editors share this config.终端、桌面端、浏览器与 ACP 编辑器共用这套配置。

-
- -

Configuration paths →配置路径 →

-

Reasonix home, credentials, sessions, archives, memory, and migration rescue.Reasonix home、凭据、会话、归档、记忆与迁移救援。

-
- -

Reasoning language →思考语言 →

-

Visible thinking language preference without changing the stable prompt prefix.可见思考语言偏好,不改变稳定 prompt 前缀。

-
- -

Checkpoints & rewind →检查点与回退 →

-

Restore code, conversation, or both from snapshot-based checkpoints.通过快照式 checkpoint 恢复代码、对话或两者。

-
- -

Capability diagnostics →能力诊断 →

-

reasonix doctor capabilities, desktop Diagnostics, and /reasonix-guide.reasonix doctor capabilities、桌面端诊断与 /reasonix-guide。

-
- -

Build an extension →开发扩展 →

-

Start with a complete Sidecar, Manifest v2, Go SDK, reload loop, and security model.从完整 Sidecar、Manifest v2、Go SDK、重载循环与安全模型开始。

-
- -

Bot guide →Bot 指南 →

-

Connect Feishu, Lark, and WeChat bots, then approve work from IM.连接飞书、Lark 与微信 Bot,并从 IM 中审批任务。

-
- -

Contribute →参与贡献 →

-

Reasonix is MIT-licensed and open source — good first issues are waiting.Reasonix 采用 MIT 许可、开源——新手友好任务等着你。

-
-
-
-
- - - diff --git a/site/src/pages/forgot.astro b/site/src/pages/forgot.astro deleted file mode 100644 index 9fc219faa5..0000000000 --- a/site/src/pages/forgot.astro +++ /dev/null @@ -1,28 +0,0 @@ ---- -import Account from '../layouts/Account.astro'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); ---- - -
-

Reset your password找回密码

-

We'll email you a link to set a new one.我们会给你发一封重置链接邮件。

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

- Back to sign in返回登录 -

-
diff --git a/site/src/pages/index.astro b/site/src/pages/index.astro deleted file mode 100644 index d63ce5b6da..0000000000 --- a/site/src/pages/index.astro +++ /dev/null @@ -1,494 +0,0 @@ ---- -import Base from '../layouts/Base.astro'; -import SiteHeader from '../components/SiteHeader.astro'; -import community from '../data/community.json'; - -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const repo = 'https://github.com/esengine/DeepSeek-Reasonix'; -const repoReleases = `${repo}/releases`; -const desktopStableFallback = repoReleases; -const vscodeMarketplace = 'https://marketplace.visualstudio.com/items?itemName=SivanLiu.reasonix-agent'; -const openVsx = 'https://open-vsx.org/extension/SivanLiu/reasonix-agent'; -const vscodeExtensionRepo = 'https://github.com/SivanCola/reasonix-vscode'; - -const goVer = 'latest'; - -const fmtN = (n) => Number(n).toLocaleString('en-US'); -const avClass = (i) => 'av' + (i % 5 === 2 ? ' sm' : i % 7 === 3 ? ' lg' : ''); -const half = Math.ceil(community.list.length / 2); -const rowA = community.list.slice(0, half); -const rowB = community.list.slice(half); - -const desc = "Open-source AI coding agent you can leave running. One local engine, four ways in — terminal, desktop app, browser, or your editor over ACP. Plan mode, permissions, a workspace sandbox and checkpoints keep long autonomous runs reviewable. A single Go binary, no runtime to install. MIT."; -const ld = { - '@context': 'https://schema.org', - '@type': 'SoftwareApplication', - name: 'Reasonix', - description: desc, - url: 'https://reasonix.io/', - applicationCategory: 'DeveloperApplication', - operatingSystem: 'macOS, Windows, Linux', - license: `${repo}/blob/main-v2/LICENSE`, - downloadUrl: `${repo}/releases`, - offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, -}; ---- - - - - diff --git a/site/src/pages/login.astro b/site/src/pages/login.astro deleted file mode 100644 index c5e5a10cfb..0000000000 --- a/site/src/pages/login.astro +++ /dev/null @@ -1,36 +0,0 @@ ---- -import Account from '../layouts/Account.astro'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); ---- - -
-

Welcome back欢迎回来

-

Sign in to your Reasonix account.登录你的 Reasonix 账号。

-
- - - -
-
- - -
-
-
- - Forgot?忘记密码? -
- -
- -
- -

- New to Reasonix? Create an account - 还没有账号?注册一个 -

-
diff --git a/site/src/pages/register.astro b/site/src/pages/register.astro deleted file mode 100644 index c731f6f113..0000000000 --- a/site/src/pages/register.astro +++ /dev/null @@ -1,38 +0,0 @@ ---- -import Account from '../layouts/Account.astro'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); ---- - -
-

Create your account创建账号

-

Join the Reasonix community.加入 Reasonix 社区。

-
- - - -
-
- - -
-
- - -
-
- - - At least 8 characters.至少 8 个字符。 -
- -
- -

- Already have an account? Sign in - 已有账号?登录 -

-
diff --git a/site/src/pages/reset.astro b/site/src/pages/reset.astro deleted file mode 100644 index 54030c3d80..0000000000 --- a/site/src/pages/reset.astro +++ /dev/null @@ -1,33 +0,0 @@ ---- -import Account from '../layouts/Account.astro'; -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); ---- - -
-

Set a new password设置新密码

-

Choose a password you haven't used before.请设置一个新密码。

-
- - - -
-
- - - At least 8 characters.至少 8 个字符。 -
-
- - -
- -
- -

- Back to sign in返回登录 -

-
diff --git a/site/src/pages/skills.astro b/site/src/pages/skills.astro deleted file mode 100644 index 77b2b8a097..0000000000 --- a/site/src/pages/skills.astro +++ /dev/null @@ -1,563 +0,0 @@ ---- -import Base from '../layouts/Base.astro'; -import SiteHeader from '../components/SiteHeader.astro'; - -const base = import.meta.env.BASE_URL.replace(/\/$/, ''); -const repo = 'https://github.com/esengine/DeepSeek-Reasonix'; -const desc = "Browse, publish, and install community skills, plugins, and MCP servers for Reasonix. One command to add any capability to your agent — install_source does the rest, SSRF-guarded and risk-rated."; ---- - - - - -
-
-
-
- Registry技能市场 -

Every skill, one install away.每个能力,一条 install 就到手。

-

Community skills, plugins, and MCP servers for your agent. The registry only stores metadata and a source pointer — installs run client-side through install_source, SSRF-guarded and risk-rated. Nothing executes here.社区贡献的技能、插件与 MCP 服务器。市场只存元数据与来源指针——安装在你本机经 install_source 执行(带 SSRF 防护与风险分级),这里不运行任何代码。

-
- -
- -
- - - - -
-
- - - -
- - Publish发布 - -
-
-
- -
-
-
-
-
-
- - -
- - -
-
- - - - -
- - - - - - - diff --git a/site/src/pages/u/index.astro b/site/src/pages/u/index.astro deleted file mode 100644 index 2d828850d1..0000000000 --- a/site/src/pages/u/index.astro +++ /dev/null @@ -1,23 +0,0 @@ ---- -import Account from '../../layouts/Account.astro'; ---- - -
Loading profile…
- - -
diff --git a/site/src/scripts/account-community-contract.test.mjs b/site/src/scripts/account-community-contract.test.mjs deleted file mode 100644 index 088f54a657..0000000000 --- a/site/src/scripts/account-community-contract.test.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import assert from "node:assert/strict"; -import { readFileSync } from "node:fs"; -import test from "node:test"; - -const auth = readFileSync(new URL("./auth.js", import.meta.url), "utf8"); -const community = readFileSync(new URL("./community.js", import.meta.url), "utf8"); -const account = readFileSync(new URL("../pages/account.astro", import.meta.url), "utf8"); -const profile = readFileSync(new URL("../pages/u/index.astro", import.meta.url), "utf8"); - -test("unverified accounts can request a fresh verification email", () => { - assert.match(account, /resend-verification-btn/); - assert.match(auth, /\/auth\/resend-verification/); -}); - -test("public profiles have a generated site route backed by the public account API", () => { - assert.match(profile, /public-profile/); - assert.match(auth, /api\("\/u\/" \+ encodeURIComponent\(handle\)\)/); -}); - -test("community renders public handles and wires reactions", () => { - assert.doesNotMatch(community, /split\(["']@["']\)/); - assert.match(community, /\/posts\/\$\{like\.dataset\.like\}\/likes/); - assert.match(community, /aria-pressed/); -}); diff --git a/site/src/scripts/auth.js b/site/src/scripts/auth.js deleted file mode 100644 index 50d8fa14d7..0000000000 --- a/site/src/scripts/auth.js +++ /dev/null @@ -1,353 +0,0 @@ -import { safeNext } from "./safe-next.js"; - -// Client for the reasonix-accounts API (id.reasonix.io). Cookie-based session, -// so every call sends credentials; the API base is build-time configurable. -const API = (import.meta.env.PUBLIC_ACCOUNTS_API || "https://id.reasonix.io").replace(/\/$/, ""); - -async function api(path, { method = "GET", body } = {}) { - const res = await fetch(API + path, { - method, - credentials: "include", - headers: body ? { "content-type": "application/json" } : undefined, - body: body ? JSON.stringify(body) : undefined, - }); - let data = null; - try { data = await res.json(); } catch {} - if (!res.ok) { - const err = new Error(data?.error?.message || "Something went wrong. Please try again."); - err.code = data?.error?.code; - err.status = res.status; - throw err; - } - return data; -} - -// Reusable helpers for account-aware pages (nav state, gated actions). Importing -// this module also runs the form auto-wiring below, but each block is guarded by -// element presence, so pages without auth forms just get these two helpers. -export async function currentAccount() { - try { return (await api("/me")).user; } catch { return null; } -} -export async function accountLogout() { - try { await api("/auth/logout", { method: "POST" }); } catch {} -} - -const $ = (id) => document.getElementById(id); -const qp = new URLSearchParams(location.search); -const withBase = (p) => (import.meta.env.BASE_URL.replace(/\/$/, "") + p) || p; - -function msg(el, kind, text) { - if (!el) return; - el.className = "auth-msg " + kind; - el.textContent = text; - el.hidden = false; -} -function clearMsg(el) { if (el) el.hidden = true; } - -function busy(btn, on) { - if (!btn) return; - btn.disabled = on; - btn.classList.toggle("loading", on); -} - -// login — POST /auth/login, then continue to ?next or /account. -const loginForm = $("login-form"); -if (loginForm) { - const box = $("login-msg"); - const verified = qp.get("verified"); - if (verified === "1") msg(box, "ok", "Email confirmed. Sign in to continue."); - else if (verified === "0") msg(box, "error", "That confirmation link was invalid or has expired."); - loginForm.addEventListener("submit", async (e) => { - e.preventDefault(); - clearMsg(box); - const btn = loginForm.querySelector("button[type=submit]"); - busy(btn, true); - try { - await api("/auth/login", { method: "POST", body: { email: $("email").value.trim(), password: $("password").value } }); - location.href = safeNext(qp.get("next"), location.origin) || withBase("/account/"); - } catch (err) { - msg(box, "error", err.message); - busy(btn, false); - } - }); -} - -// register — enumeration-safe: the API returns the same message either way. -const registerForm = $("register-form"); -if (registerForm) { - const box = $("register-msg"); - registerForm.addEventListener("submit", async (e) => { - e.preventDefault(); - clearMsg(box); - const btn = registerForm.querySelector("button[type=submit]"); - busy(btn, true); - try { - const out = await api("/auth/register", { - method: "POST", - body: { - email: $("email").value.trim(), - password: $("password").value, - displayName: $("displayName").value.trim() || undefined, - }, - }); - msg(box, "ok", out?.message || "Check your inbox to confirm your account."); - registerForm.reset(); - } catch (err) { - msg(box, "error", err.message); - } finally { - busy(btn, false); - } - }); -} - -// forgot — always a generic success (never reveals whether the email exists). -const forgotForm = $("forgot-form"); -if (forgotForm) { - const box = $("forgot-msg"); - forgotForm.addEventListener("submit", async (e) => { - e.preventDefault(); - clearMsg(box); - const btn = forgotForm.querySelector("button[type=submit]"); - busy(btn, true); - try { - const out = await api("/auth/forgot", { method: "POST", body: { email: $("email").value.trim() } }); - msg(box, "ok", out?.message || "If that account exists, a reset link is on its way."); - forgotForm.reset(); - } catch (err) { - msg(box, "error", err.message); - } finally { - busy(btn, false); - } - }); -} - -// reset — token comes from the emailed link. -const resetForm = $("reset-form"); -if (resetForm) { - const box = $("reset-msg"); - const token = qp.get("token") || ""; - if (!token) { - msg(box, "error", "This reset link is incomplete. Request a new one."); - resetForm.querySelectorAll("input, button").forEach((el) => (el.disabled = true)); - } - resetForm.addEventListener("submit", async (e) => { - e.preventDefault(); - clearMsg(box); - const password = $("password").value; - if (password !== $("confirm").value) { - msg(box, "error", "The two passwords don't match."); - return; - } - const btn = resetForm.querySelector("button[type=submit]"); - busy(btn, true); - try { - await api("/auth/reset", { method: "POST", body: { token, password } }); - msg(box, "ok", "Password updated. You can sign in now."); - resetForm.reset(); - resetForm.querySelectorAll("input, button").forEach((el) => (el.disabled = true)); - } catch (err) { - msg(box, "error", err.message); - busy(btn, false); - } - }); -} - -// account — profile view/edit, password change, sign out, delete. -const accountView = $("account-view"); -if (accountView) { - const gate = $("account-gate"); - let accountUser = null; - const fill = (user) => { - accountUser = user; - $("acct-handle").textContent = "@" + user.handle; - $("acct-email").textContent = user.email + (user.emailVerified ? "" : " · unconfirmed"); - $("acct-role").textContent = user.role; - $("acct-profile-link").href = withBase("/u/?handle=" + encodeURIComponent(user.handle)); - $("verification-wrap").hidden = user.emailVerified; - $("f-displayName").value = user.displayName || ""; - $("f-handle").value = user.handle || ""; - $("f-bio").value = user.bio || ""; - $("f-avatarUrl").value = user.avatarUrl || ""; - accountView.hidden = false; - if (gate) gate.hidden = true; - }; - - api("/me") - .then((d) => fill(d.user)) - .catch((err) => { - if (err.status === 401) location.href = withBase("/login/?next=/account/"); - else if (gate) msg(gate, "error", err.message); - }); - - const profileForm = $("profile-form"); - const pBox = $("profile-msg"); - profileForm?.addEventListener("submit", async (e) => { - e.preventDefault(); - clearMsg(pBox); - const btn = profileForm.querySelector("button[type=submit]"); - busy(btn, true); - try { - const d = await api("/me", { - method: "PATCH", - body: { - displayName: $("f-displayName").value.trim(), - handle: $("f-handle").value.trim().toLowerCase(), - bio: $("f-bio").value.trim(), - avatarUrl: $("f-avatarUrl").value.trim(), - }, - }); - fill(d.user); - msg(pBox, "ok", "Profile saved."); - } catch (err) { - msg(pBox, "error", err.message); - } finally { - busy(btn, false); - } - }); - - const passwordForm = $("password-form"); - const pwBox = $("password-msg"); - passwordForm?.addEventListener("submit", async (e) => { - e.preventDefault(); - clearMsg(pwBox); - const btn = passwordForm.querySelector("button[type=submit]"); - busy(btn, true); - try { - await api("/me/password", { - method: "POST", - body: { currentPassword: $("currentPassword").value, newPassword: $("newPassword").value }, - }); - passwordForm.reset(); - msg(pwBox, "ok", "Password changed."); - } catch (err) { - msg(pwBox, "error", err.message); - } finally { - busy(btn, false); - } - }); - - $("logout-btn")?.addEventListener("click", async () => { - try { await api("/auth/logout", { method: "POST" }); } catch {} - location.href = withBase("/login/"); - }); - - $("resend-verification-btn")?.addEventListener("click", async () => { - if (!accountUser || accountUser.emailVerified) return; - const btn = $("resend-verification-btn"); - const box = $("verification-msg"); - clearMsg(box); - busy(btn, true); - try { - await api("/auth/resend-verification", { method: "POST", body: { email: accountUser.email } }); - msg(box, "ok", "A new verification email is on its way."); - } catch (err) { - msg(box, "error", err.message); - } finally { - busy(btn, false); - } - }); - - $("delete-btn")?.addEventListener("click", async () => { - if (!confirm("Delete your account? This cannot be undone.")) return; - try { - await api("/me", { method: "DELETE" }); - location.href = withBase("/"); - } catch (err) { - msg(pBox, "error", err.message); - } - }); -} - -// public profile — the static site uses a query parameter while the accounts -// API keeps its canonical /u/:handle endpoint. -const publicProfile = $("public-profile"); -if (publicProfile) { - const gate = $("public-profile-gate"); - const handle = (qp.get("handle") || "").trim().toLowerCase(); - if (!/^[a-z0-9](?:[a-z0-9_]*[a-z0-9])?$/.test(handle) || handle.length < 3 || handle.length > 30) { - msg(gate, "error", "That public profile address is invalid."); - } else { - api("/u/" + encodeURIComponent(handle)) - .then(({ user }) => { - $("public-profile-handle").textContent = "@" + user.handle; - $("public-profile-name").textContent = user.displayName || user.handle; - $("public-profile-bio").textContent = user.bio || "No bio yet."; - $("public-profile-joined").textContent = new Date(user.joinedAt).toLocaleDateString(); - const avatar = $("public-profile-avatar"); - if (user.avatarUrl) { - try { - const url = new URL(user.avatarUrl); - if (url.protocol === "https:" || url.protocol === "http:") { - avatar.src = url.href; - avatar.hidden = false; - } - } catch {} - } - gate.hidden = true; - publicProfile.hidden = false; - }) - .catch((err) => msg(gate, "error", err.status === 404 ? "That profile doesn't exist." : err.message)); - } -} - -// device — the human-facing half of the CLI/desktop device-authorization flow. -const deviceView = $("device-view"); -if (deviceView) { - const gate = $("device-gate"); - const box = $("device-msg"); - const codeInput = $("device-code"); - const meta = $("device-meta"); - const actions = $("device-actions"); - const preset = qp.get("code"); - if (preset && codeInput) codeInput.value = preset; - - const showGrant = async () => { - clearMsg(box); - if (meta) meta.hidden = true; - if (actions) actions.hidden = true; - const code = codeInput.value.trim(); - if (!code) { msg(box, "error", "Enter the code shown in your terminal."); return; } - try { - const d = await api("/device/info?userCode=" + encodeURIComponent(code)); - if (meta) { - meta.textContent = `Requested by ${d.grant.userAgent || "a device"}`; - meta.hidden = false; - } - if (actions) actions.hidden = false; - } catch (err) { - msg(box, "error", err.message); - } - }; - - const decide = async (path, okText) => { - clearMsg(box); - const code = codeInput.value.trim(); - actions?.querySelectorAll("button").forEach((b) => (b.disabled = true)); - try { - await api(path, { method: "POST", body: { userCode: code } }); - msg(box, "ok", okText); - if (meta) meta.hidden = true; - if (actions) actions.hidden = true; - codeInput.disabled = true; - } catch (err) { - msg(box, "error", err.message); - actions?.querySelectorAll("button").forEach((b) => (b.disabled = false)); - } - }; - - api("/me") - .then(() => { - deviceView.hidden = false; - if (gate) gate.hidden = true; - $("device-check")?.addEventListener("click", showGrant); - $("device-approve")?.addEventListener("click", () => decide("/device/approve", "Approved. Return to your terminal — you're signed in.")); - $("device-deny")?.addEventListener("click", () => decide("/device/deny", "The sign-in request was rejected.")); - if (preset) showGrant(); - }) - .catch((err) => { - if (err.status === 401) { - const next = "/device/" + (preset ? "?code=" + encodeURIComponent(preset) : ""); - location.href = withBase("/login/?next=" + encodeURIComponent(next)); - } else if (gate) msg(gate, "error", err.message); - }); -} diff --git a/site/src/scripts/changelog-style-contract.test.mjs b/site/src/scripts/changelog-style-contract.test.mjs deleted file mode 100644 index 697a916806..0000000000 --- a/site/src/scripts/changelog-style-contract.test.mjs +++ /dev/null @@ -1,35 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import { test } from "node:test"; - -const css = await readFile(new URL("../styles/changelog.css", import.meta.url), "utf8"); -const component = await readFile(new URL("../components/ChangelogPage.astro", import.meta.url), "utf8"); -const versionPage = await readFile(new URL("../pages/changelog/[version].astro", import.meta.url), "utf8"); - -test("historical changelog styling remains readable", () => { - assert.doesNotMatch(css, /var\(--(?:muted|paper)\)/); - assert.match(css, /\.release-channel\s*\{/); -}); - -test("every release uses the version-ledger hero", () => { - assert.doesNotMatch(component, /isThematicTitle|isThematic/); - assert.doesNotMatch(component, /release-hero--compact|release-hero__actions|
/); - assert.match(component, /
/); - assert.match(component, /

Reasonix v\{release\.version\}<\/h1>/); - assert.match(component, /

/); - assert.doesNotMatch(css, /\.release-hero--compact|\.release-hero__actions|\.release-hero blockquote/); -}); - -test("changelog has one official navigation and marks archives noindex", () => { - assert.doesNotMatch(component, /release-channel-tabs/); - assert.match(component, /Historical archive/); - assert.match(component, /noindex=\{isPreview\}/); -}); - -test("reviewed exact-version routes redirect safely until their publication marker exists", () => { - assert.match(versionPage, /publishedReleases/); - assert.match(versionPage, /publishedVersions\.has\(release\.version\)/); - assert.match(versionPage, /if \(!published\)/); - assert.match(versionPage, /return Astro\.redirect/); - assert.match(versionPage, /Astro\.redirect\('\/changelog\/'\)/); -}); diff --git a/site/src/scripts/changelog.js b/site/src/scripts/changelog.js deleted file mode 100644 index 52526b61a8..0000000000 --- a/site/src/scripts/changelog.js +++ /dev/null @@ -1,31 +0,0 @@ -(function () { - const versionSelect = document.querySelector('[data-release-version]'); - versionSelect?.addEventListener('change', () => { - const version = String(versionSelect.value || '').replace(/^v/, ''); - if (/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(version)) { - window.location.href = `/changelog/v${version}/`; - } - }); - - const links = Array.from(document.querySelectorAll('.release-toc a[href^="#"]')); - const sections = links.map((link) => document.querySelector(link.getAttribute('href'))).filter(Boolean); - if (!links.length || !sections.length) return; - - let ticking = false; - const update = () => { - ticking = false; - let current = sections[0]; - for (const section of sections) { - if (section.getBoundingClientRect().top <= 150) current = section; - } - links.forEach((link) => link.classList.toggle('active', link.hash === `#${current.id}`)); - }; - const queue = () => { - if (ticking) return; - ticking = true; - requestAnimationFrame(update); - }; - window.addEventListener('scroll', queue, { passive: true }); - window.addEventListener('resize', queue, { passive: true }); - update(); -})(); diff --git a/site/src/scripts/community.js b/site/src/scripts/community.js deleted file mode 100644 index 320d4780b0..0000000000 --- a/site/src/scripts/community.js +++ /dev/null @@ -1,336 +0,0 @@ -// Reasonix Community client. Renders the forum from the forum.reasonix.io API and -// gates posting on the shared id.reasonix.io session (cookie sent cross-subdomain). -// Bilingual like the rest of the site: static labels via .l-en/.l-zh spans that the -// shared `reasonix-lang` choice toggles; plain-text strings pick the current lang. -import { initTheme } from "./theme.js"; -import { initMobileNav } from "./mobile-nav.js"; - -const FORUM = (import.meta.env.PUBLIC_FORUM_API || "https://forum.reasonix.io").replace(/\/$/, ""); -const ACCOUNTS = (import.meta.env.PUBLIC_ACCOUNTS_API || "https://id.reasonix.io").replace(/\/$/, ""); - -const el = (id) => document.getElementById(id); -const qp = new URLSearchParams(location.search); - -let lang = "en"; -const L = (en, zh) => `${en}${zh}`; -const t = (en, zh) => (lang === "zh" ? zh : en); - -function applyLangText() { - const attr = lang === "zh" ? "zh" : "en"; - document.querySelectorAll("[data-ph-en]").forEach((n) => { n.placeholder = n.getAttribute(`data-ph-${attr}`); }); - document.querySelectorAll("[data-l-en]").forEach((n) => { n.textContent = n.getAttribute(`data-l-${attr}`); }); -} -function setLang(l) { - lang = l; - document.body.dataset.lang = l; - document.documentElement.lang = l === "zh" ? "zh-CN" : "en"; - document.querySelectorAll(".lang-switch button").forEach((b) => b.classList.toggle("active", b.dataset.lang === l)); - try { localStorage.setItem("reasonix-lang", l); } catch {} - applyLangText(); -} -function initLang() { - let saved = ""; - try { saved = localStorage.getItem("reasonix-lang") || ""; } catch {} - setLang(saved || ((navigator.language || "").toLowerCase().startsWith("zh") ? "zh" : "en")); - document.querySelectorAll(".lang-switch button").forEach((b) => b.addEventListener("click", () => setLang(b.dataset.lang))); -} - -async function api(base, path, opts = {}) { - const res = await fetch(base + path, { - method: opts.method || "GET", - credentials: "include", - headers: opts.body ? { "content-type": "application/json" } : undefined, - body: opts.body ? JSON.stringify(opts.body) : undefined, - }); - let data = null; - try { data = await res.json(); } catch {} - if (!res.ok) { - const err = new Error(data?.error?.message || "Something went wrong."); - err.code = data?.error?.code; - err.status = res.status; - throw err; - } - return data; -} -const forum = (p, o) => api(FORUM, p, o); - -// Anti-spam / gate errors are localized by code; unknown codes fall back to the -// server message. -const ERR = { - email_unverified: ["Confirm your email address before posting.", "发帖前请先验证你的邮箱。"], - links_restricted: ["New members can't post links yet — participate a little to unlock.", "新成员暂时不能发链接——参与一段时间后解锁。"], - insufficient_trust: ["You don't have access to post in this category yet.", "你还没有在此分区发帖的权限。"], - silenced: ["Your account is temporarily restricted from posting.", "你的账号暂时被限制发帖。"], - rate_limited: ["You're posting too fast — take a short break.", "发帖太快了——稍微歇一会儿。"], - daily_limit: ["You've hit today's posting limit for your trust level.", "你已达到当前信任等级的每日发帖上限。"], - closed: ["This topic is closed to new replies.", "该话题已关闭,不能再回复。"], - self_flag: ["You can't report your own post.", "不能举报自己的帖子。"], - unauthorized: ["Sign in to continue.", "请先登录。"], -}; -const errText = (err) => (ERR[err.code] ? t(ERR[err.code][0], ERR[err.code][1]) : err.message); - -const CATS = { - announcements: ["Announcements", "公告"], - help: ["Help & Support", "帮助与支持"], - skills: ["Skills & Plugins", "技能与插件"], - show: ["Show & Tell", "作品展示"], - feedback: ["Feedback & Ideas", "反馈与建议"], -}; -const CATDESC = { - announcements: ["Releases, roadmap, and community news.", "版本发布、路线图与社区动态。"], - help: ["Stuck on setup, config, or cache behavior? Ask here.", "安装、配置或缓存问题?在这里提问。"], - skills: ["Share, request, and review community skills and MCP servers.", "分享、求助、评审社区技能与 MCP 服务。"], - show: ["Built something with Reasonix? Show the community.", "用 Reasonix 做了东西?来给社区看看。"], - feedback: ["Feature requests and product feedback.", "功能建议与产品反馈。"], -}; -const catName = (slug, apiName) => (CATS[slug] ? L(CATS[slug][0], CATS[slug][1]) : esc(apiName)); -const catText = (slug, apiName) => (CATS[slug] ? t(CATS[slug][0], CATS[slug][1]) : apiName); -const ROLES = { admin: ["admin", "管理员"], moderator: ["moderator", "版主"] }; - -function esc(s) { - return String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); -} -const AV_GRAD = [ - "var(--accent),var(--violet)", - "var(--ok),oklch(0.62 0.15 200)", - "var(--warm),var(--rose)", - "var(--violet),var(--rose)", - "oklch(0.6 0.15 200),var(--accent)", -]; -function avatar(handle, size = "") { - const h = handle || "?"; - let n = 0; - for (const ch of h) n = (n + ch.charCodeAt(0)) % AV_GRAD.length; - const initials = h.replace(/[^a-zA-Z0-9]/g, "").slice(0, 2).toUpperCase() || "?"; - return `${esc(initials)}`; -} -function ago(iso) { - if (!iso) return ""; - const s = Math.max(1, (Date.now() - new Date(iso).getTime()) / 1000); - const u = [[86400, "d", "天"], [3600, "h", "小时"], [60, "m", "分钟"]]; - for (const [sec, en, zh] of u) if (s >= sec) { const v = Math.floor(s / sec); return L(`${v}${en} ago`, `${v}${zh}前`); } - return L("just now", "刚刚"); -} -function md(body) { - const parts = esc(body).split(/```/); - let out = ""; - parts.forEach((chunk, i) => { - if (i % 2 === 1) { out += `

${chunk.replace(/^\n/, "")}
`; return; } - const paras = chunk.split(/\n{2,}/).map((p) => p.trim()).filter(Boolean); - out += paras.map((p) => `

${p.replace(/`([^`]+)`/g, "$1").replace(/\n/g, "
")}

`).join(""); - }); - return out || "

"; -} - -const CAT_ICONS = { announcements: "📣", help: "🛟", skills: "🧩", show: "✨", feedback: "💡" }; -const loginUrl = () => `/login/?next=${encodeURIComponent(location.pathname + location.search)}`; - -let account = null; -async function loadAccount() { - try { account = (await api(ACCOUNTS, "/me")).user; } catch { account = null; } - document.querySelectorAll("#nav-account, #mobile-nav-account").forEach((slot) => { - slot.innerHTML = account - ? `${avatar(account.handle)}` - : `${L("Sign in", "登录")}`; - }); -} - -/* ── home ─────────────────────────────────────────── */ -function renderHome() { - const catBox = el("cat-list"); - const topicBox = el("topic-list"); - const category = qp.get("category") || ""; - - forum("/categories").then((d) => { - const cats = d.categories; - if (el("s-cats")) el("s-cats").textContent = cats.length; - if (el("s-topics")) el("s-topics").textContent = cats.reduce((a, c) => a + (c.topicCount || 0), 0); - catBox.innerHTML = cats.map((c) => ` - - ${CAT_ICONS[c.slug] || "💬"} -

${catName(c.slug, c.name)}

${CATDESC[c.slug] ? L(CATDESC[c.slug][0], CATDESC[c.slug][1]) : esc(c.description)}

-
${c.topicCount || 0} ${L("topics", "话题")}${c.lastActivity ? " · " + ago(c.lastActivity) : ""}
-
`).join(""); - }).catch(() => { catBox.innerHTML = `
${L("Couldn't load categories.", "无法加载分区。")}
`; }); - - const loadTopics = (sort) => { - topicBox.innerHTML = `
`.repeat(3); - const q = new URLSearchParams(); - if (category) q.set("category", category); - if (sort) q.set("sort", sort); - forum("/topics?" + q).then((d) => { - if (!d.topics.length) { topicBox.innerHTML = `
${L("No topics yet —", "还没有话题 ——")} ${L("start the first one", "来发第一个")}.
`; return; } - topicBox.innerHTML = d.topics.map((tp) => ` -
- ${avatar(tp.author)} -
-
- ${tp.pinned ? `📌 ${L("Pinned", "置顶")}` : ""} - ${tp.status === "solved" ? `✓ ${L("Solved", "已解决")}` : ""} - ${esc(tp.title)} -
-
${catName(tp.category, tp.categoryName)} ${esc(tp.author)} · ${ago(tp.createdAt)}
-
-
${tp.replyCount}
${L("replies", "回复")}
-
${ago(tp.lastPostAt)}
-
`).join(""); - }).catch(() => { topicBox.innerHTML = `
${L("Couldn't load discussions.", "无法加载讨论。")}
`; }); - }; - loadTopics("latest"); - - el("sort-tabs")?.addEventListener("click", (e) => { - const b = e.target.closest("button[data-sort]"); - if (!b) return; - el("sort-tabs").querySelectorAll("button").forEach((x) => x.classList.toggle("on", x === b)); - loadTopics(b.dataset.sort); - }); -} - -/* ── thread ───────────────────────────────────────── */ -let firstPostId = 0; -function postHtml(p, topic) { - const answer = topic.acceptedPostId && topic.acceptedPostId === p.id; - const cls = answer ? "post answer" : p.id === firstPostId ? "post op" : "post"; - const roleWord = ROLES[p.role] ? L(ROLES[p.role][0], ROLES[p.role][1]) : ""; - const role = roleWord ? `${roleWord}` : ""; - return `
- ${avatar(p.handle || p.author, "lg")} -
- ${answer ? `
✓ ${L("Accepted answer", "已采纳回答")}
` : ""} -
${esc(p.handle || p.author)}${role}${ago(p.createdAt)}
-
${md(p.body)}
-
- - -
-
-
`; -} - -async function renderThread() { - const id = Number(qp.get("id")); - if (!id) { location.href = "/community/"; return; } - let data; - try { data = await forum(`/topics/${id}`); } - catch { el("posts").innerHTML = `
${L("That discussion doesn't exist or was removed.", "该讨论不存在或已被移除。")}
`; return; } - const { topic, posts } = data; - firstPostId = posts[0]?.id || 0; - - document.title = `${topic.title} — ${t("Reasonix Community", "Reasonix 社区")}`; - el("crumb-cat").textContent = catText(topic.category, topic.category); - el("crumb-title").textContent = topic.title; - el("t-title").textContent = topic.title; - el("t-meta").innerHTML = - `${topic.status === "solved" ? `✓ ${L("Solved", "已解决")}` : ""} - ${topic.replyCount} ${L("replies", "回复")} · ${topic.viewCount} ${L("views", "浏览")} · ${L("started", "发起于")} ${ago(topic.createdAt)}`; - el("posts").innerHTML = posts.map((p) => postHtml(p, topic)).join(""); - - const seen = new Set(); - el("parti").innerHTML = posts.filter((p) => !seen.has(p.author) && seen.add(p.author)).slice(0, 8).map((p) => avatar(p.handle || p.author)).join(""); - - el("posts").addEventListener("click", async (e) => { - const like = e.target.closest("[data-like]"); - if (like && account) { - const wasLiked = like.dataset.liked === "1"; - like.disabled = true; - try { - const out = await forum(`/posts/${like.dataset.like}/likes`, { method: wasLiked ? "DELETE" : "POST" }); - like.dataset.liked = out.liked ? "1" : "0"; - like.setAttribute("aria-pressed", out.liked ? "true" : "false"); - like.classList.toggle("on", out.liked); - like.querySelector("span").textContent = out.likeCount; - } catch (err) { alert(errText(err)); } - finally { like.disabled = false; } - return; - } else if (like) { - location.href = loginUrl(); - return; - } - const flag = e.target.closest("[data-flag]"); - if (flag && account) { - if (!confirm(t("Report this post as spam or abuse?", "举报该帖为垃圾/滥用内容?"))) return; - try { await forum(`/posts/${flag.dataset.flag}/flags`, { method: "POST", body: { reason: "spam" } }); flag.innerHTML = L("Reported ✓", "已举报 ✓"); flag.disabled = true; } - catch (err) { alert(errText(err)); } - } else if (flag) { location.href = loginUrl(); } - }); - - const zone = el("reply-zone"); - if (!account) { - zone.innerHTML = `

${L("Sign in with your Reasonix account to reply.", "用你的 Reasonix 账号登录后回复。")}

${L("Sign in", "登录")}
`; - return; - } - zone.innerHTML = ` - -
- -
${L("Signed in as", "已登录")} ${esc(account.handle)}
-
`; - applyLangText(); - el("reply-submit").addEventListener("click", async () => { - const body = el("reply-body").value.trim(); - const msg = el("reply-msg"); - msg.hidden = true; - if (body.length < 2) return; - el("reply-submit").disabled = true; - try { - await forum(`/topics/${id}/posts`, { method: "POST", body: { body } }); - location.reload(); - } catch (err) { - msg.textContent = errText(err); msg.hidden = false; - el("reply-submit").disabled = false; - } - }); -} - -/* ── new topic ────────────────────────────────────── */ -async function renderNew() { - if (!account) { - el("new-gate").hidden = false; - el("gate-login").href = loginUrl(); - return; - } - el("new-form").hidden = false; - const sel = el("f-category"); - try { - const { categories } = await forum("/categories"); - for (const c of categories) { - const o = document.createElement("option"); - o.value = c.id; - o.setAttribute("data-l-en", CATS[c.slug] ? CATS[c.slug][0] : c.name); - o.setAttribute("data-l-zh", CATS[c.slug] ? CATS[c.slug][1] : c.name); - o.textContent = catText(c.slug, c.name); - sel.appendChild(o); - } - const pre = qp.get("category"); - if (pre) { const m = categories.find((c) => c.slug === pre); if (m) sel.value = m.id; } - } catch {} - applyLangText(); - - el("f-submit").addEventListener("click", async () => { - const msg = el("new-msg"); - msg.hidden = true; - const categoryId = Number(sel.value); - const title = el("f-title").value.trim(); - const body = el("f-body").value.trim(); - if (!categoryId) { msg.textContent = t("Choose a category.", "请选择一个分区。"); msg.hidden = false; return; } - if (title.length < 6 || body.length < 10) { msg.textContent = t("Add a title (6+ chars) and a bit more detail (10+ chars).", "标题至少 6 个字符,正文至少 10 个字符。"); msg.hidden = false; return; } - el("f-submit").disabled = true; - try { - const { topic } = await forum("/topics", { method: "POST", body: { categoryId, title, body } }); - location.href = `/community/topic/?id=${topic.id}`; - } catch (err) { - msg.textContent = errText(err); msg.hidden = false; - el("f-submit").disabled = false; - } - }); -} - -(async function () { - initTheme(); - initMobileNav(); - initLang(); - await loadAccount(); - if (el("topic-list")) renderHome(); - else if (el("posts")) renderThread(); - else if (el("new-form")) renderNew(); -})(); diff --git a/site/src/scripts/docs-codeblock-contract.test.mjs b/site/src/scripts/docs-codeblock-contract.test.mjs deleted file mode 100644 index 29f1c62856..0000000000 --- a/site/src/scripts/docs-codeblock-contract.test.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import test from "node:test"; - -const configSource = () => readFile(new URL("../../astro.config.mjs", import.meta.url), "utf8"); -const docsSource = () => readFile(new URL("../pages/docs.astro", import.meta.url), "utf8"); -const stylesSource = () => readFile(new URL("../styles/global.css", import.meta.url), "utf8"); - -test("Astro preserves documentation code sample newlines", async () => { - const config = await configSource(); - - assert.match(config, /compressHTML:\s*false/); -}); - -test("copyable documentation code blocks reserve space for their buttons", async () => { - const [page, styles] = await Promise.all([docsSource(), stylesSource()]); - const codeblocks = [...page.matchAll(/
([\s\S]*?)<\/div>/g)]; - const copyable = codeblocks.filter(([, , body]) => body.includes("data-copy=")); - - assert.ok(copyable.length > 0); - for (const [, classes] of copyable) { - assert.match(classes, /(?:^|\s)codeblock--copy(?:\s|$)/); - } - assert.match(styles, /\.codeblock--copy\s*\{\s*padding-top:\s*52px;\s*\}/); -}); - -test("the macOS quarantine comment and command remain separate source lines", async () => { - const page = await docsSource(); - - assert.match( - page, - /# Quit Reasonix first, then run in Terminal\.<\/span>\nsudo xattr -rd com\.apple\.quarantine \/Applications\/Reasonix\.app/, - ); -}); - -test("website documents the version-matched built-in docs command", async () => { - const page = await docsSource(); - - assert.match(page, /id="embedded-docs"/); - assert.match(page, /\/docs 1\.19\.5 changelog/); - assert.match(page, /AI configured for the current session/); - assert.match(page, /normally \/reasonix:docs<\/code>/); - assert.match(page, /Reasonix never overwrites the existing command/); - assert.match(page, /Release CI rejects a build when its embedded corpus does not match/); -}); - -test("website exposes the Extension Protocol developer path", async () => { - const page = await docsSource(); - - assert.match(page, /href="#extensions"/); - assert.match(page, /id="extensions"/); - assert.match(page, /MCP or Extension Protocol\?/); - assert.match(page, /sdk\/go\/examples\/starterextension/); - assert.match(page, /plugin_root="\$\(pwd -P\)"/); - assert.match(page, /reasonix plugin install "\$plugin_root" --dry-run/); - assert.match(page, /reasonix plugin install "\$plugin_root" --link --replace --yes/); - assert.match(page, /sdk\/go\/v1\.0\.0/); - assert.match(page, /Full trust:<\/strong>/); - assert.match(page, /Native Manifest v2 is an explicit capability boundary/); - assert.match(page, /原生 Manifest v2 是显式能力边界/); - assert.match(page, /docs\/EXTENSIONS\.md/); - assert.match(page, /docs\/PLUGIN_PACKAGES\.md#manifest-v2-extensions/); - assert.match(page, /docs\/PLUGIN_PACKAGES\.zh-CN\.md#manifest-v2扩展/); - assert.match(page, /sdk\/go\/README\.md/); - assert.match(page, /docs\/EXTENSION_PROTOCOL\.md/); - assert.doesNotMatch(page, /Manifest v1/); -}); diff --git a/site/src/scripts/download-link.js b/site/src/scripts/download-link.js deleted file mode 100644 index 39d1b90487..0000000000 --- a/site/src/scripts/download-link.js +++ /dev/null @@ -1,43 +0,0 @@ -const DOWNLOAD_PANES = new Set(["npm", "brew", "desktop", "cli", "vscode"]); - -// Return the requested install pane only for the homepage download section. -// Plain #start links keep the rendered default pane; query links opt into one. -export function downloadPaneFromURL(input, base = "https://reasonix.io/") { - let url; - try { - url = new URL(input, base); - } catch { - return ""; - } - if (url.hash !== "#start") return ""; - const pane = url.searchParams.get("download") || ""; - return DOWNLOAD_PANES.has(pane) ? pane : ""; -} - -export function releaseChannelFromURL(input, base = "https://reasonix.io/") { - let url; - try { - url = new URL(input, base); - } catch { - return ""; - } - if (url.hash !== "#start") return ""; - const pane = url.searchParams.get("download") || ""; - if (pane !== "desktop" && pane !== "cli") return ""; - return ""; -} - -export function downloadURLForPane(input, pane, channel, base = "https://reasonix.io/") { - if (!DOWNLOAD_PANES.has(pane)) return ""; - let url; - try { - url = new URL(input, base); - } catch { - return ""; - } - url.searchParams.set("download", pane); - void channel; - url.searchParams.delete("channel"); - url.hash = "start"; - return url.href; -} diff --git a/site/src/scripts/download-link.test.mjs b/site/src/scripts/download-link.test.mjs deleted file mode 100644 index e8fa9c1cd5..0000000000 --- a/site/src/scripts/download-link.test.mjs +++ /dev/null @@ -1,42 +0,0 @@ -import { test } from "node:test"; -import assert from "node:assert/strict"; -import { downloadPaneFromURL, downloadURLForPane, releaseChannelFromURL } from "./download-link.js"; - -test("desktop updater deep link selects the desktop pane", () => { - assert.equal(downloadPaneFromURL("https://reasonix.io/?download=desktop#start"), "desktop"); -}); - -test("plain install links preserve the default pane", () => { - assert.equal(downloadPaneFromURL("https://reasonix.io/#start"), ""); - assert.equal(downloadPaneFromURL("https://reasonix.io/?download=desktop"), ""); -}); - -test("recognized download panes are strict", () => { - assert.equal(downloadPaneFromURL("/?download=brew#start"), "brew"); - assert.equal(downloadPaneFromURL("/?download=npm#start"), "npm"); - assert.equal(downloadPaneFromURL("/?download=vscode#start"), "vscode"); - assert.equal(downloadPaneFromURL("/?download=cli#start"), "cli"); - assert.equal(downloadPaneFromURL("/?download=DESKTOP#start"), ""); - assert.equal(downloadPaneFromURL("/?download=unknown#start"), ""); - assert.equal(downloadPaneFromURL("not a url", "not a base"), ""); -}); - -test("legacy release channel deep links never select a public channel", () => { - assert.equal(releaseChannelFromURL("/?download=desktop&channel=preview#start"), ""); - assert.equal(releaseChannelFromURL("/?download=cli&channel=stable#start"), ""); - assert.equal(releaseChannelFromURL("/?download=desktop&channel=canary#start"), ""); -}); - -test("download tab navigation keeps the pane and removes legacy channels", () => { - assert.equal( - downloadURLForPane("https://reasonix.io/?download=desktop&channel=preview#start", "cli", "stable"), - "https://reasonix.io/?download=cli#start", - ); - assert.equal( - downloadURLForPane("https://reasonix.io/?download=desktop&channel=preview#start", "npm", "preview"), - "https://reasonix.io/?download=npm#start", - ); - assert.equal(downloadURLForPane("https://reasonix.io/", "desktop", "preview"), - "https://reasonix.io/?download=desktop#start"); - assert.equal(downloadURLForPane("https://reasonix.io/", "unknown", "stable"), ""); -}); diff --git a/site/src/scripts/fx.js b/site/src/scripts/fx.js deleted file mode 100644 index a98d555d99..0000000000 --- a/site/src/scripts/fx.js +++ /dev/null @@ -1,40 +0,0 @@ -// Reasonix — motion & FX layer (all effects respect data-motion + prefers-reduced-motion) -(function () { - const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches; - const rich = () => document.body.dataset.motion === "rich" && !reduced; - - /* spotlight border on cards */ - document.querySelectorAll(".feat, .os-card, .doc-card").forEach((card) => { - card.addEventListener("mousemove", (e) => { - const r = card.getBoundingClientRect(); - card.style.setProperty("--mx", e.clientX - r.left + "px"); - card.style.setProperty("--my", e.clientY - r.top + "px"); - }); - }); - - /* stat counters (run when terminal playback finishes) */ - const counters = Array.from(document.querySelectorAll("[data-cnt]")); - const fmt = (el, v) => { - if (el.dataset.fmt === "hm") { - const m = Math.round(v); - return Math.floor(m / 60) + "h " + (m % 60) + "m"; - } - const dec = +(el.dataset.dec || 0); - return (el.dataset.pre || "") + v.toFixed(dec) + (el.dataset.suf || ""); - }; - const runCounters = () => { - counters.forEach((el) => { - const target = parseFloat(el.dataset.cnt); - if (!rich()) { el.textContent = fmt(el, target); return; } - const t0 = performance.now(), dur = 1500; - const frame = (t) => { - const p = Math.min(1, (t - t0) / dur); - const e = 1 - Math.pow(1 - p, 3); - el.textContent = fmt(el, target * e); - if (p < 1) requestAnimationFrame(frame); - }; - requestAnimationFrame(frame); - }); - }; - document.addEventListener("rx:term-played", runCounters); -})(); diff --git a/site/src/scripts/header-contract.test.mjs b/site/src/scripts/header-contract.test.mjs deleted file mode 100644 index 566ed4f467..0000000000 --- a/site/src/scripts/header-contract.test.mjs +++ /dev/null @@ -1,39 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import test from "node:test"; - -const source = (path) => readFile(new URL(path, import.meta.url), "utf8"); - -test("primary site pages share the same header component", async () => { - const pages = await Promise.all([ - source("../pages/index.astro"), - source("../pages/docs.astro"), - source("../pages/skills.astro"), - source("../components/ChangelogPage.astro"), - source("../pages/404.astro"), - ]); - - for (const page of pages) { - assert.match(page, / { - const header = await source("../components/SiteHeader.astro"); - - for (const id of ["features", "surfaces", "skills", "community", "docs", "changelog"]) { - assert.match(header, new RegExp(`id: '${id}'`)); - } - - assert.doesNotMatch(header, /id: 'start'/); - assert.equal((header.match(/#start/g) ?? []).length, 2); - assert.match(header, /nav-sign-in/); - assert.match(header, /nav-install/); - assert.match(header, /class="nav-github"/); - assert.match(header, /https:\/\/github[.]com\/esengine\/DeepSeek-Reasonix/); - assert.match(header, /target="_blank"/); - assert.match(header, /aria-label="Reasonix GitHub repository"/); - assert.match(header, /data-mobile-nav-toggle/); - assert.match(header, /id="site-mobile-nav"/); -}); diff --git a/site/src/scripts/mobile-nav-contract.test.mjs b/site/src/scripts/mobile-nav-contract.test.mjs deleted file mode 100644 index b6fad46dee..0000000000 --- a/site/src/scripts/mobile-nav-contract.test.mjs +++ /dev/null @@ -1,104 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import test from "node:test"; - -const source = (path) => readFile(new URL(path, import.meta.url), "utf8"); - -/* Extract the body of a `@media (max-width: Npx)` block (up to the next - at-rule or EOF) so assertions stay scoped to small viewports. */ -const mediaBlock = (css, px) => { - const marker = `@media (max-width: ${px}px)`; - const start = css.indexOf(marker); - assert.notEqual(start, -1, `missing ${marker}`); - const rest = css.slice(start + marker.length); - const next = rest.search(/@media|@keyframes/); - return next === -1 ? rest : rest.slice(0, next); -}; - -/* The header must fit narrow viewports while keeping a clear menu trigger. */ -test("≤640px: marketing nav contracts to fit 390px viewports", async () => { - const [css, header] = await Promise.all([ - source("../styles/global.css"), - source("../components/SiteHeader.astro"), - ]); - const block = mediaBlock(css, 640); - assert.match(block, /\.nav-sign-in \{ display: none/); - assert.match(block, /\.nav \.brand span \{ display: none/); - assert.match(block, /\.nav \.brand img \{ width: 64px; \}/); - assert.match(header, //); - assert.match(block, /\.theme-switch button \{ padding: 6px 9px/); -}); - -test("≤1100px: marketing navigation collapses before controls overlap", async () => { - const css = await source("../styles/global.css"); - const tabletBlock = mediaBlock(css, 1100); - const mobileBlock = mediaBlock(css, 900); - - assert.match(tabletBlock, /\.nav-links \{ display: none/); - assert.match(tabletBlock, /\.nav-github \{ margin-left: auto; padding-inline: 8px/); - assert.match(tabletBlock, /\.nav-github-label \{ display: none/); - assert.match(tabletBlock, /\.nav-menu-toggle \{ display: inline-flex/); - assert.match(mobileBlock, /\.nav-github \{ display: none/); -}); - -test("≤360px: marketing nav keeps the menu trigger within 320px", async () => { - const css = await source("../styles/global.css"); - const block = mediaBlock(css, 360); - assert.match(block, /\.nav-inner \{ padding: 0 12px; gap: 6px/); - assert.match(block, /\.lang-switch button \{ padding: 6px 8px/); - assert.match(block, /\.theme-switch button \{ padding: 6px 7px/); - assert.match(block, /\.nav-install \{ display: none/); - assert.match(block, /\.nav-menu-toggle \{ width: 36px; height: 36px/); -}); - -test("≤400px: marketing nav uses the compact brand mark", async () => { - const css = await source("../styles/global.css"); - const block = mediaBlock(css, 400); - assert.match(block, /\.nav \.brand img \{ width: 28px; height: 28px; border-radius: 8px; \}/); -}); - -test("≤360px: hero install command keeps its copy control inside the bar", async () => { - const [css, page] = await Promise.all([ - source("../styles/global.css"), - source("../pages/index.astro"), - ]); - const block = mediaBlock(css, 360); - assert.match(page, /class=\"install-command\">npm i -g reasonix<\/span>/); - assert.match(css, /\.hero-install \.install-command\s*\{[\s\S]*?min-width:\s*0;/); - assert.match(block, /\.hero-install \.install \{ gap: 6px; padding-inline: 6px; \}/); - assert.match(block, /\.hero-install \.install button \{ padding-inline: 10px; \}/); -}); - -test("≤440px: community nav budgets for the async account control", async () => { - const css = await source("../styles/community.css"); - const layout = await source("../layouts/Community.astro"); - const block = mediaBlock(css, 440); - assert.match(layout, /class="brand-name">Reasonix/); - assert.match(layout, /id="nav-account"/); - assert.match(block, /\.nav \.brand-name \{ display: none/); - assert.match(block, /\.nav-right \{ gap: 8px/); - assert.match(block, /\.lang-switch button \{ padding: 6px 8px/); - assert.match(block, /\.theme-switch button \{ padding: 6px 7px/); - assert.match(block, /#nav-account \.btn \{ padding: 7px 10px/); -}); - -test("shared headers expose an accessible mobile navigation", async () => { - const [header, community] = await Promise.all([ - source("../components/SiteHeader.astro"), - source("../layouts/Community.astro"), - ]); - for (const sourceText of [header, community]) { - assert.match(sourceText, /data-mobile-nav-toggle/); - assert.match(sourceText, /data-mobile-nav/); - assert.match(sourceText, /data-mobile-nav-close/); - assert.match(sourceText, /aria-expanded="false"/); - } -}); - -test("mobile navigation behavior supports close, Escape, and focus cycling", async () => { - const js = await source("./mobile-nav.js"); - assert.match(js, /event\.key === "Escape"/); - assert.match(js, /event\.key !== "Tab"/); - assert.match(js, /document\.body\.classList\.add\("mobile-nav-open"\)/); - assert.match(js, /document\.body\.classList\.remove\("mobile-nav-open"\)/); -}); diff --git a/site/src/scripts/mobile-nav.js b/site/src/scripts/mobile-nav.js deleted file mode 100644 index 7287314503..0000000000 --- a/site/src/scripts/mobile-nav.js +++ /dev/null @@ -1,72 +0,0 @@ -// Shared responsive navigation behavior for the marketing and community headers. -export function initMobileNav() { - document.querySelectorAll("[data-mobile-nav]").forEach((menu) => { - const header = menu.closest(".nav"); - const toggle = header?.querySelector("[data-mobile-nav-toggle]"); - const panel = menu.querySelector(".mobile-nav-panel"); - if (!toggle || !panel) return; - - let closeTimer; - let stateToken = 0; - let returnFocus = toggle; - const focusables = () => Array.from(panel.querySelectorAll( - 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])', - )).filter((element) => !element.closest("[hidden]")); - - const close = (restore = true) => { - stateToken += 1; - clearTimeout(closeTimer); - toggle.setAttribute("aria-expanded", "false"); - menu.setAttribute("aria-hidden", "true"); - menu.classList.remove("is-open"); - document.body.classList.remove("mobile-nav-open"); - closeTimer = window.setTimeout(() => { menu.hidden = true; }, 220); - if (restore) returnFocus.focus(); - }; - - const open = () => { - const token = ++stateToken; - clearTimeout(closeTimer); - returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : toggle; - menu.hidden = false; - menu.setAttribute("aria-hidden", "false"); - toggle.setAttribute("aria-expanded", "true"); - document.body.classList.add("mobile-nav-open"); - requestAnimationFrame(() => { - if (token === stateToken && !menu.hidden) menu.classList.add("is-open"); - }); - requestAnimationFrame(() => { - if (token === stateToken && !menu.hidden) focusables()[0]?.focus(); - }); - }; - - toggle.addEventListener("click", () => (menu.hidden ? open() : close())); - menu.querySelectorAll("[data-mobile-nav-close]").forEach((button) => button.addEventListener("click", () => close())); - menu.querySelectorAll("a[href]").forEach((link) => link.addEventListener("click", () => close(false))); - menu.addEventListener("keydown", (event) => { - if (event.key === "Escape") { - event.preventDefault(); - close(); - return; - } - if (event.key !== "Tab") return; - const items = focusables(); - if (!items.length) return; - const first = items[0]; - const last = items[items.length - 1]; - if (event.shiftKey && document.activeElement === first) { - event.preventDefault(); - last.focus(); - } else if (!event.shiftKey && document.activeElement === last) { - event.preventDefault(); - first.focus(); - } - }); - menu.addEventListener("transitionend", (event) => { - if (event.propertyName === "opacity" && !menu.classList.contains("is-open")) menu.hidden = true; - }); - window.addEventListener("resize", () => { - if (window.matchMedia("(min-width: 1101px)").matches && !menu.hidden) close(false); - }, { passive: true }); - }); -} diff --git a/site/src/scripts/release-channels.js b/site/src/scripts/release-channels.js deleted file mode 100644 index f4f36136e8..0000000000 --- a/site/src/scripts/release-channels.js +++ /dev/null @@ -1,294 +0,0 @@ -const STABLE_TAG = /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/; -const DESKTOP_DOWNLOAD_PAGE = "https://reasonix.io/?download=desktop#start"; -const DESKTOP_ASSETS = [ - ["platforms", "darwin-arm64", "Reasonix-darwin-arm64.zip"], - ["platforms", "darwin-amd64", "Reasonix-darwin-amd64.zip"], - ["platforms", "windows-amd64", "Reasonix-windows-amd64-installer.exe"], - ["platforms", "windows-arm64", "Reasonix-windows-arm64-installer.exe"], - ["platforms", "linux-amd64", "Reasonix-linux-amd64.tar.gz"], - ["native_packages", "linux-amd64", "Reasonix-linux-amd64.deb"], - ["downloads", "Reasonix-darwin-universal.dmg", "Reasonix-darwin-universal.dmg"], - ["downloads", "Reasonix-windows-amd64.zip", "Reasonix-windows-amd64.zip"], -]; -const DESKTOP_ASSET_NAMES = new Set(DESKTOP_ASSETS.map(([, , name]) => name)); -const OFFICIAL_DESKTOP_RELEASE_TAG = /^(?:desktop-)?(v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))$/; -const SHA256 = /^[0-9a-f]{64}$/; -const MAX_RELEASE_ASSET_SIZE = 1 << 30; - -// Keep in lockstep with workers/crash-report CLI asset gate. -export const CLI_RELEASE_ASSETS = [ - "reasonix-darwin-amd64.tar.gz", - "reasonix-darwin-arm64.tar.gz", - "reasonix-linux-amd64.tar.gz", - "reasonix-linux-arm64.tar.gz", - "reasonix-windows-amd64.zip", - "reasonix-windows-arm64.zip", - "SHA256SUMS", -]; -const CLI_RELEASE_ASSET_NAMES = new Set(CLI_RELEASE_ASSETS); - -export const publicReleaseChannels = new Set(["stable"]); - -export function normalizePublicReleaseChannel(_value) { - return "stable"; -} - -export function cliUpgradeCommand(_value) { - return "reasonix upgrade"; -} - -export function releaseVersionLabel(model) { - return String(model?.version || "").trim() || "latest"; -} - -function parsePublicTag(tag) { - const value = typeof tag === "string" ? tag : ""; - let match = value.match(STABLE_TAG); - if (match) { - return { tag: value, channel: "stable", order: match.slice(1) }; - } - return null; -} - -function compareDecimal(left, right) { - if (left.length !== right.length) return left.length - right.length; - return left === right ? 0 : left > right ? 1 : -1; -} - -function compareOrder(left, right) { - for (let i = 0; i < Math.max(left.length, right.length); i += 1) { - const delta = compareDecimal(left[i] || "0", right[i] || "0"); - if (delta !== 0) return delta; - } - return 0; -} - -function safeHTTPSURL(value) { - if (typeof value !== "string") return null; - try { - const url = new URL(value); - return url.protocol === "https:" && - Boolean(url.hostname) && - !url.username && - !url.password - ? url - : null; - } catch { - return null; - } -} - -function expectedCLIAssetURL(value, tag, name) { - if (typeof value !== "string") return null; - const url = safeHTTPSURL(value); - const path = `/esengine/DeepSeek-Reasonix/releases/download/${tag}/${name}`; - return url && - url.href === value && - url.hostname.toLowerCase() === "github.com" && - !url.port && - url.pathname === path && - !url.search && - !url.hash - ? url - : null; -} - -// Returns the 7 required CLI asset URLs, or null when any required asset is -// missing. Never synthesizes download URLs — incomplete releases must be -// rejected so the site never advertises 404 links. -export function releaseAssetMap(release) { - const found = {}; - const seen = new Set(); - for (const asset of Array.isArray(release?.assets) ? release.assets : []) { - const name = String(asset?.name || ""); - if (!CLI_RELEASE_ASSET_NAMES.has(name)) continue; - if (seen.has(name)) return null; - seen.add(name); - const url = expectedCLIAssetURL(asset?.browser_download_url, String(release?.tag_name || ""), name); - if ( - name && - url && - Number.isSafeInteger(asset?.size) && - asset.size > 0 && - asset.size <= MAX_RELEASE_ASSET_SIZE - ) { - found[name] = url.href; - } - } - const assets = {}; - for (const name of CLI_RELEASE_ASSETS) { - if (!found[name]) return null; - assets[name] = found[name]; - } - return assets; -} - -export function selectCLIRelease(releases, requestedChannel) { - const channel = normalizePublicReleaseChannel(requestedChannel); - let selected = null; - let selectedTag = null; - for (const release of Array.isArray(releases) ? releases : []) { - const parsed = parsePublicTag(release?.tag_name); - if (!parsed || parsed.channel !== channel) continue; - if (Boolean(release?.prerelease)) continue; - if (!releaseAssetMap(release)) continue; - if (!selectedTag || compareOrder(parsed.order, selectedTag.order) > 0) { - selected = release; - selectedTag = parsed; - } - } - return selected; -} - -export function cliReleaseModel(releases, requestedChannel) { - const channel = normalizePublicReleaseChannel(requestedChannel); - const release = selectCLIRelease(releases, channel); - if (!release) return null; - const parsed = parsePublicTag(release.tag_name); - if (!parsed) return null; - const assets = releaseAssetMap(release); - if (!assets) return null; - const releaseURL = `https://github.com/esengine/DeepSeek-Reasonix/releases/tag/${parsed.tag}`; - const exactChangelogURL = `https://reasonix.io/changelog/${parsed.tag}/`; - const changelogURL = release.release_notes_url === exactChangelogURL - ? exactChangelogURL - : "https://reasonix.io/changelog/"; - return { - channel, - version: parsed.tag, - displayVersion: parsed.tag.slice(1), - assets, - releaseURL, - changelogURL, - }; -} - -function desktopAssetBases(parsed) { - const tag = `desktop-${parsed.tag}`; - return [ - `https://dl.reasonix.io/${tag}/`, - `https://github.com/esengine/DeepSeek-Reasonix/releases/download/${tag}/`, - `https://github.com/esengine/DeepSeek-Reasonix/releases/download/${parsed.tag}/`, - ]; -} - -function normalizeDesktopManifest(manifest, requestedChannel) { - const channel = normalizePublicReleaseChannel(requestedChannel); - const parsed = parsePublicTag(manifest?.version); - if ( - !parsed || - parsed.channel !== channel || - manifest?.download_page !== DESKTOP_DOWNLOAD_PAGE - ) { - return null; - } - - const allowedBases = desktopAssetBases(parsed); - let selectedBase = ""; - for (const [group, key, name] of DESKTOP_ASSETS) { - const asset = manifest?.[group]?.[key]; - if ( - !asset || - typeof asset !== "object" || - Array.isArray(asset) || - !Number.isSafeInteger(asset.size) || - asset.size <= 0 || - asset.size > MAX_RELEASE_ASSET_SIZE || - typeof asset.sha256 !== "string" || - !SHA256.test(asset.sha256) - ) { - return null; - } - - const rawURL = typeof asset.url === "string" ? asset.url : ""; - const url = safeHTTPSURL(rawURL); - const base = allowedBases.find((candidate) => rawURL === candidate + name); - if ( - !url || - !base || - url.href !== rawURL || - asset.sig !== `${rawURL}.minisig` || - (selectedBase && selectedBase !== base) - ) { - return null; - } - selectedBase = base; - } - return selectedBase ? { parsed } : null; -} - -export function desktopReleaseModel(manifest, requestedChannel) { - const normalized = normalizeDesktopManifest(manifest, requestedChannel); - if (!normalized) return null; - const { parsed } = normalized; - const assets = Object.fromEntries(DESKTOP_ASSETS.map(([group, key, name]) => [ - name, - manifest[group][key].url, - ])); - return { - channel: parsed.channel, - version: parsed.tag, - displayVersion: parsed.tag.slice(1), - assets, - changelogURL: manifest.release_notes_url === `https://reasonix.io/changelog/${parsed.tag}/` - ? manifest.release_notes_url - : "https://reasonix.io/changelog/", - }; -} - -// Accept both historical desktop-v* releases and the combined v* release. -export function desktopGitHubReleaseModel(release) { - const match = typeof release?.tag_name === "string" - ? release.tag_name.match(OFFICIAL_DESKTOP_RELEASE_TAG) - : null; - if (!match || release?.draft !== false || release?.prerelease !== false) return null; - - const tag = release.tag_name; - const found = {}; - const seen = new Set(); - for (const asset of Array.isArray(release.assets) ? release.assets : []) { - const name = String(asset?.name || ""); - if (!DESKTOP_ASSET_NAMES.has(name)) continue; - if (seen.has(name)) return null; - seen.add(name); - const rawURL = typeof asset?.browser_download_url === "string" ? asset.browser_download_url : ""; - const url = safeHTTPSURL(rawURL); - const expected = `https://github.com/esengine/DeepSeek-Reasonix/releases/download/${tag}/${name}`; - if ( - !url || - url.href !== rawURL || - rawURL !== expected || - !Number.isSafeInteger(asset?.size) || - asset.size <= 0 || - asset.size > MAX_RELEASE_ASSET_SIZE - ) { - return null; - } - found[name] = rawURL; - } - if (DESKTOP_ASSETS.some(([, , name]) => !found[name])) return null; - - return { - channel: "stable", - version: match[1], - displayVersion: match[1].slice(1), - assets: Object.fromEntries(DESKTOP_ASSETS.map(([, , name]) => [name, found[name]])), - changelogURL: "https://reasonix.io/changelog/", - }; -} - -export async function fetchFirstJSON(urls, fetchImpl = fetch, accept = () => true) { - const failures = []; - for (const url of urls) { - try { - const response = await fetchImpl(url, { cache: "no-cache" }); - if (!response.ok) throw new Error(`${response.status} ${response.statusText}`.trim()); - const payload = await response.json(); - if (!accept(payload)) throw new Error("invalid release data"); - return payload; - } catch (error) { - failures.push(`${url}: ${String(error?.message || error)}`); - } - } - throw new Error(`release data unavailable (${failures.join("; ")})`); -} diff --git a/site/src/scripts/release-channels.test.mjs b/site/src/scripts/release-channels.test.mjs deleted file mode 100644 index 1eada8b951..0000000000 --- a/site/src/scripts/release-channels.test.mjs +++ /dev/null @@ -1,378 +0,0 @@ -import { test } from "node:test"; -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import { - CLI_RELEASE_ASSETS, - cliUpgradeCommand, - cliReleaseModel, - desktopGitHubReleaseModel, - desktopReleaseModel, - fetchFirstJSON, - releaseAssetMap, - releaseVersionLabel, - selectCLIRelease, -} from "./release-channels.js"; - -function cliAssets(tag, missing = []) { - const skip = new Set(missing); - return CLI_RELEASE_ASSETS.filter((name) => !skip.has(name)).map((name) => ({ - name, - browser_download_url: `https://github.com/esengine/DeepSeek-Reasonix/releases/download/${tag}/${name}`, - size: 42, - })); -} - -const desktopSHA256 = "a".repeat(64); - -function desktopManifest(version, base) { - const releaseBase = base || `https://dl.reasonix.io/desktop-${version}/`; - const asset = (name) => { - const url = releaseBase + name; - return { url, sig: `${url}.minisig`, size: 42, sha256: desktopSHA256 }; - }; - return { - version, - download_page: "https://reasonix.io/?download=desktop#start", - platforms: { - "darwin-arm64": asset("Reasonix-darwin-arm64.zip"), - "darwin-amd64": asset("Reasonix-darwin-amd64.zip"), - "windows-amd64": asset("Reasonix-windows-amd64-installer.exe"), - "windows-arm64": asset("Reasonix-windows-arm64-installer.exe"), - "linux-amd64": asset("Reasonix-linux-amd64.tar.gz"), - }, - native_packages: { - "linux-amd64": asset("Reasonix-linux-amd64.deb"), - }, - downloads: { - "Reasonix-darwin-universal.dmg": asset("Reasonix-darwin-universal.dmg"), - "Reasonix-windows-amd64.zip": asset("Reasonix-windows-amd64.zip"), - }, - }; -} - -function desktopGitHubRelease(version = "v1.17.21") { - const tag = `desktop-${version}`; - const names = [ - "Reasonix-darwin-arm64.zip", - "Reasonix-darwin-amd64.zip", - "Reasonix-windows-amd64-installer.exe", - "Reasonix-windows-arm64-installer.exe", - "Reasonix-linux-amd64.tar.gz", - "Reasonix-linux-amd64.deb", - "Reasonix-darwin-universal.dmg", - "Reasonix-windows-amd64.zip", - ]; - return { - tag_name: tag, - draft: false, - prerelease: false, - assets: names.map((name) => ({ - name, - browser_download_url: `https://github.com/esengine/DeepSeek-Reasonix/releases/download/${tag}/${name}`, - size: 42, - })), - }; -} - -function copy(value) { - return structuredClone(value); -} - -test("CLI always emits the official upgrade command", () => { - assert.equal(cliUpgradeCommand("stable"), "reasonix upgrade"); - assert.equal(cliUpgradeCommand("preview"), "reasonix upgrade"); - assert.equal(cliUpgradeCommand("canary"), "reasonix upgrade"); -}); - -test("release labels use a complete version or a readable fallback", () => { - assert.equal(releaseVersionLabel({ version: "v1.17.21" }), "v1.17.21"); - assert.equal(releaseVersionLabel({ version: "v1.18.0-preview.62" }), "v1.18.0-preview.62"); - assert.equal(releaseVersionLabel(null), "latest"); -}); - -test("site placeholders do not render the synthetic version vlatest", async () => { - const [home, docs, siteScript] = await Promise.all([ - readFile(new URL("../pages/index.astro", import.meta.url), "utf8"), - readFile(new URL("../pages/docs.astro", import.meta.url), "utf8"), - readFile(new URL("./site.js", import.meta.url), "utf8"), - ]); - assert.doesNotMatch(home, /v]*data-cli-asset=[^>]*\sdownload(?:[ >])/); - assert.match(home, /id="download-tab-desktop"[^>]+aria-controls="download-pane-desktop"/); - assert.match(home, /id="download-pane-cli"[^>]+role="tabpanel"[^>]+hidden/); - assert.doesNotMatch(home, /releases\/latest\/download/); - assert.doesNotMatch(siteScript, /releases\/latest\/download/); - assert.doesNotMatch(siteScript, /desktopPreviewBase/); -}); - -test("CLI strictly excludes foreign and all prereleases", () => { - const releases = [ - { tag_name: "v1.19.0-rc.1", prerelease: true, assets: cliAssets("v1.19.0-rc.1") }, - { tag_name: "v1.18.0-preview.2", prerelease: true, assets: cliAssets("v1.18.0-preview.2") }, - { tag_name: "desktop-v1.18.0", prerelease: false, assets: cliAssets("desktop-v1.18.0") }, - { tag_name: "v1.17.21", prerelease: false, assets: cliAssets("v1.17.21") }, - { tag_name: "v1.18.0-preview.12", prerelease: true, assets: cliAssets("v1.18.0-preview.12") }, - { tag_name: "v1.18.0-preview.13", prerelease: false, assets: cliAssets("v1.18.0-preview.13") }, - ]; - assert.equal(selectCLIRelease(releases, "stable")?.tag_name, "v1.17.21"); - assert.equal(selectCLIRelease(releases, "preview")?.tag_name, "v1.17.21"); -}); - -test("CLI selection rejects incomplete releases instead of synthesizing asset URLs", () => { - const releases = [ - { - tag_name: "v1.20.0", - prerelease: false, - assets: cliAssets("v1.20.0", ["reasonix-windows-arm64.zip", "SHA256SUMS"]), - }, - { - tag_name: "v1.19.5", - prerelease: false, - assets: cliAssets("v1.19.5"), - }, - ]; - assert.equal(releaseAssetMap(releases[0]), null); - assert.equal(selectCLIRelease(releases, "stable")?.tag_name, "v1.19.5"); - const model = cliReleaseModel(releases, "stable"); - assert.equal(model?.displayVersion, "1.19.5"); - assert.equal( - model?.assets["reasonix-windows-arm64.zip"], - "https://github.com/esengine/DeepSeek-Reasonix/releases/download/v1.19.5/reasonix-windows-arm64.zip", - ); - assert.equal(cliReleaseModel([releases[0]], "stable"), null); -}); - -test("CLI selection compares arbitrarily large numeric version components exactly", () => { - const releases = [ - { - tag_name: "v99999999999999999999.999.999", - prerelease: false, - assets: cliAssets("v99999999999999999999.999.999"), - }, - { - tag_name: "v100000000000000000000.0.0", - prerelease: false, - assets: cliAssets("v100000000000000000000.0.0"), - }, - ]; - assert.equal(selectCLIRelease(releases, "stable")?.tag_name, "v100000000000000000000.0.0"); -}); - -test("CLI release links are derived from the validated canonical tag", () => { - const release = { - tag_name: "v1.18.0", - prerelease: false, - html_url: "https://evil.invalid/phishing", - assets: cliAssets("v1.18.0"), - }; - assert.equal( - cliReleaseModel([release], "stable")?.releaseURL, - "https://github.com/esengine/DeepSeek-Reasonix/releases/tag/v1.18.0", - ); - assert.equal( - cliReleaseModel([release], "stable")?.changelogURL, - "https://reasonix.io/changelog/", - ); - release.release_notes_url = "https://reasonix.io/changelog/v1.18.0/"; - assert.equal(cliReleaseModel([release], "stable")?.changelogURL, release.release_notes_url); -}); - -test("CLI assets reject spoofed hosts and cross-tag URLs", () => { - const valid = { - tag_name: "v1.18.0", - prerelease: false, - assets: cliAssets("v1.18.0"), - }; - const invalidURLs = [ - "https://evil.invalid/esengine/DeepSeek-Reasonix/releases/download/v1.20.0/reasonix-darwin-amd64.tar.gz", - "https://github.com@evil.invalid/esengine/DeepSeek-Reasonix/releases/download/v1.20.0/reasonix-darwin-amd64.tar.gz", - "http://github.com/esengine/DeepSeek-Reasonix/releases/download/v1.20.0/reasonix-darwin-amd64.tar.gz", - "https://github.com/esengine/DeepSeek-Reasonix/releases/download/v1.19.0/reasonix-darwin-amd64.tar.gz", - "https://github.com/esengine/DeepSeek-Reasonix/releases/download/v1.20.0/reasonix-darwin-arm64.tar.gz", - ]; - const invalid = invalidURLs.map((browser_download_url) => { - const release = { - tag_name: "v1.20.0", - prerelease: false, - assets: cliAssets("v1.20.0"), - }; - release.assets[0].browser_download_url = browser_download_url; - return release; - }); - assert.equal(selectCLIRelease([...invalid, valid], "stable")?.tag_name, "v1.18.0"); -}); - -test("CLI assets require a bounded positive safe integer size", () => { - for (const size of [0, -1, "42", 1.5, 1073741825, Number.MAX_SAFE_INTEGER + 1, NaN, undefined]) { - const release = { - tag_name: "v1.20.0", - prerelease: false, - assets: cliAssets("v1.20.0"), - }; - release.assets[0].size = size; - assert.equal(releaseAssetMap(release), null, `size ${String(size)} must be rejected`); - } -}); - -test("CLI releases reject duplicate required asset names", () => { - const release = { - tag_name: "v1.20.0", - prerelease: false, - assets: cliAssets("v1.20.0"), - }; - release.assets.push({ ...release.assets[0] }); - assert.equal(releaseAssetMap(release), null); -}); - -test("Desktop manifests accept only official versions and old or unified asset bases", () => { - const preview = desktopManifest("v1.18.0-preview.62"); - assert.equal(desktopReleaseModel(preview, "stable"), null); - assert.equal(desktopReleaseModel(preview, "preview"), null); - - const stableR2 = desktopManifest("v1.18.0"); - assert.equal(desktopReleaseModel(stableR2, "stable")?.version, "v1.18.0"); - const githubBase = - "https://github.com/esengine/DeepSeek-Reasonix/releases/download/desktop-v1.18.0/"; - const stableGitHub = desktopManifest("v1.18.0", githubBase); - assert.equal( - desktopReleaseModel(stableGitHub, "stable")?.assets["Reasonix-linux-amd64.deb"], - `${githubBase}Reasonix-linux-amd64.deb`, - ); - const unifiedBase = "https://github.com/esengine/DeepSeek-Reasonix/releases/download/v1.18.0/"; - assert.equal(desktopReleaseModel(desktopManifest("v1.18.0", unifiedBase))?.assets["Reasonix-linux-amd64.deb"], `${unifiedBase}Reasonix-linux-amd64.deb`); -}); - -test("Desktop manifests reject hostile URLs and incomplete integrity metadata", () => { - const cases = [ - ["malicious host", (manifest) => { - const url = "https://evil.invalid/desktop-v1.18.0-preview.62/Reasonix-darwin-arm64.zip"; - Object.assign(manifest.platforms["darwin-arm64"], { url, sig: `${url}.minisig` }); - }], - ["userinfo", (manifest) => { - const url = "https://dl.reasonix.io@evil.invalid/desktop-v1.18.0-preview.62/Reasonix-darwin-arm64.zip"; - Object.assign(manifest.platforms["darwin-arm64"], { url, sig: `${url}.minisig` }); - }], - ["http", (manifest) => { - const url = "http://dl.reasonix.io/desktop-v1.18.0-preview.62/Reasonix-darwin-arm64.zip"; - Object.assign(manifest.platforms["darwin-arm64"], { url, sig: `${url}.minisig` }); - }], - ["wrong channel path", (manifest) => { - const url = "https://dl.reasonix.io/preview/Reasonix-darwin-arm64.zip"; - Object.assign(manifest.platforms["darwin-arm64"], { url, sig: `${url}.minisig` }); - }], - ["wrong filename", (manifest) => { - const url = "https://dl.reasonix.io/desktop-v1.18.0-preview.62/Reasonix-darwin-amd64.zip"; - Object.assign(manifest.platforms["darwin-arm64"], { url, sig: `${url}.minisig` }); - }], - ["missing platform", (manifest) => { - delete manifest.platforms["windows-arm64"]; - }], - ["missing website download", (manifest) => { - delete manifest.downloads["Reasonix-darwin-universal.dmg"]; - }], - ["invalid website download", (manifest) => { - manifest.downloads["Reasonix-windows-amd64.zip"].size = 0; - }], - ["bad SHA", (manifest) => { - manifest.platforms["darwin-arm64"].sha256 = "A".repeat(64); - }], - ["zero size", (manifest) => { - manifest.platforms["darwin-arm64"].size = 0; - }], - ["size above release maximum", (manifest) => { - manifest.platforms["darwin-arm64"].size = 1073741825; - }], - ["string size", (manifest) => { - manifest.platforms["darwin-arm64"].size = "42"; - }], - ["missing size", (manifest) => { - delete manifest.platforms["darwin-arm64"].size; - }], - ["bad signature URL", (manifest) => { - manifest.platforms["darwin-arm64"].sig += "?mirror=1"; - }], - ["wrong download page", (manifest) => { - manifest.download_page = "https://evil.invalid/download"; - }], - ]; - - for (const [name, mutate] of cases) { - const manifest = copy(desktopManifest("v1.18.0-preview.62")); - mutate(manifest); - assert.equal(desktopReleaseModel(manifest, "preview"), null, name); - } - - const crossVersion = desktopManifest( - "v1.18.0", - "https://dl.reasonix.io/desktop-v1.17.9/", - ); - assert.equal(desktopReleaseModel(crossVersion, "stable"), null); -}); - -test("Desktop Stable falls back to a complete exact GitHub Latest release", () => { - const release = desktopGitHubRelease(); - const model = desktopGitHubReleaseModel(release); - assert.equal(model?.version, "v1.17.21"); - assert.equal( - model?.assets["Reasonix-darwin-universal.dmg"], - "https://github.com/esengine/DeepSeek-Reasonix/releases/download/desktop-v1.17.21/Reasonix-darwin-universal.dmg", - ); - - const invalid = [ - { ...release, prerelease: true }, - { ...release, tag_name: "v1.17.21" }, - { ...release, assets: release.assets.slice(1) }, - { ...release, assets: [...release.assets, { ...release.assets[0] }] }, - ]; - const spoofed = copy(release); - spoofed.assets[0].browser_download_url = - "https://github.com.evil.invalid/esengine/DeepSeek-Reasonix/releases/download/desktop-v1.17.21/Reasonix-darwin-arm64.zip"; - invalid.push(spoofed); - for (const candidate of invalid) assert.equal(desktopGitHubReleaseModel(candidate), null); -}); - -test("release JSON fetch falls back in order", async () => { - const calls = []; - const result = await fetchFirstJSON(["https://one.invalid", "https://two.invalid"], async (url) => { - calls.push(url); - if (url.includes("one")) return { ok: false, status: 503, statusText: "Unavailable" }; - return { ok: true, json: async () => ({ version: "v1.2.3" }) }; - }); - assert.deepEqual(calls, ["https://one.invalid", "https://two.invalid"]); - assert.deepEqual(result, { version: "v1.2.3" }); -}); - -test("release JSON fetch skips a successful response that fails channel validation", async () => { - const calls = []; - const result = await fetchFirstJSON( - ["https://one.invalid", "https://two.invalid"], - async (url) => { - calls.push(url); - return { - ok: true, - json: async () => ({ version: url.includes("one") ? "v1.2.3-canary.1" : "v1.2.3-preview.1" }), - }; - }, - (payload) => payload.version === "v1.2.3-preview.1", - ); - assert.deepEqual(calls, ["https://one.invalid", "https://two.invalid"]); - assert.deepEqual(result, { version: "v1.2.3-preview.1" }); -}); - -test("Desktop JSON fetch continues after an invalid 200 response", async () => { - const invalid = desktopManifest("v1.18.0"); - invalid.platforms["darwin-arm64"].size = 0; - const valid = desktopManifest("v1.17.21"); - const calls = []; - const result = await fetchFirstJSON( - ["https://one.invalid", "https://two.invalid"], - async (url) => { - calls.push(url); - return { ok: true, json: async () => url.includes("one") ? invalid : valid }; - }, - (payload) => Boolean(desktopReleaseModel(payload)), - ); - assert.deepEqual(calls, ["https://one.invalid", "https://two.invalid"]); - assert.equal(result.version, "v1.17.21"); -}); diff --git a/site/src/scripts/safe-next.js b/site/src/scripts/safe-next.js deleted file mode 100644 index d9b5b4399f..0000000000 --- a/site/src/scripts/safe-next.js +++ /dev/null @@ -1,34 +0,0 @@ -// A post-login `next` redirect target is honoured only if it resolves — via -// full URL parsing against the real page origin, so control characters and -// protocol-relative tricks get the same normalization a browser applies -// before navigating — to a same-origin path, or to an absolute https URL -// under reasonix.io. That lets a subdomain (e.g. crash.reasonix.io) return -// here after sign-in without opening a redirect to an arbitrary host. -// -// Validating a raw string prefix (e.g. checking it starts with "/") is not -// enough: URLSearchParams decodes percent-encoding, so a value like -// "/%09/evil.example" arrives as "/\t/evil.example", which passes a naive -// prefix check but the URL parser strips the tab during navigation, leaving -// "//evil.example" — a protocol-relative redirect off-site. Parsing with -// `new URL()` first and checking the *parsed* origin/host closes that gap -// because it uses the same normalization the browser itself applies. -// -// Both branches return the fully-serialized `u.href`, never a relative -// fragment. Returning `u.pathname` would reopen the hole: dot-segment inputs -// such as "/.//evil.example" or "/a/..//evil.example" resolve to a -// same-origin URL whose *pathname* is "//evil.example", and handing that -// bare pathname back to `location.href` re-parses it as a protocol-relative -// URL to evil.example. `u.href` keeps the origin attached, so assigning it -// can never leave reasonix.io. -export function safeNext(next, origin) { - if (!next) return null; - let u; - try { - u = new URL(next, origin); - } catch { - return null; - } - if (u.origin === origin) return u.href; - if (u.protocol === "https:" && (u.host === "reasonix.io" || u.host.endsWith(".reasonix.io"))) return u.href; - return null; -} diff --git a/site/src/scripts/safe-next.test.mjs b/site/src/scripts/safe-next.test.mjs deleted file mode 100644 index d10304d5b4..0000000000 --- a/site/src/scripts/safe-next.test.mjs +++ /dev/null @@ -1,71 +0,0 @@ -import { test } from "node:test"; -import assert from "node:assert/strict"; -import { safeNext } from "./safe-next.js"; - -const ORIGIN = "https://reasonix.io"; - -// The security invariant: whatever safeNext returns, re-resolving it the way a -// browser does when it assigns `location.href` must stay on our origin or an -// allowed reasonix.io host. Asserting this (rather than a fixed string) catches -// any value that looks same-origin but re-parses off-site. -function assertLandsSomewhereSafe(returned) { - if (returned === null) return; - const landed = new URL(returned, ORIGIN); - const ok = landed.origin === ORIGIN || landed.host === "reasonix.io" || landed.host.endsWith(".reasonix.io"); - assert.ok(ok, `returned ${JSON.stringify(returned)} re-resolves off-site to ${landed.href}`); -} - -test("same-origin path passes through as an absolute same-origin URL", () => { - const got = safeNext("/account/settings?x=1#y", ORIGIN); - assert.equal(got, "https://reasonix.io/account/settings?x=1#y"); - assertLandsSomewhereSafe(got); -}); - -test("allowed reasonix.io subdomain passes through", () => { - const got = safeNext("https://crash.reasonix.io/x", ORIGIN); - assert.equal(got, "https://crash.reasonix.io/x"); - assertLandsSomewhereSafe(got); -}); - -test("empty/missing next", () => { - assert.equal(safeNext("", ORIGIN), null); - assert.equal(safeNext(null, ORIGIN), null); -}); - -test("rejects a plain protocol-relative redirect", () => { - assert.equal(safeNext("//evil.example", ORIGIN), null); -}); - -test("rejects a backslash-prefixed redirect", () => { - assert.equal(safeNext("/\\evil.example", ORIGIN), null); - assert.equal(safeNext("/\\/evil.example", ORIGIN), null); -}); - -test("rejects control characters (as decoded by URLSearchParams) smuggling a protocol-relative redirect", () => { - // URLSearchParams.get() decodes %09/%0A/%0D before this function ever sees - // the value, e.g. "?next=/%09/evil.example" arrives as "/\t/evil.example". - for (const c of ["\t", "\n", "\r"]) { - assert.equal(safeNext(`/${c}/evil.example`, ORIGIN), null, JSON.stringify(c)); - } -}); - -test("dot-segment inputs that normalize to a //host pathname do not escape", () => { - // These resolve to a same-origin URL whose pathname is "//evil.example". - // Returning the bare pathname would re-parse as a protocol-relative redirect; - // returning the absolute href keeps them on reasonix.io. Assert end to end. - for (const p of ["/.//evil.example", "/a/..//evil.example", "/..//evil.example", "/%2e//evil.example"]) { - const got = safeNext(decodeURIComponent(p), ORIGIN); - assert.notEqual(got, null, p); - assert.equal(new URL(got, ORIGIN).origin, ORIGIN, `${p} -> ${got}`); - assertLandsSomewhereSafe(got); - } -}); - -test("rejects an unrelated https host and non-https schemes", () => { - assert.equal(safeNext("https://evil.example/", ORIGIN), null); - assert.equal(safeNext("javascript:alert(1)", ORIGIN), null); -}); - -test("rejects a reasonix.io-lookalike host", () => { - assert.equal(safeNext("https://reasonix.io.evil.example/", ORIGIN), null); -}); diff --git a/site/src/scripts/site.js b/site/src/scripts/site.js deleted file mode 100644 index 08a3015ed0..0000000000 --- a/site/src/scripts/site.js +++ /dev/null @@ -1,334 +0,0 @@ -import { downloadPaneFromURL, downloadURLForPane } from "./download-link.js"; -import { - cliReleaseModel, - cliUpgradeCommand, - desktopGitHubReleaseModel, - desktopReleaseModel, - fetchFirstJSON, - releaseVersionLabel, -} from "./release-channels.js"; -import { initTheme } from "./theme.js"; -import { initMobileNav } from "./mobile-nav.js"; - -// Reasonix site — vanilla interactions -(function () { - initTheme(); - initMobileNav(); - const motionOK = () => - document.body.dataset.motion === "rich" && - !window.matchMedia("(prefers-reduced-motion: reduce)").matches; - - const nav = document.querySelector(".nav"); - if (nav) { - const onScroll = () => nav.classList.toggle("scrolled", window.scrollY > 12); - window.addEventListener("scroll", onScroll, { passive: true }); - onScroll(); - } - - const revealEls = Array.from(document.querySelectorAll(".reveal")); - const inView = (el, factor) => - el.getBoundingClientRect().top < window.innerHeight * (factor || 0.95); - - const term = document.querySelector(".term"); - const lines = Array.from(document.querySelectorAll(".term-body .tl")); - let played = false; - const playTerm = () => { - if (played) return; - played = true; - const fire = () => document.dispatchEvent(new CustomEvent("rx:term-played")); - if (!motionOK()) { - lines.forEach((l) => l.classList.add("on")); - fire(); - return; - } - lines.forEach((l, i) => setTimeout(() => l.classList.add("on"), 350 + i * 520)); - setTimeout(fire, 350 + Math.max(0, lines.length - 2) * 520); - }; - - let sweepQueued = false; - const sweep = () => { - sweepQueued = false; - revealEls.forEach((el) => { - if (!el.classList.contains("in") && inView(el, 0.95)) el.classList.add("in"); - }); - if (term && !played && inView(term, 0.85)) playTerm(); - }; - const queueSweep = () => { - if (sweepQueued) return; - sweepQueued = true; - requestAnimationFrame(sweep); - }; - window.addEventListener("scroll", queueSweep, { passive: true }); - window.addEventListener("resize", queueSweep, { passive: true }); - window.addEventListener("load", queueSweep); - sweep(); - setTimeout(sweep, 400); - - /* contributors marquee — duplicate the server-rendered set for a seamless loop */ - document.querySelectorAll(".crew-row").forEach((row) => { - const set = row.querySelector(".crew-set"); - if (set) row.appendChild(set.cloneNode(true)); - }); - - /* download / channel tabs */ - const tabs = Array.from(document.querySelectorAll(".dl-tab")); - const panes = Array.from(document.querySelectorAll(".dl-pane")); - const activatePane = (name) => { - tabs.forEach((b) => { - const active = b.dataset.pane === name; - b.classList.toggle("active", active); - b.setAttribute("aria-selected", active ? "true" : "false"); - b.tabIndex = active ? 0 : -1; - }); - panes.forEach((p) => { - const active = p.dataset.pane === name; - p.classList.toggle("active", active); - p.hidden = !active; - }); - }; - tabs.forEach((tab) => { - tab.addEventListener("click", () => { - activatePane(tab.dataset.pane); - reflectPaneURL(tab.dataset.pane); - }); - tab.addEventListener("keydown", (event) => { - const current = tabs.indexOf(tab); - let next = -1; - if (event.key === "ArrowRight" || event.key === "ArrowDown") next = (current + 1) % tabs.length; - else if (event.key === "ArrowLeft" || event.key === "ArrowUp") next = (current - 1 + tabs.length) % tabs.length; - else if (event.key === "Home") next = 0; - else if (event.key === "End") next = tabs.length - 1; - if (next < 0) return; - event.preventDefault(); - const nextTab = tabs[next]; - activatePane(nextTab.dataset.pane); - reflectPaneURL(nextTab.dataset.pane); - nextTab.focus(); - }); - }); - - /* OS detection — hero download button + card badge + highlight */ - const ua = navigator.userAgent; - const os = /Windows/i.test(ua) ? "win" : /Mac|iPhone|iPad/i.test(ua) ? "mac" : /Linux|X11/i.test(ua) ? "linux" : "mac"; - const osNames = { mac: "macOS", win: "Windows", linux: "Linux" }; - document.querySelectorAll("[data-os-dl] .os-name").forEach((s) => (s.textContent = osNames[os])); - const osCard = document.querySelector('.os-card[data-os="' + os + '"]'); - if (osCard) { - osCard.classList.add("detected"); - const chip = document.createElement("span"); - chip.className = "os-chip"; - chip.innerHTML = 'your OS当前系统'; - osCard.appendChild(chip); - } - - const flashOSCard = () => { - if (!osCard) return; - osCard.classList.remove("flash"); - void osCard.offsetWidth; - setTimeout(() => osCard.classList.add("flash"), 450); - setTimeout(() => osCard.classList.remove("flash"), 2600); - }; - - const requestedPane = downloadPaneFromURL(window.location.href); - const legacyChannelURL = new URL(window.location.href); - if (legacyChannelURL.searchParams.has("channel")) { - legacyChannelURL.searchParams.delete("channel"); - window.history.replaceState(null, "", legacyChannelURL.href); - } - if (requestedPane) { - activatePane(requestedPane); - if (requestedPane === "desktop") flashOSCard(); - requestAnimationFrame(() => { - document.getElementById("start")?.scrollIntoView({ block: "start" }); - queueSweep(); - }); - } - - /* links that deep-link into a specific download tab */ - document.querySelectorAll("[data-goto]").forEach((a) => { - a.addEventListener("click", (event) => { - event.preventDefault(); - activatePane(a.dataset.goto); - reflectPaneURL(a.dataset.goto); - if (a.hasAttribute("data-os-dl")) flashOSCard(); - document.getElementById("start")?.scrollIntoView({ block: "start" }); - setTimeout(queueSweep, 500); - }); - }); - - /* language switch */ - const LANG_KEY = "reasonix-lang"; - const langBtns = Array.from(document.querySelectorAll(".lang-switch button")); - const setLang = (l, alignHash) => { - document.body.dataset.lang = l; - document.documentElement.lang = l === "zh" ? "zh-CN" : "en"; - const t = document.body.dataset[l === "zh" ? "titleZh" : "titleEn"]; - if (t) document.title = t; - langBtns.forEach((b) => b.classList.toggle("active", b.dataset.lang === l)); - try { localStorage.setItem(LANG_KEY, l); } catch (e) {} - if (alignHash && window.location.hash) { - const target = document.getElementById(window.location.hash.slice(1)); - if (target) requestAnimationFrame(() => target.scrollIntoView({ block: "start" })); - } - }; - langBtns.forEach((b) => b.addEventListener("click", () => setLang(b.dataset.lang))); - let savedLang = ""; - try { savedLang = localStorage.getItem(LANG_KEY) || ""; } catch (e) {} - const requestedLang = new URLSearchParams(window.location.search).get("lang"); - const initialLang = requestedLang === "zh" || requestedLang === "en" - ? requestedLang - : savedLang || ((navigator.language || "").toLowerCase().startsWith("zh") ? "zh" : "en"); - setLang(initialLang, true); - - /* docs scrollspy */ - const sideLinks = Array.from(document.querySelectorAll(".docs-side a[href^='#']")); - if (sideLinks.length) { - const targets = sideLinks - .map((a) => document.getElementById(a.getAttribute("href").slice(1))) - .filter(Boolean) - // Sidebar links are grouped editorially, so their order differs from the - // page order. The spy below picks the last section past the 140px line, - // which is only correct when targets are sorted in document order. - .sort((a, b) => - a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1); - const setActive = (id) => - sideLinks.forEach((a) => { - const on = a.getAttribute("href") === "#" + id; - a.classList.toggle("active", on); - if (on) a.setAttribute("aria-current", "true"); - else a.removeAttribute("aria-current"); - }); - // While a click smooth-scrolls to a section, pin the highlight to it so it - // doesn't sweep through every section scrolled past on the way. scrollend - // releases the pin when the scroll settles — on arrival or when the user - // takes over (wheel, touch, keyboard, scrollbar). Browsers without - // scrollend just skip pinning: correct destination, no sweep suppression. - let pinned = null; - const spy = () => { - if (pinned) return; - let current = targets[0]; - for (const t of targets) if (t.getBoundingClientRect().top < 140) current = t; - if (current) setActive(current.id); - }; - if ("onscrollend" in window) { - const ids = new Set(targets.map((t) => t.id)); - document.querySelectorAll("a[href^='#']").forEach((a) => { - const id = a.getAttribute("href").slice(1); - if (ids.has(id)) a.addEventListener("click", () => { pinned = id; setActive(id); }); - }); - window.addEventListener("scrollend", () => { pinned = null; spy(); }, { passive: true }); - } - window.addEventListener("scroll", spy, { passive: true }); - spy(); - } - - /* copy-to-clipboard */ - document.querySelectorAll("[data-copy]").forEach((btn) => { - btn.addEventListener("click", () => { - const text = btn.getAttribute("data-copy"); - const done = () => { - btn.classList.add("copied"); - const prev = btn.textContent; - btn.textContent = "Copied"; - setTimeout(() => { btn.classList.remove("copied"); btn.textContent = prev; }, 1600); - }; - if (navigator.clipboard && navigator.clipboard.writeText) { - navigator.clipboard.writeText(text).then(done).catch(done); - } else done(); - }); - }); - - /* public official releases */ - const releaseModels = { desktop: null, cli: null }; - const releasesPage = "https://github.com/esengine/DeepSeek-Reasonix/releases"; - const reflectPaneURL = (surface) => { - const nextURL = downloadURLForPane(window.location.href, surface, ""); - if (nextURL) window.history.replaceState(null, "", nextURL); - }; - - // npm / Homebrew / generic product chips track the CLI stable line only. - // Desktop and CLI download panes render their own versions via - // [data-release-version=""]; never let Desktop and CLI race on .rxv. - const updateCLIPackageVersion = (model) => { - if (!model) return; - document.querySelectorAll(".rxv").forEach((element) => { element.textContent = releaseVersionLabel(model); }); - document.querySelectorAll("a.rxnotes").forEach((link) => { - link.href = new URL("changelog/v" + model.displayVersion + "/", window.location.origin + "/").href; - }); - }; - - // Never synthesize public artifact URLs. If every required asset is not - // attested by live release data, fall back to the release list instead of a - // plausible-looking URL that may 404. - const fallbackReleaseURL = () => releasesPage; - - const renderReleaseSurface = (surface) => { - const model = releaseModels[surface]; - document.querySelectorAll('[data-release-version="' + surface + '"]').forEach((element) => { - element.textContent = releaseVersionLabel(model); - }); - document.querySelectorAll('[data-release-notes="' + surface + '"]').forEach((link) => { - const path = model?.changelogURL ? new URL(model.changelogURL).pathname : "changelog/"; - link.href = new URL(path, window.location.origin + "/").href; - }); - - const assetAttribute = "data-" + surface + "-asset"; - document.querySelectorAll("[" + assetAttribute + "]").forEach((link) => { - const asset = link.getAttribute(assetAttribute); - const target = model?.assets?.[asset] || fallbackReleaseURL(); - link.href = target; - if (target === releasesPage) link.removeAttribute("download"); - else link.setAttribute("download", ""); - }); - - if (surface === "cli") { - const command = cliUpgradeCommand(); - document.querySelectorAll('[data-release-command="cli"]').forEach((element) => { element.textContent = command; }); - document.querySelectorAll('.release-upgrade-command [data-copy]').forEach((button) => { button.dataset.copy = command; }); - } - }; - - renderReleaseSurface("desktop"); - renderReleaseSurface("cli"); - if (requestedPane) reflectPaneURL(requestedPane); - - fetchFirstJSON([ - "https://dl.reasonix.io/latest/latest.json", - "https://crash.reasonix.io/v1/desktop/releases/stable/latest.json", - ], fetch, (manifest) => Boolean(desktopReleaseModel(manifest))) - .then((manifest) => desktopReleaseModel(manifest)) - .catch(() => fetchFirstJSON( - ["https://api.github.com/repos/esengine/DeepSeek-Reasonix/releases/latest"], - fetch, - (release) => Boolean(desktopGitHubReleaseModel(release)), - ).then(desktopGitHubReleaseModel)) - .then((model) => { - if (!model) return; - releaseModels.desktop = model; - renderReleaseSurface("desktop"); - }) - .catch(() => {}); - - let githubCLIReleases; - const fallbackCLIReleases = () => { - githubCLIReleases ??= fetchFirstJSON([ - "https://api.github.com/repos/esengine/DeepSeek-Reasonix/releases?per_page=100", - ]).catch(() => null); - return githubCLIReleases; - }; - fetchFirstJSON( - ["https://crash.reasonix.io/v1/cli/releases/stable/latest.json"], - fetch, - (payload) => Boolean(cliReleaseModel(Array.isArray(payload) ? payload : [payload])), - ) - .catch(() => fallbackCLIReleases()) - .then((payload) => { - const releases = Array.isArray(payload) ? payload : payload ? [payload] : []; - const model = cliReleaseModel(releases); - if (!model) return; - releaseModels.cli = model; - updateCLIPackageVersion(model); - renderReleaseSurface("cli"); - }) - .catch(() => {}); -})(); diff --git a/site/src/scripts/skills-layout-contract.test.mjs b/site/src/scripts/skills-layout-contract.test.mjs deleted file mode 100644 index 5b32ad8978..0000000000 --- a/site/src/scripts/skills-layout-contract.test.mjs +++ /dev/null @@ -1,48 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import test from "node:test"; - -const source = () => readFile(new URL("../pages/skills.astro", import.meta.url), "utf8"); - -test("the registry publish CTA does not inherit the publish panel layout", async () => { - const page = await source(); - - assert.match(page, /class="btn btn-dark reg-publish-cta" id="publish-open"/); - assert.match(page, /