diff --git a/CHANGELOG.md b/CHANGELOG.md
index db00c82ff..aeb93d838 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@
- Talk Mode: treat history timestamps as seconds or milliseconds to avoid stale assistant picks (macOS/iOS/Android).
- Chat UI: clear streaming/tool bubbles when external runs finish, preventing duplicate assistant bubbles.
- Chat UI: user bubbles use `ui.seamColor` (fallback to a calmer default blue).
+- Control UI: sync sidebar navigation with the URL for deep-linking, and auto-scroll chat to the latest message.
- Talk Mode: wait for chat history to surface the assistant reply before starting TTS (macOS/iOS/Android).
- iOS Talk Mode: fix chat completion wait to time out even if no events arrive (prevents “Thinking…” hangs).
- iOS Talk Mode: keep recognition running during playback to support interrupt-on-speech.
diff --git a/package.json b/package.json
index 293e7e4b2..30a30a37d 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,7 @@
"@mariozechner/pi-agent-core": "^0.30.2",
"@mariozechner/pi-ai": "^0.30.2",
"@mariozechner/pi-coding-agent": "^0.30.2",
- "@sinclair/typebox": "^0.34.41",
+ "@sinclair/typebox": "^0.34.45",
"@whiskeysockets/baileys": "7.0.0-rc.9",
"ajv": "^8.17.1",
"body-parser": "^2.2.1",
@@ -87,7 +87,7 @@
"discord.js": "^14.25.1",
"dotenv": "^17.2.3",
"express": "^5.2.1",
- "file-type": "^21.1.1",
+ "file-type": "^21.2.0",
"grammy": "^1.38.4",
"json5": "^2.2.3",
"long": "5.3.2",
@@ -101,7 +101,7 @@
},
"devDependencies": {
"@biomejs/biome": "^2.3.10",
- "@lit-labs/signals": "^0.1.3",
+ "@lit-labs/signals": "^0.2.0",
"@lit/context": "^1.1.6",
"@mariozechner/mini-lit": "0.2.1",
"@types/body-parser": "^1.19.6",
@@ -113,14 +113,14 @@
"@vitest/coverage-v8": "^4.0.16",
"docx-preview": "^0.3.7",
"jszip": "^3.10.1",
- "lit": "^3.3.1",
+ "lit": "^3.3.2",
"lucide": "^0.562.0",
"markdown-it": "^14.1.0",
"ollama": "^0.6.3",
- "oxlint": "^1.35.0",
+ "oxlint": "^1.36.0",
"oxlint-tsgolint": "^0.10.0",
"quicktype-core": "^23.2.6",
- "rolldown": "1.0.0-beta.55",
+ "rolldown": "1.0.0-beta.57",
"signal-utils": "^0.21.1",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 86f28ae6a..d524e4c4a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -29,8 +29,8 @@ importers:
specifier: ^0.30.2
version: 0.30.2(ws@8.18.3)(zod@4.2.1)
'@sinclair/typebox':
- specifier: ^0.34.41
- version: 0.34.41
+ specifier: ^0.34.45
+ version: 0.34.45
'@whiskeysockets/baileys':
specifier: 7.0.0-rc.9
version: 7.0.0-rc.9(audio-decode@2.2.3)(sharp@0.34.5)
@@ -68,8 +68,8 @@ importers:
specifier: ^5.2.1
version: 5.2.1
file-type:
- specifier: ^21.1.1
- version: 21.1.1
+ specifier: ^21.2.0
+ version: 21.2.0
grammy:
specifier: ^1.38.4
version: 1.38.4
@@ -105,14 +105,14 @@ importers:
specifier: ^2.3.10
version: 2.3.10
'@lit-labs/signals':
- specifier: ^0.1.3
- version: 0.1.3
+ specifier: ^0.2.0
+ version: 0.2.0
'@lit/context':
specifier: ^1.1.6
version: 1.1.6
'@mariozechner/mini-lit':
specifier: 0.2.1
- version: 0.2.1(lit@3.3.1)(tailwindcss@4.1.17)
+ version: 0.2.1(lit@3.3.2)(tailwindcss@4.1.17)
'@types/body-parser':
specifier: ^1.19.6
version: 1.19.6
@@ -133,7 +133,7 @@ importers:
version: 8.18.1
'@vitest/coverage-v8':
specifier: ^4.0.16
- version: 4.0.16(vitest@4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))
+ version: 4.0.16(@vitest/browser@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16))(vitest@4.0.16)
docx-preview:
specifier: ^0.3.7
version: 0.3.7
@@ -141,8 +141,8 @@ importers:
specifier: ^3.10.1
version: 3.10.1
lit:
- specifier: ^3.3.1
- version: 3.3.1
+ specifier: ^3.3.2
+ version: 3.3.2
lucide:
specifier: ^0.562.0
version: 0.562.0
@@ -153,8 +153,8 @@ importers:
specifier: ^0.6.3
version: 0.6.3
oxlint:
- specifier: ^1.35.0
- version: 1.35.0(oxlint-tsgolint@0.10.0)
+ specifier: ^1.36.0
+ version: 1.36.0(oxlint-tsgolint@0.10.0)
oxlint-tsgolint:
specifier: ^0.10.0
version: 0.10.0
@@ -162,8 +162,8 @@ importers:
specifier: ^23.2.6
version: 23.2.6
rolldown:
- specifier: 1.0.0-beta.55
- version: 1.0.0-beta.55
+ specifier: 1.0.0-beta.57
+ version: 1.0.0-beta.57
signal-utils:
specifier: ^0.21.1
version: 0.21.1(signal-polyfill@0.2.2)
@@ -175,7 +175,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^4.0.16
- version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ version: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
wireit:
specifier: ^0.14.12
version: 0.14.12
@@ -183,15 +183,24 @@ importers:
ui:
dependencies:
lit:
- specifier: ^3.3.1
- version: 3.3.1
+ specifier: ^3.3.2
+ version: 3.3.2
devDependencies:
+ '@vitest/browser-playwright':
+ specifier: 4.0.16
+ version: 4.0.16(playwright@1.57.0)(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)
+ playwright:
+ specifier: ^1.57.0
+ version: 1.57.0
typescript:
specifier: ^5.9.3
version: 5.9.3
vite:
specifier: 8.0.0-beta.3
version: 8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)
+ vitest:
+ specifier: 4.0.16
+ version: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
packages:
@@ -204,6 +213,10 @@ packages:
zod:
optional: true
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
@@ -285,18 +298,18 @@ packages:
'@borewit/text-codec@0.1.1':
resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==}
- '@borewit/text-codec@0.2.0':
- resolution: {integrity: sha512-X999CKBxGwX8wW+4gFibsbiNdwqmdQEXmUejIWaIqdrHBgS5ARIOOeyiQbHjP9G58xVEPcuvP6VwwH3A0OFTOA==}
+ '@borewit/text-codec@0.2.1':
+ resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==}
- '@cacheable/memory@2.0.6':
- resolution: {integrity: sha512-7e8SScMocHxcAb8YhtkbMhGG+EKLRIficb1F5sjvhSYsWTZGxvg4KIDp8kgxnV2PUJ3ddPe6J9QESjKvBWRDkg==}
+ '@cacheable/memory@2.0.7':
+ resolution: {integrity: sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==}
'@cacheable/node-cache@1.7.6':
resolution: {integrity: sha512-6Omk2SgNnjtxB5f/E6bTIWIt5xhdpx39fGNRQgU9lojvRxU68v+qY+SXXLsp3ZGukqoPjsK21wZ6XABFr/Ge3A==}
engines: {node: '>=18'}
- '@cacheable/utils@2.3.2':
- resolution: {integrity: sha512-8kGE2P+HjfY8FglaOiW+y8qxcaQAfAhVML+i66XJR3YX5FtyDqn6Txctr3K2FrbxLKixRRYYBWMbuGciOhYNDg==}
+ '@cacheable/utils@2.3.3':
+ resolution: {integrity: sha512-JsXDL70gQ+1Vc2W/KUFfkAJzgb4puKwwKehNLuB+HrNKWf91O736kGfxn4KujXCCSuh6mRRL4XEB0PkAFjWS0A==}
'@discordjs/builders@1.13.1':
resolution: {integrity: sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==}
@@ -693,17 +706,17 @@ packages:
'@keyv/serialize@1.1.1':
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
- '@lit-labs/signals@0.1.3':
- resolution: {integrity: sha512-P0yWgH5blwVyEwBg+WFspLzeu1i0ypJP1QB0l1Omr9qZLIPsUu0p4Fy2jshOg7oQyha5n163K3GJGeUhQQ682Q==}
+ '@lit-labs/signals@0.2.0':
+ resolution: {integrity: sha512-68plyIbciumbwKaiilhLNyhz4Vg6/+nJwDufG2xxWA9r/fUw58jxLHCAlKs+q1CE5Lmh3cZ3ShyYKnOCebEpVA==}
- '@lit-labs/ssr-dom-shim@1.4.0':
- resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==}
+ '@lit-labs/ssr-dom-shim@1.5.0':
+ resolution: {integrity: sha512-HLomZXMmrCFHSRKESF5vklAKsDY7/fsT/ZhqCu3V0UoW/Qbv8wxmO4W9bx4KnCCF2Zak4yuk+AGraK/bPmI4kA==}
'@lit/context@1.1.6':
resolution: {integrity: sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==}
- '@lit/reactive-element@2.1.1':
- resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==}
+ '@lit/reactive-element@2.1.2':
+ resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==}
'@mariozechner/mini-lit@0.2.1':
resolution: {integrity: sha512-u300euLgCsDDlb8o2Wbz+55eSJga5X2vB58s9XBuFIr2Bi3iI+GMR7t/NYo/O6Vr6obXShXgYjR3SRUJVgo+kQ==}
@@ -731,8 +744,8 @@ packages:
'@mistralai/mistralai@1.10.0':
resolution: {integrity: sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg==}
- '@napi-rs/wasm-runtime@1.1.0':
- resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
+ '@napi-rs/wasm-runtime@1.1.1':
+ resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
@@ -783,43 +796,43 @@ packages:
cpu: [x64]
os: [win32]
- '@oxlint/darwin-arm64@1.35.0':
- resolution: {integrity: sha512-ieiYVHkNZPo77Hgrxav595wGS4rRNKuDNrljf+4xhwpJsddrxMpM64IQUf2IvR3MhK4FxdGzhhB6OVmGVHY5/w==}
+ '@oxlint/darwin-arm64@1.36.0':
+ resolution: {integrity: sha512-MJkj82GH+nhvWKJhSIM6KlZ8tyGKdogSQXtNdpIyP02r/tTayFJQaAEWayG2Jhsn93kske+nimg5MYFhwO/rlg==}
cpu: [arm64]
os: [darwin]
- '@oxlint/darwin-x64@1.35.0':
- resolution: {integrity: sha512-1jNHu3j66X5jKySvgtE+jGtjx4ye+xioAucVTi2IuROZO6keK2YG74pnD+9FT+DpWZAtWRZGoW0r0x6aN9sEEg==}
+ '@oxlint/darwin-x64@1.36.0':
+ resolution: {integrity: sha512-VvEhfkqj/99dCTqOcfkyFXOSbx4lIy5u2m2GHbK4WCMDySokOcMTNRHGw8fH/WgQ5cDrDMSTYIGQTmnBGi9tiQ==}
cpu: [x64]
os: [darwin]
- '@oxlint/linux-arm64-gnu@1.35.0':
- resolution: {integrity: sha512-T1lc0UaYbTxZyqVpLfC7eipbauNG8pBpkaZEW4JGz8Y68rxTH7d9s+CF0zxUxNr5RCtcmT669RLVjQT7VrKVLg==}
+ '@oxlint/linux-arm64-gnu@1.36.0':
+ resolution: {integrity: sha512-EMx92X5q+hHc3olTuj/kgkx9+yP0p/AVs4yvHbUfzZhBekXNpUWxWvg4hIKmQWn+Ee2j4o80/0ACGO0hDYJ9mg==}
cpu: [arm64]
os: [linux]
- '@oxlint/linux-arm64-musl@1.35.0':
- resolution: {integrity: sha512-7Wv5Pke9kwWKFycUziSHsmi3EM0389TLzraB0KE/MArrKxx30ycwfJ5PYoMj9ERoW+Ybs0txdaOF/xJy/XyYkg==}
+ '@oxlint/linux-arm64-musl@1.36.0':
+ resolution: {integrity: sha512-7YCxtrPIctVYLqWrWkk8pahdCxch6PtsaucfMLC7TOlDt4nODhnQd4yzEscKqJ8Gjrw1bF4g+Ngob1gB+Qr9Fw==}
cpu: [arm64]
os: [linux]
- '@oxlint/linux-x64-gnu@1.35.0':
- resolution: {integrity: sha512-HDMPOzyVVy+rQl3H7UOq8oGHt7m1yaiWCanlhAu4jciK8dvXeO9OG/OQd74lD/h05IcJh93pCLEJ3wWOG8hTiQ==}
+ '@oxlint/linux-x64-gnu@1.36.0':
+ resolution: {integrity: sha512-lnaJVlx5r3NWmoOMesfQXJSf78jHTn8Z+sdAf795Kgteo72+qGC1Uax2SToCJVN2J8PNG3oRV5bLriiCNR2i6Q==}
cpu: [x64]
os: [linux]
- '@oxlint/linux-x64-musl@1.35.0':
- resolution: {integrity: sha512-kAPBBsUOM3HQQ6n3nnZauvFR9EoXqCSoj4O3OSXXarzsRTiItNrHabVUwxeswZEc+xMzQNR0FHEWg/d4QAAWLw==}
+ '@oxlint/linux-x64-musl@1.36.0':
+ resolution: {integrity: sha512-AhuEU2Qdl66lSfTGu/Htirq8r/8q2YnZoG3yEXLMQWnPMn7efy8spD/N1NA7kH0Hll+cdfwgQkQqC2G4MS2lPQ==}
cpu: [x64]
os: [linux]
- '@oxlint/win32-arm64@1.35.0':
- resolution: {integrity: sha512-qrpBkkOASS0WT8ra9xmBRXOEliN6D/MV9JhI/68lFHrtLhfFuRwg4AjzjxrCWrQCnQ0WkvAVpJzu73F4ICLYZw==}
+ '@oxlint/win32-arm64@1.36.0':
+ resolution: {integrity: sha512-GlWCBjUJY2QgvBFuNRkiRJu7K/djLmM0UQKfZV8IN+UXbP/JbjZHWKRdd4LXlQmzoz7M5Hd6p+ElCej8/90FCg==}
cpu: [arm64]
os: [win32]
- '@oxlint/win32-x64@1.35.0':
- resolution: {integrity: sha512-yPFcj6umrhusnG/kMS5wh96vblsqZ0kArQJS+7kEOSJDrH+DsFWaDCsSRF8U6gmSmZJ26KVMU3C3TMpqDN4M1g==}
+ '@oxlint/win32-x64@1.36.0':
+ resolution: {integrity: sha512-J+Vc00Utcf8p77lZPruQgb0QnQXuKnFogN88kCnOqs2a83I+vTBB8ILr0+L9sTwVRvIDMSC0pLdeQH4svWGFZg==}
cpu: [x64]
os: [win32]
@@ -830,6 +843,9 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
+ '@polka/url@1.0.0-next.29':
+ resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
+
'@preact/signals-core@1.12.1':
resolution: {integrity: sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==}
@@ -869,80 +885,160 @@ packages:
cpu: [arm64]
os: [android]
+ '@rolldown/binding-android-arm64@1.0.0-beta.57':
+ resolution: {integrity: sha512-GoOVDy8bjw9z1K30Oo803nSzXJS/vWhFijFsW3kzvZCO8IZwFnNa6pGctmbbJstKl3Fv6UBwyjJQN6msejW0IQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
'@rolldown/binding-darwin-arm64@1.0.0-beta.55':
resolution: {integrity: sha512-l0887CGU2SXZr0UJmeEcXSvtDCOhDTTYXuoWbhrEJ58YQhQk24EVhDhHMTyjJb1PBRniUgNc1G0T51eF8z+TWw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.57':
+ resolution: {integrity: sha512-9c4FOhRGpl+PX7zBK5p17c5efpF9aSpTPgyigv57hXf5NjQUaJOOiejPLAtFiKNBIfm5Uu6yFkvLKzOafNvlTw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
'@rolldown/binding-darwin-x64@1.0.0-beta.55':
resolution: {integrity: sha512-d7qP2AVYzN0tYIP4vJ7nmr26xvmlwdkLD/jWIc9Z9dqh5y0UGPigO3m5eHoHq9BNazmwdD9WzDHbQZyXFZjgtA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
+ '@rolldown/binding-darwin-x64@1.0.0-beta.57':
+ resolution: {integrity: sha512-6RsB8Qy4LnGqNGJJC/8uWeLWGOvbRL/KG5aJ8XXpSEupg/KQtlBEiFaYU/Ma5Usj1s+bt3ItkqZYAI50kSplBA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
'@rolldown/binding-freebsd-x64@1.0.0-beta.55':
resolution: {integrity: sha512-j311E4NOB0VMmXHoDDZhrWidUf7L/Sa6bu/+i2cskvHKU40zcUNPSYeD2YiO2MX+hhDFa5bJwhliYfs+bTrSZw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.57':
+ resolution: {integrity: sha512-uA9kG7+MYkHTbqwv67Tx+5GV5YcKd33HCJIi0311iYBd25yuwyIqvJfBdt1VVB8tdOlyTb9cPAgfCki8nhwTQg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.55':
resolution: {integrity: sha512-lAsaYWhfNTW2A/9O7zCpb5eIJBrFeNEatOS/DDOZ5V/95NHy50g4b/5ViCqchfyFqRb7MKUR18/+xWkIcDkeIw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.57':
+ resolution: {integrity: sha512-3KkS0cHsllT2T+Te+VZMKHNw6FPQihYsQh+8J4jkzwgvAQpbsbXmrqhkw3YU/QGRrD8qgcOvBr6z5y6Jid+rmw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.55':
resolution: {integrity: sha512-2x6ffiVLZrQv7Xii9+JdtyT1U3bQhKj59K3eRnYlrXsKyjkjfmiDUVx2n+zSyijisUqD62fcegmx2oLLfeTkCA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.57':
+ resolution: {integrity: sha512-A3/wu1RgsHhqP3rVH2+sM81bpk+Qd2XaHTl8LtX5/1LNR7QVBFBCpAoiXwjTdGnI5cMdBVi7Z1pi52euW760Fw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.55':
resolution: {integrity: sha512-QbNncvqAXziya5wleI+OJvmceEE15vE4yn4qfbI/hwT/+8ZcqxyfRZOOh62KjisXxp4D0h3JZspycXYejxAU3w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.57':
+ resolution: {integrity: sha512-d0kIVezTQtazpyWjiJIn5to8JlwfKITDqwsFv0Xc6s31N16CD2PC/Pl2OtKgS7n8WLOJbfqgIp5ixYzTAxCqMg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.55':
resolution: {integrity: sha512-YZCTZZM+rujxwVc6A+QZaNMJXVtmabmFYLG2VGQTKaBfYGvBKUgtbMEttnp/oZ88BMi2DzadBVhOmfQV8SuHhw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.57':
+ resolution: {integrity: sha512-E199LPijo98yrLjPCmETx8EF43sZf9t3guSrLee/ej1rCCc3zDVTR4xFfN9BRAapGVl7/8hYqbbiQPTkv73kUg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
'@rolldown/binding-linux-x64-musl@1.0.0-beta.55':
resolution: {integrity: sha512-28q9OQ/DDpFh2keS4BVAlc3N65/wiqKbk5K1pgLdu/uWbKa8hgUJofhXxqO+a+Ya2HVTUuYHneWsI2u+eu3N5Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.57':
+ resolution: {integrity: sha512-++EQDpk/UJ33kY/BNsh7A7/P1sr/jbMuQ8cE554ZIy+tCUWCivo9zfyjDUoiMdnxqX6HLJEqqGnbGQOvzm2OMQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
'@rolldown/binding-openharmony-arm64@1.0.0-beta.55':
resolution: {integrity: sha512-LiCA4BjCnm49B+j1lFzUtlC+4ZphBv0d0g5VqrEJua/uyv9Ey1v9tiaMql1C8c0TVSNDUmrkfHQ71vuQC7YfpQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
+ '@rolldown/binding-openharmony-arm64@1.0.0-beta.57':
+ resolution: {integrity: sha512-voDEBcNqxbUv/GeXKFtxXVWA+H45P/8Dec4Ii/SbyJyGvCqV1j+nNHfnFUIiRQ2Q40DwPe/djvgYBs9PpETiMA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
'@rolldown/binding-wasm32-wasi@1.0.0-beta.55':
resolution: {integrity: sha512-nZ76tY7T0Oe8vamz5Cv5CBJvrqeQxwj1WaJ2GxX8Msqs0zsQMMcvoyxOf0glnJlxxgKjtoBxAOxaAU8ERbW6Tg==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.57':
+ resolution: {integrity: sha512-bRhcF7NLlCnpkzLVlVhrDEd0KH22VbTPkPTbMjlYvqhSmarxNIq5vtlQS8qmV7LkPKHrNLWyJW/V/sOyFba26Q==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.55':
resolution: {integrity: sha512-TFVVfLfhL1G+pWspYAgPK/FSqjiBtRKYX9hixfs508QVEZPQlubYAepHPA7kEa6lZXYj5ntzF87KC6RNhxo+ew==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.57':
+ resolution: {integrity: sha512-rnDVGRks2FQ2hgJ2g15pHtfxqkGFGjJQUDWzYznEkE8Ra2+Vag9OffxdbJMZqBWXHVM0iS4dv8qSiEn7bO+n1Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.55':
resolution: {integrity: sha512-j1WBlk0p+ISgLzMIgl0xHp1aBGXenoK2+qWYc/wil2Vse7kVOdFq9aeQ8ahK6/oxX2teQ5+eDvgjdywqTL+daA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.57':
+ resolution: {integrity: sha512-OqIUyNid1M4xTj6VRXp/Lht/qIP8fo25QyAZlCP+p6D2ATCEhyW4ZIFLnC9zAGN/HMbXoCzvwfa8Jjg/8J4YEg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@rolldown/pluginutils@1.0.0-beta.55':
resolution: {integrity: sha512-vajw/B3qoi7aYnnD4BQ4VoCcXQWnF0roSwE2iynbNxgW4l9mFwtLmLmUhpDdcTBfKyZm1p/T0D13qG94XBLohA==}
+ '@rolldown/pluginutils@1.0.0-beta.57':
+ resolution: {integrity: sha512-aQNelgx14tGA+n2tNSa9x6/jeoCL9fkDeCei7nOKnHx0fEFRRMu5ReiITo+zZD5TzWDGGRjbSYCs93IfRIyTuQ==}
+
'@rollup/rollup-android-arm-eabi@4.54.0':
resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==}
cpu: [arm]
@@ -1065,18 +1161,28 @@ packages:
resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
- '@sinclair/typebox@0.34.41':
- resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==}
+ '@sinclair/typebox@0.34.45':
+ resolution: {integrity: sha512-qJcFVfCa5jxBFSuv7S5WYbA8XdeCPmhnaVVfX/2Y6L8WYg8sk3XY2+6W0zH+3mq1Cz+YC7Ki66HfqX6IHAwnkg==}
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
- '@thi.ng/bitstream@2.4.36':
- resolution: {integrity: sha512-ACdNVjFEQSWKRj/BekNggXVBZgnUnLjmwg7nPL1DKdGZ3IlZl8lz48ETHi2c1bFJxFIbFqkoEFk4yNj2tPvuNA==}
+ '@testing-library/dom@10.4.1':
+ resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
engines: {node: '>=18'}
- '@thi.ng/errors@2.5.50':
- resolution: {integrity: sha512-81I9IHwrCAHpfzEVMaJQpRYaq87MvIXi7YQ/wccKSxtiaz4IpB8dz3zwds33Oy9g+v+6nQbahZ02+syhKFYSXQ==}
+ '@testing-library/user-event@14.6.1':
+ resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==}
+ engines: {node: '>=12', npm: '>=6'}
+ peerDependencies:
+ '@testing-library/dom': '>=7.21.4'
+
+ '@thi.ng/bitstream@2.4.37':
+ resolution: {integrity: sha512-ghVt+/73cChlhHDNQH9+DnxvoeVYYBu7AYsS0Gvwq25fpCa4LaqnEk5LAJfsY043HInwcV7/0KGO7P+XZCzumQ==}
+ engines: {node: '>=18'}
+
+ '@thi.ng/errors@2.6.0':
+ resolution: {integrity: sha512-wBfSWz81sqM1FWX2ucW9KGLSFzGvsBxwX5y5t6Oty0QWO9mY8JIZC+ZBPzX5E6ExZiuGIgM8NtkTboTnXXlfUQ==}
engines: {node: '>=18'}
'@tokenizer/inflate@0.4.1':
@@ -1089,6 +1195,9 @@ packages:
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+ '@types/aria-query@5.0.4':
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+
'@types/body-parser@1.19.6':
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
@@ -1155,6 +1264,22 @@ packages:
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+ '@vitest/browser-playwright@4.0.16':
+ resolution: {integrity: sha512-I2Fy/ANdphi1yI46d15o0M1M4M0UJrUiVKkH5oKeRZZCdPg0fw/cfTKZzv9Ge9eobtJYp4BGblMzXdXH0vcl5g==}
+ peerDependencies:
+ playwright: '*'
+ vitest: 4.0.16
+
+ '@vitest/browser-preview@4.0.16':
+ resolution: {integrity: sha512-dfxJs4D5qSst4zY25txsklu0ZGPSQUhCq4VUuO2aOYtOO5+2EH7Dil37BTf1PG6DDdM8kF8NjAvnvZfsE2uzAQ==}
+ peerDependencies:
+ vitest: 4.0.16
+
+ '@vitest/browser@4.0.16':
+ resolution: {integrity: sha512-t4toy8X/YTnjYEPoY0pbDBg3EvDPg1elCDrfc+VupPHwoN/5/FNQ8Z+xBYIaEnOE2vVEyKwqYBzZ9h9rJtZVcg==}
+ peerDependencies:
+ vitest: 4.0.16
+
'@vitest/coverage-v8@4.0.16':
resolution: {integrity: sha512-2rNdjEIsPRzsdu6/9Eq0AYAzYdpP6Bx9cje9tL3FE5XzXRQF1fNU9pe/1yE8fCrS0HD+fBtt6gLPh6LI57tX7A==}
peerDependencies:
@@ -1270,6 +1395,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
@@ -1284,12 +1413,15 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
- ast-v8-to-istanbul@0.3.9:
- resolution: {integrity: sha512-dSC6tJeOJxbZrPzPbv5mMd6CMiQ1ugaVXXPRad2fXUSsy1kstFn9XQWemV9VW7Y7kpxgQ/4WMoZfwdH8XSU48w==}
+ ast-v8-to-istanbul@0.3.10:
+ resolution: {integrity: sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==}
async-mutex@0.5.0:
resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==}
@@ -1370,8 +1502,8 @@ packages:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
- chai@6.2.1:
- resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==}
+ chai@6.2.2:
+ resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
chalk@4.1.2:
@@ -1481,6 +1613,10 @@ packages:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
+ 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'}
@@ -1502,6 +1638,9 @@ packages:
docx-preview@0.3.7:
resolution: {integrity: sha512-Lav69CTA/IYZPJTsKH7oYeoZjyg96N0wEJMNslGJnZJ+dMUZK85Lt5ASC79yUlD48ecWjuv+rkcmFt6EVPV0Xg==}
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
dotenv@17.2.3:
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
engines: {node: '>=12'}
@@ -1599,8 +1738,8 @@ packages:
fast-uri@3.1.0:
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
- fastq@1.19.1:
- resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+ fastq@1.20.1:
+ resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
@@ -1615,8 +1754,8 @@ packages:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
- file-type@21.1.1:
- resolution: {integrity: sha512-ifJXo8zUqbQ/bLbl9sFoqHNTNWbnPY1COImFfM6CCy7z+E+jC1eY9YfOKkx0fckIg+VljAy2/87T61fp0+eEkg==}
+ file-type@21.2.0:
+ resolution: {integrity: sha512-vCYBgFOrJQLoTzDyAXAL/RFfKnXXpUYt4+tipVy26nJJhT7ftgGETf2tAQF59EEL61i3MrorV/PG6tf7LJK7eg==}
engines: {node: '>=20'}
fill-range@7.1.1:
@@ -1643,6 +1782,11 @@ packages:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -1833,6 +1977,9 @@ packages:
js-base64@3.7.8:
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
@@ -1946,14 +2093,14 @@ packages:
linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
- lit-element@4.2.1:
- resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==}
+ lit-element@4.2.2:
+ resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==}
- lit-html@3.3.1:
- resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==}
+ lit-html@3.3.2:
+ resolution: {integrity: sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==}
- lit@3.3.1:
- resolution: {integrity: sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==}
+ lit@3.3.2:
+ resolution: {integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==}
lodash.snakecase@4.1.1:
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
@@ -1980,6 +2127,10 @@ packages:
lucide@0.562.0:
resolution: {integrity: sha512-k1Fb8ZMnRQovWRlea7Jr0b9UKA29IM7/cu79+mJrhVohvA2YC/Ti3Sk+G+h/SIu3IlrKT4RAbWMHUBBQd1O6XA==}
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
magic-bytes.js@1.12.1:
resolution: {integrity: sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==}
@@ -2056,6 +2207,10 @@ packages:
mpg123-decoder@1.0.3:
resolution: {integrity: sha512-+fjxnWigodWJm3+4pndi+KUg9TBojgn31DPk85zEsim7C6s0X5Ztc/hQYdytXkwuGXH+aB0/aEkG40Emukv6oQ==}
+ mrmime@2.0.1:
+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+ engines: {node: '>=10'}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -2148,8 +2303,8 @@ packages:
resolution: {integrity: sha512-LDDSIu5J/4D4gFUuQQIEQpAC6maNEbMg4nC8JL/+Pe0cUDR86dtVZ09E2x5MwCh8f9yfktoaxt5x6UIVyzrajg==}
hasBin: true
- oxlint@1.35.0:
- resolution: {integrity: sha512-QDX1aUgaiqznkGfTM2qHwva2wtKqhVoqPSVXrnPz+yLUhlNadikD3QRuRtppHl7WGuy3wG6nKAuR8lash3aWSg==}
+ oxlint@1.36.0:
+ resolution: {integrity: sha512-IicUdXfXgI8OKrDPnoSjvBfeEF8PkKtm+CoLlg4LYe4ypc8U+T4r7730XYshdBGZdelg+JRw8GtCb2w/KaaZvw==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -2230,19 +2385,36 @@ packages:
resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==}
hasBin: true
+ pixelmatch@7.1.0:
+ resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==}
+ hasBin: true
+
playwright-core@1.57.0:
resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==}
engines: {node: '>=18'}
hasBin: true
+ playwright@1.57.0:
+ resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
+ pngjs@7.0.0:
+ resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==}
+ engines: {node: '>=14.19.0'}
+
postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
+ pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
@@ -2283,8 +2455,8 @@ packages:
resolution: {integrity: sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==}
hasBin: true
- qs@6.14.0:
- resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+ qs@6.14.1:
+ resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==}
engines: {node: '>=0.6'}
queue-microtask@1.2.3:
@@ -2304,6 +2476,9 @@ packages:
resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
engines: {node: '>= 0.10'}
+ react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
@@ -2351,6 +2526,11 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
+ rolldown@1.0.0-beta.57:
+ resolution: {integrity: sha512-lMMxcNN71GMsSko8RyeTaFoATHkCh4IWU7pYF73ziMYjhHZWfVesC6GQ+iaJCvZmVjvgSks9Ks1aaqEkBd8udg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
rollup@4.54.0:
resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -2444,6 +2624,10 @@ packages:
simple-yenc@1.0.4:
resolution: {integrity: sha512-5gvxpSd79e9a3V4QDYUqnqxeD4HGlhCakVpb6gMnDD7lexJggSBJRBO5h52y/iJrdXRilX9UCuDaIJhSWm5OWw==}
+ sirv@3.0.2:
+ resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==}
+ engines: {node: '>=18'}
+
sonic-boom@4.2.0:
resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==}
@@ -2562,6 +2746,10 @@ packages:
resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==}
engines: {node: '>=14.16'}
+ totalist@3.0.1:
+ resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
+ engines: {node: '>=6'}
+
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@@ -2818,8 +3006,8 @@ packages:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
engines: {node: '>=10'}
- zod-to-json-schema@3.25.0:
- resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==}
+ zod-to-json-schema@3.25.1:
+ resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
peerDependencies:
zod: ^3.25 || ^4
@@ -2837,6 +3025,13 @@ snapshots:
optionalDependencies:
zod: 4.2.1
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+ optional: true
+
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.28.5': {}
@@ -2891,11 +3086,11 @@ snapshots:
'@borewit/text-codec@0.1.1': {}
- '@borewit/text-codec@0.2.0': {}
+ '@borewit/text-codec@0.2.1': {}
- '@cacheable/memory@2.0.6':
+ '@cacheable/memory@2.0.7':
dependencies:
- '@cacheable/utils': 2.3.2
+ '@cacheable/utils': 2.3.3
'@keyv/bigmap': 1.3.0(keyv@5.5.5)
hookified: 1.14.0
keyv: 5.5.5
@@ -2906,7 +3101,7 @@ snapshots:
hookified: 1.14.0
keyv: 5.5.5
- '@cacheable/utils@2.3.2':
+ '@cacheable/utils@2.3.3':
dependencies:
hashery: 1.3.0
keyv: 5.5.5
@@ -3218,22 +3413,22 @@ snapshots:
'@keyv/serialize@1.1.1': {}
- '@lit-labs/signals@0.1.3':
+ '@lit-labs/signals@0.2.0':
dependencies:
- lit: 3.3.1
+ lit: 3.3.2
signal-polyfill: 0.2.2
- '@lit-labs/ssr-dom-shim@1.4.0': {}
+ '@lit-labs/ssr-dom-shim@1.5.0': {}
'@lit/context@1.1.6':
dependencies:
- '@lit/reactive-element': 2.1.1
+ '@lit/reactive-element': 2.1.2
- '@lit/reactive-element@2.1.1':
+ '@lit/reactive-element@2.1.2':
dependencies:
- '@lit-labs/ssr-dom-shim': 1.4.0
+ '@lit-labs/ssr-dom-shim': 1.5.0
- '@mariozechner/mini-lit@0.2.1(lit@3.3.1)(tailwindcss@4.1.17)':
+ '@mariozechner/mini-lit@0.2.1(lit@3.3.2)(tailwindcss@4.1.17)':
dependencies:
'@preact/signals-core': 1.12.1
class-variance-authority: 0.7.1
@@ -3241,7 +3436,7 @@ snapshots:
highlight.js: 11.11.1
html-parse-string: 0.0.9
katex: 0.16.27
- lit: 3.3.1
+ lit: 3.3.2
lucide: 0.544.0
marked: 16.4.2
tailwind-merge: 3.4.0
@@ -3267,13 +3462,13 @@ snapshots:
'@anthropic-ai/sdk': 0.71.2(zod@4.2.1)
'@google/genai': 1.34.0
'@mistralai/mistralai': 1.10.0
- '@sinclair/typebox': 0.34.41
+ '@sinclair/typebox': 0.34.45
ajv: 8.17.1
ajv-formats: 3.0.1(ajv@8.17.1)
chalk: 5.6.2
openai: 6.10.0(ws@8.18.3)(zod@4.2.1)
partial-json: 0.1.7
- zod-to-json-schema: 3.25.0(zod@4.2.1)
+ zod-to-json-schema: 3.25.1(zod@4.2.1)
transitivePeerDependencies:
- '@modelcontextprotocol/sdk'
- bufferutil
@@ -3290,7 +3485,7 @@ snapshots:
chalk: 5.6.2
cli-highlight: 2.1.11
diff: 8.0.2
- file-type: 21.1.1
+ file-type: 21.2.0
glob: 11.1.0
jiti: 2.6.1
marked: 15.0.12
@@ -3313,9 +3508,9 @@ snapshots:
'@mistralai/mistralai@1.10.0':
dependencies:
zod: 3.25.76
- zod-to-json-schema: 3.25.0(zod@3.25.76)
+ zod-to-json-schema: 3.25.1(zod@3.25.76)
- '@napi-rs/wasm-runtime@1.1.0':
+ '@napi-rs/wasm-runtime@1.1.1':
dependencies:
'@emnapi/core': 1.7.1
'@emnapi/runtime': 1.7.1
@@ -3332,7 +3527,7 @@ snapshots:
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
- fastq: 1.19.1
+ fastq: 1.20.1
'@oxc-project/runtime@0.103.0': {}
@@ -3356,28 +3551,28 @@ snapshots:
'@oxlint-tsgolint/win32-x64@0.10.0':
optional: true
- '@oxlint/darwin-arm64@1.35.0':
+ '@oxlint/darwin-arm64@1.36.0':
optional: true
- '@oxlint/darwin-x64@1.35.0':
+ '@oxlint/darwin-x64@1.36.0':
optional: true
- '@oxlint/linux-arm64-gnu@1.35.0':
+ '@oxlint/linux-arm64-gnu@1.36.0':
optional: true
- '@oxlint/linux-arm64-musl@1.35.0':
+ '@oxlint/linux-arm64-musl@1.36.0':
optional: true
- '@oxlint/linux-x64-gnu@1.35.0':
+ '@oxlint/linux-x64-gnu@1.36.0':
optional: true
- '@oxlint/linux-x64-musl@1.35.0':
+ '@oxlint/linux-x64-musl@1.36.0':
optional: true
- '@oxlint/win32-arm64@1.35.0':
+ '@oxlint/win32-arm64@1.36.0':
optional: true
- '@oxlint/win32-x64@1.35.0':
+ '@oxlint/win32-x64@1.36.0':
optional: true
'@pinojs/redact@0.4.0': {}
@@ -3385,6 +3580,8 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
+ '@polka/url@1.0.0-next.29': {}
+
'@preact/signals-core@1.12.1': {}
'@protobufjs/aspromise@1.1.2': {}
@@ -3413,46 +3610,89 @@ snapshots:
'@rolldown/binding-android-arm64@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-android-arm64@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-darwin-arm64@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-darwin-x64@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-darwin-x64@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-freebsd-x64@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-linux-x64-musl@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-openharmony-arm64@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-openharmony-arm64@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-wasm32-wasi@1.0.0-beta.55':
dependencies:
- '@napi-rs/wasm-runtime': 1.1.0
+ '@napi-rs/wasm-runtime': 1.1.1
+ optional: true
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.57':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.1
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.57':
+ optional: true
+
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.55':
optional: true
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.57':
+ optional: true
+
'@rolldown/pluginutils@1.0.0-beta.55': {}
+ '@rolldown/pluginutils@1.0.0-beta.57': {}
+
'@rollup/rollup-android-arm-eabi@4.54.0':
optional: true
@@ -3528,16 +3768,33 @@ snapshots:
'@sapphire/snowflake@3.5.3': {}
- '@sinclair/typebox@0.34.41': {}
+ '@sinclair/typebox@0.34.45': {}
'@standard-schema/spec@1.1.0': {}
- '@thi.ng/bitstream@2.4.36':
+ '@testing-library/dom@10.4.1':
dependencies:
- '@thi.ng/errors': 2.5.50
+ '@babel/code-frame': 7.27.1
+ '@babel/runtime': 7.28.4
+ '@types/aria-query': 5.0.4
+ aria-query: 5.3.0
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ picocolors: 1.1.1
+ pretty-format: 27.5.1
optional: true
- '@thi.ng/errors@2.5.50':
+ '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)':
+ dependencies:
+ '@testing-library/dom': 10.4.1
+ optional: true
+
+ '@thi.ng/bitstream@2.4.37':
+ dependencies:
+ '@thi.ng/errors': 2.6.0
+ optional: true
+
+ '@thi.ng/errors@2.6.0':
optional: true
'@tokenizer/inflate@0.4.1':
@@ -3554,6 +3811,9 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@types/aria-query@5.0.4':
+ optional: true
+
'@types/body-parser@1.19.6':
dependencies:
'@types/connect': 3.4.38
@@ -3627,11 +3887,72 @@ snapshots:
dependencies:
'@types/node': 25.0.3
- '@vitest/coverage-v8@4.0.16(vitest@4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))':
+ '@vitest/browser-playwright@4.0.16(playwright@1.57.0)(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)':
+ dependencies:
+ '@vitest/browser': 4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)
+ '@vitest/mocker': 4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))
+ playwright: 1.57.0
+ tinyrainbow: 3.0.3
+ vitest: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - bufferutil
+ - msw
+ - utf-8-validate
+ - vite
+
+ '@vitest/browser-preview@4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)':
+ dependencies:
+ '@testing-library/dom': 10.4.1
+ '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1)
+ '@vitest/browser': 4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)
+ vitest: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - bufferutil
+ - msw
+ - utf-8-validate
+ - vite
+ optional: true
+
+ '@vitest/browser@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)':
+ dependencies:
+ '@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/utils': 4.0.16
+ magic-string: 0.30.21
+ pixelmatch: 7.1.0
+ pngjs: 7.0.0
+ sirv: 3.0.2
+ tinyrainbow: 3.0.3
+ vitest: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ ws: 8.18.3
+ transitivePeerDependencies:
+ - bufferutil
+ - msw
+ - utf-8-validate
+ - vite
+ optional: true
+
+ '@vitest/browser@4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)':
+ dependencies:
+ '@vitest/mocker': 4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))
+ '@vitest/utils': 4.0.16
+ magic-string: 0.30.21
+ pixelmatch: 7.1.0
+ pngjs: 7.0.0
+ sirv: 3.0.2
+ tinyrainbow: 3.0.3
+ vitest: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ ws: 8.18.3
+ transitivePeerDependencies:
+ - bufferutil
+ - msw
+ - utf-8-validate
+ - vite
+
+ '@vitest/coverage-v8@4.0.16(@vitest/browser@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16))(vitest@4.0.16)':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.16
- ast-v8-to-istanbul: 0.3.9
+ ast-v8-to-istanbul: 0.3.10
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
@@ -3640,7 +3961,9 @@ snapshots:
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ vitest: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ optionalDependencies:
+ '@vitest/browser': 4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)
transitivePeerDependencies:
- supports-color
@@ -3650,7 +3973,7 @@ snapshots:
'@types/chai': 5.2.3
'@vitest/spy': 4.0.16
'@vitest/utils': 4.0.16
- chai: 6.2.1
+ chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))':
@@ -3661,6 +3984,14 @@ snapshots:
optionalDependencies:
vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
+ '@vitest/mocker@4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))':
+ dependencies:
+ '@vitest/spy': 4.0.16
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ optionalDependencies:
+ vite: 8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)
+
'@vitest/pretty-format@4.0.16':
dependencies:
tinyrainbow: 3.0.3
@@ -3769,6 +4100,9 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ ansi-styles@5.2.0:
+ optional: true
+
ansi-styles@6.2.3: {}
any-promise@1.3.0: {}
@@ -3780,9 +4114,14 @@ snapshots:
argparse@2.0.1: {}
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+ optional: true
+
assertion-error@2.0.1: {}
- ast-v8-to-istanbul@0.3.9:
+ ast-v8-to-istanbul@0.3.10:
dependencies:
'@jridgewell/trace-mapping': 0.3.31
estree-walker: 3.0.3
@@ -3830,7 +4169,7 @@ snapshots:
http-errors: 2.0.1
iconv-lite: 0.7.1
on-finished: 2.4.1
- qs: 6.14.0
+ qs: 6.14.1
raw-body: 3.0.2
type-is: 2.0.1
transitivePeerDependencies:
@@ -3865,8 +4204,8 @@ snapshots:
cacheable@2.3.1:
dependencies:
- '@cacheable/memory': 2.0.6
- '@cacheable/utils': 2.3.2
+ '@cacheable/memory': 2.0.7
+ '@cacheable/utils': 2.3.3
hookified: 1.14.0
keyv: 5.5.5
qified: 0.5.3
@@ -3881,7 +4220,7 @@ snapshots:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
- chai@6.2.1: {}
+ chai@6.2.2: {}
chalk@4.1.2:
dependencies:
@@ -3982,6 +4321,9 @@ snapshots:
depd@2.0.0: {}
+ dequal@2.0.3:
+ optional: true
+
detect-libc@2.1.2: {}
devtools-protocol@0.0.1561482: {}
@@ -4013,6 +4355,9 @@ snapshots:
dependencies:
jszip: 3.10.1
+ dom-accessibility-api@0.5.16:
+ optional: true
+
dotenv@17.2.3: {}
dunder-proto@1.0.1:
@@ -4116,7 +4461,7 @@ snapshots:
once: 1.4.0
parseurl: 1.3.3
proxy-addr: 2.0.7
- qs: 6.14.0
+ qs: 6.14.1
range-parser: 1.2.1
router: 2.2.0
send: 1.2.1
@@ -4141,7 +4486,7 @@ snapshots:
fast-uri@3.1.0: {}
- fastq@1.19.1:
+ fastq@1.20.1:
dependencies:
reusify: 1.1.0
@@ -4154,7 +4499,7 @@ snapshots:
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
- file-type@21.1.1:
+ file-type@21.2.0:
dependencies:
'@tokenizer/inflate': 0.4.1
strtok3: 10.3.4
@@ -4191,6 +4536,9 @@ snapshots:
fresh@2.0.0: {}
+ fsevents@2.3.2:
+ optional: true
+
fsevents@2.3.3:
optional: true
@@ -4402,6 +4750,9 @@ snapshots:
js-base64@3.7.8: {}
+ js-tokens@4.0.0:
+ optional: true
+
js-tokens@9.0.1: {}
json-bigint@1.0.0:
@@ -4502,21 +4853,21 @@ snapshots:
dependencies:
uc.micro: 2.1.0
- lit-element@4.2.1:
+ lit-element@4.2.2:
dependencies:
- '@lit-labs/ssr-dom-shim': 1.4.0
- '@lit/reactive-element': 2.1.1
- lit-html: 3.3.1
+ '@lit-labs/ssr-dom-shim': 1.5.0
+ '@lit/reactive-element': 2.1.2
+ lit-html: 3.3.2
- lit-html@3.3.1:
+ lit-html@3.3.2:
dependencies:
'@types/trusted-types': 2.0.7
- lit@3.3.1:
+ lit@3.3.2:
dependencies:
- '@lit/reactive-element': 2.1.1
- lit-element: 4.2.1
- lit-html: 3.3.1
+ '@lit/reactive-element': 2.1.2
+ lit-element: 4.2.2
+ lit-html: 3.3.2
lodash.snakecase@4.1.1: {}
@@ -4534,6 +4885,9 @@ snapshots:
lucide@0.562.0: {}
+ lz-string@1.5.0:
+ optional: true
+
magic-bytes.js@1.12.1: {}
magic-string@0.30.21:
@@ -4601,15 +4955,17 @@ snapshots:
'@wasm-audio-decoders/common': 9.0.7
optional: true
+ mrmime@2.0.1: {}
+
ms@2.1.3: {}
music-metadata@11.10.3:
dependencies:
- '@borewit/text-codec': 0.2.0
+ '@borewit/text-codec': 0.2.1
'@tokenizer/token': 0.3.0
content-type: 1.0.5
debug: 4.4.3
- file-type: 21.1.1
+ file-type: 21.2.0
media-typer: 1.1.0
strtok3: 10.3.4
token-types: 6.1.1
@@ -4691,16 +5047,16 @@ snapshots:
'@oxlint-tsgolint/win32-arm64': 0.10.0
'@oxlint-tsgolint/win32-x64': 0.10.0
- oxlint@1.35.0(oxlint-tsgolint@0.10.0):
+ oxlint@1.36.0(oxlint-tsgolint@0.10.0):
optionalDependencies:
- '@oxlint/darwin-arm64': 1.35.0
- '@oxlint/darwin-x64': 1.35.0
- '@oxlint/linux-arm64-gnu': 1.35.0
- '@oxlint/linux-arm64-musl': 1.35.0
- '@oxlint/linux-x64-gnu': 1.35.0
- '@oxlint/linux-x64-musl': 1.35.0
- '@oxlint/win32-arm64': 1.35.0
- '@oxlint/win32-x64': 1.35.0
+ '@oxlint/darwin-arm64': 1.36.0
+ '@oxlint/darwin-x64': 1.36.0
+ '@oxlint/linux-arm64-gnu': 1.36.0
+ '@oxlint/linux-arm64-musl': 1.36.0
+ '@oxlint/linux-x64-gnu': 1.36.0
+ '@oxlint/linux-x64-musl': 1.36.0
+ '@oxlint/win32-arm64': 1.36.0
+ '@oxlint/win32-x64': 1.36.0
oxlint-tsgolint: 0.10.0
p-queue@9.0.1:
@@ -4770,16 +5126,35 @@ snapshots:
sonic-boom: 4.2.0
thread-stream: 3.1.0
+ pixelmatch@7.1.0:
+ dependencies:
+ pngjs: 7.0.0
+
playwright-core@1.57.0: {}
+ playwright@1.57.0:
+ dependencies:
+ playwright-core: 1.57.0
+ optionalDependencies:
+ fsevents: 2.3.2
+
pluralize@8.0.0: {}
+ pngjs@7.0.0: {}
+
postcss@8.5.6:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
+ pretty-format@27.5.1:
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+ optional: true
+
process-nextick-args@2.0.1: {}
process-warning@5.0.0: {}
@@ -4836,12 +5211,12 @@ snapshots:
qoa-format@1.0.1:
dependencies:
- '@thi.ng/bitstream': 2.4.36
+ '@thi.ng/bitstream': 2.4.37
optional: true
qrcode-terminal@0.12.0: {}
- qs@6.14.0:
+ qs@6.14.1:
dependencies:
side-channel: 1.1.0
@@ -4877,6 +5252,9 @@ snapshots:
iconv-lite: 0.7.1
unpipe: 1.0.0
+ react-is@17.0.2:
+ optional: true
+
readable-stream@2.3.8:
dependencies:
core-util-is: 1.0.3
@@ -4936,6 +5314,25 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.55
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.55
+ rolldown@1.0.0-beta.57:
+ dependencies:
+ '@oxc-project/types': 0.103.0
+ '@rolldown/pluginutils': 1.0.0-beta.57
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.0-beta.57
+ '@rolldown/binding-darwin-arm64': 1.0.0-beta.57
+ '@rolldown/binding-darwin-x64': 1.0.0-beta.57
+ '@rolldown/binding-freebsd-x64': 1.0.0-beta.57
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.57
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.57
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.57
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.57
+ '@rolldown/binding-linux-x64-musl': 1.0.0-beta.57
+ '@rolldown/binding-openharmony-arm64': 1.0.0-beta.57
+ '@rolldown/binding-wasm32-wasi': 1.0.0-beta.57
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.57
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.57
+
rollup@4.54.0:
dependencies:
'@types/estree': 1.0.8
@@ -5097,6 +5494,12 @@ snapshots:
simple-yenc@1.0.4:
optional: true
+ sirv@3.0.2:
+ dependencies:
+ '@polka/url': 1.0.0-next.29
+ mrmime: 2.0.1
+ totalist: 3.0.1
+
sonic-boom@4.2.0:
dependencies:
atomic-sleep: 1.0.0
@@ -5206,6 +5609,8 @@ snapshots:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
+ totalist@3.0.1: {}
+
tr46@0.0.3: {}
ts-algebra@2.0.0: {}
@@ -5295,7 +5700,7 @@ snapshots:
tsx: 4.21.0
yaml: 2.8.2
- vitest@4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2):
+ vitest@4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/browser-preview@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@vitest/expect': 4.0.16
'@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))
@@ -5319,6 +5724,8 @@ snapshots:
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 25.0.3
+ '@vitest/browser-playwright': 4.0.16(playwright@1.57.0)(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)
+ '@vitest/browser-preview': 4.0.16(vite@8.0.0-beta.3(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.16)
transitivePeerDependencies:
- jiti
- less
@@ -5394,11 +5801,11 @@ snapshots:
y18n: 5.0.8
yargs-parser: 20.2.9
- zod-to-json-schema@3.25.0(zod@3.25.76):
+ zod-to-json-schema@3.25.1(zod@3.25.76):
dependencies:
zod: 3.25.76
- zod-to-json-schema@3.25.0(zod@4.2.1):
+ zod-to-json-schema@3.25.1(zod@4.2.1):
dependencies:
zod: 4.2.1
diff --git a/ui/package.json b/ui/package.json
index 9df8528b5..6c6e1ba95 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -5,13 +5,17 @@
"scripts": {
"dev": "vite",
"build": "vite build",
- "preview": "vite preview"
+ "preview": "vite preview",
+ "test": "vitest run --config vitest.config.ts"
},
"dependencies": {
- "lit": "^3.3.1"
+ "lit": "^3.3.2"
},
"devDependencies": {
+ "@vitest/browser-playwright": "4.0.16",
+ "playwright": "^1.57.0",
"typescript": "^5.9.3",
- "vite": "8.0.0-beta.3"
+ "vite": "8.0.0-beta.3",
+ "vitest": "4.0.16"
}
-}
\ No newline at end of file
+}
diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts
index 6558a70e8..1130954dc 100644
--- a/ui/src/ui/app-render.ts
+++ b/ui/src/ui/app-render.ts
@@ -1,7 +1,13 @@
import { html, nothing } from "lit";
import type { GatewayBrowserClient, GatewayHelloOk } from "./gateway";
-import { TAB_GROUPS, subtitleForTab, titleForTab, type Tab } from "./navigation";
+import {
+ TAB_GROUPS,
+ pathForTab,
+ subtitleForTab,
+ titleForTab,
+ type Tab,
+} from "./navigation";
import type {
ConfigSnapshot,
CronJob,
@@ -51,6 +57,7 @@ export type AppViewState = {
settings: { gatewayUrl: string; token: string; sessionKey: string };
password: string;
tab: Tab;
+ basePath: string;
connected: boolean;
hello: GatewayHelloOk | null;
lastError: string | null;
@@ -352,12 +359,27 @@ export function renderApp(state: AppViewState) {
}
function renderTab(state: AppViewState, tab: Tab) {
+ const href = pathForTab(tab, state.basePath);
return html`
-
+
`;
}
diff --git a/ui/src/ui/app.ts b/ui/src/ui/app.ts
index 4eacbb840..c206d67c9 100644
--- a/ui/src/ui/app.ts
+++ b/ui/src/ui/app.ts
@@ -4,7 +4,7 @@ import { customElement, state } from "lit/decorators.js";
import { GatewayBrowserClient, type GatewayEventFrame, type GatewayHelloOk } from "./gateway";
import { loadSettings, saveSettings, type UiSettings } from "./storage";
import { renderApp } from "./app-render";
-import type { Tab } from "./navigation";
+import { normalizePath, pathForTab, tabFromPath, type Tab } from "./navigation";
import type {
ConfigSnapshot,
CronJob,
@@ -157,6 +157,8 @@ export class ClawdisApp extends LitElement {
client: GatewayBrowserClient | null = null;
private chatScrollFrame: number | null = null;
+ basePath = "";
+ private popStateHandler = () => this.onPopState();
createRenderRoot() {
return this;
@@ -164,9 +166,17 @@ export class ClawdisApp extends LitElement {
connectedCallback() {
super.connectedCallback();
+ this.basePath = this.inferBasePath();
+ this.syncTabWithLocation(true);
+ window.addEventListener("popstate", this.popStateHandler);
this.connect();
}
+ disconnectedCallback() {
+ window.removeEventListener("popstate", this.popStateHandler);
+ super.disconnectedCallback();
+ }
+
protected updated(changed: Map) {
if (
this.tab === "chat" &&
@@ -264,8 +274,9 @@ export class ClawdisApp extends LitElement {
}
setTab(next: Tab) {
- this.tab = next;
+ if (this.tab !== next) this.tab = next;
void this.refreshActiveTab();
+ this.syncUrlWithTab(next, false);
}
private async refreshActiveTab() {
@@ -276,11 +287,54 @@ export class ClawdisApp extends LitElement {
if (this.tab === "cron") await this.loadCron();
if (this.tab === "skills") await loadSkills(this);
if (this.tab === "nodes") await loadNodes(this);
- if (this.tab === "chat") await loadChatHistory(this);
+ if (this.tab === "chat") {
+ await loadChatHistory(this);
+ this.scheduleChatScroll();
+ }
if (this.tab === "config") await loadConfig(this);
if (this.tab === "debug") await loadDebug(this);
}
+ private inferBasePath() {
+ if (typeof window === "undefined") return "";
+ const path = window.location.pathname;
+ if (path === "/ui" || path.startsWith("/ui/")) return "/ui";
+ return "";
+ }
+
+ private syncTabWithLocation(replace: boolean) {
+ if (typeof window === "undefined") return;
+ const resolved = tabFromPath(window.location.pathname, this.basePath) ?? "chat";
+ this.setTabFromRoute(resolved);
+ this.syncUrlWithTab(resolved, replace);
+ }
+
+ private onPopState() {
+ if (typeof window === "undefined") return;
+ const resolved = tabFromPath(window.location.pathname, this.basePath);
+ if (!resolved) return;
+ this.setTabFromRoute(resolved);
+ }
+
+ private setTabFromRoute(next: Tab) {
+ if (this.tab !== next) this.tab = next;
+ if (this.connected) void this.refreshActiveTab();
+ }
+
+ private syncUrlWithTab(tab: Tab, replace: boolean) {
+ if (typeof window === "undefined") return;
+ const targetPath = normalizePath(pathForTab(tab, this.basePath));
+ const currentPath = normalizePath(window.location.pathname);
+ if (currentPath === targetPath) return;
+ const url = new URL(window.location.href);
+ url.pathname = targetPath;
+ if (replace) {
+ window.history.replaceState({}, "", url.toString());
+ } else {
+ window.history.pushState({}, "", url.toString());
+ }
+ }
+
async loadOverview() {
await Promise.all([
loadProviders(this, false),
diff --git a/ui/src/ui/navigation.browser.test.ts b/ui/src/ui/navigation.browser.test.ts
new file mode 100644
index 000000000..de8dd84ec
--- /dev/null
+++ b/ui/src/ui/navigation.browser.test.ts
@@ -0,0 +1,93 @@
+import { afterEach, beforeEach, describe, expect, it } from "vitest";
+
+import { ClawdisApp } from "./app";
+
+const originalConnect = ClawdisApp.prototype.connect;
+
+function mountApp(pathname: string) {
+ window.history.replaceState({}, "", pathname);
+ const app = document.createElement("clawdis-app") as ClawdisApp;
+ document.body.append(app);
+ return app;
+}
+
+function nextFrame() {
+ return new Promise((resolve) => {
+ requestAnimationFrame(() => resolve());
+ });
+}
+
+beforeEach(() => {
+ ClawdisApp.prototype.connect = () => {
+ // no-op: avoid real gateway WS connections in browser tests
+ };
+ document.body.innerHTML = "";
+});
+
+afterEach(() => {
+ ClawdisApp.prototype.connect = originalConnect;
+ document.body.innerHTML = "";
+});
+
+describe("control UI routing", () => {
+ it("hydrates the tab from the location", async () => {
+ const app = mountApp("/sessions");
+ await app.updateComplete;
+
+ expect(app.tab).toBe("sessions");
+ expect(window.location.pathname).toBe("/sessions");
+ });
+
+ it("respects /ui base paths", async () => {
+ const app = mountApp("/ui/cron");
+ await app.updateComplete;
+
+ expect(app.basePath).toBe("/ui");
+ expect(app.tab).toBe("cron");
+ expect(window.location.pathname).toBe("/ui/cron");
+ });
+
+ it("updates the URL when clicking nav items", async () => {
+ const app = mountApp("/chat");
+ await app.updateComplete;
+
+ const link = app.querySelector(
+ 'a.nav-item[href="/connections"]',
+ );
+ expect(link).not.toBeNull();
+ link?.dispatchEvent(
+ new MouseEvent("click", { bubbles: true, cancelable: true, button: 0 }),
+ );
+
+ await app.updateComplete;
+ expect(app.tab).toBe("connections");
+ expect(window.location.pathname).toBe("/connections");
+ });
+
+ it("auto-scrolls chat history to the latest message", async () => {
+ const app = mountApp("/chat");
+ await app.updateComplete;
+
+ const initialContainer = app.querySelector(".messages") as HTMLElement | null;
+ expect(initialContainer).not.toBeNull();
+ if (!initialContainer) return;
+ initialContainer.style.maxHeight = "180px";
+ initialContainer.style.overflow = "auto";
+
+ app.chatMessages = Array.from({ length: 60 }, (_, index) => ({
+ role: "assistant",
+ content: `Line ${index} - ${"x".repeat(200)}`,
+ timestamp: Date.now() + index,
+ }));
+
+ await app.updateComplete;
+ await nextFrame();
+
+ const container = app.querySelector(".messages") as HTMLElement | null;
+ expect(container).not.toBeNull();
+ if (!container) return;
+ const maxScroll = container.scrollHeight - container.clientHeight;
+ expect(maxScroll).toBeGreaterThan(0);
+ expect(container.scrollTop).toBe(maxScroll);
+ });
+});
diff --git a/ui/src/ui/navigation.ts b/ui/src/ui/navigation.ts
index 6e74791d6..77ac49571 100644
--- a/ui/src/ui/navigation.ts
+++ b/ui/src/ui/navigation.ts
@@ -20,6 +20,64 @@ export type Tab =
| "config"
| "debug";
+const TAB_PATHS: Record = {
+ overview: "/overview",
+ connections: "/connections",
+ instances: "/instances",
+ sessions: "/sessions",
+ cron: "/cron",
+ skills: "/skills",
+ nodes: "/nodes",
+ chat: "/chat",
+ config: "/config",
+ debug: "/debug",
+};
+
+const PATH_TO_TAB = new Map(
+ Object.entries(TAB_PATHS).map(([tab, path]) => [path, tab as Tab]),
+);
+
+function normalizeBasePath(basePath: string): string {
+ if (!basePath) return "";
+ let base = basePath.trim();
+ if (!base.startsWith("/")) base = `/${base}`;
+ if (base === "/") return "";
+ if (base.endsWith("/")) base = base.slice(0, -1);
+ return base;
+}
+
+export function normalizePath(path: string): string {
+ if (!path) return "/";
+ let normalized = path.trim();
+ if (!normalized.startsWith("/")) normalized = `/${normalized}`;
+ if (normalized.length > 1 && normalized.endsWith("/")) {
+ normalized = normalized.slice(0, -1);
+ }
+ return normalized;
+}
+
+export function pathForTab(tab: Tab, basePath = ""): string {
+ const base = normalizeBasePath(basePath);
+ const path = TAB_PATHS[tab];
+ return base ? `${base}${path}` : path;
+}
+
+export function tabFromPath(pathname: string, basePath = ""): Tab | null {
+ const base = normalizeBasePath(basePath);
+ let path = pathname || "/";
+ if (base) {
+ if (path === base) {
+ path = "/";
+ } else if (path.startsWith(`${base}/`)) {
+ path = path.slice(base.length);
+ }
+ }
+ let normalized = normalizePath(path).toLowerCase();
+ if (normalized.endsWith("/index.html")) normalized = "/";
+ if (normalized === "/") return "chat";
+ return PATH_TO_TAB.get(normalized) ?? null;
+}
+
export function titleForTab(tab: Tab) {
switch (tab) {
case "overview":
diff --git a/ui/vitest.config.ts b/ui/vitest.config.ts
new file mode 100644
index 000000000..38d7342ff
--- /dev/null
+++ b/ui/vitest.config.ts
@@ -0,0 +1,15 @@
+import { playwright } from "@vitest/browser-playwright";
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ test: {
+ include: ["src/**/*.test.ts"],
+ browser: {
+ enabled: true,
+ provider: playwright(),
+ instances: [{ browser: "chromium", name: "chromium" }],
+ headless: true,
+ ui: false,
+ },
+ },
+});