diff --git a/package-lock.json b/package-lock.json index fe4fe6bfd..9a82b4359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "@testing-library/react": "16.3.2", "@types/node": "26.1.2", "@types/react": "19.2.17", - "@types/react-dom": "^19.2.4", + "@types/react-dom": "19.2.4", "@typescript-eslint/parser": "8.64.0", "@vitejs/plugin-react": "6.0.3", "electron": "43.3.0", @@ -42,7 +42,7 @@ "globals": "17.7.0", "jsdom": "30.0.1", "react": "19.2.8", - "react-dom": "^19.2.8", + "react-dom": "19.2.8", "typescript": "7.0.2", "vitest": "4.1.10", "zod": "3.25.76" @@ -94,7 +94,7 @@ "@opentelemetry/context-zone": "2.9.0", "@opentelemetry/exporter-trace-otlp-http": "0.220.0", "@opentelemetry/instrumentation": "0.221.0", - "@opentelemetry/instrumentation-document-load": "^0.66.0", + "@opentelemetry/instrumentation-document-load": "0.66.0", "@opentelemetry/instrumentation-fetch": "0.220.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/sdk-trace-web": "2.9.0", @@ -103,12 +103,12 @@ "@vitejs/plugin-react": "6.0.3", "qrcode.react": "4.2.0", "react": "19.2.8", - "react-dom": "^19.2.8", + "react-dom": "19.2.8", "recharts": "2.15.4", "streamdown": "2.5.0", "tinykeys": "4.0.0", "typescript": "7.0.2", - "vite": "^8.2.0" + "vite": "8.2.0" }, "devDependencies": { "@testing-library/jest-dom": "7.0.0", @@ -116,7 +116,7 @@ "@testing-library/user-event": "14.6.3", "@types/node": "26.1.2", "@types/react": "19.2.17", - "@types/react-dom": "^19.2.4", + "@types/react-dom": "19.2.4", "@typescript-eslint/parser": "8.64.0", "eslint": "10.8.0", "globals": "17.7.0", @@ -816,11 +816,564 @@ "@astrojs/react": "^6.0.1", "astro": "^7.2.0", "react": "19.2.8", - "react-dom": "^19.0.0" + "react-dom": "19.2.8" + }, + "devDependencies": { + "@types/react": "19.2.17", + "@types/react-dom": "19.2.4" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.4.1.tgz", + "integrity": "sha512-ZYVDW1P58OXyxqZbOMp+/2U9KA7y2esIx9r4pWdpZ/l6fCZhaw4ul+D7EgpRVxYLkyTWqzANbTTUFGPFP8zDHA==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-android-arm64": "0.4.1", + "@astrojs/compiler-binding-darwin-arm64": "0.4.1", + "@astrojs/compiler-binding-darwin-x64": "0.4.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.4.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.4.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.4.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.4.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.4.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.4.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.4.1" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.4.1.tgz", + "integrity": "sha512-7iwXcU+hB60Y1SvOfnWHNioT72gDsDQKaDipXh2Onwp/TvQMozhbvhy13wJR8Af940a0h6PbddCeJFpj791UDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.4.1.tgz", + "integrity": "sha512-pifjICos49RXhSVKSDu5gDB0/8j0O7DmxSp1DaWW2PyLG5ekwSkcrfOZto5JqhdI7QYMZB3XOiXpsdOXpS4npA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.4.1.tgz", + "integrity": "sha512-hsZMlNWc6LqWHh9LlSwTq1/XCY7pxA5rkkKIdZRV8mgbOz9OwLvjEoe5Jry13eIZjMUQO8XnQyzk8o/Pjw2YFA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.4.1.tgz", + "integrity": "sha512-a3EW27f+Z9uf57vYmpLgUriA1y9wDhKz57PT8D8XlFZt2HZEWhUxKuxI1jvKVI9p8okYee11WXEm/FHY1G9yoQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.4.1.tgz", + "integrity": "sha512-XruPTKB/SS4DFzeAjQ1ZyM0ieHDjapHkOSnnzRApZ4FXY2YAI7UY3mETjfJiIS/acyZyrnPH5jObv1gATTdUJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.4.1.tgz", + "integrity": "sha512-E8j7lGanqNpudtkUbsFaOLJhmwFe4Ecqux7K9hkj4wULIPNZRM2bYZNcMSj8r1oWvaUiwZl8LaaNwv3+14jqhw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.4.1.tgz", + "integrity": "sha512-vNLxIv41ZE+nmPFtw24cRW5ZXG+ZPcAGtgigtjCP8lvcxKI7u2GrXoMsCgEH5fMw8WCEJpwLvsVBg15rJKAkyA==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.2.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.4.1.tgz", + "integrity": "sha512-/xTDgRsFDoTh0/+KFXJ74DY4Jqn8CoSHwa8UP5RAblHfnRHkenwfSl4zYDET61O9vXKLk09UzHjjq09yP20/AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.4.1.tgz", + "integrity": "sha512-0x5J6iHZO0Fjo/CVzoIbXKzWnGESftDbEUQ/oXQ61HhUAFoR7+T1jfToZSNAS+gYyBXHSTpMWYC7lzarbhClcg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/compiler-rs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.4.1.tgz", + "integrity": "sha512-//NmAuRhy7eU9iP0ceI5Pymy55M+nUZ//kS6XeOyhBWdDib2KbJOyFaVJ52k7sDkJwTKVox7oPu3SpYiVnGm5A==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-binding": "0.4.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "apps/website/node_modules/@astrojs/internal-helpers": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.11.0.tgz", + "integrity": "sha512-3rzxJ+xbo0+8YyqOzLziIN32wmsHdCjEVz2sGOpRxJ+Ben/KiLph4ItxBy1abEL+E8fkRzqjg0rfXmaHJGw9JA==", + "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" + } + }, + "apps/website/node_modules/@astrojs/markdown-satteri": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.1.tgz", + "integrity": "sha512-EniHbFNa6SQHDih7JnpPos3NWXO6hdt4raBcOosfGmlfc3gP9CI/sESA3VOf1PgJZ7SFfewlZW9Livn0JugEZg==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.11.0", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "satteri": "^0.10.3" + } + }, + "apps/website/node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "apps/website/node_modules/@bruits/satteri-darwin-x64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "apps/website/node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "apps/website/node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "apps/website/node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "apps/website/node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "apps/website/node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "apps/website/node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "apps/website/node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "apps/website/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "apps/website/node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", + "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", + "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.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "apps/website/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" + } + }, + "apps/website/node_modules/astro": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.3.3.tgz", + "integrity": "sha512-NF08hk3edFkVmr9avf9HW/rQyf6NrpbVDyYj2cVN3JfijDhfJYh1ivWVTY5PUd5+rRZn/Vtu4iaeyNlP0Iv6mg==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-rs": "^0.4.0", + "@astrojs/internal-helpers": "0.11.0", + "@astrojs/markdown-satteri": "0.4.1", + "@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": "^9.0.0", + "dset": "^3.1.4", + "es-module-lexer": "^2.0.0", + "esbuild": "^0.28.0", + "find-proc": "0.2.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", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "svgo": "^4.0.2", + "tinyclip": "^0.1.12", + "tinyexec": "^1.0.4", + "tinyglobby": "^0.2.15", + "ultrahtml": "^1.6.0", + "unifont": "~0.7.5", + "unstorage": "^1.17.5", + "verkit": "^0.4.0", + "vite": "^8.0.13", + "vitefu": "^1.1.2", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^22.0.0", + "zod": "^4.5.4" + }, + "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.35.4" + }, + "peerDependencies": { + "@astrojs/markdown-remark": "^7.3.0" + }, + "peerDependenciesMeta": { + "@astrojs/markdown-remark": { + "optional": true + } + } + }, + "apps/website/node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "apps/website/node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "apps/website/node_modules/p-limit": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.3.tgz", + "integrity": "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "apps/website/node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" + } + }, + "apps/website/node_modules/undici": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", + "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "apps/website/node_modules/unifont": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.5.tgz", + "integrity": "sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ohash": "^2.0.11", + "undici": "^8.0.0" + } + }, + "apps/website/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" + } + }, + "apps/website/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" }, - "devDependencies": { - "@types/react": "19.2.17", - "@types/react-dom": "^19.0.3" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "apps/website/node_modules/zod": { + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@0x-copilot/api-types": { @@ -918,244 +1471,22 @@ "node": "^22.13.0 || >=24.0.0" } }, - "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-wasm32-wasi/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/@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==", + "node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.4.1.tgz", + "integrity": "sha512-Wtx2DZORuNTLASLLZ8hlrjFaJe1LUloatcCn9EPq7knBhRpjMGXeJANIJMeBZG4igvz7x+3nyAJM2iwCSW9xog==", "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" + "android" ], "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", @@ -1545,165 +1876,31 @@ "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/@braintree/sanitize-url": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", - "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", - "license": "MIT" - }, - "node_modules/@bramus/specificity": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", - "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "css-tree": "^3.0.0" - }, - "bin": { - "specificity": "bin/cli.js" - } - }, - "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" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.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/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" }, - "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" - ], + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } }, "node_modules/@capsizecss/unpack": { "version": "4.0.1", @@ -2813,9 +3010,9 @@ } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz", + "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==", "cpu": [ "arm64" ], @@ -2831,13 +3028,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" + "@img/sharp-libvips-darwin-arm64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz", + "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==", "cpu": [ "x64" ], @@ -2853,20 +3050,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" + "@img/sharp-libvips-darwin-x64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz", + "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==", "license": "Apache-2.0", "optional": true, "os": [ "freebsd" ], "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.4" }, "engines": { "node": ">=20.9.0" @@ -2876,9 +3073,9 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz", + "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==", "cpu": [ "arm64" ], @@ -2892,9 +3089,9 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz", + "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==", "cpu": [ "x64" ], @@ -2908,15 +3105,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz", + "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==", "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -2927,15 +3121,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz", + "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==", "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -2946,15 +3137,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz", + "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==", "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -2965,15 +3153,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz", + "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==", "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -2984,15 +3169,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz", + "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==", "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -3003,15 +3185,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz", + "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==", "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -3022,15 +3201,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz", + "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -3041,15 +3217,12 @@ } }, "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==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz", + "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==", "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -3060,15 +3233,12 @@ } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz", + "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==", "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3081,19 +3251,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" + "@img/sharp-libvips-linux-arm": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz", + "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==", "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3106,19 +3273,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" + "@img/sharp-libvips-linux-arm64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz", + "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==", "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3131,19 +3295,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" + "@img/sharp-libvips-linux-ppc64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz", + "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==", "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3156,19 +3317,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" + "@img/sharp-libvips-linux-riscv64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz", + "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==", "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3181,19 +3339,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" + "@img/sharp-libvips-linux-s390x": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz", + "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==", "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3206,19 +3361,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" + "@img/sharp-libvips-linux-x64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz", + "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3231,19 +3383,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz", + "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==", "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3256,17 +3405,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + "@img/sharp-libvips-linuxmusl-x64": "1.3.3" } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz", + "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==", "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.11.1" + "@emnapi/runtime": "^1.11.3" }, "engines": { "node": ">=20.9.0" @@ -3275,17 +3424,27 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-wasm32/node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz", + "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==", "cpu": [ "wasm32" ], "license": "Apache-2.0", "optional": true, "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.4" }, "engines": { "node": ">=20.9.0" @@ -3295,9 +3454,9 @@ } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz", + "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==", "cpu": [ "arm64" ], @@ -3314,9 +3473,9 @@ } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz", + "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==", "cpu": [ "ia32" ], @@ -3333,9 +3492,9 @@ } }, "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==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz", + "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==", "cpu": [ "x64" ], @@ -5967,9 +6126,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", - "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", "dev": true, "license": "MIT", "engines": { @@ -6357,152 +6516,6 @@ "node": ">=12" } }, - "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/astro/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/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/astro/node_modules/p-limit": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", - "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.2.1" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/astro/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/astro/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/astro/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/async-exit-hook": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", @@ -6588,9 +6601,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.43", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz", - "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", + "version": "2.11.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz", + "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -6645,9 +6658,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.6.tgz", - "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==", + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", "funding": [ { "type": "opencollective", @@ -6664,11 +6677,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.42", - "caniuse-lite": "^1.0.30001803", - "electron-to-chromium": "^1.5.389", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" @@ -6778,9 +6791,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "funding": [ { "type": "opencollective", @@ -7114,16 +7127,16 @@ } }, "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==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "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" + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" }, "funding": { "url": "https://github.com/sponsors/fb55" @@ -7143,9 +7156,9 @@ } }, "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==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -7928,15 +7941,6 @@ "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/dmg-builder": { "version": "26.15.3", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.15.3.tgz", @@ -8196,9 +8200,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.393", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.393.tgz", - "integrity": "sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg==", + "version": "1.5.433", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.433.tgz", + "integrity": "sha512-5lCAbyZBjtmUt/RAGHRqrL2q0oEFRThDAsZHHDn9XHa89Qw7gMYOeSicBTy+AHfvo0r6vwsZvqNJTQIQy1BLzA==", "license": "ISC" }, "node_modules/electron-updater": { @@ -8763,9 +8767,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -8818,6 +8822,15 @@ "node": ">=16.0.0" } }, + "node_modules/find-proc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/find-proc/-/find-proc-0.2.0.tgz", + "integrity": "sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -9261,24 +9274,6 @@ "node": ">= 0.4" } }, - "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", @@ -9839,9 +9834,9 @@ "license": "MIT" }, "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==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -11697,9 +11692,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "version": "2.0.56", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.56.tgz", + "integrity": "sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==", "license": "MIT", "engines": { "node": ">=18" @@ -13042,33 +13037,10 @@ "truncate-utf8-bytes": "^1.0.0" } }, - "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==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -13131,9 +13103,9 @@ } }, "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz", + "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==", "license": "Apache-2.0", "optional": true, "dependencies": { @@ -13148,31 +13120,31 @@ "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" + "@img/sharp-darwin-arm64": "0.35.4", + "@img/sharp-darwin-x64": "0.35.4", + "@img/sharp-freebsd-wasm32": "0.35.4", + "@img/sharp-libvips-darwin-arm64": "1.3.3", + "@img/sharp-libvips-darwin-x64": "1.3.3", + "@img/sharp-libvips-linux-arm": "1.3.3", + "@img/sharp-libvips-linux-arm64": "1.3.3", + "@img/sharp-libvips-linux-ppc64": "1.3.3", + "@img/sharp-libvips-linux-riscv64": "1.3.3", + "@img/sharp-libvips-linux-s390x": "1.3.3", + "@img/sharp-libvips-linux-x64": "1.3.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", + "@img/sharp-libvips-linuxmusl-x64": "1.3.3", + "@img/sharp-linux-arm": "0.35.4", + "@img/sharp-linux-arm64": "0.35.4", + "@img/sharp-linux-ppc64": "0.35.4", + "@img/sharp-linux-riscv64": "0.35.4", + "@img/sharp-linux-s390x": "0.35.4", + "@img/sharp-linux-x64": "0.35.4", + "@img/sharp-linuxmusl-arm64": "0.35.4", + "@img/sharp-linuxmusl-x64": "0.35.4", + "@img/sharp-webcontainers-wasm32": "0.35.4", + "@img/sharp-win32-arm64": "0.35.4", + "@img/sharp-win32-ia32": "0.35.4", + "@img/sharp-win32-x64": "0.35.4" }, "peerDependenciesMeta": { "@types/node": { @@ -13269,9 +13241,9 @@ "license": "MIT" }, "node_modules/smol-toml": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", - "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.8.0.tgz", + "integrity": "sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -13495,18 +13467,18 @@ } }, "node_modules/svgo": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", - "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", "license": "MIT", "dependencies": { "commander": "^11.1.0", - "css-select": "^5.1.0", + "css-select": "^6.0.0", "css-tree": "^3.0.1", - "css-what": "^6.1.0", + "css-what": "^7.0.0", "csso": "^5.0.5", "picocolors": "^1.1.1", - "sax": "^1.5.0" + "sax": "1.6.1" }, "bin": { "svgo": "bin/svgo.js" @@ -13919,17 +13891,6 @@ "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", @@ -14134,9 +14095,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", "funding": [ { "type": "opencollective", @@ -14243,6 +14204,18 @@ "uuid": "dist-node/bin/uuid" } }, + "node_modules/verkit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.4.1.tgz", + "integrity": "sha512-mMVzj0TXExtVdlDEq+Mzp0eyOuyznNpFobNM3uAqe3HVm/Ps2c+u17BligMkZjZCA6EiXpoon8iRTer3iu40SQ==", + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -14906,14 +14879,14 @@ "@testing-library/user-event": "14.6.3", "@types/mdast": "4.0.4", "@types/react": "19.2.17", - "@types/react-dom": "^19.2.4", + "@types/react-dom": "19.2.4", "@typescript-eslint/parser": "8.64.0", "@vitejs/plugin-react": "6.0.3", "eslint": "10.8.0", "globals": "17.7.0", "jsdom": "30.0.1", "react": "19.2.8", - "react-dom": "^19.2.8", + "react-dom": "19.2.8", "typescript": "7.0.2", "vitest": "4.1.10" }, @@ -15009,13 +14982,13 @@ "version": "0.1.0", "devDependencies": { "@types/react": "19.2.17", - "@types/react-dom": "^19.2.4", + "@types/react-dom": "19.2.4", "typescript": "7.0.2" }, "peerDependencies": { "@radix-ui/react-popover": "^1.1.23", "react": "^19.2.6", - "react-dom": "^19.2.8" + "react-dom": "^19.2.7" } }, "packages/design-system/node_modules/typescript": { @@ -15066,14 +15039,14 @@ "@testing-library/react": "16.3.2", "@testing-library/user-event": "14.6.3", "@types/react": "19.2.17", - "@types/react-dom": "^19.2.4", + "@types/react-dom": "19.2.4", "@typescript-eslint/parser": "8.64.0", "@vitejs/plugin-react": "6.0.3", "eslint": "10.8.0", "globals": "17.7.0", "jsdom": "30.0.1", "react": "19.2.8", - "react-dom": "^19.2.8", + "react-dom": "19.2.8", "typescript": "7.0.2", "vitest": "4.1.10" }, @@ -15119,7 +15092,7 @@ }, "tools/cli": { "name": "@0x-copilot/cli", - "version": "0.2.0", + "version": "0.3.0", "license": "MIT", "dependencies": { "electron": "43.3.0", diff --git a/packages/chat-surface/src/activity/ToolRunGroup.test.tsx b/packages/chat-surface/src/activity/ToolRunGroup.test.tsx index 1ed55ba45..d1c5c6bcb 100644 --- a/packages/chat-surface/src/activity/ToolRunGroup.test.tsx +++ b/packages/chat-surface/src/activity/ToolRunGroup.test.tsx @@ -136,3 +136,37 @@ describe("ToolRunGroup", () => { ); }); }); + +describe("ToolRunGroup — the digest", () => { + const DIGEST = "Searched the web · Read 3 files"; + + it("names the work a settled group folds, keeping the 'Worked for' prefix", () => { + // `Worked for` is pinned by the TR-16 journey (`label.startswith`), so the + // digest replaces only the count after it. + render(g({ digest: DIGEST })); + expect(label()).toBe(`Worked for 8.3s · ${DIGEST}`); + }); + + it("names the work a FAILED group folds too", () => { + render(g({ state: "failed", digest: DIGEST })); + expect(label()).toBe(`Failed after 8.3s · ${DIGEST}`); + }); + + it("leaves the running label alone — an open group's cards already say it", () => { + render(g({ state: "running", done: 1, total: 6, digest: DIGEST })); + expect(label()).toBe("Working · 1 of 6"); + }); + + it("falls back to the count rather than folding silently", () => { + render(g({ digest: " " })); + expect(label()).toBe("Worked for 8.3s · 3 steps"); + }); + + it("keeps the full sentence recoverable when the label ellipsizes", () => { + render(g({ digest: DIGEST })); + expect(screen.getByTestId("tool-run-group-label")).toHaveAttribute( + "title", + `Worked for 8.3s · ${DIGEST}`, + ); + }); +}); diff --git a/packages/chat-surface/src/activity/ToolRunGroup.tsx b/packages/chat-surface/src/activity/ToolRunGroup.tsx index d8af6b928..a92b9562f 100644 --- a/packages/chat-surface/src/activity/ToolRunGroup.tsx +++ b/packages/chat-surface/src/activity/ToolRunGroup.tsx @@ -48,6 +48,19 @@ export interface ToolRunGroupProps { readonly retried?: number; /** Pre-formatted elapsed (PRD-07's single formatter). `null` → omitted. */ readonly elapsed?: string | null; + /** + * WHAT the members did — "Searched the web · Read 3 files" — from + * `describeActivity`. Replaces the bare `N steps` in the SETTLED and FAILED + * labels; the running label keeps its `N of M`, because a running group is + * open and its cards are already saying this themselves. + * + * PRD-03's reference table shows the half this component originally dropped: + * Codex folds to `Worked for 26s ›`, but Claude Desktop keeps a noun — + * `Read depth.py ›`. A count tells the reader work is folded; only a noun + * tells them what it was, and a settled group is the one moment nothing else + * on screen can. + */ + readonly digest?: string | null; /** The member cards. */ readonly children?: ReactNode; /** @@ -71,9 +84,15 @@ function summaryLabel(props: { total: number; elapsed: string | null; compact: boolean; + digest: string | null; }): string { - const { state, done, total, elapsed, compact } = props; - const steps = `${total} step${total === 1 ? "" : "s"}`; + const { state, done, total, elapsed, compact, digest } = props; + // The digest wins when there is one; the count is the fallback, so a caller + // that cannot describe its members still never folds them silently. + const steps = + digest !== null && digest.trim() !== "" + ? digest + : `${total} step${total === 1 ? "" : "s"}`; if (state === "running") { return compact ? `${done}/${total}` : `Working · ${done} of ${total}`; } @@ -91,6 +110,7 @@ export function ToolRunGroup({ total, retried = 0, elapsed = null, + digest = null, children, compact = false, id, @@ -144,7 +164,7 @@ export function ToolRunGroup({ [], ); - const label = summaryLabel({ state, done, total, elapsed, compact }); + const label = summaryLabel({ state, done, total, elapsed, compact, digest }); return (
- + {/* `title` because the label ellipsizes in a narrow column, and a + sentence that names the work is worth recovering on hover. */} + {label} {/* PRD-04 territory: the red lives inside the group, not on it. This is diff --git a/packages/chat-surface/src/messages/ThinkingShimmer.test.tsx b/packages/chat-surface/src/messages/ThinkingShimmer.test.tsx index b76e30d86..490480483 100644 --- a/packages/chat-surface/src/messages/ThinkingShimmer.test.tsx +++ b/packages/chat-surface/src/messages/ThinkingShimmer.test.tsx @@ -249,3 +249,57 @@ describe("ThinkingBlock · folded activity", () => { expect(block().open).toBe(false); }); }); + +describe("ThinkingBlock — the digest", () => { + const DIGEST = "Searched the web · Dispatched 1 subagent"; + const steps = (): HTMLElement => + screen.getByTestId("cs-thinking-block-steps"); + + it("names what the folded cards did instead of counting them", () => { + // The live capture behind this: a settled turn read + // "Thought process · 2 steps" and nothing recorded the search or the + // subagent. A number says work exists; it takes a noun to say what it was. + render( + , + ); + expect(steps()).toHaveTextContent(`· ${DIGEST}`); + expect(screen.getByTestId("cs-thinking-block")).toHaveAttribute( + "data-steps", + "2", + ); + }); + + it("falls back to the count when the caller cannot describe its cards", () => { + render(); + expect(steps()).toHaveTextContent("· 2 steps"); + }); + + it("says nothing about steps when there are none, digest or not", () => { + render( + , + ); + expect(screen.queryByTestId("cs-thinking-block-steps")).toBeNull(); + }); + + it("makes the digest the ONE item that yields in a narrow column", () => { + // jsdom runs no layout, so this asserts the shrink CONTRACT that decides + // clipping order. The digest is the only unbounded string in the header; if + // it were `flex: none`, a ~335px Studio column would push the chevron — the + // only affordance this control has — off the edge instead. + render( + , + ); + expect(steps()).toHaveStyle({ + flex: "0 1 auto", + minWidth: "0", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + }); + expect(steps()).toHaveAttribute("title", DIGEST); + const summary = screen + .getByTestId("cs-thinking-block") + .querySelector("summary") as HTMLElement; + expect(summary).toHaveStyle({ maxWidth: "100%" }); + }); +}); diff --git a/packages/chat-surface/src/messages/ThinkingShimmer.tsx b/packages/chat-surface/src/messages/ThinkingShimmer.tsx index dad108924..a0211b029 100644 --- a/packages/chat-surface/src/messages/ThinkingShimmer.tsx +++ b/packages/chat-surface/src/messages/ThinkingShimmer.tsx @@ -136,6 +136,13 @@ const summaryStyle: CSSProperties = { margin: "0 -6px", borderRadius: 6, width: "fit-content", + // Bounded, because the header now carries one unbounded string — the digest. + // `fit-content` alone grows past the column, and the Studio chat column is + // ~335px: the row would push its own chevron (the only affordance this + // control has) off the edge. + maxWidth: "100%", + minWidth: 0, + boxSizing: "border-box", }; const bodyStyle: CSSProperties = { @@ -165,6 +172,8 @@ const activityListStyle: CSSProperties = { const settledLabelStyle: CSSProperties = { color: "var(--color-text-muted, #98989f)", fontSize: CHROME_SIZE, + flex: "none", + whiteSpace: "nowrap", }; /** The step count riding next to the label. Deliberately NOT inside the @@ -174,6 +183,23 @@ const stepsStyle: CSSProperties = { color: "var(--color-text-subtle, #64646d)", fontSize: CHROME_SIZE, whiteSpace: "nowrap", + // THE item that gives way. The label and the chevron stay `flex: none`; this + // span is the only arbitrary-length thing in the row, so it is the one that + // ellipsizes in a narrow column. The full sentence stays on `title`. + flex: "0 1 auto", + minWidth: 0, + overflow: "hidden", + textOverflow: "ellipsis", +}; + +/** The digest variant. The bare count is decoration and sits one rung quieter + * than the label; a sentence naming the work is CONTENT — after a run settles + * it is the only record on screen of what the agent did — so it gets the + * label's contrast. `--color-text-subtle` on the app background is ~3.3:1, + * under AA for text; `--color-text-muted` is ~7:1. */ +const digestStyle: CSSProperties = { + ...stepsStyle, + color: "var(--color-text-muted, #98989f)", }; const failedStepsStyle: CSSProperties = { @@ -197,6 +223,19 @@ export interface ThinkingBlockProps { readonly activity?: ReactNode; /** How many cards `activity` holds. Drives the header's `· N steps`. */ readonly stepCount?: number; + /** + * WHAT those cards did — "Searched the web · Dispatched 1 subagent" — + * supplied by `TcChat` from `describeActivity`. When present it REPLACES the + * bare count in the header. + * + * The count was written as the guard against this block hiding work ("the + * only thing that tells a reader work is folded under a collapsed row"), and + * a live capture showed it is not enough of one: a settled turn read + * "Thought process · 2 steps" and nothing on screen recorded that a search + * and a subagent had happened. A number says work exists; it takes a noun to + * say what it was. A plain string, so this module never learns about tools. + */ + readonly digest?: string | null; /** How many of them failed. Drives the header's red `· N failed`. */ readonly failedCount?: number; /** @@ -227,6 +266,7 @@ export function ThinkingBlock({ children, activity, stepCount = 0, + digest = null, failedCount = 0, activityRunning = false, }: ThinkingBlockProps): ReactElement { @@ -275,8 +315,15 @@ export function ThinkingBlock({ [], ); + // The digest wins when there is one; the count stays as the fallback so a + // caller that cannot describe its cards still never folds them silently. + const hasDigest = digest !== null && digest.trim() !== ""; const steps = - stepCount > 0 ? `${stepCount} step${stepCount === 1 ? "" : "s"}` : null; + stepCount <= 0 + ? null + : hasDigest + ? digest + : `${stepCount} step${stepCount === 1 ? "" : "s"}`; return (
+ · {steps} ) : null} diff --git a/packages/chat-surface/src/thread-canvas/TcChat.test.tsx b/packages/chat-surface/src/thread-canvas/TcChat.test.tsx index b7f2c5280..f719e8b88 100644 --- a/packages/chat-surface/src/thread-canvas/TcChat.test.tsx +++ b/packages/chat-surface/src/thread-canvas/TcChat.test.tsx @@ -2726,9 +2726,13 @@ describe("TcChat — tool calls folded into the thought", () => { expect(screen.queryByTestId("tool-run-group")).not.toBeInTheDocument(); }); - it("states how many steps it folded away", () => { - // The count is the honesty guarantee: the row is collapsed by default, so - // without it, folding the cards in would simply be hiding them. + it("NAMES the work it folded away, not just how much of it", () => { + // The row is collapsed by default, so without a statement of what is under + // it, folding the cards in would simply be hiding them. That statement used + // to be a count ("· 2 steps"), and a live capture showed the count is not + // enough: a settled turn that had searched the web and dispatched a + // subagent read "Thought process · 2 steps", and nothing on screen recorded + // that either had happened. The guarantee is now a NOUN. renderTurn({ toolCalls: [ toolCall({ id: "call-1", runId: RUN, sequenceNo: 2 }), @@ -2736,7 +2740,12 @@ describe("TcChat — tool calls folded into the thought", () => { ], }); expect(screen.getByTestId("cs-thinking-block-steps")).toHaveTextContent( - "· 2 steps", + "· Searched the web ×2", + ); + // The count survives as data for anything that needs the number. + expect(screen.getByTestId("cs-thinking-block")).toHaveAttribute( + "data-steps", + "2", ); }); diff --git a/packages/chat-surface/src/thread-canvas/TcChat.tsx b/packages/chat-surface/src/thread-canvas/TcChat.tsx index 9e9fda4bc..c75c47ace 100644 --- a/packages/chat-surface/src/thread-canvas/TcChat.tsx +++ b/packages/chat-surface/src/thread-canvas/TcChat.tsx @@ -78,6 +78,7 @@ import { ToolRunGroup } from "../activity/ToolRunGroup"; // PRD-03 FR-3.10 — reuse the formatter that already exists rather than adding a // third. PRD-07 renames/consolidates it; this call site moves with it. import { formatSubagentDuration } from "../subagents/labels"; +import { describeActivity, type ActivityDigestMember } from "./activityDigest"; import { groupActivityStream, summariseGroup, @@ -1729,6 +1730,7 @@ function MessageListBody(props: MessageListBodyProps): ReactNode { runFailed, ), total: absorbed.length, + digest: describeActivity(absorbed.flatMap(toDigestMember)), }, ); } @@ -1877,6 +1879,7 @@ function MessageListBody(props: MessageListBodyProps): ReactNode { ? null : formatSubagentDuration(summary.elapsedMs) } + digest={describeActivity(members.flatMap(toDigestMember))} compact={compact} > {members.map(renderItem)} @@ -2043,6 +2046,7 @@ function renderPart( : { activity: activity.cards, stepCount: activity.total, + digest: activity.digest, failedCount: activity.summary.retried, activityRunning: activity.summary.state === "running", })} @@ -2127,6 +2131,31 @@ interface ThoughtActivity { readonly cards: readonly ReactNode[]; readonly summary: GroupSummary; readonly total: number; + /** What the cards did, for the settled header — see `activityDigest.ts`. */ + readonly digest: string | null; +} + +/** + * One folded stream item, as the digest sees it. + * + * `flatMap`-shaped (an array of zero or one) because BOTH fold sites call it and + * a group's members are not only tools and fleets: anything else contributes no + * phrase rather than a wrong one. + */ +function toDigestMember(item: StreamItem): readonly ActivityDigestMember[] { + if (item.kind === "tool") { + return [ + { + kind: "tool", + toolName: item.toolCall.toolName, + args: item.toolCall.args, + }, + ]; + } + if (item.kind === "fleet") { + return [{ kind: "fleet", total: item.fleet.total }]; + } + return []; } // PR-3.8 — reuse the hoisted `SubagentFleetCard` (Phase 1D) with the projected diff --git a/packages/chat-surface/src/thread-canvas/ToolCallCard.test.tsx b/packages/chat-surface/src/thread-canvas/ToolCallCard.test.tsx index 943138a09..b6fb166a1 100644 --- a/packages/chat-surface/src/thread-canvas/ToolCallCard.test.tsx +++ b/packages/chat-surface/src/thread-canvas/ToolCallCard.test.tsx @@ -366,3 +366,38 @@ describe("ToolCallCard — refused vs waiting on a decision", () => { ).toBeInTheDocument(); }); }); + +describe("ToolCallCard — which tool, as data", () => { + // The visible title is model-authored ("Get Linear issue", "math.isqrt + // docs"), so the raw tool name is on no pixel. A live journey that read copy + // to learn the tool broke the day the title stopped being the name; this is + // what it reads instead, stamped beside `data-tool-status`. + it("stamps the raw tool name on a card WITH details", () => { + const { container } = render(); + const root = container.querySelector("[data-tool-status]"); + expect(root).toHaveAttribute("data-tool-name", "get_issue"); + expect(root?.tagName).toBe("DETAILS"); + }); + + it("stamps it on a card with NO details too — both render arms", () => { + const { container } = render( + arm needs them equal — which is what a + // call looks like before the projector has a display title for it. + title: "web_search", + toolName: "web_search", + }} + />, + ); + const root = container.querySelector("[data-tool-status]"); + expect(root).toHaveAttribute("data-tool-name", "web_search"); + expect(root?.tagName).toBe("DIV"); + }); +}); diff --git a/packages/chat-surface/src/thread-canvas/ToolCallCard.tsx b/packages/chat-surface/src/thread-canvas/ToolCallCard.tsx index 9735766c8..0459ddfbf 100644 --- a/packages/chat-surface/src/thread-canvas/ToolCallCard.tsx +++ b/packages/chat-surface/src/thread-canvas/ToolCallCard.tsx @@ -74,6 +74,11 @@ export function ToolCallCard({ role="group" aria-label={`Tool: ${toolCall.title}`} data-tool-status={toolCall.status} + // WHICH tool, as data. The card's visible title is model-authored + // ("math.isqrt docs"), so the raw name appears nowhere on screen, and a + // journey that read copy to learn the tool broke the day the title + // stopped being the name. Same reasoning as `data-tool-status`. + data-tool-name={toolCall.toolName} data-tool-waiting={waiting ? "true" : "false"} {...(blocked === null ? {} : { "data-tool-blocked": blocked })} > @@ -89,6 +94,7 @@ export function ToolCallCard({ style={activityCardFrameStyle} aria-label={`Tool: ${toolCall.title}`} data-tool-status={toolCall.status} + data-tool-name={toolCall.toolName} data-tool-waiting={waiting ? "true" : "false"} {...(blocked === null ? {} : { "data-tool-blocked": blocked })} // CONTROLLED, seeded from the view. A bare `open={true}` would be diff --git a/packages/chat-surface/src/thread-canvas/activityDigest.test.ts b/packages/chat-surface/src/thread-canvas/activityDigest.test.ts new file mode 100644 index 000000000..cfc59fb8e --- /dev/null +++ b/packages/chat-surface/src/thread-canvas/activityDigest.test.ts @@ -0,0 +1,104 @@ +import { describe, expect, it } from "vitest"; + +import { + ACTIVITY_DIGEST_MAX_PHRASES, + describeActivity, + type ActivityDigestMember, +} from "./activityDigest"; + +const tool = ( + toolName: string, + args?: Record, +): ActivityDigestMember => ({ kind: "tool", toolName, args }); + +const fleet = (total: number): ActivityDigestMember => ({ + kind: "fleet", + total, +}); + +describe("describeActivity", () => { + it("says nothing when nothing was folded", () => { + expect(describeActivity([])).toBeNull(); + }); + + it("names the turn from the live capture that motivated it", () => { + // One web search and one subagent used to settle into + // "Thought process · 2 steps" — a count, with no record of either. + expect(describeActivity([tool("web_search"), fleet(1)])).toBe( + "Searched the web · Dispatched 1 subagent", + ); + }); + + it("reads in the order the run went, not by a priority table", () => { + expect( + describeActivity([ + tool("read_file", { file_path: "/w/a.py" }), + tool("web_search"), + tool("edit_file", { file_path: "/w/a.py" }), + ]), + ).toBe("Read 1 file · Searched the web · Edited 1 file"); + }); + + it("counts FILES, so three edits to one file are one file", () => { + expect( + describeActivity([ + tool("edit_file", { file_path: "/w/a.py" }), + tool("edit_file", { file_path: "/w/a.py" }), + tool("edit_file", { file_path: "/w/b.py" }), + ]), + ).toBe("Edited 2 files"); + }); + + it("counts each call when a file tool carries no path", () => { + // A streamed call whose args have not parsed yet still happened. + expect(describeActivity([tool("read_file"), tool("read_file")])).toBe( + "Read 2 files", + ); + }); + + it("counts subagents, not dispatches", () => { + expect(describeActivity([fleet(2), fleet(3)])).toBe( + "Dispatched 5 subagents", + ); + }); + + it("rounds an unknown fleet size up to one rather than claiming zero", () => { + expect(describeActivity([fleet(0)])).toBe("Dispatched 1 subagent"); + }); + + it("repeats a verb with a multiplier instead of a fake noun", () => { + expect( + describeActivity([tool("web_search"), tool("web_search"), tool("grep")]), + ).toBe("Searched the web ×2 · Searched files"); + }); + + it("files a shell alias under commands with run_command", () => { + expect(describeActivity([tool("run_command"), tool("shell")])).toBe( + "Ran 2 commands", + ); + }); + + it("keeps a connector call's own name — it is not '1 step'", () => { + // Title case is `humanizeIdentifier`'s house style, reused as-is so a + // connector reads the same here as it does in the subagent rows. + expect(describeActivity([tool("create_issue"), tool("create_issue")])).toBe( + "Create Issue ×2", + ); + }); + + it("folds the long tail into '+N more', counting STEPS", () => { + const line = describeActivity([ + tool("web_search"), + tool("read_file", { file_path: "/w/a.py" }), + tool("edit_file", { file_path: "/w/a.py" }), + tool("run_command"), + tool("run_command"), + fleet(1), + ]); + // Three phrases shown; the two commands and the dispatch are the rest. + expect(line).toBe( + "Searched the web · Read 1 file · Edited 1 file · +3 more", + ); + expect(line?.split(" · ")).toHaveLength(ACTIVITY_DIGEST_MAX_PHRASES + 1); + }); +}); diff --git a/packages/chat-surface/src/thread-canvas/activityDigest.ts b/packages/chat-surface/src/thread-canvas/activityDigest.ts new file mode 100644 index 000000000..6a3dc3bcc --- /dev/null +++ b/packages/chat-surface/src/thread-canvas/activityDigest.ts @@ -0,0 +1,171 @@ +// activityDigest — say WHAT a folded run of activity did, in one quiet line. +// +// PRD-03 ("the answer wins") folds a settled run of tool/fleet cards into one +// row, and `absorbThoughtActivity` folds the same cards into the thought that +// produced them. Both were right about density and both shipped a label that +// names only a COUNT: "Thought process · 2 steps", "Worked for 3s · 2 steps". +// +// A live capture is what that costs. One turn searched the web and dispatched a +// subagent; the moment it settled the transcript read +// +// Thought process · 2 steps ⌄ +// +// +// and nothing on screen said a search or a subagent had ever happened. In Focus +// the Run-details column is folded too, so that row was the ENTIRE record of the +// agent's work — which is the literal content of the bug report "in Focus mode I +// can't see anything". PRD-03's own reference table shows the half we dropped: +// Codex folds to `Worked for 26s ›`, but Claude Desktop keeps `Read depth.py ›`. +// We copied the fold and lost the noun. +// +// So the fold stays and the label learns to talk: +// +// Thought for 8s · Searched the web · Dispatched 1 subagent ⌄ +// +// Pure on purpose. Both fold sites hold the member list already, and a digest +// that needed the DOM could not be unit-tested against the one thing that +// matters here — the sentence. + +import { classifyTool, toolDisplayName } from "../subagents/subagentHelpers"; +import { toolViewFor } from "./toolViews"; + +/** What the digest needs to know about one folded card. */ +export type ActivityDigestMember = + | { + readonly kind: "tool"; + readonly toolName: string; + /** The tool's raw args. Only `file_path` is read — to count FILES, not + * calls, so three edits to one file read "Edited 1 file". */ + readonly args?: Readonly> | undefined; + } + | { + readonly kind: "fleet"; + /** Children in this fleet. `0` means "not known yet" and counts as one — + * a dispatch happened, and a digest that said "0 subagents" would be a + * stranger lie than rounding up. */ + readonly total: number; + }; + +/** Phrases shown before the rest collapse into `+N more`. Three is what fits + * beside "Thought for 12s" in a 730px Focus column without wrapping. */ +export const ACTIVITY_DIGEST_MAX_PHRASES = 3; + +type Bucket = { + /** Distinct units: file paths where the tool names one, else one per call. */ + readonly units: Set; + /** Every folded step in this bucket — what `+N more` counts. */ + steps: number; + readonly phrase: (count: number) => string; +}; + +const plural = (count: number, noun: string): string => + `${count} ${noun}${count === 1 ? "" : "s"}`; + +const repeated = (label: string, count: number): string => + count === 1 ? label : `${label} ×${count}`; + +function filePathOf( + args: Readonly> | undefined, +): string | null { + const value = args?.["file_path"]; + return typeof value === "string" && value.trim() !== "" ? value : null; +} + +/** + * Which sentence a tool call contributes to. + * + * The registry (`toolViewFor`) is asked first because it is the product's one + * statement of what a tool IS; `classifyTool` covers the two families the + * registry files under "generic" but a reader thinks of as their own verbs (a + * web search, a shell alias). Everything else keeps its own humanised name — a + * connector call is not "1 step", it is "Create issue". + */ +function bucketFor(toolName: string): { + readonly key: string; + readonly phrase: (count: number) => string; +} { + switch (toolViewFor(toolName).kind) { + case "edit": + return { key: "edit", phrase: (n) => `Edited ${plural(n, "file")}` }; + case "write": + return { key: "write", phrase: (n) => `Wrote ${plural(n, "file")}` }; + case "read": + return { key: "read", phrase: (n) => `Read ${plural(n, "file")}` }; + case "search": + return { key: "search", phrase: (n) => repeated("Searched files", n) }; + case "command": + return { key: "command", phrase: (n) => `Ran ${plural(n, "command")}` }; + case "generic": + break; + } + switch (classifyTool(toolName)) { + case "web_search": + return { key: "web", phrase: (n) => repeated("Searched the web", n) }; + case "shell": + return { key: "command", phrase: (n) => `Ran ${plural(n, "command")}` }; + default: { + const label = toolDisplayName(toolName); + return { key: `other:${label}`, phrase: (n) => repeated(label, n) }; + } + } +} + +/** + * One line naming the work a folded row hides, or `null` for nothing to say. + * + * Phrases appear in FIRST-OCCURRENCE order, so the line reads as the run went — + * "Searched the web · Read 3 files · Edited 1 file" — rather than sorted by a + * priority the reader would have to learn. + */ +export function describeActivity( + members: readonly ActivityDigestMember[], +): string | null { + const buckets = new Map(); + let anonymous = 0; + + for (const member of members) { + if (member.kind === "fleet") { + const bucket = buckets.get("fleet") ?? { + units: new Set(), + steps: 0, + phrase: (n: number) => `Dispatched ${plural(n, "subagent")}`, + }; + // One unit per CHILD: the phrase counts subagents, not dispatches. + const children = Math.max(member.total, 1); + for (let i = 0; i < children; i += 1) { + bucket.units.add(`fleet-${bucket.steps}-${i}`); + } + bucket.steps += 1; + buckets.set("fleet", bucket); + continue; + } + + const { key, phrase } = bucketFor(member.toolName); + const bucket = buckets.get(key) ?? { + units: new Set(), + steps: 0, + phrase, + }; + const path = + key === "edit" || key === "write" || key === "read" + ? filePathOf(member.args) + : null; + // No path (or not a file tool) → every call is its own unit. + anonymous += 1; + bucket.units.add(path ?? `call-${anonymous}`); + bucket.steps += 1; + buckets.set(key, bucket); + } + + if (buckets.size === 0) return null; + + const all = [...buckets.values()]; + const shown = all.slice(0, ACTIVITY_DIGEST_MAX_PHRASES); + const hiddenSteps = all + .slice(ACTIVITY_DIGEST_MAX_PHRASES) + .reduce((sum, bucket) => sum + bucket.steps, 0); + + const phrases = shown.map((bucket) => bucket.phrase(bucket.units.size)); + if (hiddenSteps > 0) phrases.push(`+${hiddenSteps} more`); + return phrases.join(" · "); +} diff --git a/packages/design-system/src/styles.css b/packages/design-system/src/styles.css index 07df08110..fc34fd1ed 100644 --- a/packages/design-system/src/styles.css +++ b/packages/design-system/src/styles.css @@ -620,6 +620,22 @@ body { background: var(--color-bg); color: var(--color-text); font-family: var(--font-sans); + /* Grayscale smoothing, matching the committed design and OUR OWN SPLASH. + * + * Every design mock sets this on body (design-kit/app-v3/copilot.css:110), and + * the boot splash sets it on `.boot` (apps/desktop/renderer/BootProgress.css:34) + * — so until this rule existed, text rendering visibly CHANGED the moment the + * splash unmounted: stems went from the splash's thin grayscale to Blink's + * heavier default, inside one React root. On a dark theme the default reads + * as slightly bold and slightly smeared, which is a fair description of "the + * fonts look off" that has nothing to do with the typeface. + * + * macOS-only properties: inert on Windows, where ClearType owns this. Face- + * independent, so it holds whichever way the A-vs-C typeface decision in + * docs/plan/agent-execution/TYPOGRAPHY-PROPOSAL.md goes. Revert = delete two + * lines. */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; /* v3 "quiet" base body size. The design anchors general body text at a literal * 13px (copilot.css:104 `body{font-size:13px}`); before this token existed on * `body` at all, every text node WITHOUT an explicit size fell back to the diff --git a/tools/desktop-journeys/transcript_rendering.py b/tools/desktop-journeys/transcript_rendering.py index 2d007182f..9d1a96d57 100644 --- a/tools/desktop-journeys/transcript_rendering.py +++ b/tools/desktop-journeys/transcript_rendering.py @@ -123,6 +123,48 @@ def wait_new_assistant(s: DriverSession, before: int, timeout_s: int = 60) -> No raise AssertionError("no assistant turn appeared after sending the prompt") +#: Read a node as if every disclosure above it were open, then put them back. +#: +#: WHY THIS EXISTS. These journeys were written against a model that emits no +#: reasoning, where a tool or fleet card is a top-level transcript row. On a +#: REASONING model — what a real user on Claude Opus or a thinking Sonnet has — +#: `absorbThoughtActivity` folds every card into the "Thought process" block, +#: and that block closes when the run settles. `innerText` is layout-aware, so a +#: settled card then reads as `''` and phases failed with messages that look like +#: product bugs ("no required new fleet card appeared … 'text': ''"). +#: +#: Open → read → restore happens inside ONE evaluate, and reading `innerText` +#: forces the layout flush, so the text is real and nothing repaints. Restoring +#: matters: TR-16 asserts every settled group IS collapsed, and a snapshot that +#: left older groups open would fail it three phases later with no trail back. +JS_WITH_REVEALED = """ +const withRevealed=(node,read)=>{ + const opened=[]; + let p=node.parentElement; + while(p){ if(p.tagName==='DETAILS'&&!p.open){ p.open=true; opened.push(p); } p=p.parentElement; } + try { return read(node); } finally { opened.forEach((d)=>{ d.open=false; }); } +}; +""" + + +def reveal(s: DriverSession, selector: str) -> int: + """Open every disclosure ABOVE ``selector`` and leave it open. + + The mutating sibling of ``JS_WITH_REVEALED``, for phases that go on to CLICK + the element: a user who wants to operate a folded card opens the fold first, + and Playwright will not click what has no visible box. + """ + + return int( + s.evaluate( + "(()=>{const el=document.querySelector(%s);if(!el)return 0;let n=0," + "p=el.parentElement;while(p){if(p.tagName==='DETAILS'&&!p.open)" + "{p.open=true;n++;}p=p.parentElement;}return n})()" % json.dumps(selector) + ) + or 0 + ) + + def card_snapshots(s: DriverSession, kind: str) -> list[dict]: """Read the activity card hosts a user sees, preserving their stable ids.""" if kind == "tool": @@ -132,8 +174,9 @@ def card_snapshots(s: DriverSession, kind: str) -> list[dict]: else: raise ValueError(f"unsupported card kind {kind!r}") js = f"""(()=>{{ + {JS_WITH_REVEALED} const selector={json.dumps(selector)}; - return JSON.stringify([...document.querySelectorAll(selector)].map((node)=>{{ + return JSON.stringify([...document.querySelectorAll(selector)].map((host)=>withRevealed(host,(node)=>{{ const fleet=node.querySelector('[data-fleet-id]'); return {{ testId:node.getAttribute('data-testid'), @@ -148,7 +191,7 @@ def card_snapshots(s: DriverSession, kind: str) -> list[dict]: }})), hasDetails:!!node.querySelector('details > summary'), }}; - }})); + }}))); }})()""" raw = s.evaluate(js) return json.loads(raw) if raw else [] @@ -261,6 +304,9 @@ def is_open() -> bool: ) assert s.present(summary), f"{label}: disclosure summary is missing" + opened = reveal(s, details_selector) + if opened: + log(f" {label}: opened {opened} enclosing disclosure(s) first") if is_open(): s.click(summary) assert not is_open(), f"{label}: could not establish a closed disclosure" @@ -364,12 +410,7 @@ def expanded() -> str | None: # after 15s reporting "element is not visible". Open every enclosing # disclosure first; the sibling tool-card check already does this via # `ensure_native_disclosure`, and the asymmetry was the whole bug. - opened = s.evaluate( - "(() => {const el=document.querySelector(%s);if(!el)return 0;" - "let n=0,p=el.parentElement;" - "while(p){if(p.tagName==='DETAILS'&&!p.open){p.open=true;n++;}p=p.parentElement;}" - "return n})()" % json.dumps(host) - ) + opened = reveal(s, host) if opened: log(f" opened {opened} enclosing disclosure(s) to reach the fleet toggle") assert expanded() == "false", "terminal fleet should start compact" @@ -495,27 +536,89 @@ def fa_poll_growth( return steps -def fa_tool_card_state(s: DriverSession) -> dict | None: +def fa_tool_card_state(s: DriverSession, known: set[str] | None = None) -> dict | None: + """The NEWEST tool card this phase produced — see ``fa_fleet_card_state``. + + Same two stale assumptions (first card in a shared conversation; `innerText` + of a folded card), plus a third of its own: it learned WHICH tool ran by + reading the card's copy. The title is model-authored now ("math.isqrt + docs"), so the raw name is on no pixel — it is on `data-tool-name`. + """ + js = ( - "(()=>{const c=document.querySelector('[data-testid^=tc-chat-tool-]:not([data-testid$=-args])" - ":not([data-testid$=-result])');if(!c)return null;" - "const sum=c.querySelector('summary');return JSON.stringify({" - "status:c.getAttribute('data-tool-status'),text:c.innerText," - "hasDetails:!!(sum&&/Details/.test(sum.innerText))})})()" - ) + "(()=>{" + JS_WITH_REVEALED + "const known=new Set(%s);" + # HOSTS only: the
  • carrying data-tool-status. The bare prefix also + # matches a card's own `…-details` / `…-args` children, and "the last + # match" is then a fragment of a card rather than a card. + "const all=[...document.querySelectorAll('[data-testid^=tc-chat-tool-][data-tool-status]')]" + ".filter(c=>!known.has(c.getAttribute('data-testid')));" + "const c=all[all.length-1];if(!c)return null;" + "return JSON.stringify(withRevealed(c,(n)=>{" + "const named=n.matches('[data-tool-name]')?n:n.querySelector('[data-tool-name]');" + "const stat=n.matches('[data-tool-status]')?n:n.querySelector('[data-tool-status]');" + "const sum=n.querySelector('summary');return {" + "status:(stat||n).getAttribute('data-tool-status')," + "toolName:named?named.getAttribute('data-tool-name'):null," + "text:n.innerText,hasDetails:!!sum}}))})()" + ) % json.dumps(sorted(known or ())) raw = s.evaluate(js) return json.loads(raw) if raw else None -def fa_fleet_card_state(s: DriverSession) -> dict | None: - js = ( - "(()=>{const c=document.querySelector('[data-testid^=tc-chat-fleet-]');" - "if(!c)return null;return JSON.stringify({text:c.innerText})})()" +def fa_known_tool_ids(s: DriverSession) -> set[str]: + raw = s.evaluate( + "JSON.stringify([...document.querySelectorAll(" + "'[data-testid^=tc-chat-tool-][data-tool-status]')]" + ".map(c=>c.getAttribute('data-testid')))" ) + return set(json.loads(raw or "[]")) + + +def fa_fleet_card_state(s: DriverSession, known: set[str] | None = None) -> dict | None: + """The NEWEST fleet card this phase produced, read the way a user sees it. + + Two assumptions from this helper's first life no longer hold, and each + failed as "fleet card missing 'Dispatched' copy: ''" — a message that reads + like Focus dropping subagents, which it does not: + + * **It took the FIRST fleet card in the DOM.** When this was its own journey + that was the only one. Grouped phases share a boot AND a conversation, so + by TR-8 the first fleet card is TR-2's, six turns old. + * **It read `innerText` without opening anything.** `innerText` is + layout-aware, so it is `''` for a card inside a closed disclosure — and a + settled card sits inside one twice over: the run-group a later run folds + it into, and the "Thought process" block a reasoning model's work is + absorbed by. + + So: skip the cards that existed before this phase sent, take the last of + what is left, and read it THROUGH its folds (`JS_WITH_REVEALED`: open, read, + restore). That does not weaken the assertion, which is about the card's + COPY — and it leaves the transcript as the user left it. + """ + + js = ( + "(()=>{const known=new Set(%s);" + "const all=[...document.querySelectorAll('[data-testid^=tc-chat-fleet-]')]" + ".filter(c=>!known.has(c.getAttribute('data-testid')));" + "const c=all[all.length-1];if(!c)return null;" + "return JSON.stringify(withRevealed(c,(n)=>({text:n.innerText," + "testId:n.getAttribute('data-testid')})))})()" + ) % json.dumps(sorted(known or ())) + js = js.replace("(()=>{", "(()=>{" + JS_WITH_REVEALED, 1) raw = s.evaluate(js) return json.loads(raw) if raw else None +def fa_known_fleet_ids(s: DriverSession) -> set[str]: + """Fleet cards already on screen — everything a new turn did NOT produce.""" + + raw = s.evaluate( + "JSON.stringify([...document.querySelectorAll('[data-testid^=tc-chat-fleet-]')]" + ".map(c=>c.getAttribute('data-testid')))" + ) + return set(json.loads(raw or "[]")) + + def enter_focus(s: DriverSession) -> None: """Switch the cockpit into Focus the way a user does, then verify it took. @@ -588,6 +691,7 @@ def fa_streaming(s: DriverSession) -> None: def fa_tool_card(s: DriverSession) -> None: log("── J2 tool card ─────────────────────────────────────────────") enter_focus(s) + known = fa_known_tool_ids(s) prev = int(s.evaluate(JS_ASSISTANT_COUNT) or 0) send_in_run(s, P_TOOL) assert fa_wait_new_turn(s, prev), ( @@ -596,7 +700,7 @@ def fa_tool_card(s: DriverSession) -> None: card = None for _ in range(160): # up to ~40s for the model to call the tool - card = fa_tool_card_state(s) + card = fa_tool_card_state(s, known) if card is not None: break time.sleep(0.25) @@ -609,17 +713,18 @@ def fa_tool_card(s: DriverSession) -> None: ) return - assert "web_search" in card["text"], ( - f"tool card did not name web_search: {card['text']!r}" + assert card["toolName"] == "web_search", ( + f"newest tool card is {card['toolName']!r}, not web_search; text={card['text']!r}" ) - log("PASS inline tool card present and names web_search") + assert card["text"].strip(), "the web_search card rendered no visible copy" + log("PASS inline tool card present, is web_search, and has visible copy") # wait for it to resolve to done # The renderer's durable status token is ``complete``; older staged # payloads used ``done``. The visible label remains “done” in both cases. done = card["status"] in {"complete", "done"} for _ in range(120): - card = fa_tool_card_state(s) + card = fa_tool_card_state(s, known) if card and card["status"] in {"complete", "done"}: done = True break @@ -641,13 +746,14 @@ def fa_tool_card(s: DriverSession) -> None: def fa_fleet_card(s: DriverSession) -> None: log("── J3 subagent fleet card ───────────────────────────────────") enter_focus(s) + known = fa_known_fleet_ids(s) prev = int(s.evaluate(JS_ASSISTANT_COUNT) or 0) send_in_run(s, P_FLEET) assert fa_wait_new_turn(s, prev), "no new assistant turn after the subagent prompt" fleet = None for _ in range(200): # up to ~50s — subagent dispatch can be slower - fleet = fa_fleet_card_state(s) + fleet = fa_fleet_card_state(s, known) if fleet is not None: break time.sleep(0.25) @@ -670,7 +776,7 @@ def fa_fleet_card(s: DriverSession) -> None: # observe progression to done done = "done" in text.lower() or "1/1" in text for _ in range(160): - fleet = fa_fleet_card_state(s) + fleet = fa_fleet_card_state(s, known) if fleet and ("done" in fleet["text"].lower() or "1/1" in fleet["text"]): done = True break @@ -1319,6 +1425,10 @@ def tr1_direct_web_search_card(s: DriverSession) -> None: host = css_test_id(tool["testId"]) details, body = f"{host} details", f"{host} [data-testid$=-details]" assert tool["hasDetails"], "completed web-search card is missing its disclosure" + # On a reasoning model the settled card sits inside a closed "Thought + # process" block, so the summary has no visible box until the fold above + # it is opened — which is also what a user would do to reach it. + reveal(s, details) s.click(f"{details} > summary") detail_text = s.evaluate( f"(document.querySelector({json.dumps(body)})||{{}}).innerText||''"