From 7179095f3bb0ca9bff978d5a3de65c46087c8eee Mon Sep 17 00:00:00 2001 From: Sergio Marcelino Date: Fri, 15 May 2026 19:27:31 -0300 Subject: [PATCH 1/2] fix: pnpm lock --- .gitignore | 1 + console/web/package.json | 1 + console/web/pnpm-lock.yaml | 2229 ++++++++++++++++++++++++++++++++++++ 3 files changed, 2231 insertions(+) create mode 100644 console/web/pnpm-lock.yaml diff --git a/.gitignore b/.gitignore index 2437871e..16efd333 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ pnpm-lock.yaml yarn.lock !iii-database/tests/e2e/workers/harness/package-lock.json !shell/tests/e2e/workers/harness/package-lock.json +!console/web/pnpm-lock.yaml # Python .venv/ diff --git a/console/web/package.json b/console/web/package.json index 746c02fc..126a30d4 100644 --- a/console/web/package.json +++ b/console/web/package.json @@ -3,6 +3,7 @@ "private": true, "version": "0.0.0", "type": "module", + "packageManager": "pnpm@10.18.2", "scripts": { "dev": "vite", "build": "tsc -b && vite build", diff --git a/console/web/pnpm-lock.yaml b/console/web/pnpm-lock.yaml new file mode 100644 index 00000000..87969601 --- /dev/null +++ b/console/web/pnpm-lock.yaml @@ -0,0 +1,2229 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@lexical/react': + specifier: ^0.44.0 + version: 0.44.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(yjs@13.6.30) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.4(@types/react@19.2.14)(react@19.2.6) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lexical: + specifier: ^0.44.0 + version: 0.44.0 + prism-react-renderer: + specifier: ^2.4.1 + version: 2.4.1(react@19.2.6) + react: + specifier: ^19.2.6 + version: 19.2.6 + react-dom: + specifier: ^19.2.6 + version: 19.2.6(react@19.2.6) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.14)(react@19.2.6) + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + tailwind-merge: + specifier: ^3.6.0 + version: 3.6.0 + devDependencies: + '@biomejs/biome': + specifier: ^2.4.15 + version: 2.4.15 + '@tailwindcss/vite': + specifier: ^4.3.0 + version: 4.3.0(vite@8.0.13(@types/node@25.8.0)(jiti@2.7.0)) + '@types/hast': + specifier: ^3.0.4 + version: 3.0.4 + '@types/node': + specifier: ^25.8.0 + version: 25.8.0 + '@types/react': + specifier: ^19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^6.0.2 + version: 6.0.2(vite@8.0.13(@types/node@25.8.0)(jiti@2.7.0)) + tailwindcss: + specifier: ^4.3.0 + version: 4.3.0 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vite: + specifier: ^8.0.13 + version: 8.0.13(@types/node@25.8.0)(jiti@2.7.0) + +packages: + + '@biomejs/biome@2.4.15': + resolution: {integrity: sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@2.4.15': + resolution: {integrity: sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@2.4.15': + resolution: {integrity: sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@2.4.15': + resolution: {integrity: sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@2.4.15': + resolution: {integrity: sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@2.4.15': + resolution: {integrity: sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@2.4.15': + resolution: {integrity: sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@2.4.15': + resolution: {integrity: sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.4.15': + resolution: {integrity: sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.27.19': + resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lexical/clipboard@0.44.0': + resolution: {integrity: sha512-nfmNIs7uENqlDI7cm2E4I1Yp8mDJGMhEQIrIV2rNWnL1oeHVXQ7yuYdyoPdcY1zuj/9nvkYBQYUEh0QiGwpETA==} + + '@lexical/code-core@0.44.0': + resolution: {integrity: sha512-m57JyXTIvW1tsqw/Vuogk8jqWCZZIeFQbWybRc46ytR8ReDgzPRODpN8+dacIIeRH5yC5UC3lAa743mtdNkxqg==} + + '@lexical/devtools-core@0.44.0': + resolution: {integrity: sha512-X3uNG3P1vOsdzmEcy+7m9DxAcIVtVUZnvskmLqqLs6VluVVwH9xy7h1bPsvlDKvj1Nj73tWJ3TW0qXQWDTo5tw==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.44.0': + resolution: {integrity: sha512-RhlsjVDket9k1+YFEkDE0/7Qyrh2BI0vxBMzrWwPJTXX/4YFanYN9su8RSabkIukBBJ3QiNOOoC8FKK4Lkr4qg==} + + '@lexical/extension@0.44.0': + resolution: {integrity: sha512-BsYtoc+0EU0pqcOpf/lIUDU6LQVO6zX2AawZoUWJzT3Wzfov23qsqZWvl2WGM9dnRTN5iISJL3Fl53bQVxiXxw==} + + '@lexical/hashtag@0.44.0': + resolution: {integrity: sha512-0WATahDSqYKVTudQv3KpFbLeCpmrCpRptPFbjxOMckAX2MRpYlrExlqKfgfpri5BSQPtG49EPSGeNfSx/Faavw==} + + '@lexical/history@0.44.0': + resolution: {integrity: sha512-RGXcbFTgYL1GIWaReBI26mNSsJTfiA9EAtDY4LBeZ14NrIQhYNokKgNiOxq5Bn8xXrl2+mawQEqoMfgpWp/5YA==} + + '@lexical/html@0.44.0': + resolution: {integrity: sha512-5X6eGsgwtqPxABsuShUxF7ZfyB/U4GwSEyeonvwH1Vc/5Q2uQVjlB+FAYd+MNwWMHMh4d4+yZ3l70AtIuhr5eg==} + + '@lexical/link@0.44.0': + resolution: {integrity: sha512-uvEqEol/mLEzGVQd8Rok9I48RgYPKokM/nsclI9nYcEdccVOM2Nri4ntoRwodhbccFLtjMPl8OBldwXbfc77tQ==} + + '@lexical/list@0.44.0': + resolution: {integrity: sha512-ZTCWxDz1okPrC9FBXi1yV3W5fbQQeMUlFIcSVF9HibcVPmCsPa900IxthuiQbGiTycUyXDTOB3IUYRtlJNtpjw==} + + '@lexical/mark@0.44.0': + resolution: {integrity: sha512-bWMowllwe6BcgYMAkrsZx6Z+CX/72qCQpFKhlkR4ael92yOWSBkz68xp1wxxkSnQX9zoI1gYTeWBofVsSDKcsQ==} + + '@lexical/markdown@0.44.0': + resolution: {integrity: sha512-DwlXdp85pYMo3exDF6W3iz8plpuP+RQ4Me4Iljm7O5aPDp0SSrIoZxyX4zS668mVAoz5HHj1Ka0kQkft8mq26Q==} + + '@lexical/overflow@0.44.0': + resolution: {integrity: sha512-5GYaYjSxn27pqHRfU+tQ2STF10wgJvI+MUnwTnUFSzy3dko1b+oV94K/Yx0TuEewPbwDibfoFA8CwqUvOLHAyw==} + + '@lexical/plain-text@0.44.0': + resolution: {integrity: sha512-bIV4Lljk0x70zFhkZIwzSPK5q3m9FpDisjGm2/3Q/chb+5BW3Tv8QJmqnpCiSO6S2KXO7gfSy81ZfkQ1dcd4EQ==} + + '@lexical/react@0.44.0': + resolution: {integrity: sha512-p/NQd/fMh3pXb1XqegE2ruvWDcUmfB12OidQ9nwtMtj5VfcUjQu2I+trUhgGRIADxSYxMWmw+8PPj5YSf4m5oA==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + yjs: '>=13.5.22' + peerDependenciesMeta: + yjs: + optional: true + + '@lexical/rich-text@0.44.0': + resolution: {integrity: sha512-IIdrutK5GY47ITjPlZB7KzUi9dBDwygsyFOwolnrYSL7m6TtGhAqrYiFg/YNOTT/nBzK3KQeCJRbnxpjJAVZtQ==} + + '@lexical/selection@0.44.0': + resolution: {integrity: sha512-AEyeZJFFr5YRLeqVR+X0QAW19c4Fk4MFAQu52z2gxAyDGTj9xwVJxjfepVpfUp4P9K+sPtJ/yaqfMXH506ksSQ==} + + '@lexical/table@0.44.0': + resolution: {integrity: sha512-5Uq0O/fBCxcZp9y17fXUONY7dU9lVo/mB5JHy23laIiKzBKP5IzzTLMU9ikZTppIXbMNxYXd+R2pmy7PYTLyvw==} + + '@lexical/text@0.44.0': + resolution: {integrity: sha512-1XJD8ZbwaXljTl8k4+jjiopdhnYZm26IJw9Gv8+cIThVC0b6B3JZ/WxH97BMDcSloKvWHFkGiPztxRwNwA29Rw==} + + '@lexical/utils@0.44.0': + resolution: {integrity: sha512-/D2ptztNevfBJgtkj4uaiYBeRcvSy+1mQj6pNYaCFZIoPJIwl6H5fXwWAvpvr11vcQKP9DEEoXR+V4qkMOA+EA==} + + '@lexical/yjs@0.44.0': + resolution: {integrity: sha512-b3QTub9J/3LuwSSdooynb6GbMHBRyBT4xUbXzXqNPbDHgYe6CDrqf/uJIHRihIjAhOnPaHYqo9XUzitl++N1DQ==} + peerDependencies: + yjs: '>=13.5.22' + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.130.0': + resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} + + '@preact/signals-core@1.14.2': + resolution: {integrity: sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A==} + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@rolldown/binding-android-arm64@1.0.1': + resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.1': + resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.1': + resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.1': + resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.1': + resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.1': + resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.1': + resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.1': + resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.0': + resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@25.8.0': + resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} + + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + enhanced-resolve@5.21.3: + resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} + engines: {node: '>=10.13.0'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + lexical@0.44.0: + resolution: {integrity: sha512-ReDUjRlFgkGoPWzvdjr7s16PUVpHATN+2NH2NiZs+PLlISTaIFFgKil2P467oP3Vg+XgmpDsUgmWZsFJTztYjg==} + + lib0@0.2.117: + resolution: {integrity: sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==} + engines: {node: '>=16'} + hasBin: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + engines: {node: ^10 || ^12 || >=14} + + prism-react-renderer@2.4.1: + resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} + peerDependencies: + react: '>=16.0.0' + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 + + react-error-boundary@6.1.1: + resolution: {integrity: sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + rolldown@1.0.1: + resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@8.0.13: + resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + yjs@13.6.30: + resolution: {integrity: sha512-vv/9h42eCMC81ZHDFswuu/MKzkl/vyq1BhaNGfHyOonwlG4CJbQF4oiBBJPvfdeCt/PlVDWh7Nov9D34YY09uQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@biomejs/biome@2.4.15': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.4.15 + '@biomejs/cli-darwin-x64': 2.4.15 + '@biomejs/cli-linux-arm64': 2.4.15 + '@biomejs/cli-linux-arm64-musl': 2.4.15 + '@biomejs/cli-linux-x64': 2.4.15 + '@biomejs/cli-linux-x64-musl': 2.4.15 + '@biomejs/cli-win32-arm64': 2.4.15 + '@biomejs/cli-win32-x64': 2.4.15 + + '@biomejs/cli-darwin-arm64@2.4.15': + optional: true + + '@biomejs/cli-darwin-x64@2.4.15': + optional: true + + '@biomejs/cli-linux-arm64-musl@2.4.15': + optional: true + + '@biomejs/cli-linux-arm64@2.4.15': + optional: true + + '@biomejs/cli-linux-x64-musl@2.4.15': + optional: true + + '@biomejs/cli-linux-x64@2.4.15': + optional: true + + '@biomejs/cli-win32-arm64@2.4.15': + optional: true + + '@biomejs/cli-win32-x64@2.4.15': + optional: true + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@floating-ui/react@0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@floating-ui/utils': 0.2.11 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + tabbable: 6.4.0 + + '@floating-ui/utils@0.2.11': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lexical/clipboard@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + '@lexical/html': 0.44.0 + '@lexical/list': 0.44.0 + '@lexical/selection': 0.44.0 + '@lexical/utils': 0.44.0 + '@types/trusted-types': 2.0.7 + lexical: 0.44.0 + + '@lexical/code-core@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + lexical: 0.44.0 + + '@lexical/devtools-core@0.44.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@lexical/html': 0.44.0 + '@lexical/link': 0.44.0 + '@lexical/mark': 0.44.0 + '@lexical/table': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@lexical/dragon@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + lexical: 0.44.0 + + '@lexical/extension@0.44.0': + dependencies: + '@lexical/utils': 0.44.0 + '@preact/signals-core': 1.14.2 + lexical: 0.44.0 + + '@lexical/hashtag@0.44.0': + dependencies: + '@lexical/text': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/history@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/html@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + '@lexical/selection': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/link@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/list@0.44.0': + dependencies: + '@lexical/extension': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/mark@0.44.0': + dependencies: + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/markdown@0.44.0': + dependencies: + '@lexical/code-core': 0.44.0 + '@lexical/link': 0.44.0 + '@lexical/list': 0.44.0 + '@lexical/rich-text': 0.44.0 + '@lexical/text': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/overflow@0.44.0': + dependencies: + lexical: 0.44.0 + + '@lexical/plain-text@0.44.0': + dependencies: + '@lexical/clipboard': 0.44.0 + '@lexical/dragon': 0.44.0 + '@lexical/selection': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/react@0.44.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(yjs@13.6.30)': + dependencies: + '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@lexical/devtools-core': 0.44.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@lexical/dragon': 0.44.0 + '@lexical/extension': 0.44.0 + '@lexical/hashtag': 0.44.0 + '@lexical/history': 0.44.0 + '@lexical/link': 0.44.0 + '@lexical/list': 0.44.0 + '@lexical/mark': 0.44.0 + '@lexical/markdown': 0.44.0 + '@lexical/overflow': 0.44.0 + '@lexical/plain-text': 0.44.0 + '@lexical/rich-text': 0.44.0 + '@lexical/table': 0.44.0 + '@lexical/text': 0.44.0 + '@lexical/utils': 0.44.0 + '@lexical/yjs': 0.44.0(yjs@13.6.30) + lexical: 0.44.0 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-error-boundary: 6.1.1(react@19.2.6) + optionalDependencies: + yjs: 13.6.30 + + '@lexical/rich-text@0.44.0': + dependencies: + '@lexical/clipboard': 0.44.0 + '@lexical/dragon': 0.44.0 + '@lexical/selection': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/selection@0.44.0': + dependencies: + lexical: 0.44.0 + + '@lexical/table@0.44.0': + dependencies: + '@lexical/clipboard': 0.44.0 + '@lexical/extension': 0.44.0 + '@lexical/utils': 0.44.0 + lexical: 0.44.0 + + '@lexical/text@0.44.0': + dependencies: + lexical: 0.44.0 + + '@lexical/utils@0.44.0': + dependencies: + '@lexical/selection': 0.44.0 + lexical: 0.44.0 + + '@lexical/yjs@0.44.0(yjs@13.6.30)': + dependencies: + '@lexical/selection': 0.44.0 + lexical: 0.44.0 + yjs: 13.6.30 + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@oxc-project/types@0.130.0': {} + + '@preact/signals-core@1.14.2': {} + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + + '@rolldown/binding-android-arm64@1.0.1': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.1': + optional: true + + '@rolldown/binding-darwin-x64@1.0.1': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.1': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.1': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.1': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.1': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.1': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.1': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.1': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.1': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.1': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.1': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.1': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/vite@4.3.0(vite@8.0.13(@types/node@25.8.0)(jiti@2.7.0))': + dependencies: + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + tailwindcss: 4.3.0 + vite: 8.0.13(@types/node@25.8.0)(jiti@2.7.0) + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@25.8.0': + dependencies: + undici-types: 7.24.6 + + '@types/prismjs@1.26.6': {} + + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + + '@types/trusted-types@2.0.7': {} + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.1': {} + + '@vitejs/plugin-react@6.0.2(vite@8.0.13(@types/node@25.8.0)(jiti@2.7.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.13(@types/node@25.8.0)(jiti@2.7.0) + + bail@2.0.2: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + + comma-separated-tokens@2.0.3: {} + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + enhanced-resolve@5.21.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + escape-string-regexp@5.0.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + extend@3.0.2: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fsevents@2.3.3: + optional: true + + graceful-fs@4.2.11: {} + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + html-url-attributes@3.0.1: {} + + inline-style-parser@0.2.7: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + + isomorphic.js@0.2.5: {} + + jiti@2.7.0: {} + + lexical@0.44.0: {} + + lib0@0.2.117: + dependencies: + isomorphic.js: 0.2.5 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + longest-streak@3.1.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + markdown-table@3.0.4: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + ms@2.1.3: {} + + nanoid@3.3.12: {} + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + postcss@8.5.14: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prism-react-renderer@2.4.1(react@19.2.6): + dependencies: + '@types/prismjs': 1.26.6 + clsx: 2.1.1 + react: 19.2.6 + + property-information@7.1.0: {} + + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + + react-error-boundary@6.1.1(react@19.2.6): + dependencies: + react: 19.2.6 + + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.6): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.14 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.6 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + react@19.2.6: {} + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + rolldown@1.0.1: + dependencies: + '@oxc-project/types': 0.130.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.1 + '@rolldown/binding-darwin-arm64': 1.0.1 + '@rolldown/binding-darwin-x64': 1.0.1 + '@rolldown/binding-freebsd-x64': 1.0.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.1 + '@rolldown/binding-linux-arm64-musl': 1.0.1 + '@rolldown/binding-linux-ppc64-gnu': 1.0.1 + '@rolldown/binding-linux-s390x-gnu': 1.0.1 + '@rolldown/binding-linux-x64-gnu': 1.0.1 + '@rolldown/binding-linux-x64-musl': 1.0.1 + '@rolldown/binding-openharmony-arm64': 1.0.1 + '@rolldown/binding-wasm32-wasi': 1.0.1 + '@rolldown/binding-win32-arm64-msvc': 1.0.1 + '@rolldown/binding-win32-x64-msvc': 1.0.1 + + scheduler@0.27.0: {} + + source-map-js@1.2.1: {} + + space-separated-tokens@2.0.2: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + tabbable@6.4.0: {} + + tailwind-merge@3.6.0: {} + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + tslib@2.8.1: + optional: true + + typescript@6.0.3: {} + + undici-types@7.24.6: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@8.0.13(@types/node@25.8.0)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.14 + rolldown: 1.0.1 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.8.0 + fsevents: 2.3.3 + jiti: 2.7.0 + + yjs@13.6.30: + dependencies: + lib0: 0.2.117 + + zwitch@2.0.4: {} From 61da8ed62234562a0d27c6b8c64ae37e4b6ec6b9 Mon Sep 17 00:00:00 2001 From: Sergio Marcelino Date: Fri, 15 May 2026 19:29:47 -0300 Subject: [PATCH 2/2] chore: playground --- .gitignore | 1 - console/web/src/pages/Playground/EventLog.tsx | 222 ++++++++++++++++++ .../src/pages/Playground/ScenarioPicker.tsx | 92 ++++++++ console/web/src/pages/Playground/index.tsx | 144 ++++++++++++ .../Playground/scenarios/abort-mid-thought.ts | 22 ++ .../Playground/scenarios/error-on-fcall.ts | 47 ++++ .../pages/Playground/scenarios/fast-tokens.ts | 24 ++ .../pages/Playground/scenarios/happy-agent.ts | 38 +++ .../pages/Playground/scenarios/happy-ask.ts | 26 ++ .../pages/Playground/scenarios/happy-plan.ts | 31 +++ .../src/pages/Playground/scenarios/helpers.ts | 125 ++++++++++ .../src/pages/Playground/scenarios/index.ts | 140 +++++++++++ .../Playground/scenarios/long-markdown.ts | 103 ++++++++ .../Playground/scenarios/markdown-stress.ts | 94 ++++++++ .../Playground/scenarios/multi-tool-agent.ts | 64 +++++ .../Playground/scenarios/pending-approval.ts | 35 +++ .../pages/Playground/scenarios/slow-tokens.ts | 21 ++ 17 files changed, 1228 insertions(+), 1 deletion(-) create mode 100644 console/web/src/pages/Playground/EventLog.tsx create mode 100644 console/web/src/pages/Playground/ScenarioPicker.tsx create mode 100644 console/web/src/pages/Playground/index.tsx create mode 100644 console/web/src/pages/Playground/scenarios/abort-mid-thought.ts create mode 100644 console/web/src/pages/Playground/scenarios/error-on-fcall.ts create mode 100644 console/web/src/pages/Playground/scenarios/fast-tokens.ts create mode 100644 console/web/src/pages/Playground/scenarios/happy-agent.ts create mode 100644 console/web/src/pages/Playground/scenarios/happy-ask.ts create mode 100644 console/web/src/pages/Playground/scenarios/happy-plan.ts create mode 100644 console/web/src/pages/Playground/scenarios/helpers.ts create mode 100644 console/web/src/pages/Playground/scenarios/index.ts create mode 100644 console/web/src/pages/Playground/scenarios/long-markdown.ts create mode 100644 console/web/src/pages/Playground/scenarios/markdown-stress.ts create mode 100644 console/web/src/pages/Playground/scenarios/multi-tool-agent.ts create mode 100644 console/web/src/pages/Playground/scenarios/pending-approval.ts create mode 100644 console/web/src/pages/Playground/scenarios/slow-tokens.ts diff --git a/.gitignore b/.gitignore index 16efd333..dd235731 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,6 @@ engine.pid /config.yaml # harness/config.yaml is generated by `make engine` via `iii worker add .` harness/config.yaml -playground/ # Tooling / agent scratch .claude/ diff --git a/console/web/src/pages/Playground/EventLog.tsx b/console/web/src/pages/Playground/EventLog.tsx new file mode 100644 index 00000000..f763fee4 --- /dev/null +++ b/console/web/src/pages/Playground/EventLog.tsx @@ -0,0 +1,222 @@ +import { + forwardRef, + useCallback, + useEffect, + useImperativeHandle, + useRef, + useState, +} from 'react' +import { Button } from '@/components/ui/Button' +import type { StreamEvent } from '@/lib/backend' +import { JsonHighlight } from '@/lib/syntax' +import { cn } from '@/lib/utils' + +interface TaggedEvent extends Record { + kind: StreamEvent['kind'] + /** monotonic counter so list keys stay unique even with duplicate timestamps */ + seq: number + ts: number +} + +export interface EventLogHandle { + push: (event: StreamEvent) => void + clear: () => void +} + +interface EventLogProps { + /** when null/undefined, the log is collapsed to a vertical strip */ + open: boolean + onToggle: () => void +} + +export const EventLog = forwardRef( + ({ open, onToggle }, ref) => { + const [events, setEvents] = useState([]) + const seqRef = useRef(0) + + useImperativeHandle( + ref, + () => ({ + push: (event) => { + seqRef.current += 1 + setEvents((prev) => [ + ...prev, + { ...event, seq: seqRef.current, ts: Date.now() }, + ]) + }, + clear: () => setEvents([]), + }), + [], + ) + + const handleClear = useCallback(() => setEvents([]), []) + + if (!open) { + return ( + + ) + } + + return ( + + ) + }, +) +EventLog.displayName = 'EventLog' + +function EventList({ events }: { events: TaggedEvent[] }) { + const bottomRef = useRef(null) + const containerRef = useRef(null) + + // biome-ignore lint/correctness/useExhaustiveDependencies: events.length is the trigger. + useEffect(() => { + const c = containerRef.current + if (!c) return + const distanceFromBottom = c.scrollHeight - c.scrollTop - c.clientHeight + if (distanceFromBottom < 80) { + bottomRef.current?.scrollIntoView({ block: 'end' }) + } + }, [events.length]) + + if (events.length === 0) { + return ( +
+
+ no events yet. pick a scenario and send a message to populate. +
+
+ ) + } + + return ( +
+
    + {events.map((e) => ( + + ))} +
    +
+
+ ) +} + +function EventRow({ event }: { event: TaggedEvent }) { + const { kind, seq: _seq, ts, ...rest } = event + const tone = toneFor(kind) + const time = formatTime(ts) + const hasPayload = Object.keys(rest).length > 0 + const summary = summarize(kind, rest) + + return ( +
  • +
    + {time} + {kind} + {summary ? ( + {summary} + ) : null} +
    + {hasPayload && shouldExpandPayload(kind) ? ( +
    + +
    + ) : null} +
  • + ) +} + +function toneFor(kind: StreamEvent['kind']): string { + switch (kind) { + case 'thought-start': + case 'thought-end': + return 'text-ink-faint' + case 'thought-token': + return 'text-ink-ghost' + case 'fcall-start': + case 'fcall-end': + return 'text-accent' + case 'assistant-token': + return 'text-ink-ghost' + case 'assistant-end': + return 'text-ink' + } +} + +function shouldExpandPayload(kind: StreamEvent['kind']): boolean { + return kind === 'fcall-start' || kind === 'fcall-end' +} + +function summarize( + kind: StreamEvent['kind'], + rest: Record, +): string | null { + if (kind === 'thought-token' || kind === 'assistant-token') { + const t = rest.token + if (typeof t !== 'string') return null + const visible = t.replace(/\s+/g, ' ').trim() + return visible ? `“${truncate(visible, 32)}”` : '·whitespace·' + } + if (kind === 'thought-end' || kind === 'fcall-end') { + const d = rest.durationMs + if (typeof d === 'number') return `${d}ms` + } + if (kind === 'fcall-start') { + const id = rest.functionId + return typeof id === 'string' ? id : null + } + return null +} + +function truncate(s: string, n: number): string { + return s.length > n ? `${s.slice(0, n)}…` : s +} + +function formatTime(ts: number): string { + const d = new Date(ts) + const ms = String(d.getMilliseconds()).padStart(3, '0') + return `${d.getMinutes().toString().padStart(2, '0')}:${d + .getSeconds() + .toString() + .padStart(2, '0')}.${ms}` +} diff --git a/console/web/src/pages/Playground/ScenarioPicker.tsx b/console/web/src/pages/Playground/ScenarioPicker.tsx new file mode 100644 index 00000000..c319a315 --- /dev/null +++ b/console/web/src/pages/Playground/ScenarioPicker.tsx @@ -0,0 +1,92 @@ +import { Prompt } from '@/components/ui/Prompt' +import { cn } from '@/lib/utils' +import { + type PlaygroundScenario, + SCENARIO_GROUPS, + SCENARIOS, +} from './scenarios' + +interface ScenarioPickerProps { + selectedId: string + onSelect: (id: string) => void +} + +export function ScenarioPicker({ selectedId, onSelect }: ScenarioPickerProps) { + return ( + + ) +} + +interface ScenarioRowProps { + scenario: PlaygroundScenario + active: boolean + onSelect: () => void +} + +function ScenarioRow({ scenario, active, onSelect }: ScenarioRowProps) { + return ( +
  • + +
  • + ) +} diff --git a/console/web/src/pages/Playground/index.tsx b/console/web/src/pages/Playground/index.tsx new file mode 100644 index 00000000..124a0f05 --- /dev/null +++ b/console/web/src/pages/Playground/index.tsx @@ -0,0 +1,144 @@ +import { useCallback, useMemo, useRef, useState } from 'react' +import { ChatView } from '@/components/chat/ChatView' +import { uid } from '@/hooks/use-conversations' +import type { ChatBackend, StreamEvent } from '@/lib/backend' +import { + type Conversation, + DEFAULT_MODEL, + type Message, + type MessagePatch, + type Mode, + type ModelId, +} from '@/types/chat' +import { EventLog, type EventLogHandle } from './EventLog' +import { ScenarioPicker } from './ScenarioPicker' +import { findScenario, SCENARIOS } from './scenarios' + +function makeConvo(mode: Mode): Conversation { + const now = Date.now() + return { + id: uid(), + title: 'playground', + model: DEFAULT_MODEL, + mode, + messages: [], + createdAt: now, + updatedAt: now, + } +} + +/** Wrap a backend so each yielded event is also pushed into the event log. */ +function tapBackend( + source: ChatBackend, + onEvent: (event: StreamEvent) => void, +): ChatBackend { + return { + id: `${source.id}:tapped`, + async *stream(prompt, mode, model, opts) { + for await (const event of source.stream(prompt, mode, model, opts)) { + onEvent(event) + yield event + } + }, + } +} + +const FIRST = SCENARIOS[0] + +export function Playground() { + const [selectedId, setSelectedId] = useState(FIRST.id) + const [convo, setConvo] = useState(() => + makeConvo(FIRST.preferredMode ?? 'agent'), + ) + const [logOpen, setLogOpen] = useState(true) + const eventLogRef = useRef(null) + + const scenario = findScenario(selectedId) ?? FIRST + + const tappedBackend = useMemo( + () => tapBackend(scenario.backend, (e) => eventLogRef.current?.push(e)), + [scenario.backend], + ) + + const handleSelect = useCallback((id: string) => { + const next = findScenario(id) + if (!next) return + setSelectedId(id) + setConvo(makeConvo(next.preferredMode ?? 'agent')) + eventLogRef.current?.clear() + }, []) + + const handleReset = useCallback(() => { + setConvo(makeConvo(scenario.preferredMode ?? 'agent')) + eventLogRef.current?.clear() + }, [scenario.preferredMode]) + + const setMode = useCallback((_id: string, mode: Mode) => { + setConvo((c) => ({ ...c, mode, updatedAt: Date.now() })) + }, []) + + const setModel = useCallback((_id: string, model: ModelId) => { + setConvo((c) => ({ ...c, model, updatedAt: Date.now() })) + }, []) + + const appendMessage = useCallback((_id: string, message: Message) => { + setConvo((c) => ({ + ...c, + messages: [...c.messages, message], + updatedAt: Date.now(), + })) + }, []) + + const updateMessage = useCallback( + (_id: string, messageId: string, patch: MessagePatch) => { + setConvo((c) => ({ + ...c, + messages: c.messages.map((m) => + m.id === messageId ? ({ ...m, ...patch } as Message) : m, + ), + updatedAt: Date.now(), + })) + }, + [], + ) + + return ( +
    + + +
    +
    +
    + scenario + · + {scenario.label} +
    + +
    + + +
    + + setLogOpen((v) => !v)} + /> +
    + ) +} diff --git a/console/web/src/pages/Playground/scenarios/abort-mid-thought.ts b/console/web/src/pages/Playground/scenarios/abort-mid-thought.ts new file mode 100644 index 00000000..80dd802e --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/abort-mid-thought.ts @@ -0,0 +1,22 @@ +import { makeBackend, streamThought } from './helpers' + +const THOUGHT = `let me reason about this carefully — i'll lay out the +constraints first, then sketch the data flow, then ask whether the simplest +implementation actually meets the requirements before we add complexity.` + +/** + * Streams half the thought tokens, then throws an AbortError. Verifies that + * ChatView's catch+finally clears the streaming flag on the dangling thought + * message and the surface returns to "ready" without an unhandled rejection. + */ +export const abortMidThought = makeBackend( + 'abort-mid-thought', + async function* (_prompt, _mode, _model, opts) { + yield* streamThought(THOUGHT, { + signal: opts?.signal, + meanDelayMs: 18, + truncateAt: 0.5, + }) + throw new DOMException('aborted by scenario', 'AbortError') + }, +) diff --git a/console/web/src/pages/Playground/scenarios/error-on-fcall.ts b/console/web/src/pages/Playground/scenarios/error-on-fcall.ts new file mode 100644 index 00000000..2cbefbe6 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/error-on-fcall.ts @@ -0,0 +1,47 @@ +import { + makeBackend, + streamAssistant, + streamFcall, + streamThought, +} from './helpers' + +const THOUGHT = `dispatching to the rate-limiter behind engine::echo. if +this comes back with an error i'll surface it in plain language without +retrying — the user can decide whether to back off.` + +const BODY = `## blocked + +the call returned a structured error rather than data, so i'm stopping +here. the contract is: errors are shaped \`{ "error": { "kind", "message" } }\`, +which gives the chat surface enough to render them without guessing. + +retry once after a few seconds; if it persists, the upstream worker is +saturated and the rate-limit policy needs a tuning pass.` + +/** + * Function-call ends with an error payload (instead of a data payload). + * Backends should never throw to signal semantic failures — they should + * embed the error in the fcall-end output so the renderer can show it. + */ +export const errorOnFcall = makeBackend( + 'error-on-fcall', + async function* (prompt, _mode, _model, opts) { + const signal = opts?.signal + const text = prompt.replace(/\s+/g, ' ').trim().slice(0, 200) || '(empty)' + yield* streamThought(THOUGHT, { signal }) + yield* streamFcall({ + functionId: 'engine::echo', + input: { text }, + output: { + error: { + kind: 'rate_limited', + message: 'too many requests in window; retry after 5s', + retryAfterMs: 5000, + }, + }, + waitMs: 600, + signal, + }) + yield* streamAssistant(BODY, { signal }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/fast-tokens.ts b/console/web/src/pages/Playground/scenarios/fast-tokens.ts new file mode 100644 index 00000000..8a1c9f93 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/fast-tokens.ts @@ -0,0 +1,24 @@ +import { makeBackend, streamAssistant } from './helpers' + +const BODY = `fast firehose. tokens arrive about every 5ms. this stresses +the patch path — onPatchMessage runs once per token, so any react re-render +cost shows up as dropped frames here. + +paragraphs are intentionally long so we hit the renderer's hot path with a +non-trivial amount of inline content. emphasis like *italic* and **bold** +plus inline code like \`useMemo\` is sprinkled in to keep the markdown +processor honest under high token rate. + +| metric | budget | +|-----------|--------| +| latency | < 16ms | +| throughput| ~ 200 tok/s | +| dropped | 0 | +` + +export const fastTokens = makeBackend( + 'fast-tokens', + async function* (_prompt, _mode, _model, opts) { + yield* streamAssistant(BODY, { signal: opts?.signal, meanDelayMs: 5 }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/happy-agent.ts b/console/web/src/pages/Playground/scenarios/happy-agent.ts new file mode 100644 index 00000000..fdb2ae46 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/happy-agent.ts @@ -0,0 +1,38 @@ +import { + makeBackend, + streamAssistant, + streamFcall, + streamThought, +} from './helpers' + +const THOUGHT = `straightforward dispatch: this is an echo through +the engine, so i'll call \`engine::echo\` with the user's text verbatim and +report what comes back.` + +const BODY = `## echoed + +i ran \`engine::echo\` against your prompt and got the expected mirror back. +nothing else to do here — the worker is alive and responsive. + +\`\`\`json +{ "ok": true } +\`\`\` + +ready for the next instruction.` + +export const happyAgent = makeBackend( + 'happy-agent', + async function* (prompt, _mode, _model, opts) { + const signal = opts?.signal + const text = prompt.replace(/\s+/g, ' ').trim().slice(0, 200) || '(empty)' + yield* streamThought(THOUGHT, { signal }) + yield* streamFcall({ + functionId: 'engine::echo', + input: { text }, + output: { text }, + waitMs: 700, + signal, + }) + yield* streamAssistant(BODY, { signal }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/happy-ask.ts b/console/web/src/pages/Playground/scenarios/happy-ask.ts new file mode 100644 index 00000000..eb75f9a8 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/happy-ask.ts @@ -0,0 +1,26 @@ +import { makeBackend, streamAssistant } from './helpers' + +const BODY = `## what i can tell you + +short answer: it depends on whether you're optimizing for **read** speed or +**write** speed. a few things worth keeping in mind: + +- a flat \`Map\` gives you \`O(1)\` lookups but is awkward for ordered iteration. +- a sorted list trades insert cost for cheap range scans. +- if you need both, a btree-backed index is usually the right tool. + +| structure | lookup | ordered range | +|-----------|--------|---------------| +| map | o(1) | no | +| sorted | o(log) | yes | +| btree | o(log) | yes | + +pick the one whose worst case matches your hottest path. you can always swap +later — the interface is the thing that matters.` + +export const happyAsk = makeBackend( + 'happy-ask', + async function* (_prompt, _mode, _model, opts) { + yield* streamAssistant(BODY, { signal: opts?.signal }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/happy-plan.ts b/console/web/src/pages/Playground/scenarios/happy-plan.ts new file mode 100644 index 00000000..217bf72e --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/happy-plan.ts @@ -0,0 +1,31 @@ +import { makeBackend, streamAssistant, streamThought } from './helpers' + +const THOUGHT = `restating the request in one line, then enumerating +constraints. the user mentioned shape and direction but not scale, so i'll +plan for the smaller end of the range and flag the bigger case as a follow-up.` + +const BODY = `## plan + +i'd start by laying out the work as a sequence of small, reversible steps — +this keeps the surface area auditable and lets you bail out if the shape of +the problem changes. + +1. read the request carefully and restate it in one sentence. +2. enumerate the constraints (latency, footprint, dependencies). +3. sketch the data flow on paper before writing any code. +4. pick the smallest slice that proves the design, then iterate. + +\`\`\`text +problem -> constraints -> sketch -> slice -> ship +\`\`\` + +a one-liner you can keep in your back pocket: *plan the work, then work the +plan*. nothing fancy, but it survives contact with reality.` + +export const happyPlan = makeBackend( + 'happy-plan', + async function* (_prompt, _mode, _model, opts) { + yield* streamThought(THOUGHT, { signal: opts?.signal }) + yield* streamAssistant(BODY, { signal: opts?.signal }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/helpers.ts b/console/web/src/pages/Playground/scenarios/helpers.ts new file mode 100644 index 00000000..057434ae --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/helpers.ts @@ -0,0 +1,125 @@ +import type { ChatBackend, ChatStreamOptions, StreamEvent } from '@/lib/backend' +import type { Mode, ModelId } from '@/types/chat' + +export type ScenarioStream = ( + prompt: string, + mode: Mode, + model: ModelId, + opts?: ChatStreamOptions, +) => AsyncGenerator + +export function makeBackend(id: string, stream: ScenarioStream): ChatBackend { + return { id, stream } +} + +export function tokenize(body: string): string[] { + return body.split(/(\s+)/) +} + +export function sleep(ms: number, signal?: AbortSignal): Promise { + return new Promise((resolve) => { + if (signal?.aborted) return resolve() + const t = setTimeout(resolve, ms) + signal?.addEventListener( + 'abort', + () => { + clearTimeout(t) + resolve() + }, + { once: true }, + ) + }) +} + +interface ThoughtOptions { + signal?: AbortSignal + /** mean delay between thought tokens, in ms */ + meanDelayMs?: number + /** if set, hard-stop after this fraction of tokens (0..1] */ + truncateAt?: number +} + +export async function* streamThought( + body: string, + options: ThoughtOptions = {}, +): AsyncGenerator { + const { signal, meanDelayMs = 14, truncateAt } = options + const startedAt = Date.now() + yield { kind: 'thought-start' } + const tokens = tokenize(body) + const limit = + typeof truncateAt === 'number' + ? Math.max(1, Math.floor(tokens.length * truncateAt)) + : tokens.length + for (let i = 0; i < limit; i++) { + if (signal?.aborted) return + const tok = tokens[i] + if (tok) yield { kind: 'thought-token', token: tok } + await sleep(meanDelayMs * (0.6 + Math.random() * 0.8), signal) + } + if (typeof truncateAt === 'number') return + yield { kind: 'thought-end', durationMs: Date.now() - startedAt } +} + +interface AssistantOptions { + signal?: AbortSignal + meanDelayMs?: number + /** when false, do NOT yield assistant-end (used by truncation tests) */ + emitEnd?: boolean +} + +export async function* streamAssistant( + body: string, + options: AssistantOptions = {}, +): AsyncGenerator { + const { signal, meanDelayMs = 22, emitEnd = true } = options + for (const tok of tokenize(body)) { + if (signal?.aborted) return + if (tok) yield { kind: 'assistant-token', token: tok } + await sleep(meanDelayMs * (0.5 + Math.random()), signal) + } + if (emitEnd) yield { kind: 'assistant-end' } +} + +interface FcallOptions { + functionId: string + input: unknown + output: unknown + /** how long the call "runs" before fcall-end */ + waitMs?: number + /** when true, emit pendingApproval and wait for an arbitrary timeout */ + pendingApproval?: boolean + /** signal */ + signal?: AbortSignal + /** how long to "wait for approval" before resolving */ + approvalWaitMs?: number +} + +export async function* streamFcall( + options: FcallOptions, +): AsyncGenerator { + const { + functionId, + input, + output, + waitMs = 600, + pendingApproval, + signal, + approvalWaitMs = 1500, + } = options + const startedAt = Date.now() + yield { + kind: 'fcall-start', + functionId, + input, + pendingApproval, + } + if (pendingApproval) { + /* simulate the lag between "user clicks approve" and the call running */ + await sleep(approvalWaitMs, signal) + if (signal?.aborted) return + } + await sleep(waitMs, signal) + if (signal?.aborted) return + yield { kind: 'fcall-end', output, durationMs: Date.now() - startedAt } +} diff --git a/console/web/src/pages/Playground/scenarios/index.ts b/console/web/src/pages/Playground/scenarios/index.ts new file mode 100644 index 00000000..426db00a --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/index.ts @@ -0,0 +1,140 @@ +import type { ChatBackend } from '@/lib/backend' +import type { Mode } from '@/types/chat' +import { abortMidThought } from './abort-mid-thought' +import { errorOnFcall } from './error-on-fcall' +import { fastTokens } from './fast-tokens' +import { happyAgent } from './happy-agent' +import { happyAsk } from './happy-ask' +import { happyPlan } from './happy-plan' +import { longMarkdown } from './long-markdown' +import { markdownStress } from './markdown-stress' +import { multiToolAgent } from './multi-tool-agent' +import { pendingApproval } from './pending-approval' +import { slowTokens } from './slow-tokens' + +export type ScenarioGroup = + | 'happy paths' + | 'timing' + | 'failure modes' + | 'markdown' + | 'agent' + +export interface PlaygroundScenario { + id: string + label: string + description: string + group: ScenarioGroup + /** mode the chat surface should be put into to make the scenario read right */ + preferredMode?: Mode + backend: ChatBackend +} + +export const SCENARIOS: PlaygroundScenario[] = [ + { + id: 'happy-plan', + label: 'happy · plan', + description: 'thought + assistant body, no function calls.', + group: 'happy paths', + preferredMode: 'plan', + backend: happyPlan, + }, + { + id: 'happy-ask', + label: 'happy · ask', + description: 'assistant body only, no thought, no function calls.', + group: 'happy paths', + preferredMode: 'ask', + backend: happyAsk, + }, + { + id: 'happy-agent', + label: 'happy · agent', + description: 'thought + one function call + assistant body.', + group: 'happy paths', + preferredMode: 'agent', + backend: happyAgent, + }, + { + id: 'slow-tokens', + label: 'slow tokens', + description: + '~200ms between assistant tokens — watch for renderer flicker.', + group: 'timing', + preferredMode: 'ask', + backend: slowTokens, + }, + { + id: 'fast-tokens', + label: 'fast tokens', + description: '~5ms between assistant tokens — stresses the patch path.', + group: 'timing', + preferredMode: 'ask', + backend: fastTokens, + }, + { + id: 'abort-mid-thought', + label: 'abort mid-thought', + description: + 'half a thought, then throws AbortError. ChatView should clean up and stay responsive.', + group: 'failure modes', + preferredMode: 'plan', + backend: abortMidThought, + }, + { + id: 'error-on-fcall', + label: 'error on fcall', + description: + 'function call ends with an error payload (rate_limited) instead of data.', + group: 'failure modes', + preferredMode: 'agent', + backend: errorOnFcall, + }, + { + id: 'multi-tool-agent', + label: 'multi-tool agent', + description: + 'three sequential function calls before the assistant body — surfaces fcall pointer reuse.', + group: 'agent', + preferredMode: 'agent', + backend: multiToolAgent, + }, + { + id: 'pending-approval', + label: 'pending approval', + description: + 'fcall that requires user approval; auto-resolves after a delay so you can watch the lifecycle.', + group: 'agent', + preferredMode: 'agent', + backend: pendingApproval, + }, + { + id: 'long-markdown', + label: 'long markdown', + description: + '~4kB body: headings, lists, tables, fenced code in 3 langs, blockquotes, task lists.', + group: 'markdown', + preferredMode: 'ask', + backend: longMarkdown, + }, + { + id: 'markdown-stress', + label: 'markdown stress', + description: + 'pathological markdown: nested lists, footnotes, autolinks, hard breaks, busy tables.', + group: 'markdown', + preferredMode: 'ask', + backend: markdownStress, + }, +] + +export const SCENARIO_GROUPS: ScenarioGroup[] = [ + 'happy paths', + 'agent', + 'failure modes', + 'timing', + 'markdown', +] + +export function findScenario(id: string): PlaygroundScenario | undefined { + return SCENARIOS.find((s) => s.id === id) +} diff --git a/console/web/src/pages/Playground/scenarios/long-markdown.ts b/console/web/src/pages/Playground/scenarios/long-markdown.ts new file mode 100644 index 00000000..1dc92f5d --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/long-markdown.ts @@ -0,0 +1,103 @@ +import { makeBackend, streamAssistant } from './helpers' + +const BODY = `# system overview + +a deeper walkthrough of the architecture, written long-form so the markdown +renderer has plenty of surface to chew on. paragraphs interleave with lists, +tables, fenced code, and quotes. + +## components + +each component owns one job and exposes one boundary. the boundaries are the +contract; everything else is implementation detail. + +1. **gateway** — terminates tls, authenticates, rate-limits. + 1. tls is offloaded to the load balancer; gateway sees plaintext. + 2. auth is jwt verification with a rolling jwks cache. + - cache hits short-circuit the call to the issuer. + - cache misses fall through to the issuer with a 200ms timeout. + 3. rate-limits are token-bucket, keyed on (subject, route). +2. **router** — map verb + path to a handler ref. +3. **handler** — pure function over (request, deps) → response. +4. **store** — the only stateful component; the rest are stateless workers. + +## a worked example + +> "show me what happens when a user creates a new conversation." + +the gateway accepts the request, validates the bearer token, checks the +rate-limit, and forwards the validated envelope to the router. the router +matches \`POST /conversations\` to the create-conversation handler, which +inserts a row in \`conversations\`, appends a system event, and returns the +new id. + +\`\`\`ts +// handlers/conversations.ts +export async function create( + req: ValidatedRequest, + { db, clock }: Deps, +): Promise> { + const id = ulid() + await db.tx(async (tx) => { + await tx.run(insertConversation, { id, userId: req.subject, createdAt: clock.now() }) + await tx.run(insertEvent, { conversationId: id, kind: 'created' }) + }) + return ok({ id }) +} +\`\`\` + +\`\`\`sql +-- migrations/0001_conversations.sql +create table conversations ( + id text primary key, + user_id text not null, + title text, + created_at timestamp not null, + updated_at timestamp not null +); + +create index conversations_user_id_idx on conversations (user_id, updated_at desc); +\`\`\` + +\`\`\`bash +$ curl -X POST https://api.example.com/conversations \\ + -H 'authorization: bearer $TOKEN' \\ + -H 'content-type: application/json' \\ + -d '{}' +{"id":"01HV2..."} +\`\`\` + +## error semantics + +| layer | shape | retry? | +|----------|------------------------|----------------------------| +| gateway | http 4xx | no — caller fix | +| gateway | http 5xx | yes — exponential backoff | +| router | not_found | no | +| handler | domain.error | depends on \`kind\` | +| store | conflict / deadlock | yes — bounded retry | + +domain errors carry a stable \`kind\` so callers can branch on the contract: + +- \`kind: 'rate_limited'\` — back off and retry with jitter. +- \`kind: 'unauthorized'\` — refresh the token, retry once. +- \`kind: 'invalid_argument'\` — caller bug; do not retry. +- \`kind: 'conflict'\` — deterministic conflict; refetch and replay. + +## checklist before shipping + +- [ ] every public endpoint has a test exercising the unhappy path. +- [ ] every domain error has a stable \`kind\` and is documented. +- [ ] migrations are reversible. +- [x] release notes are written. +- [ ] dashboards show p50/p95/p99 latency for the new route. + +> *the goal isn't to anticipate every failure — it's to make every failure +> debuggable when it happens.*` + +export const longMarkdown = makeBackend( + 'long-markdown', + async function* (_prompt, _mode, _model, opts) { + yield* streamAssistant(BODY, { signal: opts?.signal, meanDelayMs: 6 }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/markdown-stress.ts b/console/web/src/pages/Playground/scenarios/markdown-stress.ts new file mode 100644 index 00000000..e2fcf0b9 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/markdown-stress.ts @@ -0,0 +1,94 @@ +import { makeBackend, streamAssistant } from './helpers' + +const BODY = `# markdown stress + +paragraph with [a regular link](https://example.com) and a bare autolink +. inline code: \`useDeferredValue\`. emphasis: +*italic*, **bold**, ***both***, ~~struck~~. + +## task list (gfm) + +- [x] write the renderer +- [x] handle gfm tables +- [ ] handle footnotes[^note] +- [ ] handle hard breaks + this line follows a hard break (two trailing spaces). + +## footnotes + +here is a sentence with a footnote reference[^1] and another[^2]. + +[^1]: footnote one — short and sweet. +[^2]: footnote two — multi-line. + second line of footnote two indented under the marker. +[^note]: a named footnote, just to vary the syntax. + +## fenced code variants + +\`\`\`ts +type Result = { ok: true; value: T } | { ok: false; error: E } + +export function ok(value: T): Result { + return { ok: true, value } +} +\`\`\` + +\`\`\`python +def fib(n: int) -> int: + a, b = 0, 1 + for _ in range(n): + a, b = b, a + b + return a +\`\`\` + +\`\`\`rust +fn main() { + let xs: Vec = (1..=10).collect(); + let sum: i32 = xs.iter().sum(); + println!("{}", sum); +} +\`\`\` + +## deep nesting + +- level one + - level two + - level three + - level four + - level five — too deep, but renderers must not crash. +- back to level one + 1. ordered nested + 2. inside unordered + 1. and back to ordered three deep. + +## quotes + +> single-line quote. + +> multi-line +> quote that wraps +> across three lines. + +>> nested quote with emphasis: *still readable?* + +## a busy table + +| feature | status | notes | +|-------------------|-------------|---------------------------------| +| headings | ok | h1–h6, all weights | +| inline code | ok | backticks render mono | +| fenced code | ok | language hint drives highlight | +| tables | ok | gfm pipe tables | +| task lists | ok | checkbox renders | +| footnotes | depends | requires \`remark-gfm\` | +| autolinks | ok | bare urls become anchors | +| hard breaks | ok | trailing two-space → \`
    \` | + +end of stress.` + +export const markdownStress = makeBackend( + 'markdown-stress', + async function* (_prompt, _mode, _model, opts) { + yield* streamAssistant(BODY, { signal: opts?.signal, meanDelayMs: 4 }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/multi-tool-agent.ts b/console/web/src/pages/Playground/scenarios/multi-tool-agent.ts new file mode 100644 index 00000000..48bd0c40 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/multi-tool-agent.ts @@ -0,0 +1,64 @@ +import { + makeBackend, + streamAssistant, + streamFcall, + streamThought, +} from './helpers' + +const THOUGHT = `multi-step agent: i'll list workers, then inspect the +healthiest one, then echo a probe through it. each tool call is sequential +so the chat surface needs to reset its fcall pointer between calls.` + +const BODY = `## probe complete + +ran three tools end-to-end: listed workers, inspected \`worker-7\` (least +loaded), and echoed a probe through it. all three calls returned cleanly, +so the dispatch path is healthy. + +\`\`\`text +list -> info(worker-7) -> echo(worker-7, "ping") +\`\`\` + +ready for the next instruction.` + +/** + * Three sequential function calls back-to-back. Surfaces any pointer-reset + * bug in ChatView (the consumer must clear its fcallId after each fcall-end + * so the next fcall-start gets a fresh slot). + */ +export const multiToolAgent = makeBackend( + 'multi-tool-agent', + async function* (_prompt, _mode, _model, opts) { + const signal = opts?.signal + yield* streamThought(THOUGHT, { signal }) + yield* streamFcall({ + functionId: 'engine::list', + input: {}, + output: { + workers: ['worker-1', 'worker-3', 'worker-7'], + }, + waitMs: 450, + signal, + }) + yield* streamFcall({ + functionId: 'engine::info', + input: { id: 'worker-7' }, + output: { + id: 'worker-7', + load: 0.12, + version: '0.4.1', + skills: ['echo', 'tokenize', 'embed'], + }, + waitMs: 500, + signal, + }) + yield* streamFcall({ + functionId: 'engine::echo', + input: { workerId: 'worker-7', text: 'ping' }, + output: { text: 'ping' }, + waitMs: 350, + signal, + }) + yield* streamAssistant(BODY, { signal }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/pending-approval.ts b/console/web/src/pages/Playground/scenarios/pending-approval.ts new file mode 100644 index 00000000..8ae967b8 --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/pending-approval.ts @@ -0,0 +1,35 @@ +import { makeBackend, streamAssistant, streamFcall } from './helpers' + +const BODY = `## triggered + +approval was granted, the trigger fired, the downstream function returned +the expected ack. nothing else to do here.` + +/** + * Function call gated on user approval. The renderer shows approve/deny + * affordances; this scenario auto-resolves after a short wait so we can + * see the lifecycle pending → running → done in motion. + */ +export const pendingApproval = makeBackend( + 'pending-approval', + async function* (_prompt, _mode, _model, opts) { + const signal = opts?.signal + yield* streamFcall({ + functionId: 'trigger::run', + input: { + triggerId: 'deploy::staging', + actor: 'you', + confirm: 'this will redeploy staging — proceed?', + }, + output: { + ack: true, + deploymentId: 'dep_01HV2...', + }, + pendingApproval: true, + approvalWaitMs: 1800, + waitMs: 600, + signal, + }) + yield* streamAssistant(BODY, { signal }) + }, +) diff --git a/console/web/src/pages/Playground/scenarios/slow-tokens.ts b/console/web/src/pages/Playground/scenarios/slow-tokens.ts new file mode 100644 index 00000000..778f3a4c --- /dev/null +++ b/console/web/src/pages/Playground/scenarios/slow-tokens.ts @@ -0,0 +1,21 @@ +import { makeBackend, streamAssistant } from './helpers' + +const BODY = `slow drip. each token arrives roughly every 200ms so you can +watch the renderer settle. useful for catching layout-jitter or cursor +flicker that fast streams hide. + +- bullet one +- bullet two +- bullet three + +\`\`\`text +sl o w +\`\`\` +` + +export const slowTokens = makeBackend( + 'slow-tokens', + async function* (_prompt, _mode, _model, opts) { + yield* streamAssistant(BODY, { signal: opts?.signal, meanDelayMs: 200 }) + }, +)